mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-06-23 08:50:56 -04:00
Merge branch 'v5-develop' of https://github.com/invoiceninja/invoiceninja into feature-inbound-email-expenses
This commit is contained in:
commit
3fc35aefe7
@ -69,3 +69,6 @@ MICROSOFT_REDIRECT_URI=
|
|||||||
APPLE_CLIENT_ID=
|
APPLE_CLIENT_ID=
|
||||||
APPLE_CLIENT_SECRET=
|
APPLE_CLIENT_SECRET=
|
||||||
APPLE_REDIRECT_URI=
|
APPLE_REDIRECT_URI=
|
||||||
|
|
||||||
|
NORDIGEN_SECRET_ID=
|
||||||
|
NORDIGEN_SECRET_KEY=
|
||||||
|
@ -36,7 +36,8 @@ We offer a $30 per year white-label license to remove the Invoice Ninja branding
|
|||||||
### Desktop Apps
|
### Desktop Apps
|
||||||
* [macOS](https://apps.apple.com/app/id1503970375?platform=mac)
|
* [macOS](https://apps.apple.com/app/id1503970375?platform=mac)
|
||||||
* [Windows](https://microsoft.com/en-us/p/invoice-ninja/9n3f2bbcfdr6)
|
* [Windows](https://microsoft.com/en-us/p/invoice-ninja/9n3f2bbcfdr6)
|
||||||
* [Linux](https://snapcraft.io/invoiceninja)
|
* [Linux - Snap](https://snapcraft.io/invoiceninja)
|
||||||
|
* [Linux - Flatpak](https://flathub.org/apps/com.invoiceninja.InvoiceNinja)
|
||||||
|
|
||||||
### Installation Options
|
### Installation Options
|
||||||
* [Docker File](https://hub.docker.com/r/invoiceninja/invoiceninja/)
|
* [Docker File](https://hub.docker.com/r/invoiceninja/invoiceninja/)
|
||||||
|
@ -1 +1 @@
|
|||||||
5.7.59
|
5.7.63
|
@ -314,7 +314,7 @@ class CheckData extends Command
|
|||||||
$new_contact->client_id = $client->id;
|
$new_contact->client_id = $client->id;
|
||||||
$new_contact->contact_key = Str::random(40);
|
$new_contact->contact_key = Str::random(40);
|
||||||
$new_contact->is_primary = true;
|
$new_contact->is_primary = true;
|
||||||
$new_contact->save();
|
$new_contact->saveQuietly();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -362,7 +362,7 @@ class CheckData extends Command
|
|||||||
$new_contact->vendor_id = $vendor->id;
|
$new_contact->vendor_id = $vendor->id;
|
||||||
$new_contact->contact_key = Str::random(40);
|
$new_contact->contact_key = Str::random(40);
|
||||||
$new_contact->is_primary = true;
|
$new_contact->is_primary = true;
|
||||||
$new_contact->save();
|
$new_contact->saveQuietly();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -392,7 +392,7 @@ class CheckData extends Command
|
|||||||
$invitation->invoice_id = $invoice->id;
|
$invitation->invoice_id = $invoice->id;
|
||||||
$invitation->client_contact_id = ClientContact::whereClientId($invoice->client_id)->first()->id;
|
$invitation->client_contact_id = ClientContact::whereClientId($invoice->client_id)->first()->id;
|
||||||
$invitation->key = Str::random(config('ninja.key_length'));
|
$invitation->key = Str::random(config('ninja.key_length'));
|
||||||
$invitation->save();
|
$invitation->saveQuietly();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -583,7 +583,7 @@ class CheckData extends Command
|
|||||||
if ($this->option('paid_to_date')) {
|
if ($this->option('paid_to_date')) {
|
||||||
$this->logMessage("# {$client->id} " . $client->present()->name().' - '.$client->number." Fixing {$client->paid_to_date} to {$total_paid_to_date}");
|
$this->logMessage("# {$client->id} " . $client->present()->name().' - '.$client->number." Fixing {$client->paid_to_date} to {$total_paid_to_date}");
|
||||||
$client->paid_to_date = $total_paid_to_date;
|
$client->paid_to_date = $total_paid_to_date;
|
||||||
$client->save();
|
$client->saveQuietly();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -632,7 +632,7 @@ class CheckData extends Command
|
|||||||
if ($this->option('client_balance')) {
|
if ($this->option('client_balance')) {
|
||||||
$this->logMessage("# {$client_object->id} " . $client_object->present()->name().' - '.$client_object->number." Fixing {$client_object->balance} to " . $client['invoice_balance']);
|
$this->logMessage("# {$client_object->id} " . $client_object->present()->name().' - '.$client_object->number." Fixing {$client_object->balance} to " . $client['invoice_balance']);
|
||||||
$client_object->balance = $client['invoice_balance'];
|
$client_object->balance = $client['invoice_balance'];
|
||||||
$client_object->save();
|
$client_object->saveQuietly();
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->isValid = false;
|
$this->isValid = false;
|
||||||
@ -678,7 +678,7 @@ class CheckData extends Command
|
|||||||
$this->logMessage("# {$client->id} " . $client->present()->name().' - '.$client->number." Fixing {$client->balance} to 0");
|
$this->logMessage("# {$client->id} " . $client->present()->name().' - '.$client->number." Fixing {$client->balance} to 0");
|
||||||
|
|
||||||
$client->balance = $over_payment;
|
$client->balance = $over_payment;
|
||||||
$client->save();
|
$client->saveQuietly();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -732,7 +732,7 @@ class CheckData extends Command
|
|||||||
if ($this->option('client_balance')) {
|
if ($this->option('client_balance')) {
|
||||||
$this->logMessage("# {$client->id} " . $client->present()->name().' - '.$client->number." Fixing {$client->balance} to {$invoice_balance}");
|
$this->logMessage("# {$client->id} " . $client->present()->name().' - '.$client->number." Fixing {$client->balance} to {$invoice_balance}");
|
||||||
$client->balance = $invoice_balance;
|
$client->balance = $invoice_balance;
|
||||||
$client->save();
|
$client->saveQuietly();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($ledger && (number_format($invoice_balance, 4) != number_format($ledger->balance, 4))) {
|
if ($ledger && (number_format($invoice_balance, 4) != number_format($ledger->balance, 4))) {
|
||||||
@ -766,7 +766,7 @@ class CheckData extends Command
|
|||||||
if ($this->option('ledger_balance')) {
|
if ($this->option('ledger_balance')) {
|
||||||
$this->logMessage("# {$client->id} " . $client->present()->name().' - '.$client->number." Fixing {$client->balance} to {$invoice_balance}");
|
$this->logMessage("# {$client->id} " . $client->present()->name().' - '.$client->number." Fixing {$client->balance} to {$invoice_balance}");
|
||||||
$client->balance = $invoice_balance;
|
$client->balance = $invoice_balance;
|
||||||
$client->save();
|
$client->saveQuietly();
|
||||||
|
|
||||||
$ledger->adjustment = $invoice_balance;
|
$ledger->adjustment = $invoice_balance;
|
||||||
$ledger->balance = $invoice_balance;
|
$ledger->balance = $invoice_balance;
|
||||||
@ -884,7 +884,7 @@ class CheckData extends Command
|
|||||||
if ($this->option('fix') == 'true') {
|
if ($this->option('fix') == 'true') {
|
||||||
Client::query()->whereNull('country_id')->cursor()->each(function ($client) {
|
Client::query()->whereNull('country_id')->cursor()->each(function ($client) {
|
||||||
$client->country_id = $client->company->settings->country_id;
|
$client->country_id = $client->company->settings->country_id;
|
||||||
$client->save();
|
$client->saveQuietly();
|
||||||
|
|
||||||
$this->logMessage("Fixing country for # {$client->id}");
|
$this->logMessage("Fixing country for # {$client->id}");
|
||||||
});
|
});
|
||||||
@ -896,7 +896,7 @@ class CheckData extends Command
|
|||||||
if ($this->option('fix') == 'true') {
|
if ($this->option('fix') == 'true') {
|
||||||
Vendor::query()->whereNull('currency_id')->orWhere('currency_id', '')->cursor()->each(function ($vendor) {
|
Vendor::query()->whereNull('currency_id')->orWhere('currency_id', '')->cursor()->each(function ($vendor) {
|
||||||
$vendor->currency_id = $vendor->company->settings->currency_id;
|
$vendor->currency_id = $vendor->company->settings->currency_id;
|
||||||
$vendor->save();
|
$vendor->saveQuietly();
|
||||||
|
|
||||||
$this->logMessage("Fixing vendor currency for # {$vendor->id}");
|
$this->logMessage("Fixing vendor currency for # {$vendor->id}");
|
||||||
});
|
});
|
||||||
@ -919,14 +919,14 @@ class CheckData extends Command
|
|||||||
|
|
||||||
$invoice->balance = 0;
|
$invoice->balance = 0;
|
||||||
$invoice->paid_to_date=$val;
|
$invoice->paid_to_date=$val;
|
||||||
$invoice->save();
|
$invoice->saveQuietly();
|
||||||
|
|
||||||
$p = $invoice->payments->first();
|
$p = $invoice->payments->first();
|
||||||
|
|
||||||
if ($p && (int)$p->amount == 0) {
|
if ($p && (int)$p->amount == 0) {
|
||||||
$p->amount = $val;
|
$p->amount = $val;
|
||||||
$p->applied = $val;
|
$p->applied = $val;
|
||||||
$p->save();
|
$p->saveQuietly();
|
||||||
|
|
||||||
$pivot = $p->paymentables->first();
|
$pivot = $p->paymentables->first();
|
||||||
$pivot->amount = $val;
|
$pivot->amount = $val;
|
||||||
|
@ -100,7 +100,7 @@ class TypeCheck extends Command
|
|||||||
$entity_settings = $this->checkSettingType($client->settings);
|
$entity_settings = $this->checkSettingType($client->settings);
|
||||||
$entity_settings->md5 = md5(time());
|
$entity_settings->md5 = md5(time());
|
||||||
$client->settings = $entity_settings;
|
$client->settings = $entity_settings;
|
||||||
$client->save();
|
$client->saveQuietly();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function checkCompany($company)
|
private function checkCompany($company)
|
||||||
@ -119,7 +119,7 @@ class TypeCheck extends Command
|
|||||||
$entity_settings = $this->checkSettingType($client->settings);
|
$entity_settings = $this->checkSettingType($client->settings);
|
||||||
$entity_settings->md5 = md5(time());
|
$entity_settings->md5 = md5(time());
|
||||||
$client->settings = $entity_settings;
|
$client->settings = $entity_settings;
|
||||||
$client->save();
|
$client->saveQuietly();
|
||||||
});
|
});
|
||||||
|
|
||||||
Company::query()->cursor()->each(function ($company) {
|
Company::query()->cursor()->each(function ($company) {
|
||||||
|
@ -101,9 +101,12 @@ class Kernel extends ConsoleKernel
|
|||||||
/* Check ExpenseMainboxes */
|
/* Check ExpenseMainboxes */
|
||||||
$schedule->job(new ExpenseMailboxJob)->everyThirtyMinutes()->withoutOverlapping()->name('expense-mailboxes-job')->onOneServer();
|
$schedule->job(new ExpenseMailboxJob)->everyThirtyMinutes()->withoutOverlapping()->name('expense-mailboxes-job')->onOneServer();
|
||||||
|
|
||||||
|
/* Pulls in bank transactions from third party services */
|
||||||
|
$schedule->job(new BankTransactionSync)->everyFourHours()->withoutOverlapping()->name('bank-trans-sync-job')->onOneServer();
|
||||||
|
|
||||||
if (Ninja::isSelfHost()) {
|
if (Ninja::isSelfHost()) {
|
||||||
$schedule->call(function () {
|
$schedule->call(function () {
|
||||||
Account::whereNotNull('id')->update(['is_scheduler_running' => true]);
|
Account::query()->whereNotNull('id')->update(['is_scheduler_running' => true]);
|
||||||
})->everyFiveMinutes();
|
})->everyFiveMinutes();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,9 +114,6 @@ class Kernel extends ConsoleKernel
|
|||||||
if (Ninja::isHosted()) {
|
if (Ninja::isHosted()) {
|
||||||
$schedule->job(new AdjustEmailQuota)->dailyAt('23:30')->withoutOverlapping();
|
$schedule->job(new AdjustEmailQuota)->dailyAt('23:30')->withoutOverlapping();
|
||||||
|
|
||||||
/* Pulls in bank transactions from third party services */
|
|
||||||
$schedule->job(new BankTransactionSync)->everyFourHours()->withoutOverlapping()->name('bank-trans-sync-job')->onOneServer();
|
|
||||||
|
|
||||||
/* Checks ACH verification status and updates state to authorize when verified */
|
/* Checks ACH verification status and updates state to authorize when verified */
|
||||||
$schedule->job(new CheckACHStatus)->everySixHours()->withoutOverlapping()->name('ach-status-job')->onOneServer();
|
$schedule->job(new CheckACHStatus)->everySixHours()->withoutOverlapping()->name('ach-status-job')->onOneServer();
|
||||||
|
|
||||||
|
@ -15,6 +15,23 @@ use Illuminate\Support\Facades\App;
|
|||||||
|
|
||||||
class EmailTemplateDefaults
|
class EmailTemplateDefaults
|
||||||
{
|
{
|
||||||
|
public array $templates = [
|
||||||
|
'email_template_invoice',
|
||||||
|
'email_template_quote',
|
||||||
|
'email_template_credit',
|
||||||
|
'email_template_payment',
|
||||||
|
'email_template_payment_partial',
|
||||||
|
'email_template_statement',
|
||||||
|
'email_template_reminder1',
|
||||||
|
'email_template_reminder2',
|
||||||
|
'email_template_reminder3',
|
||||||
|
'email_template_reminder_endless',
|
||||||
|
'email_template_custom1',
|
||||||
|
'email_template_custom2',
|
||||||
|
'email_template_custom3',
|
||||||
|
'email_template_purchase_order',
|
||||||
|
];
|
||||||
|
|
||||||
public static function getDefaultTemplate($template, $locale)
|
public static function getDefaultTemplate($template, $locale)
|
||||||
{
|
{
|
||||||
App::setLocale($locale);
|
App::setLocale($locale);
|
||||||
|
@ -12,7 +12,8 @@
|
|||||||
|
|
||||||
namespace App\DataProviders;
|
namespace App\DataProviders;
|
||||||
|
|
||||||
class Domains {
|
class Domains
|
||||||
|
{
|
||||||
|
|
||||||
private static array $verify_domains = [
|
private static array $verify_domains = [
|
||||||
'0-00.usa.cc',
|
'0-00.usa.cc',
|
||||||
|
@ -181,9 +181,9 @@ class ClientExport extends BaseExport
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $entity;
|
// return $entity;
|
||||||
|
|
||||||
// return $this->decorateAdvancedFields($client, $entity);
|
return $this->decorateAdvancedFields($client, $entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function processMetaData(array $row, $resource): array
|
public function processMetaData(array $row, $resource): array
|
||||||
@ -221,21 +221,21 @@ class ClientExport extends BaseExport
|
|||||||
$entity['client.assigned_user'] = $client->assigned_user ? $client->user->present()->name() : '';
|
$entity['client.assigned_user'] = $client->assigned_user ? $client->user->present()->name() : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in_array('client.country_id', $this->input['report_keys'])) {
|
// if (in_array('client.country_id', $this->input['report_keys'])) {
|
||||||
$entity['client.country_id'] = $client->country ? ctrans("texts.country_{$client->country->name}") : '';
|
// $entity['client.country_id'] = $client->country ? ctrans("texts.country_{$client->country->name}") : '';
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('client.shipping_country_id', $this->input['report_keys'])) {
|
// if (in_array('client.shipping_country_id', $this->input['report_keys'])) {
|
||||||
$entity['client.shipping_country_id'] = $client->shipping_country ? ctrans("texts.country_{$client->shipping_country->name}") : '';
|
// $entity['client.shipping_country_id'] = $client->shipping_country ? ctrans("texts.country_{$client->shipping_country->name}") : '';
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('client.currency_id', $this->input['report_keys'])) {
|
// if (in_array('client.currency_id', $this->input['report_keys'])) {
|
||||||
$entity['client.currency_id'] = $client->currency() ? $client->currency()->code : $client->company->currency()->code;
|
// $entity['client.currency_id'] = $client->currency() ? $client->currency()->code : $client->company->currency()->code;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('client.industry_id', $this->input['report_keys'])) {
|
// if (in_array('client.industry_id', $this->input['report_keys'])) {
|
||||||
$entity['industry_id'] = $client->industry ? ctrans("texts.industry_{$client->industry->name}") : '';
|
// $entity['industry_id'] = $client->industry ? ctrans("texts.industry_{$client->industry->name}") : '';
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('client.classification', $this->input['report_keys']) && isset($client->classification)) {
|
if (in_array('client.classification', $this->input['report_keys']) && isset($client->classification)) {
|
||||||
$entity['client.classification'] = ctrans("texts.{$client->classification}") ?? '';
|
$entity['client.classification'] = ctrans("texts.{$client->classification}") ?? '';
|
||||||
|
@ -129,8 +129,8 @@ class ContactExport extends BaseExport
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $entity;
|
// return $entity;
|
||||||
// return $this->decorateAdvancedFields($contact->client, $entity);
|
return $this->decorateAdvancedFields($contact->client, $entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function decorateAdvancedFields(Client $client, array $entity) :array
|
private function decorateAdvancedFields(Client $client, array $entity) :array
|
||||||
@ -151,6 +151,15 @@ class ContactExport extends BaseExport
|
|||||||
$entity['industry_id'] = $client->industry ? ctrans("texts.industry_{$client->industry->name}") : '';
|
$entity['industry_id'] = $client->industry ? ctrans("texts.industry_{$client->industry->name}") : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (in_array('client.user_id', $this->input['report_keys'])) {
|
||||||
|
$entity['client.user_id'] = $client->user ? $client->user->present()->name() : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_array('client.assigned_user_id', $this->input['report_keys'])) {
|
||||||
|
$entity['client.assigned_user_id'] = $client->assigned_user ? $client->assigned_user->present()->name() : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return $entity;
|
return $entity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -161,29 +161,29 @@ class CreditExport extends BaseExport
|
|||||||
|
|
||||||
private function decorateAdvancedFields(Credit $credit, array $entity) :array
|
private function decorateAdvancedFields(Credit $credit, array $entity) :array
|
||||||
{
|
{
|
||||||
if (in_array('country_id', $this->input['report_keys'])) {
|
// if (in_array('country_id', $this->input['report_keys'])) {
|
||||||
$entity['country'] = $credit->client->country ? ctrans("texts.country_{$credit->client->country->name}") : '';
|
// $entity['country'] = $credit->client->country ? ctrans("texts.country_{$credit->client->country->name}") : '';
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('currency_id', $this->input['report_keys'])) {
|
// if (in_array('currency_id', $this->input['report_keys'])) {
|
||||||
$entity['currency_id'] = $credit->client->currency() ? $credit->client->currency()->code : $credit->company->currency()->code;
|
// $entity['currency_id'] = $credit->client->currency() ? $credit->client->currency()->code : $credit->company->currency()->code;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('invoice_id', $this->input['report_keys'])) {
|
// if (in_array('invoice_id', $this->input['report_keys'])) {
|
||||||
$entity['invoice'] = $credit->invoice ? $credit->invoice->number : '';
|
// $entity['invoice'] = $credit->invoice ? $credit->invoice->number : '';
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('client_id', $this->input['report_keys'])) {
|
// if (in_array('client_id', $this->input['report_keys'])) {
|
||||||
$entity['client'] = $credit->client->present()->name();
|
// $entity['client'] = $credit->client->present()->name();
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('status_id', $this->input['report_keys'])) {
|
// if (in_array('status_id', $this->input['report_keys'])) {
|
||||||
$entity['status'] = $credit->stringStatus($credit->status_id);
|
// $entity['status'] = $credit->stringStatus($credit->status_id);
|
||||||
}
|
// }
|
||||||
|
|
||||||
if(in_array('credit.status', $this->input['report_keys'])) {
|
// if(in_array('credit.status', $this->input['report_keys'])) {
|
||||||
$entity['credit.status'] = $credit->stringStatus($credit->status_id);
|
// $entity['credit.status'] = $credit->stringStatus($credit->status_id);
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('credit.assigned_user_id', $this->input['report_keys'])) {
|
if (in_array('credit.assigned_user_id', $this->input['report_keys'])) {
|
||||||
$entity['credit.assigned_user_id'] = $credit->assigned_user ? $credit->assigned_user->present()->name(): '';
|
$entity['credit.assigned_user_id'] = $credit->assigned_user ? $credit->assigned_user->present()->name(): '';
|
||||||
|
@ -126,35 +126,35 @@ class ExpenseExport extends BaseExport
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $entity;
|
// return $entity;
|
||||||
// return $this->decorateAdvancedFields($expense, $entity);
|
return $this->decorateAdvancedFields($expense, $entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function decorateAdvancedFields(Expense $expense, array $entity) :array
|
private function decorateAdvancedFields(Expense $expense, array $entity) :array
|
||||||
{
|
{
|
||||||
if (in_array('expense.currency_id', $this->input['report_keys'])) {
|
// if (in_array('expense.currency_id', $this->input['report_keys'])) {
|
||||||
$entity['expense.currency_id'] = $expense->currency ? $expense->currency->code : '';
|
// $entity['expense.currency_id'] = $expense->currency ? $expense->currency->code : '';
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('expense.client_id', $this->input['report_keys'])) {
|
// if (in_array('expense.client_id', $this->input['report_keys'])) {
|
||||||
$entity['expense.client'] = $expense->client ? $expense->client->present()->name() : '';
|
// $entity['expense.client'] = $expense->client ? $expense->client->present()->name() : '';
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('expense.invoice_id', $this->input['report_keys'])) {
|
// if (in_array('expense.invoice_id', $this->input['report_keys'])) {
|
||||||
$entity['expense.invoice_id'] = $expense->invoice ? $expense->invoice->number : '';
|
// $entity['expense.invoice_id'] = $expense->invoice ? $expense->invoice->number : '';
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('expense.category', $this->input['report_keys'])) {
|
// if (in_array('expense.category', $this->input['report_keys'])) {
|
||||||
$entity['expense.category'] = $expense->category ? $expense->category->name : '';
|
// $entity['expense.category'] = $expense->category ? $expense->category->name : '';
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('expense.vendor_id', $this->input['report_keys'])) {
|
// if (in_array('expense.vendor_id', $this->input['report_keys'])) {
|
||||||
$entity['expense.vendor'] = $expense->vendor ? $expense->vendor->name : '';
|
// $entity['expense.vendor'] = $expense->vendor ? $expense->vendor->name : '';
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('expense.payment_type_id', $this->input['report_keys'])) {
|
// if (in_array('expense.payment_type_id', $this->input['report_keys'])) {
|
||||||
$entity['expense.payment_type_id'] = $expense->payment_type ? $expense->payment_type->name : '';
|
// $entity['expense.payment_type_id'] = $expense->payment_type ? $expense->payment_type->name : '';
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('expense.project_id', $this->input['report_keys'])) {
|
if (in_array('expense.project_id', $this->input['report_keys'])) {
|
||||||
$entity['expense.project_id'] = $expense->project ? $expense->project->name : '';
|
$entity['expense.project_id'] = $expense->project ? $expense->project->name : '';
|
||||||
|
@ -128,32 +128,32 @@ class InvoiceExport extends BaseExport
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $entity;
|
// return $entity;
|
||||||
// return $this->decorateAdvancedFields($invoice, $entity);
|
return $this->decorateAdvancedFields($invoice, $entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function decorateAdvancedFields(Invoice $invoice, array $entity) :array
|
private function decorateAdvancedFields(Invoice $invoice, array $entity) :array
|
||||||
{
|
{
|
||||||
|
|
||||||
if (in_array('invoice.country_id', $this->input['report_keys'])) {
|
// if (in_array('invoice.country_id', $this->input['report_keys'])) {
|
||||||
$entity['invoice.country_id'] = $invoice->client->country ? ctrans("texts.country_{$invoice->client->country->name}") : '';
|
// $entity['invoice.country_id'] = $invoice->client->country ? ctrans("texts.country_{$invoice->client->country->name}") : '';
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('invoice.currency_id', $this->input['report_keys'])) {
|
// if (in_array('invoice.currency_id', $this->input['report_keys'])) {
|
||||||
$entity['invoice.currency_id'] = $invoice->client->currency() ? $invoice->client->currency()->code : $invoice->company->currency()->code;
|
// $entity['invoice.currency_id'] = $invoice->client->currency() ? $invoice->client->currency()->code : $invoice->company->currency()->code;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('invoice.client_id', $this->input['report_keys'])) {
|
// if (in_array('invoice.client_id', $this->input['report_keys'])) {
|
||||||
$entity['invoice.client_id'] = $invoice->client->present()->name();
|
// $entity['invoice.client_id'] = $invoice->client->present()->name();
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('invoice.status', $this->input['report_keys'])) {
|
// if (in_array('invoice.status', $this->input['report_keys'])) {
|
||||||
$entity['invoice.status'] = $invoice->stringStatus($invoice->status_id);
|
// $entity['invoice.status'] = $invoice->stringStatus($invoice->status_id);
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('invoice.recurring_id', $this->input['report_keys'])) {
|
// if (in_array('invoice.recurring_id', $this->input['report_keys'])) {
|
||||||
$entity['invoice.recurring_id'] = $invoice->recurring_invoice->number ?? '';
|
// $entity['invoice.recurring_id'] = $invoice->recurring_invoice->number ?? '';
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('invoice.auto_bill_enabled', $this->input['report_keys'])) {
|
if (in_array('invoice.auto_bill_enabled', $this->input['report_keys'])) {
|
||||||
$entity['invoice.auto_bill_enabled'] = $invoice->auto_bill_enabled ? ctrans('texts.yes') : ctrans('texts.no');
|
$entity['invoice.auto_bill_enabled'] = $invoice->auto_bill_enabled ? ctrans('texts.yes') : ctrans('texts.no');
|
||||||
|
@ -196,43 +196,43 @@ class InvoiceItemExport extends BaseExport
|
|||||||
// $entity[$key] = $this->resolveKey($key, $invoice, $this->invoice_transformer);
|
// $entity[$key] = $this->resolveKey($key, $invoice, $this->invoice_transformer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $entity;
|
// return $entity;
|
||||||
// return $this->decorateAdvancedFields($invoice, $entity);
|
return $this->decorateAdvancedFields($invoice, $entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function decorateAdvancedFields(Invoice $invoice, array $entity) :array
|
private function decorateAdvancedFields(Invoice $invoice, array $entity) :array
|
||||||
{
|
{
|
||||||
if (in_array('currency_id', $this->input['report_keys'])) {
|
// if (in_array('currency_id', $this->input['report_keys'])) {
|
||||||
$entity['currency'] = $invoice->client->currency() ? $invoice->client->currency()->code : $invoice->company->currency()->code;
|
// $entity['currency'] = $invoice->client->currency() ? $invoice->client->currency()->code : $invoice->company->currency()->code;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if(array_key_exists('type', $entity)) {
|
// if(array_key_exists('type', $entity)) {
|
||||||
$entity['type'] = $invoice->typeIdString($entity['type']);
|
// $entity['type'] = $invoice->typeIdString($entity['type']);
|
||||||
}
|
// }
|
||||||
|
|
||||||
if(array_key_exists('tax_category', $entity)) {
|
// if(array_key_exists('tax_category', $entity)) {
|
||||||
$entity['tax_category'] = $invoice->taxTypeString($entity['tax_category']);
|
// $entity['tax_category'] = $invoice->taxTypeString($entity['tax_category']);
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('invoice.country_id', $this->input['report_keys'])) {
|
// if (in_array('invoice.country_id', $this->input['report_keys'])) {
|
||||||
$entity['invoice.country_id'] = $invoice->client->country ? ctrans("texts.country_{$invoice->client->country->name}") : '';
|
// $entity['invoice.country_id'] = $invoice->client->country ? ctrans("texts.country_{$invoice->client->country->name}") : '';
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('invoice.currency_id', $this->input['report_keys'])) {
|
// if (in_array('invoice.currency_id', $this->input['report_keys'])) {
|
||||||
$entity['invoice.currency_id'] = $invoice->client->currency() ? $invoice->client->currency()->code : $invoice->company->currency()->code;
|
// $entity['invoice.currency_id'] = $invoice->client->currency() ? $invoice->client->currency()->code : $invoice->company->currency()->code;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('invoice.client_id', $this->input['report_keys'])) {
|
// if (in_array('invoice.client_id', $this->input['report_keys'])) {
|
||||||
$entity['invoice.client_id'] = $invoice->client->present()->name();
|
// $entity['invoice.client_id'] = $invoice->client->present()->name();
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('invoice.status', $this->input['report_keys'])) {
|
// if (in_array('invoice.status', $this->input['report_keys'])) {
|
||||||
$entity['invoice.status'] = $invoice->stringStatus($invoice->status_id);
|
// $entity['invoice.status'] = $invoice->stringStatus($invoice->status_id);
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('invoice.recurring_id', $this->input['report_keys'])) {
|
// if (in_array('invoice.recurring_id', $this->input['report_keys'])) {
|
||||||
$entity['invoice.recurring_id'] = $invoice->recurring_invoice->number ?? '';
|
// $entity['invoice.recurring_id'] = $invoice->recurring_invoice->number ?? '';
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('invoice.assigned_user_id', $this->input['report_keys'])) {
|
if (in_array('invoice.assigned_user_id', $this->input['report_keys'])) {
|
||||||
$entity['invoice.assigned_user_id'] = $invoice->assigned_user ? $invoice->assigned_user->present()->name(): '';
|
$entity['invoice.assigned_user_id'] = $invoice->assigned_user ? $invoice->assigned_user->present()->name(): '';
|
||||||
|
@ -125,55 +125,55 @@ class PaymentExport extends BaseExport
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $entity;
|
// return $entity;
|
||||||
// return $this->decorateAdvancedFields($payment, $entity);
|
return $this->decorateAdvancedFields($payment, $entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function decorateAdvancedFields(Payment $payment, array $entity) :array
|
private function decorateAdvancedFields(Payment $payment, array $entity) :array
|
||||||
{
|
{
|
||||||
if (in_array('status_id', $this->input['report_keys'])) {
|
// if (in_array('status_id', $this->input['report_keys'])) {
|
||||||
$entity['status'] = $payment->stringStatus($payment->status_id);
|
// $entity['status'] = $payment->stringStatus($payment->status_id);
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('vendor_id', $this->input['report_keys'])) {
|
// if (in_array('vendor_id', $this->input['report_keys'])) {
|
||||||
$entity['vendor'] = $payment->vendor()->exists() ? $payment->vendor->name : '';
|
// $entity['vendor'] = $payment->vendor()->exists() ? $payment->vendor->name : '';
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('project_id', $this->input['report_keys'])) {
|
// if (in_array('project_id', $this->input['report_keys'])) {
|
||||||
$entity['project'] = $payment->project()->exists() ? $payment->project->name : '';
|
// $entity['project'] = $payment->project()->exists() ? $payment->project->name : '';
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('currency_id', $this->input['report_keys'])) {
|
// if (in_array('currency_id', $this->input['report_keys'])) {
|
||||||
$entity['currency'] = $payment->currency()->exists() ? $payment->currency->code : '';
|
// $entity['currency'] = $payment->currency()->exists() ? $payment->currency->code : '';
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('payment.currency', $this->input['report_keys'])) {
|
// if (in_array('payment.currency', $this->input['report_keys'])) {
|
||||||
$entity['payment.currency'] = $payment->currency()->exists() ? $payment->currency->code : '';
|
// $entity['payment.currency'] = $payment->currency()->exists() ? $payment->currency->code : '';
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('exchange_currency_id', $this->input['report_keys'])) {
|
// if (in_array('exchange_currency_id', $this->input['report_keys'])) {
|
||||||
$entity['exchange_currency'] = $payment->exchange_currency()->exists() ? $payment->exchange_currency->code : '';
|
// $entity['exchange_currency'] = $payment->exchange_currency()->exists() ? $payment->exchange_currency->code : '';
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('client_id', $this->input['report_keys'])) {
|
// if (in_array('client_id', $this->input['report_keys'])) {
|
||||||
$entity['client'] = $payment->client->present()->name();
|
// $entity['client'] = $payment->client->present()->name();
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('type_id', $this->input['report_keys'])) {
|
// if (in_array('type_id', $this->input['report_keys'])) {
|
||||||
$entity['type'] = $payment->translatedType();
|
// $entity['type'] = $payment->translatedType();
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('payment.method', $this->input['report_keys'])) {
|
// if (in_array('payment.method', $this->input['report_keys'])) {
|
||||||
$entity['payment.method'] = $payment->translatedType();
|
// $entity['payment.method'] = $payment->translatedType();
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('payment.status', $this->input['report_keys'])) {
|
// if (in_array('payment.status', $this->input['report_keys'])) {
|
||||||
$entity['payment.status'] = $payment->stringStatus($payment->status_id);
|
// $entity['payment.status'] = $payment->stringStatus($payment->status_id);
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('gateway_type_id', $this->input['report_keys'])) {
|
// if (in_array('gateway_type_id', $this->input['report_keys'])) {
|
||||||
$entity['gateway'] = $payment->gateway_type ? $payment->gateway_type->name : 'Unknown Type';
|
// $entity['gateway'] = $payment->gateway_type ? $payment->gateway_type->name : 'Unknown Type';
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('payment.assigned_user_id', $this->input['report_keys'])) {
|
if (in_array('payment.assigned_user_id', $this->input['report_keys'])) {
|
||||||
$entity['payment.assigned_user_id'] = $payment->assigned_user ? $payment->assigned_user->present()->name() : '';
|
$entity['payment.assigned_user_id'] = $payment->assigned_user ? $payment->assigned_user->present()->name() : '';
|
||||||
|
@ -173,8 +173,8 @@ class PurchaseOrderExport extends BaseExport
|
|||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return $entity;
|
// return $entity;
|
||||||
// return $this->decorateAdvancedFields($purchase_order, $entity);
|
return $this->decorateAdvancedFields($purchase_order, $entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function decorateAdvancedFields(PurchaseOrder $purchase_order, array $entity) :array
|
private function decorateAdvancedFields(PurchaseOrder $purchase_order, array $entity) :array
|
||||||
@ -195,6 +195,15 @@ class PurchaseOrderExport extends BaseExport
|
|||||||
$entity['purchase_order.status'] = $purchase_order->stringStatus($purchase_order->status_id);
|
$entity['purchase_order.status'] = $purchase_order->stringStatus($purchase_order->status_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (in_array('purchase_order.user_id', $this->input['report_keys'])) {
|
||||||
|
$entity['purchase_order.user_id'] = $purchase_order->user ? $purchase_order->user->present()->name() : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_array('purchase_order.assigned_user_id', $this->input['report_keys'])) {
|
||||||
|
$entity['purchase_order.assigned_user_id'] = $purchase_order->assigned_user ? $purchase_order->assigned_user->present()->name() : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return $entity;
|
return $entity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -206,6 +206,16 @@ class PurchaseOrderItemExport extends BaseExport
|
|||||||
$entity['status'] = $purchase_order->stringStatus($purchase_order->status_id);
|
$entity['status'] = $purchase_order->stringStatus($purchase_order->status_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (in_array('purchase_order.user_id', $this->input['report_keys'])) {
|
||||||
|
$entity['purchase_order.user_id'] = $purchase_order->user ? $purchase_order->user->present()->name() : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_array('purchase_order.assigned_user_id', $this->input['report_keys'])) {
|
||||||
|
$entity['purchase_order.assigned_user_id'] = $purchase_order->assigned_user ? $purchase_order->assigned_user->present()->name() : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return $entity;
|
return $entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,8 +133,8 @@ class QuoteExport extends BaseExport
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return $entity;
|
// return $entity;
|
||||||
// return $this->decorateAdvancedFields($quote, $entity);
|
return $this->decorateAdvancedFields($quote, $entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function decorateAdvancedFields(Quote $quote, array $entity) :array
|
private function decorateAdvancedFields(Quote $quote, array $entity) :array
|
||||||
|
@ -189,22 +189,22 @@ class QuoteItemExport extends BaseExport
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $entity;
|
// return $entity;
|
||||||
// return $this->decorateAdvancedFields($quote, $entity);
|
return $this->decorateAdvancedFields($quote, $entity);
|
||||||
}
|
}
|
||||||
private function decorateAdvancedFields(Quote $quote, array $entity) :array
|
private function decorateAdvancedFields(Quote $quote, array $entity) :array
|
||||||
{
|
{
|
||||||
if (in_array('currency_id', $this->input['report_keys'])) {
|
// if (in_array('currency_id', $this->input['report_keys'])) {
|
||||||
$entity['currency'] = $quote->client->currency() ? $quote->client->currency()->code : $quote->company->currency()->code;
|
// $entity['currency'] = $quote->client->currency() ? $quote->client->currency()->code : $quote->company->currency()->code;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('client_id', $this->input['report_keys'])) {
|
// if (in_array('client_id', $this->input['report_keys'])) {
|
||||||
$entity['client'] = $quote->client->present()->name();
|
// $entity['client'] = $quote->client->present()->name();
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('status_id', $this->input['report_keys'])) {
|
// if (in_array('status_id', $this->input['report_keys'])) {
|
||||||
$entity['status'] = $quote->stringStatus($quote->status_id);
|
// $entity['status'] = $quote->stringStatus($quote->status_id);
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('quote.assigned_user_id', $this->input['report_keys'])) {
|
if (in_array('quote.assigned_user_id', $this->input['report_keys'])) {
|
||||||
$entity['quote.assigned_user_id'] = $quote->assigned_user ? $quote->assigned_user->present()->name(): '';
|
$entity['quote.assigned_user_id'] = $quote->assigned_user ? $quote->assigned_user->present()->name(): '';
|
||||||
|
@ -109,8 +109,6 @@ class RecurringInvoiceExport extends BaseExport
|
|||||||
private function buildRow(RecurringInvoice $invoice) :array
|
private function buildRow(RecurringInvoice $invoice) :array
|
||||||
{
|
{
|
||||||
$transformed_invoice = $this->invoice_transformer->transform($invoice);
|
$transformed_invoice = $this->invoice_transformer->transform($invoice);
|
||||||
$transformed_invoice['frequency_id'] = $invoice->frequencyForKey($invoice->frequency_id); //need to inject this here because it is also a valid key
|
|
||||||
// nlog($transformed_invoice);
|
|
||||||
|
|
||||||
$entity = [];
|
$entity = [];
|
||||||
|
|
||||||
@ -131,36 +129,36 @@ class RecurringInvoiceExport extends BaseExport
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
// nlog($entity);
|
|
||||||
return $entity;
|
// return $entity;
|
||||||
// return $this->decorateAdvancedFields($invoice, $entity);
|
return $this->decorateAdvancedFields($invoice, $entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function decorateAdvancedFields(RecurringInvoice $invoice, array $entity) :array
|
private function decorateAdvancedFields(RecurringInvoice $invoice, array $entity) :array
|
||||||
{
|
{
|
||||||
if (in_array('country_id', $this->input['report_keys'])) {
|
// if (in_array('country_id', $this->input['report_keys'])) {
|
||||||
$entity['country'] = $invoice->client->country ? ctrans("texts.country_{$invoice->client->country->name}") : '';
|
// $entity['country'] = $invoice->client->country ? ctrans("texts.country_{$invoice->client->country->name}") : '';
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('currency_id', $this->input['report_keys'])) {
|
// if (in_array('currency_id', $this->input['report_keys'])) {
|
||||||
$entity['currency'] = $invoice->client->currency() ? $invoice->client->currency()->code : $invoice->company->currency()->code;
|
// $entity['currency'] = $invoice->client->currency() ? $invoice->client->currency()->code : $invoice->company->currency()->code;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('client_id', $this->input['report_keys'])) {
|
// if (in_array('client_id', $this->input['report_keys'])) {
|
||||||
$entity['client'] = $invoice->client->present()->name();
|
// $entity['client'] = $invoice->client->present()->name();
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('recurring_invoice.status', $this->input['report_keys'])) {
|
// if (in_array('recurring_invoice.status', $this->input['report_keys'])) {
|
||||||
$entity['recurring_invoice.status'] = $invoice->stringStatus($invoice->status_id);
|
// $entity['recurring_invoice.status'] = $invoice->stringStatus($invoice->status_id);
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('project_id', $this->input['report_keys'])) {
|
// if (in_array('project_id', $this->input['report_keys'])) {
|
||||||
$entity['project'] = $invoice->project ? $invoice->project->name : '';
|
// $entity['project'] = $invoice->project ? $invoice->project->name : '';
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('vendor_id', $this->input['report_keys'])) {
|
// if (in_array('vendor_id', $this->input['report_keys'])) {
|
||||||
$entity['vendor'] = $invoice->vendor ? $invoice->vendor->name : '';
|
// $entity['vendor'] = $invoice->vendor ? $invoice->vendor->name : '';
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (in_array('recurring_invoice.frequency_id', $this->input['report_keys']) || in_array('frequency_id', $this->input['report_keys'])) {
|
if (in_array('recurring_invoice.frequency_id', $this->input['report_keys']) || in_array('frequency_id', $this->input['report_keys'])) {
|
||||||
$entity['recurring_invoice.frequency_id'] = $invoice->frequencyForKey($invoice->frequency_id);
|
$entity['recurring_invoice.frequency_id'] = $invoice->frequencyForKey($invoice->frequency_id);
|
||||||
|
@ -197,7 +197,7 @@ class TaskExport extends BaseExport
|
|||||||
$entity['task.duration'] = $task->calcDuration();
|
$entity['task.duration'] = $task->calcDuration();
|
||||||
}
|
}
|
||||||
|
|
||||||
// $entity = $this->decorateAdvancedFields($task, $entity);
|
$entity = $this->decorateAdvancedFields($task, $entity);
|
||||||
|
|
||||||
$this->storage_array[] = $entity;
|
$this->storage_array[] = $entity;
|
||||||
|
|
||||||
@ -218,6 +218,15 @@ class TaskExport extends BaseExport
|
|||||||
$entity['task.project_id'] = $task->project()->exists() ? $task->project->name : '';
|
$entity['task.project_id'] = $task->project()->exists() ? $task->project->name : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (in_array('task.user_id', $this->input['report_keys'])) {
|
||||||
|
$entity['task.user_id'] = $task->user ? $task->user->present()->name() : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_array('task.assigned_user_id', $this->input['report_keys'])) {
|
||||||
|
$entity['task.assigned_user_id'] = $task->assigned_user ? $task->assigned_user->present()->name() : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return $entity;
|
return $entity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,15 +126,14 @@ class VendorExport extends BaseExport
|
|||||||
} elseif (is_array($parts) && $parts[0] == 'vendor_contact' && isset($transformed_contact[$parts[1]])) {
|
} elseif (is_array($parts) && $parts[0] == 'vendor_contact' && isset($transformed_contact[$parts[1]])) {
|
||||||
$entity[$key] = $transformed_contact[$parts[1]];
|
$entity[$key] = $transformed_contact[$parts[1]];
|
||||||
} else {
|
} else {
|
||||||
// nlog($key);
|
|
||||||
$entity[$key] = $this->decorator->transform($key, $vendor);
|
$entity[$key] = $this->decorator->transform($key, $vendor);
|
||||||
|
|
||||||
// $entity[$key] = $this->resolveKey($key, $vendor, $this->vendor_transformer);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $entity;
|
// return $entity;
|
||||||
// return $this->decorateAdvancedFields($vendor, $entity);
|
return $this->decorateAdvancedFields($vendor, $entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function decorateAdvancedFields(Vendor $vendor, array $entity) :array
|
private function decorateAdvancedFields(Vendor $vendor, array $entity) :array
|
||||||
@ -151,6 +150,15 @@ class VendorExport extends BaseExport
|
|||||||
$entity['vendor.classification'] = ctrans("texts.{$vendor->classification}") ?? '';
|
$entity['vendor.classification'] = ctrans("texts.{$vendor->classification}") ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (in_array('vendor.user_id', $this->input['report_keys'])) {
|
||||||
|
$entity['vendor.user_id'] = $vendor->user ? $vendor->user->present()->name() : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_array('vendor.assigned_user_id', $this->input['report_keys'])) {
|
||||||
|
$entity['vendor.assigned_user_id'] = $vendor->assigned_user ? $vendor->assigned_user->present()->name() : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// $entity['status'] = $this->calculateStatus($vendor);
|
// $entity['status'] = $this->calculateStatus($vendor);
|
||||||
|
|
||||||
return $entity;
|
return $entity;
|
||||||
|
@ -97,7 +97,9 @@ class BankIntegrationFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
$dir = ($sort_col[1] == 'asc') ? 'asc' : 'desc';
|
||||||
|
|
||||||
|
return $this->builder->orderBy($sort_col[0], $dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -129,12 +129,14 @@ class BankTransactionFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$dir = ($sort_col[1] == 'asc') ? 'asc' : 'desc';
|
||||||
|
|
||||||
if ($sort_col[0] == 'deposit') {
|
if ($sort_col[0] == 'deposit') {
|
||||||
return $this->builder->where('base_type', 'CREDIT')->orderBy('amount', $sort_col[1]);
|
return $this->builder->where('base_type', 'CREDIT')->orderBy('amount', $dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($sort_col[0] == 'withdrawal') {
|
if ($sort_col[0] == 'withdrawal') {
|
||||||
return $this->builder->where('base_type', 'DEBIT')->orderBy('amount', $sort_col[1]);
|
return $this->builder->where('base_type', 'DEBIT')->orderBy('amount', $dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($sort_col[0] == 'status') {
|
if ($sort_col[0] == 'status') {
|
||||||
@ -145,7 +147,7 @@ class BankTransactionFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
return $this->builder->orderBy($sort_col[0], $dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -65,7 +65,9 @@ class BankTransactionRuleFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
$dir = ($sort_col[1] == 'asc') ? 'asc' : 'desc';
|
||||||
|
|
||||||
|
return $this->builder->orderBy($sort_col[0], $dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -162,7 +162,9 @@ class ClientFilters extends QueryFilters
|
|||||||
$sort_col[0] = 'name';
|
$sort_col[0] = 'name';
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
$dir = ($sort_col[1] == 'asc') ? 'asc' : 'desc';
|
||||||
|
|
||||||
|
return $this->builder->orderBy($sort_col[0], $dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -50,7 +50,9 @@ class CompanyGatewayFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
$dir = ($sort_col[1] == 'asc') ? 'asc' : 'desc';
|
||||||
|
|
||||||
|
return $this->builder->orderBy($sort_col[0], $dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -139,12 +139,14 @@ class CreditFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$dir = ($sort_col[1] == 'asc') ? 'asc' : 'desc';
|
||||||
|
|
||||||
if ($sort_col[0] == 'client_id') {
|
if ($sort_col[0] == 'client_id') {
|
||||||
return $this->builder->orderBy(\App\Models\Client::select('name')
|
return $this->builder->orderBy(\App\Models\Client::select('name')
|
||||||
->whereColumn('clients.id', 'credits.client_id'), $sort_col[1]);
|
->whereColumn('clients.id', 'credits.client_id'), $dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
return $this->builder->orderBy($sort_col[0], $dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -51,7 +51,9 @@ class DesignFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
$dir = ($sort_col[1] == 'asc') ? 'asc' : 'desc';
|
||||||
|
|
||||||
|
return $this->builder->orderBy($sort_col[0], $dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function entities(string $entities = ''): Builder
|
public function entities(string $entities = ''): Builder
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
namespace App\Filters;
|
namespace App\Filters;
|
||||||
|
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
|
use App\Filters\QueryFilters;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -63,7 +64,9 @@ class DocumentFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
$dir = ($sort_col[1] == 'asc') ? 'asc' : 'desc';
|
||||||
|
|
||||||
|
return $this->builder->orderBy($sort_col[0], $dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -65,7 +65,9 @@ class GroupSettingFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
$dir = ($sort_col[1] == 'asc') ? 'asc' : 'desc';
|
||||||
|
|
||||||
|
return $this->builder->orderBy($sort_col[0], $dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -146,16 +146,26 @@ class InvoiceFilters extends QueryFilters
|
|||||||
*/
|
*/
|
||||||
public function upcoming(): Builder
|
public function upcoming(): Builder
|
||||||
{
|
{
|
||||||
return $this->builder->whereIn('status_id', [Invoice::STATUS_PARTIAL, Invoice::STATUS_SENT])
|
|
||||||
->whereNull('due_date')
|
return $this->builder->where(function ($query) {
|
||||||
|
$query->whereIn('status_id', [Invoice::STATUS_PARTIAL, Invoice::STATUS_SENT])
|
||||||
|
->where('is_deleted', 0)
|
||||||
|
->where('balance', '>', 0)
|
||||||
|
->where(function ($query) {
|
||||||
|
|
||||||
|
$query->whereNull('due_date')
|
||||||
->orWhere(function ($q) {
|
->orWhere(function ($q) {
|
||||||
$q->where('due_date', '>=', now()->startOfDay()->subSecond())->where('partial', 0);
|
$q->where('due_date', '>=', now()->startOfDay()->subSecond())->where('partial', 0);
|
||||||
})
|
})
|
||||||
->orWhere(function ($q) {
|
->orWhere(function ($q) {
|
||||||
$q->where('partial_due_date', '>=', now()->startOfDay()->subSecond())->where('partial', '>', 0);
|
$q->where('partial_due_date', '>=', now()->startOfDay()->subSecond())->where('partial', '>', 0);
|
||||||
|
});
|
||||||
|
|
||||||
})
|
})
|
||||||
->orderByRaw('ISNULL(due_date), due_date ' . 'desc')
|
->orderByRaw('ISNULL(due_date), due_date ' . 'desc')
|
||||||
->orderByRaw('ISNULL(partial_due_date), partial_due_date ' . 'desc');
|
->orderByRaw('ISNULL(partial_due_date), partial_due_date ' . 'desc');
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -165,13 +175,18 @@ class InvoiceFilters extends QueryFilters
|
|||||||
*/
|
*/
|
||||||
public function overdue(): Builder
|
public function overdue(): Builder
|
||||||
{
|
{
|
||||||
return $this->builder->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL])
|
return $this->builder->where(function ($query) {
|
||||||
|
|
||||||
|
$query->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL])
|
||||||
->where('is_deleted', 0)
|
->where('is_deleted', 0)
|
||||||
|
->where('balance', '>', 0)
|
||||||
->where(function ($query) {
|
->where(function ($query) {
|
||||||
$query->where('due_date', '<', now())
|
$query->where('due_date', '<', now())
|
||||||
->orWhere('partial_due_date', '<', now());
|
->orWhere('partial_due_date', '<', now());
|
||||||
})
|
})
|
||||||
->orderBy('due_date', 'ASC');
|
->orderBy('due_date', 'ASC');
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -271,14 +286,16 @@ class InvoiceFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$dir = ($sort_col[1] == 'asc') ? 'asc' : 'desc';
|
||||||
|
|
||||||
if ($sort_col[0] == 'client_id') {
|
if ($sort_col[0] == 'client_id') {
|
||||||
|
|
||||||
return $this->builder->orderBy(\App\Models\Client::select('name')
|
return $this->builder->orderBy(\App\Models\Client::select('name')
|
||||||
->whereColumn('clients.id', 'invoices.client_id'), $sort_col[1]);
|
->whereColumn('clients.id', 'invoices.client_id'), $dir);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
return $this->builder->orderBy($sort_col[0], $dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -69,9 +69,11 @@ class ProjectFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_array($sort_col)) {
|
if (is_array($sort_col) && in_array($sort_col[1], ['asc','desc'])) {
|
||||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -123,12 +123,14 @@ class PurchaseOrderFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$dir = ($sort_col[1] == 'asc') ? 'asc' : 'desc';
|
||||||
|
|
||||||
if ($sort_col[0] == 'vendor_id') {
|
if ($sort_col[0] == 'vendor_id') {
|
||||||
return $this->builder->orderBy(\App\Models\Vendor::select('name')
|
return $this->builder->orderBy(\App\Models\Vendor::select('name')
|
||||||
->whereColumn('vendors.id', 'purchase_orders.vendor_id'), $sort_col[1]);
|
->whereColumn('vendors.id', 'purchase_orders.vendor_id'), $dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
return $this->builder->orderBy($sort_col[0], $dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -146,10 +146,12 @@ class QuoteFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$dir = ($sort_col[1] == 'asc') ? 'asc' : 'desc';
|
||||||
|
|
||||||
if($sort_col[0] == 'client_id') {
|
if($sort_col[0] == 'client_id') {
|
||||||
|
|
||||||
return $this->builder->orderBy(\App\Models\Client::select('name')
|
return $this->builder->orderBy(\App\Models\Client::select('name')
|
||||||
->whereColumn('clients.id', 'quotes.client_id'), $sort_col[1]);
|
->whereColumn('clients.id', 'quotes.client_id'), $dir);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,7 +159,7 @@ class QuoteFilters extends QueryFilters
|
|||||||
$sort_col[0] = 'due_date';
|
$sort_col[0] = 'due_date';
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
return $this->builder->orderBy($sort_col[0], $dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -63,7 +63,9 @@ class RecurringExpenseFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
$dir = ($sort_col[1] == 'asc') ? 'asc' : 'desc';
|
||||||
|
|
||||||
|
return $this->builder->orderBy($sort_col[0], $dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -114,20 +114,25 @@ class RecurringInvoiceFilters extends QueryFilters
|
|||||||
*/
|
*/
|
||||||
public function sort(string $sort = ''): Builder
|
public function sort(string $sort = ''): Builder
|
||||||
{
|
{
|
||||||
|
|
||||||
$sort_col = explode('|', $sort);
|
$sort_col = explode('|', $sort);
|
||||||
|
|
||||||
if (!is_array($sort_col) || count($sort_col) != 2) {
|
if (!is_array($sort_col) || count($sort_col) != 2) {
|
||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$dir = ($sort_col[1] == 'asc') ? 'asc' : 'desc';
|
||||||
|
|
||||||
if ($sort_col[0] == 'client_id') {
|
if ($sort_col[0] == 'client_id') {
|
||||||
return $this->builder->orderBy(\App\Models\Client::select('name')
|
return $this->builder->orderBy(\App\Models\Client::select('name')
|
||||||
->whereColumn('clients.id', 'recurring_invoices.client_id'), $sort_col[1]);
|
->whereColumn('clients.id', 'recurring_invoices.client_id'), $dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if($sort_col[0] == 'number'){
|
||||||
|
return $this->builder->orderByRaw("ABS(number) {$dir}");
|
||||||
|
}
|
||||||
|
|
||||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
return $this->builder->orderBy($sort_col[0], $dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -62,7 +62,9 @@ class RecurringQuoteFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
$dir = ($sort_col[1] == 'asc') ? 'asc' : 'desc';
|
||||||
|
|
||||||
|
return $this->builder->orderBy($sort_col[0], $dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -50,7 +50,9 @@ class SchedulerFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
$dir = ($sort_col[1] == 'asc') ? 'asc' : 'desc';
|
||||||
|
|
||||||
|
return $this->builder->orderBy($sort_col[0], $dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -50,7 +50,9 @@ class SubscriptionFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
$dir = ($sort_col[1] == 'asc') ? 'asc' : 'desc';
|
||||||
|
|
||||||
|
return $this->builder->orderBy($sort_col[0], $dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -75,7 +75,9 @@ class SystemLogFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
$dir = ($sort_col[1] == 'asc') ? 'asc' : 'desc';
|
||||||
|
|
||||||
|
return $this->builder->orderBy($sort_col[0], $dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -131,17 +131,19 @@ class TaskFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$dir = ($sort_col[1] == 'asc') ? 'asc' : 'desc';
|
||||||
|
|
||||||
if ($sort_col[0] == 'client_id') {
|
if ($sort_col[0] == 'client_id') {
|
||||||
return $this->builder->orderBy(\App\Models\Client::select('name')
|
return $this->builder->orderBy(\App\Models\Client::select('name')
|
||||||
->whereColumn('clients.id', 'tasks.client_id'), $sort_col[1]);
|
->whereColumn('clients.id', 'tasks.client_id'), $dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($sort_col[0] == 'user_id') {
|
if ($sort_col[0] == 'user_id') {
|
||||||
return $this->builder->orderBy(\App\Models\User::select('first_name')
|
return $this->builder->orderBy(\App\Models\User::select('first_name')
|
||||||
->whereColumn('users.id', 'tasks.user_id'), $sort_col[1]);
|
->whereColumn('users.id', 'tasks.user_id'), $dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
return $this->builder->orderBy($sort_col[0], $dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function task_status(string $value = ''): Builder
|
public function task_status(string $value = ''): Builder
|
||||||
|
@ -50,7 +50,9 @@ class TaskStatusFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
$dir = ($sort_col[1] == 'asc') ? 'asc' : 'desc';
|
||||||
|
|
||||||
|
return $this->builder->orderBy($sort_col[0], $dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -50,7 +50,9 @@ class TaxRateFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
$dir = ($sort_col[1] == 'asc') ? 'asc' : 'desc';
|
||||||
|
|
||||||
|
return $this->builder->orderBy($sort_col[0], $dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -56,7 +56,9 @@ class TokenFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
$dir = ($sort_col[1] == 'asc') ? 'asc' : 'desc';
|
||||||
|
|
||||||
|
return $this->builder->orderBy($sort_col[0], $dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -54,7 +54,9 @@ class UserFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
$dir = ($sort_col[1] == 'asc') ? 'asc' : 'desc';
|
||||||
|
|
||||||
|
return $this->builder->orderBy($sort_col[0], $dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -64,21 +66,44 @@ class UserFilters extends QueryFilters
|
|||||||
*/
|
*/
|
||||||
public function entityFilter()
|
public function entityFilter()
|
||||||
{
|
{
|
||||||
return $this->builder->whereHas('company_users', function ($q) {
|
|
||||||
$q->where('company_id', '=', auth()->user()->company()->id);
|
/** @var \App\Models\User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
return $this->builder->whereHas('company_users', function ($q) use ($user){
|
||||||
|
$q->where('company_id', '=', $user->company()->id);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hides owner users from the list.
|
||||||
|
*
|
||||||
|
* @return Builder
|
||||||
|
*/
|
||||||
|
public function hideOwnerUsers(): Builder
|
||||||
|
{
|
||||||
|
/** @var \App\Models\User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
return $this->builder->whereHas('company_users', function ($q) use ($user) {
|
||||||
|
$q->where('company_id', '=', $user->company()->id)->where('is_owner', false);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filters users that have been removed from the
|
* Filters users that have been removed from the
|
||||||
* company, but not deleted from the system.
|
* company, but not deleted from the system.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return Builder
|
||||||
*/
|
*/
|
||||||
public function hideRemovedUsers()
|
public function hideRemovedUsers(): Builder
|
||||||
{
|
{
|
||||||
return $this->builder->whereHas('company_users', function ($q) {
|
/** @var \App\Models\User $user */
|
||||||
$q->where('company_id', '=', auth()->user()->company()->id)->whereNull('deleted_at');
|
$user = auth()->user();
|
||||||
|
|
||||||
|
return $this->builder->whereHas('company_users', function ($q) use ($user) {
|
||||||
|
$q->where('company_id', '=', $user->company()->id)->whereNull('deleted_at');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,12 +121,21 @@ class UserFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @var \App\Models\User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
return $this->builder
|
return $this->builder
|
||||||
->orWhere($this->with_property, $value)
|
->orWhere($this->with_property, $value)
|
||||||
->orderByRaw("{$this->with_property} = ? DESC", [$value])
|
->orderByRaw("{$this->with_property} = ? DESC", [$value])
|
||||||
->where('account_id', auth()->user()->account_id);
|
->where('account_id', $user->account_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns users with permissions to send emails via OAuth
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
* @return Builder
|
||||||
|
*/
|
||||||
public function sending_users(string $value = ''): Builder
|
public function sending_users(string $value = ''): Builder
|
||||||
{
|
{
|
||||||
if (strlen($value) == 0 || $value != 'true') {
|
if (strlen($value) == 0 || $value != 'true') {
|
||||||
|
@ -69,7 +69,9 @@ class VendorFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
$dir = ($sort_col[1] == 'asc') ? 'asc' : 'desc';
|
||||||
|
|
||||||
|
return $this->builder->orderBy($sort_col[0], $dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -50,7 +50,9 @@ class WebhookFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
$dir = ($sort_col[1] == 'asc') ? 'asc' : 'desc';
|
||||||
|
|
||||||
|
return $this->builder->orderBy($sort_col[0], $dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
137
app/Helpers/Bank/Nordigen/Nordigen.php
Normal file
137
app/Helpers/Bank/Nordigen/Nordigen.php
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*
|
||||||
|
* Documentation of Api-Usage: https://developer.gocardless.com/bank-account-data/overview
|
||||||
|
*
|
||||||
|
* Institutions: Are Banks or Payment-Providers, which manages bankaccounts.
|
||||||
|
*
|
||||||
|
* Accounts: Accounts are existing bank_accounts at a specific institution.
|
||||||
|
*
|
||||||
|
* Requisitions: Are registered/active user-flows to authenticate one or many accounts. After completition, the accoundId could be used to fetch data for this account. After the access expires, the user could create a new requisition to connect accounts again.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Helpers\Bank\Nordigen;
|
||||||
|
|
||||||
|
use App\Helpers\Bank\Nordigen\Transformer\AccountTransformer;
|
||||||
|
use App\Helpers\Bank\Nordigen\Transformer\TransactionTransformer;
|
||||||
|
|
||||||
|
class Nordigen
|
||||||
|
{
|
||||||
|
public bool $test_mode; // https://developer.gocardless.com/bank-account-data/sandbox
|
||||||
|
|
||||||
|
public string $sandbox_institutionId = "SANDBOXFINANCE_SFIN0000";
|
||||||
|
|
||||||
|
protected \Nordigen\NordigenPHP\API\NordigenClient $client;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->test_mode = config('ninja.nordigen.test_mode');
|
||||||
|
|
||||||
|
if (!(config('ninja.nordigen.secret_id') && config('ninja.nordigen.secret_key')))
|
||||||
|
throw new \Exception('missing nordigen credentials');
|
||||||
|
|
||||||
|
$this->client = new \Nordigen\NordigenPHP\API\NordigenClient(config('ninja.nordigen.secret_id'), config('ninja.nordigen.secret_key'));
|
||||||
|
|
||||||
|
$this->client->createAccessToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
// metadata-section for frontend
|
||||||
|
public function getInstitutions()
|
||||||
|
{
|
||||||
|
if ($this->test_mode)
|
||||||
|
return [$this->client->institution->getInstitution($this->sandbox_institutionId)];
|
||||||
|
|
||||||
|
return $this->client->institution->getInstitutions();
|
||||||
|
}
|
||||||
|
|
||||||
|
// requisition-section
|
||||||
|
public function createRequisition(string $redirect, string $initutionId, string $reference, string $userLanguage)
|
||||||
|
{
|
||||||
|
if ($this->test_mode && $initutionId != $this->sandbox_institutionId)
|
||||||
|
throw new \Exception('invalid institutionId while in test-mode');
|
||||||
|
|
||||||
|
return $this->client->requisition->createRequisition($redirect, $initutionId, null, $reference, $userLanguage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRequisition(string $requisitionId)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return $this->client->requisition->getRequisition($requisitionId);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
if (strpos($e->getMessage(), "Invalid Requisition ID") !== false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: return null on not found
|
||||||
|
public function getAccount(string $account_id)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$out = new \stdClass();
|
||||||
|
|
||||||
|
$out->data = $this->client->account($account_id)->getAccountDetails()["account"];
|
||||||
|
$out->metadata = $this->client->account($account_id)->getAccountMetaData();
|
||||||
|
$out->balances = $this->client->account($account_id)->getAccountBalances()["balances"];
|
||||||
|
$out->institution = $this->client->institution->getInstitution($out->metadata["institution_id"]);
|
||||||
|
|
||||||
|
$it = new AccountTransformer();
|
||||||
|
return $it->transform($out);
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
if (strpos($e->getMessage(), "Invalid Account ID") !== false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* isAccountActive
|
||||||
|
*
|
||||||
|
* @param string $account_id
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isAccountActive(string $account_id): bool
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$account = $this->client->account($account_id)->getAccountMetaData();
|
||||||
|
|
||||||
|
if ($account["status"] != "READY") {
|
||||||
|
nlog('nordigen account was not in status ready. accountId: ' . $account_id . ' status: ' . $account["status"]);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
if (strpos($e->getMessage(), "Invalid Account ID") !== false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getTransactions
|
||||||
|
*
|
||||||
|
* @param string $accountId
|
||||||
|
* @param string $dateFrom
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getTransactions(string $accountId, string $dateFrom = null): array
|
||||||
|
{
|
||||||
|
$transactionResponse = $this->client->account($accountId)->getAccountTransactions($dateFrom);
|
||||||
|
|
||||||
|
$it = new TransactionTransformer();
|
||||||
|
return $it->transform($transactionResponse);
|
||||||
|
}
|
||||||
|
}
|
121
app/Helpers/Bank/Nordigen/Transformer/AccountTransformer.php
Normal file
121
app/Helpers/Bank/Nordigen/Transformer/AccountTransformer.php
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Helpers\Bank\Nordigen\Transformer;
|
||||||
|
|
||||||
|
use App\Helpers\Bank\AccountTransformerInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
[0] => stdClass Object
|
||||||
|
(
|
||||||
|
[data] => stdClass Object
|
||||||
|
(
|
||||||
|
[resourceId] => XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
|
||||||
|
[iban] => DE0286055592XXXXXXXXXX
|
||||||
|
[currency] => EUR
|
||||||
|
[ownerName] => Max Mustermann
|
||||||
|
[product] => GiroKomfort
|
||||||
|
[bic] => WELADE8LXXX
|
||||||
|
[usage] => PRIV
|
||||||
|
)
|
||||||
|
[metadata] => stdClass Object
|
||||||
|
(
|
||||||
|
[id] => XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
|
||||||
|
[created] => 2022-12-05T18:41:53.986028Z
|
||||||
|
[last_accessed] => 2023-10-29T08:35:34.003611Z
|
||||||
|
[iban] => DE0286055592XXXXXXXXXX
|
||||||
|
[institution_id] => STADT_KREISSPARKASSE_LEIPZIG_WELADE8LXXX
|
||||||
|
[status] => READY
|
||||||
|
[owner_name] => Max Mustermann
|
||||||
|
)
|
||||||
|
[balances] => [
|
||||||
|
{
|
||||||
|
[balanceAmount]: {
|
||||||
|
[amount] => 9825.64
|
||||||
|
[currency] => EUR
|
||||||
|
},
|
||||||
|
[balanceType] => closingBooked
|
||||||
|
[referenceDate] => 2023-12-01
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[balanceAmount[: {
|
||||||
|
[amount] => 10325.64
|
||||||
|
[currency] => EUR
|
||||||
|
},
|
||||||
|
[balanceType] => interimAvailable
|
||||||
|
[creditLimitIncluded]: true,
|
||||||
|
[referenceDate] => 2023-12-01
|
||||||
|
}
|
||||||
|
]
|
||||||
|
[institution] => stdClass Object
|
||||||
|
(
|
||||||
|
[id] => STADT_KREISSPARKASSE_LEIPZIG_WELADE8LXXX
|
||||||
|
[name] => Stadt- und Kreissparkasse Leipzig
|
||||||
|
[bic] => WELADE8LXXX
|
||||||
|
[transaction_total_days] => 360
|
||||||
|
[countries] => [
|
||||||
|
"DE"
|
||||||
|
],
|
||||||
|
[logo] => https://storage.googleapis.com/gc-prd-institution_icons-production/DE/PNG/sparkasse.png
|
||||||
|
[supported_payments] => {
|
||||||
|
[single-payment] => [
|
||||||
|
"SCT",
|
||||||
|
"ISCT"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
[supported_features] => [
|
||||||
|
"card_accounts",
|
||||||
|
"payments",
|
||||||
|
"pending_transactions"
|
||||||
|
],
|
||||||
|
[identification_codes] => []
|
||||||
|
)
|
||||||
|
|
||||||
|
)
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
class AccountTransformer implements AccountTransformerInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
public function transform($nordigen_account)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!property_exists($nordigen_account, 'data') || !property_exists($nordigen_account, 'metadata') || !property_exists($nordigen_account, 'balances') || !property_exists($nordigen_account, 'institution'))
|
||||||
|
throw new \Exception('invalid dataset');
|
||||||
|
|
||||||
|
$used_balance = $nordigen_account->balances[0];
|
||||||
|
// prefer entry with closingBooked
|
||||||
|
foreach ($nordigen_account->balances as $entry) {
|
||||||
|
if ($entry["balanceType"] === 'closingBooked') { // available: closingBooked, interimAvailable
|
||||||
|
$used_balance = $entry;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'id' => $nordigen_account->metadata["id"],
|
||||||
|
'account_type' => "bank",
|
||||||
|
'account_name' => $nordigen_account->data["iban"],
|
||||||
|
'account_status' => $nordigen_account->metadata["status"],
|
||||||
|
'account_number' => '**** ' . substr($nordigen_account->data["iban"], -7),
|
||||||
|
'provider_account_id' => $nordigen_account->metadata["id"],
|
||||||
|
'provider_id' => $nordigen_account->institution["id"],
|
||||||
|
'provider_name' => $nordigen_account->institution["name"],
|
||||||
|
'nickname' => $nordigen_account->data["ownerName"] ? $nordigen_account->data["ownerName"] : '',
|
||||||
|
'current_balance' => (int) $used_balance ? $used_balance["balanceAmount"]["amount"] : 0,
|
||||||
|
'account_currency' => $used_balance ? $used_balance["balanceAmount"]["currency"] : '',
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
149
app/Helpers/Bank/Nordigen/Transformer/TransactionTransformer.php
Normal file
149
app/Helpers/Bank/Nordigen/Transformer/TransactionTransformer.php
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Helpers\Bank\Nordigen\Transformer;
|
||||||
|
|
||||||
|
use App\Helpers\Bank\BankRevenueInterface;
|
||||||
|
use App\Models\BankIntegration;
|
||||||
|
use App\Utils\Traits\AppSetup;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
{
|
||||||
|
"transactions": {
|
||||||
|
"booked": [
|
||||||
|
{
|
||||||
|
"transactionId": "string",
|
||||||
|
"debtorName": "string",
|
||||||
|
"debtorAccount": {
|
||||||
|
"iban": "string"
|
||||||
|
},
|
||||||
|
"transactionAmount": {
|
||||||
|
"currency": "string",
|
||||||
|
"amount": "328.18"
|
||||||
|
},
|
||||||
|
"bankTransactionCode": "string",
|
||||||
|
"bookingDate": "date",
|
||||||
|
"valueDate": "date",
|
||||||
|
"remittanceInformationUnstructured": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"transactionId": "string",
|
||||||
|
"transactionAmount": {
|
||||||
|
"currency": "string",
|
||||||
|
"amount": "947.26"
|
||||||
|
},
|
||||||
|
"bankTransactionCode": "string",
|
||||||
|
"bookingDate": "date",
|
||||||
|
"valueDate": "date",
|
||||||
|
"remittanceInformationUnstructured": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"pending": [
|
||||||
|
{
|
||||||
|
"transactionAmount": {
|
||||||
|
"currency": "string",
|
||||||
|
"amount": "99.20"
|
||||||
|
},
|
||||||
|
"valueDate": "date",
|
||||||
|
"remittanceInformationUnstructured": "string"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
class TransactionTransformer implements BankRevenueInterface
|
||||||
|
{
|
||||||
|
use AppSetup;
|
||||||
|
|
||||||
|
public function transform($transactionResponse)
|
||||||
|
{
|
||||||
|
$data = [];
|
||||||
|
|
||||||
|
if (!array_key_exists('transactions', $transactionResponse) || !array_key_exists('booked', $transactionResponse["transactions"]))
|
||||||
|
throw new \Exception('invalid dataset');
|
||||||
|
|
||||||
|
foreach ($transactionResponse["transactions"]["booked"] as $transaction) {
|
||||||
|
$data[] = $this->transformTransaction($transaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function transformTransaction($transaction)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!array_key_exists('transactionId', $transaction) || !array_key_exists('transactionAmount', $transaction))
|
||||||
|
throw new \Exception('invalid dataset');
|
||||||
|
|
||||||
|
// description could be in varios places
|
||||||
|
$description = '';
|
||||||
|
if (array_key_exists('remittanceInformationStructured', $transaction))
|
||||||
|
$description = $transaction["remittanceInformationStructured"];
|
||||||
|
else if (array_key_exists('remittanceInformationStructuredArray', $transaction))
|
||||||
|
$description = implode('\n', $transaction["remittanceInformationStructuredArray"]);
|
||||||
|
else if (array_key_exists('remittanceInformationUnstructured', $transaction))
|
||||||
|
$description = $transaction["remittanceInformationUnstructured"];
|
||||||
|
else if (array_key_exists('remittanceInformationUnstructuredArray', $transaction))
|
||||||
|
$description = implode('\n', $transaction["remittanceInformationUnstructuredArray"]);
|
||||||
|
else
|
||||||
|
Log::warning("Missing description for the following transaction: " . json_encode($transaction));
|
||||||
|
|
||||||
|
// participant
|
||||||
|
$participant = array_key_exists('debtorAccount', $transaction) && array_key_exists('iban', $transaction["debtorAccount"]) ?
|
||||||
|
$transaction['debtorAccount']['iban'] :
|
||||||
|
(array_key_exists('creditorAccount', $transaction) && array_key_exists('iban', $transaction["creditorAccount"]) ?
|
||||||
|
$transaction['creditorAccount']['iban'] : null);
|
||||||
|
$participant_name = array_key_exists('debtorName', $transaction) ?
|
||||||
|
$transaction['debtorName'] :
|
||||||
|
(array_key_exists('creditorName', $transaction) ?
|
||||||
|
$transaction['creditorName'] : null);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'transaction_id' => $transaction["transactionId"],
|
||||||
|
'amount' => abs((int) $transaction["transactionAmount"]["amount"]),
|
||||||
|
'currency_id' => $this->convertCurrency($transaction["transactionAmount"]["currency"]),
|
||||||
|
'category_id' => null,
|
||||||
|
'category_type' => array_key_exists('additionalInformation', $transaction) ? $transaction["additionalInformation"] : '',
|
||||||
|
'date' => $transaction["bookingDate"],
|
||||||
|
'description' => $description,
|
||||||
|
'participant' => $participant,
|
||||||
|
'participant_name' => $participant_name,
|
||||||
|
'base_type' => (int) $transaction["transactionAmount"]["amount"] <= 0 ? 'DEBIT' : 'CREDIT',
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function convertCurrency(string $code)
|
||||||
|
{
|
||||||
|
|
||||||
|
$currencies = Cache::get('currencies');
|
||||||
|
|
||||||
|
if (!$currencies) {
|
||||||
|
$this->buildCache(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$currency = $currencies->filter(function ($item) use ($code) {
|
||||||
|
return $item->code == $code;
|
||||||
|
})->first();
|
||||||
|
|
||||||
|
if ($currency)
|
||||||
|
return $currency->id;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
41
app/Helpers/Encrypt/Secure.php
Normal file
41
app/Helpers/Encrypt/Secure.php
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Helpers\Encrypt;
|
||||||
|
|
||||||
|
class Secure
|
||||||
|
{
|
||||||
|
public static function encrypt(string $hash): ?string
|
||||||
|
{
|
||||||
|
$data = null;
|
||||||
|
|
||||||
|
$public_key = openssl_pkey_get_public(config('ninja.encryption.public_key'));
|
||||||
|
|
||||||
|
if (openssl_public_encrypt($hash, $encrypted, $public_key)) {
|
||||||
|
$data = base64_encode($encrypted);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function decrypt(string $hash): ?string
|
||||||
|
{
|
||||||
|
$data = null;
|
||||||
|
|
||||||
|
$private_key = openssl_pkey_get_private(config('ninja.encryption.private_key'));
|
||||||
|
|
||||||
|
if (openssl_private_decrypt(base64_decode($hash), $decrypted, $private_key)) {
|
||||||
|
$data = $decrypted;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
}
|
@ -11,17 +11,18 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Http\Requests\Account\CreateAccountRequest;
|
|
||||||
use App\Http\Requests\Account\UpdateAccountRequest;
|
|
||||||
use App\Jobs\Account\CreateAccount;
|
|
||||||
use App\Libraries\MultiDB;
|
|
||||||
use App\Models\Account;
|
use App\Models\Account;
|
||||||
|
use App\Libraries\MultiDB;
|
||||||
|
use App\Utils\TruthSource;
|
||||||
use App\Models\CompanyUser;
|
use App\Models\CompanyUser;
|
||||||
|
use Illuminate\Http\Response;
|
||||||
|
use App\Helpers\Encrypt\Secure;
|
||||||
|
use App\Jobs\Account\CreateAccount;
|
||||||
use App\Transformers\AccountTransformer;
|
use App\Transformers\AccountTransformer;
|
||||||
use App\Transformers\CompanyUserTransformer;
|
use App\Transformers\CompanyUserTransformer;
|
||||||
use App\Utils\TruthSource;
|
|
||||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||||
use Illuminate\Http\Response;
|
use App\Http\Requests\Account\CreateAccountRequest;
|
||||||
|
use App\Http\Requests\Account\UpdateAccountRequest;
|
||||||
|
|
||||||
class AccountController extends BaseController
|
class AccountController extends BaseController
|
||||||
{
|
{
|
||||||
@ -65,6 +66,33 @@ class AccountController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function store(CreateAccountRequest $request)
|
public function store(CreateAccountRequest $request)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if($request->has('cf-turnstile-response') && config('ninja.cloudflare.turnstile.secret')) {
|
||||||
|
$r = \Illuminate\Support\Facades\Http::post('https://challenges.cloudflare.com/turnstile/v0/siteverify', [
|
||||||
|
'secret' => config('ninja.cloudflare.turnstile.secret'),
|
||||||
|
'response' => $request->input('cf-turnstile-response'),
|
||||||
|
'remoteip' => $request->getClientIp(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
if($r->successful()){
|
||||||
|
|
||||||
|
if($r->json()['success'] === true) {
|
||||||
|
// Captcha passed
|
||||||
|
} else {
|
||||||
|
return response()->json(['message' => 'Captcha Failed'], 400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if($request->has('hash') && config('ninja.cloudflare.turnstile.secret')) { //@todo once all platforms are implemented, we disable access to the rest of this route without a success response.
|
||||||
|
|
||||||
|
if(Secure::decrypt($request->input('hash')) !== $request->input('email')) {
|
||||||
|
return response()->json(['message' => 'Invalid Signup Payload'], 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
$account = (new CreateAccount($request->all(), $request->getClientIp()))->handle();
|
$account = (new CreateAccount($request->all(), $request->getClientIp()))->handle();
|
||||||
if (! ($account instanceof Account)) {
|
if (! ($account instanceof Account)) {
|
||||||
return $account;
|
return $account;
|
||||||
|
308
app/Http/Controllers/Bank/NordigenController.php
Normal file
308
app/Http/Controllers/Bank/NordigenController.php
Normal file
@ -0,0 +1,308 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Bank;
|
||||||
|
|
||||||
|
use App\Helpers\Bank\Nordigen\Nordigen;
|
||||||
|
use App\Http\Controllers\BaseController;
|
||||||
|
use App\Http\Requests\Nordigen\ConfirmNordigenBankIntegrationRequest;
|
||||||
|
use App\Http\Requests\Nordigen\ConnectNordigenBankIntegrationRequest;
|
||||||
|
use App\Jobs\Bank\ProcessBankTransactionsNordigen;
|
||||||
|
use App\Models\BankIntegration;
|
||||||
|
use App\Utils\Ninja;
|
||||||
|
use Cache;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Nordigen\NordigenPHP\Exceptions\NordigenExceptions\NordigenException;
|
||||||
|
|
||||||
|
class NordigenController extends BaseController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* VIEW: Connect Nordigen Bank Integration
|
||||||
|
* @param ConnectNordigenBankIntegrationRequest $request
|
||||||
|
*/
|
||||||
|
public function connect(ConnectNordigenBankIntegrationRequest $request)
|
||||||
|
{
|
||||||
|
$data = $request->all();
|
||||||
|
|
||||||
|
/** @var array $context */
|
||||||
|
$context = $request->getTokenContent();
|
||||||
|
$company = $request->getCompany();
|
||||||
|
$lang = $company->locale();
|
||||||
|
$context["lang"] = $lang;
|
||||||
|
|
||||||
|
if (!$context)
|
||||||
|
return view('bank.nordigen.handler', [
|
||||||
|
'lang' => $lang,
|
||||||
|
'failed_reason' => "token-invalid",
|
||||||
|
"redirectUrl" => config("ninja.app_url") . "?action=nordigen_connect&status=failed&reason=token-invalid",
|
||||||
|
]);
|
||||||
|
|
||||||
|
$context["redirect"] = $data["redirect"];
|
||||||
|
if ($context["context"] != "nordigen" || array_key_exists("requisitionId", $context))
|
||||||
|
return view('bank.nordigen.handler', [
|
||||||
|
'lang' => $lang,
|
||||||
|
'failed_reason' => "token-invalid",
|
||||||
|
"redirectUrl" => ($context["redirect"]) . "?action=nordigen_connect&status=failed&reason=token-invalid",
|
||||||
|
]);
|
||||||
|
|
||||||
|
$company = $request->getCompany();
|
||||||
|
$account = $company->account;
|
||||||
|
|
||||||
|
if (!(config('ninja.nordigen.secret_id') && config('ninja.nordigen.secret_key')))
|
||||||
|
return view('bank.nordigen.handler', [
|
||||||
|
'lang' => $lang,
|
||||||
|
'company' => $company,
|
||||||
|
'account' => $company->account,
|
||||||
|
'failed_reason' => "account-config-invalid",
|
||||||
|
"redirectUrl" => $context["redirect"] . "?action=nordigen_connect&status=failed&reason=account-config-invalid",
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!(Ninja::isSelfHost() || (Ninja::isHosted() && $account->isEnterprisePaidClient())))
|
||||||
|
return view('bank.nordigen.handler', [
|
||||||
|
'lang' => $lang,
|
||||||
|
'company' => $company,
|
||||||
|
'account' => $company->account,
|
||||||
|
'failed_reason' => "not-available",
|
||||||
|
"redirectUrl" => $context["redirect"] . "?action=nordigen_connect&status=failed&reason=not-available",
|
||||||
|
]);
|
||||||
|
|
||||||
|
$nordigen = new Nordigen();
|
||||||
|
|
||||||
|
// show bank_selection_screen, when institution_id is not present
|
||||||
|
if (!array_key_exists("institution_id", $data))
|
||||||
|
return view('bank.nordigen.handler', [
|
||||||
|
'lang' => $lang,
|
||||||
|
'company' => $company,
|
||||||
|
'account' => $company->account,
|
||||||
|
'institutions' => $nordigen->getInstitutions(),
|
||||||
|
'redirectUrl' => $context["redirect"] . "?action=nordigen_connect&status=user-aborted"
|
||||||
|
]);
|
||||||
|
|
||||||
|
// redirect to requisition flow
|
||||||
|
try {
|
||||||
|
$requisition = $nordigen->createRequisition(config('ninja.app_url') . '/nordigen/confirm', $data['institution_id'], $request->token, $lang);
|
||||||
|
} catch (NordigenException $e) { // TODO: property_exists returns null in these cases... => why => therefore we just get unknown error everytime $responseBody is typeof GuzzleHttp\Psr7\Stream
|
||||||
|
$responseBody = (string) $e->getResponse()->getBody();
|
||||||
|
|
||||||
|
if (str_contains($responseBody, '"institution_id"')) // provided institution_id was wrong
|
||||||
|
return view('bank.nordigen.handler', [
|
||||||
|
'lang' => $lang,
|
||||||
|
'company' => $company,
|
||||||
|
'account' => $company->account,
|
||||||
|
'failed_reason' => "institution-invalid",
|
||||||
|
"redirectUrl" => $context["redirect"] . "?action=nordigen_connect&status=failed&reason=institution-invalid",
|
||||||
|
]);
|
||||||
|
else if (str_contains($responseBody, '"reference"')) // this error can occur, when a reference was used double or is invalid => therefor we suggest the frontend to use another token
|
||||||
|
return view('bank.nordigen.handler', [
|
||||||
|
'lang' => $lang,
|
||||||
|
'company' => $company,
|
||||||
|
'account' => $company->account,
|
||||||
|
'failed_reason' => "token-invalid",
|
||||||
|
"redirectUrl" => $context["redirect"] . "?action=nordigen_connect&status=failed&reason=token-invalid",
|
||||||
|
]);
|
||||||
|
else {
|
||||||
|
nlog("Unknown Error from nordigen: " . $e);
|
||||||
|
nlog($responseBody);
|
||||||
|
|
||||||
|
return view('bank.nordigen.handler', [
|
||||||
|
'lang' => $lang,
|
||||||
|
'company' => $company,
|
||||||
|
'account' => $company->account,
|
||||||
|
'failed_reason' => "unknown",
|
||||||
|
"redirectUrl" => $context["redirect"] . "?action=nordigen_connect&status=failed&reason=unknown",
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// save cache
|
||||||
|
$context["requisitionId"] = $requisition["id"];
|
||||||
|
Cache::put($request->token, $context, 3600);
|
||||||
|
|
||||||
|
return response()->redirectTo($requisition["link"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* VIEW: Confirm Nordigen Bank Integration (redirect after nordigen flow)
|
||||||
|
* @param ConfirmNordigenBankIntegrationRequest $request
|
||||||
|
*/
|
||||||
|
public function confirm(ConfirmNordigenBankIntegrationRequest $request)
|
||||||
|
{
|
||||||
|
$data = $request->all();
|
||||||
|
$company = $request->getCompany();
|
||||||
|
$account = $company->account;
|
||||||
|
$lang = $company->locale();
|
||||||
|
|
||||||
|
/** @var array $context */
|
||||||
|
$context = $request->getTokenContent();
|
||||||
|
if (!array_key_exists('lang', $data) && $context['lang'] != 'en')
|
||||||
|
return redirect()->route('nordigen.confirm', array_merge(["lang" => $context['lang']], $request->query()));
|
||||||
|
|
||||||
|
if (!$context || $context["context"] != "nordigen" || !array_key_exists("requisitionId", $context))
|
||||||
|
return view('bank.nordigen.handler', [
|
||||||
|
'lang' => $lang,
|
||||||
|
'failed_reason' => "ref-invalid",
|
||||||
|
"redirectUrl" => ($context && array_key_exists("redirect", $context) ? $context["redirect"] : config('ninja.app_url')) . "?action=nordigen_connect&status=failed&reason=ref-invalid",
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!(config('ninja.nordigen.secret_id') && config('ninja.nordigen.secret_key')))
|
||||||
|
return view('bank.nordigen.handler', [
|
||||||
|
'lang' => $lang,
|
||||||
|
'company' => $company,
|
||||||
|
'account' => $company->account,
|
||||||
|
'failed_reason' => "account-config-invalid",
|
||||||
|
"redirectUrl" => $context["redirect"] . "?action=nordigen_connect&status=failed&reason=account-config-invalid",
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!(Ninja::isSelfHost() || (Ninja::isHosted() && $account->isPaid() && $account->plan == 'enterprise')))
|
||||||
|
return view('bank.nordigen.handler', [
|
||||||
|
'lang' => $lang,
|
||||||
|
'company' => $company,
|
||||||
|
'account' => $company->account,
|
||||||
|
'failed_reason' => "not-available",
|
||||||
|
"redirectUrl" => $context["redirect"] . "?action=nordigen_connect&status=failed&reason=not-available",
|
||||||
|
]);
|
||||||
|
|
||||||
|
// fetch requisition
|
||||||
|
$nordigen = new Nordigen();
|
||||||
|
$requisition = $nordigen->getRequisition($context["requisitionId"]);
|
||||||
|
|
||||||
|
// check validity of requisition
|
||||||
|
if (!$requisition)
|
||||||
|
return view('bank.nordigen.handler', [
|
||||||
|
'lang' => $lang,
|
||||||
|
'company' => $company,
|
||||||
|
'account' => $company->account,
|
||||||
|
'failed_reason' => "requisition-not-found",
|
||||||
|
"redirectUrl" => $context["redirect"] . "?action=nordigen_connect&status=failed&reason=requisition-not-found",
|
||||||
|
]);
|
||||||
|
if ($requisition["status"] != "LN")
|
||||||
|
return view('bank.nordigen.handler', [
|
||||||
|
'lang' => $lang,
|
||||||
|
'company' => $company,
|
||||||
|
'account' => $company->account,
|
||||||
|
'failed_reason' => "requisition-invalid-status",
|
||||||
|
"redirectUrl" => $context["redirect"] . "?action=nordigen_connect&status=failed&reason=requisition-invalid-status&status=" . $requisition["status"],
|
||||||
|
]);
|
||||||
|
if (sizeof($requisition["accounts"]) == 0)
|
||||||
|
return view('bank.nordigen.handler', [
|
||||||
|
'lang' => $lang,
|
||||||
|
'company' => $company,
|
||||||
|
'account' => $company->account,
|
||||||
|
'failed_reason' => "requisition-no-accounts",
|
||||||
|
"redirectUrl" => $context["redirect"] . "?action=nordigen_connect&status=failed&reason=requisition-no-accounts",
|
||||||
|
]);
|
||||||
|
|
||||||
|
// connect new accounts
|
||||||
|
$bank_integration_ids = [];
|
||||||
|
foreach ($requisition["accounts"] as $nordigenAccountId) {
|
||||||
|
|
||||||
|
$nordigen_account = $nordigen->getAccount($nordigenAccountId);
|
||||||
|
|
||||||
|
$existing_bank_integration = BankIntegration::withTrashed()->where('nordigen_account_id', $nordigen_account['id'])->where('company_id', $company->id)->first();
|
||||||
|
|
||||||
|
if (!$existing_bank_integration) {
|
||||||
|
|
||||||
|
$bank_integration = new BankIntegration();
|
||||||
|
$bank_integration->integration_type = BankIntegration::INTEGRATION_TYPE_NORDIGEN;
|
||||||
|
$bank_integration->company_id = $company->id;
|
||||||
|
$bank_integration->account_id = $company->account_id;
|
||||||
|
$bank_integration->user_id = $company->owner()->id;
|
||||||
|
$bank_integration->nordigen_account_id = $nordigen_account['id'];
|
||||||
|
$bank_integration->bank_account_type = $nordigen_account['account_type'];
|
||||||
|
$bank_integration->bank_account_name = $nordigen_account['account_name'];
|
||||||
|
$bank_integration->bank_account_status = $nordigen_account['account_status'];
|
||||||
|
$bank_integration->bank_account_number = $nordigen_account['account_number'];
|
||||||
|
$bank_integration->nordigen_institution_id = $nordigen_account['provider_id'];
|
||||||
|
$bank_integration->provider_name = $nordigen_account['provider_name'];
|
||||||
|
$bank_integration->nickname = $nordigen_account['nickname'];
|
||||||
|
$bank_integration->balance = $nordigen_account['current_balance'];
|
||||||
|
$bank_integration->currency = $nordigen_account['account_currency'];
|
||||||
|
$bank_integration->disabled_upstream = false;
|
||||||
|
$bank_integration->auto_sync = true;
|
||||||
|
$bank_integration->from_date = now()->subDays(90); // default max-fetch interval of nordigen is 90 days
|
||||||
|
|
||||||
|
$bank_integration->save();
|
||||||
|
|
||||||
|
array_push($bank_integration_ids, $bank_integration->id);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// resetting metadata for account status
|
||||||
|
$existing_bank_integration->balance = $account['current_balance'];
|
||||||
|
$existing_bank_integration->bank_account_status = $account['account_status'];
|
||||||
|
$existing_bank_integration->disabled_upstream = false;
|
||||||
|
$existing_bank_integration->auto_sync = true;
|
||||||
|
$existing_bank_integration->from_date = now()->subDays(90); // default max-fetch interval of nordigen is 90 days
|
||||||
|
$existing_bank_integration->deleted_at = null;
|
||||||
|
|
||||||
|
$existing_bank_integration->save();
|
||||||
|
|
||||||
|
array_push($bank_integration_ids, $existing_bank_integration->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// perform update in background
|
||||||
|
$company->account->bank_integrations->where("integration_type", BankIntegration::INTEGRATION_TYPE_NORDIGEN)->where('auto_sync', true)->each(function ($bank_integration) {
|
||||||
|
ProcessBankTransactionsNordigen::dispatch($bank_integration);
|
||||||
|
});
|
||||||
|
|
||||||
|
// prevent rerun of this method with same ref
|
||||||
|
Cache::delete($data["ref"]);
|
||||||
|
|
||||||
|
// Successfull Response => Redirect
|
||||||
|
return response()->redirectTo($context["redirect"] . "?action=nordigen_connect&status=success&bank_integrations=" . implode(',', $bank_integration_ids));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process Nordigen Institutions GETTER.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @OA\Post(
|
||||||
|
* path="/api/v1/nordigen/institutions",
|
||||||
|
* operationId="nordigenRefreshWebhook",
|
||||||
|
* tags={"nordigen"},
|
||||||
|
* summary="Getting available institutions from nordigen",
|
||||||
|
* description="Used to determine the available institutions for sending and creating a new connect-link",
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/include"),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="",
|
||||||
|
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Credit"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=422,
|
||||||
|
* description="Validation error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
|
||||||
|
*
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="Unexpected Error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Error"),
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function institutions(Request $request)
|
||||||
|
{
|
||||||
|
if (!(config('ninja.nordigen.secret_id') && config('ninja.nordigen.secret_key')))
|
||||||
|
return response()->json(['message' => 'Not yet authenticated with Nordigen Bank Integration service'], 400);
|
||||||
|
|
||||||
|
$nordigen = new Nordigen();
|
||||||
|
return response()->json($nordigen->getInstitutions());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -16,7 +16,7 @@ use App\Helpers\Bank\Yodlee\Yodlee;
|
|||||||
use App\Http\Controllers\BaseController;
|
use App\Http\Controllers\BaseController;
|
||||||
use App\Http\Requests\Yodlee\YodleeAdminRequest;
|
use App\Http\Requests\Yodlee\YodleeAdminRequest;
|
||||||
use App\Http\Requests\Yodlee\YodleeAuthRequest;
|
use App\Http\Requests\Yodlee\YodleeAuthRequest;
|
||||||
use App\Jobs\Bank\ProcessBankTransactions;
|
use App\Jobs\Bank\ProcessBankTransactionsYodlee;
|
||||||
use App\Models\BankIntegration;
|
use App\Models\BankIntegration;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
@ -90,6 +90,7 @@ class YodleeController extends BaseController
|
|||||||
$bank_integration->balance = $account['current_balance'];
|
$bank_integration->balance = $account['current_balance'];
|
||||||
$bank_integration->currency = $account['account_currency'];
|
$bank_integration->currency = $account['account_currency'];
|
||||||
$bank_integration->from_date = now()->subYear();
|
$bank_integration->from_date = now()->subYear();
|
||||||
|
|
||||||
$bank_integration->auto_sync = true;
|
$bank_integration->auto_sync = true;
|
||||||
|
|
||||||
$bank_integration->save();
|
$bank_integration->save();
|
||||||
@ -97,12 +98,11 @@ class YodleeController extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$company->account->bank_integrations->each(function ($bank_integration) use ($company) {
|
$company->account->bank_integrations->where("integration_type", BankIntegration::INTEGRATION_TYPE_YODLEE)->where('auto_sync', true)->each(function ($bank_integration) use ($company) { // TODO: filter to yodlee only
|
||||||
ProcessBankTransactions::dispatch($company->account->bank_integration_account_id, $bank_integration);
|
ProcessBankTransactionsYodlee::dispatch($company->account->id, $bank_integration);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process Yodlee Refresh Webhook.
|
* Process Yodlee Refresh Webhook.
|
||||||
*
|
*
|
||||||
@ -137,7 +137,6 @@ class YodleeController extends BaseController
|
|||||||
* ),
|
* ),
|
||||||
* )
|
* )
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
{
|
{
|
||||||
"event":{
|
"event":{
|
||||||
|
@ -14,6 +14,7 @@ namespace App\Http\Controllers;
|
|||||||
use App\Factory\BankIntegrationFactory;
|
use App\Factory\BankIntegrationFactory;
|
||||||
use App\Filters\BankIntegrationFilters;
|
use App\Filters\BankIntegrationFilters;
|
||||||
use App\Helpers\Bank\Yodlee\Yodlee;
|
use App\Helpers\Bank\Yodlee\Yodlee;
|
||||||
|
use App\Helpers\Bank\Nordigen\Nordigen;
|
||||||
use App\Http\Requests\BankIntegration\AdminBankIntegrationRequest;
|
use App\Http\Requests\BankIntegration\AdminBankIntegrationRequest;
|
||||||
use App\Http\Requests\BankIntegration\BulkBankIntegrationRequest;
|
use App\Http\Requests\BankIntegration\BulkBankIntegrationRequest;
|
||||||
use App\Http\Requests\BankIntegration\CreateBankIntegrationRequest;
|
use App\Http\Requests\BankIntegration\CreateBankIntegrationRequest;
|
||||||
@ -22,10 +23,14 @@ use App\Http\Requests\BankIntegration\EditBankIntegrationRequest;
|
|||||||
use App\Http\Requests\BankIntegration\ShowBankIntegrationRequest;
|
use App\Http\Requests\BankIntegration\ShowBankIntegrationRequest;
|
||||||
use App\Http\Requests\BankIntegration\StoreBankIntegrationRequest;
|
use App\Http\Requests\BankIntegration\StoreBankIntegrationRequest;
|
||||||
use App\Http\Requests\BankIntegration\UpdateBankIntegrationRequest;
|
use App\Http\Requests\BankIntegration\UpdateBankIntegrationRequest;
|
||||||
use App\Jobs\Bank\ProcessBankTransactions;
|
use App\Jobs\Bank\ProcessBankTransactionsYodlee;
|
||||||
|
use App\Jobs\Bank\ProcessBankTransactionsNordigen;
|
||||||
|
use App\Models\Account;
|
||||||
use App\Models\BankIntegration;
|
use App\Models\BankIntegration;
|
||||||
|
use App\Models\User;
|
||||||
use App\Repositories\BankIntegrationRepository;
|
use App\Repositories\BankIntegrationRepository;
|
||||||
use App\Transformers\BankIntegrationTransformer;
|
use App\Transformers\BankIntegrationTransformer;
|
||||||
|
use App\Utils\Ninja;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
@ -189,27 +194,45 @@ class BankIntegrationController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function refreshAccounts(AdminBankIntegrationRequest $request)
|
public function refreshAccounts(AdminBankIntegrationRequest $request)
|
||||||
{
|
{
|
||||||
// As yodlee is the first integration we don't need to perform switches yet, however
|
|
||||||
// if we add additional providers we can reuse this class
|
|
||||||
|
|
||||||
|
|
||||||
/** @var \App\Models\User $user */
|
/** @var \App\Models\User $user */
|
||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
|
|
||||||
$user_account = $user->account;
|
$user_account = $user->account;
|
||||||
|
|
||||||
$bank_account_id = $user_account->bank_integration_account_id;
|
$this->refreshAccountsYodlee($user);
|
||||||
|
|
||||||
if (!$bank_account_id) {
|
$this->refreshAccountsNordigen($user);
|
||||||
return response()->json(['message' => 'Not yet authenticated with Bank Integration service'], 400);
|
|
||||||
|
if (Cache::get("throttle_polling:{$user_account->key}"))
|
||||||
|
return response()->json(BankIntegration::query()->company(), 200);
|
||||||
|
|
||||||
|
// Processing transactions for each bank account
|
||||||
|
if (Ninja::isHosted() && $user->account->bank_integration_account_id)
|
||||||
|
$user_account->bank_integrations->where("integration_type", BankIntegration::INTEGRATION_TYPE_YODLEE)->each(function ($bank_integration) use ($user_account) {
|
||||||
|
ProcessBankTransactionsYodlee::dispatch($user_account->id, $bank_integration);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (config('ninja.nordigen.secret_id') && config('ninja.nordigen.secret_key') && (Ninja::isSelfHost() || (Ninja::isHosted() && $user_account->isEnterprisePaidClient())))
|
||||||
|
$user_account->bank_integrations->where("integration_type", BankIntegration::INTEGRATION_TYPE_NORDIGEN)->each(function ($bank_integration) {
|
||||||
|
ProcessBankTransactionsNordigen::dispatch($bank_integration);
|
||||||
|
});
|
||||||
|
|
||||||
|
Cache::put("throttle_polling:{$user_account->key}", true, 300);
|
||||||
|
|
||||||
|
return response()->json(BankIntegration::query()->company(), 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
$yodlee = new Yodlee($bank_account_id);
|
private function refreshAccountsYodlee(User $user)
|
||||||
|
{
|
||||||
|
if (!Ninja::isHosted() || !$user->account->bank_integration_account_id)
|
||||||
|
return;
|
||||||
|
|
||||||
|
$yodlee = new Yodlee($user->account->bank_integration_account_id);
|
||||||
|
|
||||||
$accounts = $yodlee->getAccounts();
|
$accounts = $yodlee->getAccounts();
|
||||||
|
|
||||||
foreach ($accounts as $account) {
|
foreach ($accounts as $account) {
|
||||||
if ($bi = BankIntegration::withTrashed()->where('bank_account_id', $account['id'])->where('company_id', $user->company()->id)->first()) {
|
if ($bi = BankIntegration::withTrashed()->where("integration_type", BankIntegration::INTEGRATION_TYPE_YODLEE)->where('bank_account_id', $account['id'])->where('company_id', $user->company()->id)->first()) {
|
||||||
$bi->balance = $account['current_balance'];
|
$bi->balance = $account['current_balance'];
|
||||||
$bi->currency = $account['account_currency'];
|
$bi->currency = $account['account_currency'];
|
||||||
$bi->save();
|
$bi->save();
|
||||||
@ -233,18 +256,31 @@ class BankIntegrationController extends BaseController
|
|||||||
$bank_integration->save();
|
$bank_integration->save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Cache::get("throttle_polling:{$user_account->key}")) {
|
|
||||||
return response()->json(BankIntegration::query()->company(), 200);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$user_account->bank_integrations->each(function ($bank_integration) use ($user_account) {
|
private function refreshAccountsNordigen(User $user)
|
||||||
ProcessBankTransactions::dispatch($user_account->bank_integration_account_id, $bank_integration);
|
{
|
||||||
|
if (!(config('ninja.nordigen.secret_id') && config('ninja.nordigen.secret_key')))
|
||||||
|
return;
|
||||||
|
|
||||||
|
$nordigen = new Nordigen();
|
||||||
|
|
||||||
|
BankIntegration::where("integration_type", BankIntegration::INTEGRATION_TYPE_NORDIGEN)->whereNotNull('nordigen_account_id')->each(function (BankIntegration $bank_integration) use ($nordigen) {
|
||||||
|
$account = $nordigen->getAccount($bank_integration->nordigen_account_id);
|
||||||
|
if (!$account) {
|
||||||
|
$bank_integration->disabled_upstream = true;
|
||||||
|
|
||||||
|
$bank_integration->save();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$bank_integration->disabled_upstream = false;
|
||||||
|
$bank_integration->bank_account_status = $account['account_status'];
|
||||||
|
$bank_integration->balance = $account['current_balance'];
|
||||||
|
$bank_integration->currency = $account['account_currency'];
|
||||||
|
|
||||||
|
$bank_integration->save();
|
||||||
});
|
});
|
||||||
|
|
||||||
Cache::put("throttle_polling:{$user_account->key}", true, 300);
|
|
||||||
|
|
||||||
return response()->json(BankIntegration::query()->company(), 200);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -262,23 +298,30 @@ class BankIntegrationController extends BaseController
|
|||||||
|
|
||||||
$account = $user->account;
|
$account = $user->account;
|
||||||
|
|
||||||
$bank_account_id = $account->bank_integration_account_id;
|
$bank_integration = BankIntegration::withTrashed()
|
||||||
|
->where('bank_account_id', $acc_id)
|
||||||
|
->orWhere('nordigen_account_id', $acc_id)
|
||||||
|
->company()
|
||||||
|
->firstOrFail();
|
||||||
|
|
||||||
if (!$bank_account_id) {
|
if ($bank_integration->integration_type == BankIntegration::INTEGRATION_TYPE_YODLEE)
|
||||||
|
$this->removeAccountYodlee($account, $bank_integration);
|
||||||
|
|
||||||
|
$this->bank_integration_repo->delete($bank_integration);
|
||||||
|
|
||||||
|
return $this->itemResponse($bank_integration->fresh());
|
||||||
|
}
|
||||||
|
|
||||||
|
private function removeAccountYodlee(Account $account, BankIntegration $bank_integration)
|
||||||
|
{
|
||||||
|
if (!$account->bank_integration_account_id) {
|
||||||
return response()->json(['message' => 'Not yet authenticated with Bank Integration service'], 400);
|
return response()->json(['message' => 'Not yet authenticated with Bank Integration service'], 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
$bi = BankIntegration::withTrashed()->where('bank_account_id', $acc_id)->company()->firstOrFail();
|
$yodlee = new Yodlee($account->bank_integration_account_id);
|
||||||
|
$yodlee->deleteAccount($bank_integration->bank_account_id);
|
||||||
$yodlee = new Yodlee($bank_account_id);
|
|
||||||
$res = $yodlee->deleteAccount($acc_id);
|
|
||||||
|
|
||||||
$this->bank_integration_repo->delete($bi);
|
|
||||||
|
|
||||||
return $this->itemResponse($bi->fresh());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the remote list of accounts stored on the third party provider
|
* Return the remote list of accounts stored on the third party provider
|
||||||
* and update our local cache.
|
* and update our local cache.
|
||||||
@ -288,12 +331,20 @@ class BankIntegrationController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function getTransactions(AdminBankIntegrationRequest $request)
|
public function getTransactions(AdminBankIntegrationRequest $request)
|
||||||
{
|
{
|
||||||
/** @var \App\Models\User $user */
|
/** @var \App\Models\Account $account */
|
||||||
$user = auth()->user();
|
$account = auth()->user()->account;
|
||||||
|
|
||||||
$user->account->bank_integrations->each(function ($bank_integration) use ($user) {
|
if (Ninja::isHosted() && $account->isPaid() && $account->plan == 'enterprise') {
|
||||||
(new ProcessBankTransactions($user->account->bank_integration_account_id, $bank_integration))->handle();
|
$account->bank_integrations()->where('integration_type', BankIntegration::INTEGRATION_TYPE_YODLEE)->where('auto_sync', true)->cursor()->each(function ($bank_integration) use ($account) {
|
||||||
|
(new ProcessBankTransactionsYodlee($account->id, $bank_integration))->handle();
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config("ninja.nordigen.secret_id") && config("ninja.nordigen.secret_key") && (Ninja::isSelfHost() || (Ninja::isHosted() && $account->isPaid() && $account->plan == 'enterprise'))) {
|
||||||
|
$account->bank_integrations()->where('integration_type', BankIntegration::INTEGRATION_TYPE_NORDIGEN)->where('auto_sync', true)->cursor()->each(function ($bank_integration) {
|
||||||
|
(new ProcessBankTransactionsNordigen($bank_integration))->handle();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return response()->json(['message' => 'Fetching transactions....'], 200);
|
return response()->json(['message' => 'Fetching transactions....'], 200);
|
||||||
}
|
}
|
||||||
|
@ -168,7 +168,7 @@ class PaymentMethodController extends Controller
|
|||||||
return $client_contact->client->getBACSGateway();
|
return $client_contact->client->getBACSGateway();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in_array(request()->query('method'), [GatewayType::BANK_TRANSFER, GatewayType::DIRECT_DEBIT, GatewayType::SEPA])) {
|
if (in_array(request()->query('method'), [GatewayType::BANK_TRANSFER, GatewayType::DIRECT_DEBIT, GatewayType::SEPA, GatewayType::ACSS])) {
|
||||||
return $client_contact->client->getBankTransferGateway();
|
return $client_contact->client->getBankTransferGateway();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,36 +11,37 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Events\Credit\CreditWasCreated;
|
use App\Utils\Ninja;
|
||||||
use App\Events\Credit\CreditWasUpdated;
|
use App\Models\Client;
|
||||||
use App\Factory\CloneCreditFactory;
|
use App\Models\Credit;
|
||||||
|
use App\Models\Account;
|
||||||
|
use App\Models\Invoice;
|
||||||
|
use App\Models\Webhook;
|
||||||
|
use Illuminate\Http\Response;
|
||||||
use App\Factory\CreditFactory;
|
use App\Factory\CreditFactory;
|
||||||
use App\Filters\CreditFilters;
|
use App\Filters\CreditFilters;
|
||||||
use App\Http\Requests\Credit\ActionCreditRequest;
|
use App\Jobs\Credit\ZipCredits;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use App\Jobs\Entity\EmailEntity;
|
||||||
|
use App\Factory\CloneCreditFactory;
|
||||||
|
use App\Services\PdfMaker\PdfMerge;
|
||||||
|
use Illuminate\Support\Facades\App;
|
||||||
|
use App\Utils\Traits\SavesDocuments;
|
||||||
|
use App\Repositories\CreditRepository;
|
||||||
|
use App\Events\Credit\CreditWasCreated;
|
||||||
|
use App\Events\Credit\CreditWasUpdated;
|
||||||
|
use App\Transformers\CreditTransformer;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use App\Services\Template\TemplateAction;
|
||||||
use App\Http\Requests\Credit\BulkCreditRequest;
|
use App\Http\Requests\Credit\BulkCreditRequest;
|
||||||
use App\Http\Requests\Credit\CreateCreditRequest;
|
|
||||||
use App\Http\Requests\Credit\DestroyCreditRequest;
|
|
||||||
use App\Http\Requests\Credit\EditCreditRequest;
|
use App\Http\Requests\Credit\EditCreditRequest;
|
||||||
use App\Http\Requests\Credit\ShowCreditRequest;
|
use App\Http\Requests\Credit\ShowCreditRequest;
|
||||||
use App\Http\Requests\Credit\StoreCreditRequest;
|
use App\Http\Requests\Credit\StoreCreditRequest;
|
||||||
|
use App\Http\Requests\Credit\ActionCreditRequest;
|
||||||
|
use App\Http\Requests\Credit\CreateCreditRequest;
|
||||||
use App\Http\Requests\Credit\UpdateCreditRequest;
|
use App\Http\Requests\Credit\UpdateCreditRequest;
|
||||||
use App\Http\Requests\Credit\UploadCreditRequest;
|
use App\Http\Requests\Credit\UploadCreditRequest;
|
||||||
use App\Jobs\Credit\ZipCredits;
|
use App\Http\Requests\Credit\DestroyCreditRequest;
|
||||||
use App\Jobs\Entity\EmailEntity;
|
|
||||||
use App\Models\Account;
|
|
||||||
use App\Models\Client;
|
|
||||||
use App\Models\Credit;
|
|
||||||
use App\Models\Invoice;
|
|
||||||
use App\Repositories\CreditRepository;
|
|
||||||
use App\Services\PdfMaker\PdfMerge;
|
|
||||||
use App\Services\Template\TemplateAction;
|
|
||||||
use App\Transformers\CreditTransformer;
|
|
||||||
use App\Utils\Ninja;
|
|
||||||
use App\Utils\Traits\MakesHash;
|
|
||||||
use App\Utils\Traits\SavesDocuments;
|
|
||||||
use Illuminate\Http\Response;
|
|
||||||
use Illuminate\Support\Facades\App;
|
|
||||||
use Illuminate\Support\Facades\Storage;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class CreditController.
|
* Class CreditController.
|
||||||
@ -153,6 +154,7 @@ class CreditController extends BaseController
|
|||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
|
|
||||||
$credit = CreditFactory::create($user->company()->id, $user->id);
|
$credit = CreditFactory::create($user->company()->id, $user->id);
|
||||||
|
$credit->date = now()->addSeconds($user->company()->utc_offset())->format('Y-m-d');
|
||||||
|
|
||||||
return $this->itemResponse($credit);
|
return $this->itemResponse($credit);
|
||||||
}
|
}
|
||||||
@ -638,23 +640,14 @@ class CreditController extends BaseController
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'email':
|
case 'email':
|
||||||
|
|
||||||
$credit->invitations->load('contact.client.country', 'credit.client.country', 'credit.company')->each(function ($invitation) use ($credit) {
|
|
||||||
EmailEntity::dispatch($invitation, $credit->company, 'credit');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
if (! $bulk) {
|
|
||||||
return response()->json(['message'=>'email sent'], 200);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'send_email':
|
case 'send_email':
|
||||||
|
|
||||||
$credit->invitations->load('contact.client.country', 'credit.client.country', 'credit.company')->each(function ($invitation) use ($credit) {
|
$credit->invitations->load('contact.client.country', 'credit.client.country', 'credit.company')->each(function ($invitation) use ($credit) {
|
||||||
EmailEntity::dispatch($invitation, $credit->company, 'credit');
|
EmailEntity::dispatch($invitation, $credit->company, 'credit');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$credit->sendEvent(Webhook::EVENT_SENT_CREDIT, "client");
|
||||||
|
|
||||||
if (! $bulk) {
|
if (! $bulk) {
|
||||||
return response()->json(['message'=>'email sent'], 200);
|
return response()->json(['message'=>'email sent'], 200);
|
||||||
}
|
}
|
||||||
|
@ -11,25 +11,26 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Events\Credit\CreditWasEmailed;
|
use App\Utils\Ninja;
|
||||||
use App\Events\Quote\QuoteWasEmailed;
|
use App\Models\Quote;
|
||||||
use App\Http\Requests\Email\SendEmailRequest;
|
|
||||||
use App\Jobs\PurchaseOrder\PurchaseOrderEmail;
|
|
||||||
use App\Models\Credit;
|
use App\Models\Credit;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
|
use App\Models\Webhook;
|
||||||
use App\Models\PurchaseOrder;
|
use App\Models\PurchaseOrder;
|
||||||
use App\Models\Quote;
|
|
||||||
use App\Models\RecurringInvoice;
|
|
||||||
use App\Services\Email\Email;
|
use App\Services\Email\Email;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use App\Models\RecurringInvoice;
|
||||||
use App\Services\Email\EmailObject;
|
use App\Services\Email\EmailObject;
|
||||||
|
use App\Events\Quote\QuoteWasEmailed;
|
||||||
|
use App\Transformers\QuoteTransformer;
|
||||||
|
use Illuminate\Mail\Mailables\Address;
|
||||||
|
use App\Events\Credit\CreditWasEmailed;
|
||||||
use App\Transformers\CreditTransformer;
|
use App\Transformers\CreditTransformer;
|
||||||
use App\Transformers\InvoiceTransformer;
|
use App\Transformers\InvoiceTransformer;
|
||||||
|
use App\Http\Requests\Email\SendEmailRequest;
|
||||||
|
use App\Jobs\PurchaseOrder\PurchaseOrderEmail;
|
||||||
use App\Transformers\PurchaseOrderTransformer;
|
use App\Transformers\PurchaseOrderTransformer;
|
||||||
use App\Transformers\QuoteTransformer;
|
|
||||||
use App\Transformers\RecurringInvoiceTransformer;
|
use App\Transformers\RecurringInvoiceTransformer;
|
||||||
use App\Utils\Ninja;
|
|
||||||
use App\Utils\Traits\MakesHash;
|
|
||||||
use Illuminate\Mail\Mailables\Address;
|
|
||||||
|
|
||||||
class EmailController extends BaseController
|
class EmailController extends BaseController
|
||||||
{
|
{
|
||||||
@ -100,6 +101,7 @@ class EmailController extends BaseController
|
|||||||
|
|
||||||
if ($entity_obj->invitations->count() >= 1) {
|
if ($entity_obj->invitations->count() >= 1) {
|
||||||
$entity_obj->entityEmailEvent($entity_obj->invitations->first(), 'invoice', $template);
|
$entity_obj->entityEmailEvent($entity_obj->invitations->first(), 'invoice', $template);
|
||||||
|
$entity_obj->sendEvent(Webhook::EVENT_SENT_INVOICE, "client");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,6 +111,8 @@ class EmailController extends BaseController
|
|||||||
|
|
||||||
if ($entity_obj->invitations->count() >= 1) {
|
if ($entity_obj->invitations->count() >= 1) {
|
||||||
event(new QuoteWasEmailed($entity_obj->invitations->first(), $entity_obj->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), 'quote'));
|
event(new QuoteWasEmailed($entity_obj->invitations->first(), $entity_obj->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), 'quote'));
|
||||||
|
$entity_obj->sendEvent(Webhook::EVENT_SENT_QUOTE, "client");
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,6 +122,7 @@ class EmailController extends BaseController
|
|||||||
|
|
||||||
if ($entity_obj->invitations->count() >= 1) {
|
if ($entity_obj->invitations->count() >= 1) {
|
||||||
event(new CreditWasEmailed($entity_obj->invitations->first(), $entity_obj->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), 'credit'));
|
event(new CreditWasEmailed($entity_obj->invitations->first(), $entity_obj->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), 'credit'));
|
||||||
|
$entity_obj->sendEvent(Webhook::EVENT_SENT_CREDIT, "client");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,6 +148,7 @@ class EmailController extends BaseController
|
|||||||
$data['template'] = $template;
|
$data['template'] = $template;
|
||||||
|
|
||||||
PurchaseOrderEmail::dispatch($entity_obj, $entity_obj->company, $data);
|
PurchaseOrderEmail::dispatch($entity_obj, $entity_obj->company, $data);
|
||||||
|
$entity_obj->sendEvent(Webhook::EVENT_SENT_PURCHASE_ORDER, "vendor");
|
||||||
|
|
||||||
return $this->itemResponse($entity_obj);
|
return $this->itemResponse($entity_obj);
|
||||||
}
|
}
|
||||||
|
@ -166,6 +166,7 @@ class InvoiceController extends BaseController
|
|||||||
/** @var \App\Models\User $user */
|
/** @var \App\Models\User $user */
|
||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
$invoice = InvoiceFactory::create($user->company()->id, $user->id);
|
$invoice = InvoiceFactory::create($user->company()->id, $user->id);
|
||||||
|
$invoice->date = now()->addSeconds($user->company()->utc_offset())->format('Y-m-d');
|
||||||
|
|
||||||
return $this->itemResponse($invoice);
|
return $this->itemResponse($invoice);
|
||||||
}
|
}
|
||||||
@ -538,8 +539,6 @@ class InvoiceController extends BaseController
|
|||||||
return (new \App\Jobs\Entity\CreateRawPdf($invoice->invitations->first()))->handle();
|
return (new \App\Jobs\Entity\CreateRawPdf($invoice->invitations->first()))->handle();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return response()->streamDownload(function () use ($paths) {
|
return response()->streamDownload(function () use ($paths) {
|
||||||
echo $merge = (new PdfMerge($paths->toArray()))->run();
|
echo $merge = (new PdfMerge($paths->toArray()))->run();
|
||||||
}, 'print.pdf', ['Content-Type' => 'application/pdf']);
|
}, 'print.pdf', ['Content-Type' => 'application/pdf']);
|
||||||
|
@ -155,6 +155,7 @@ class PaymentController extends BaseController
|
|||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
|
|
||||||
$payment = PaymentFactory::create($user->company()->id, $user->id);
|
$payment = PaymentFactory::create($user->company()->id, $user->id);
|
||||||
|
$payment->date = now()->addSeconds($user->company()->utc_offset())->format('Y-m-d');
|
||||||
|
|
||||||
return $this->itemResponse($payment);
|
return $this->itemResponse($payment);
|
||||||
}
|
}
|
||||||
|
@ -144,6 +144,7 @@ class PurchaseOrderController extends BaseController
|
|||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
|
|
||||||
$purchase_order = PurchaseOrderFactory::create($user->company()->id, $user->id);
|
$purchase_order = PurchaseOrderFactory::create($user->company()->id, $user->id);
|
||||||
|
$purchase_order->date = now()->addSeconds($user->company()->utc_offset())->format('Y-m-d');
|
||||||
|
|
||||||
return $this->itemResponse($purchase_order);
|
return $this->itemResponse($purchase_order);
|
||||||
}
|
}
|
||||||
|
@ -168,6 +168,7 @@ class QuoteController extends BaseController
|
|||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
|
|
||||||
$quote = QuoteFactory::create($user->company()->id, $user->id);
|
$quote = QuoteFactory::create($user->company()->id, $user->id);
|
||||||
|
$quote->date = now()->addSeconds($user->company()->utc_offset())->format('Y-m-d');
|
||||||
|
|
||||||
return $this->itemResponse($quote);
|
return $this->itemResponse($quote);
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,12 @@ class SubdomainController extends BaseController
|
|||||||
return response()->json(['message' => ctrans('texts.subdomain_is_not_available')], 401);
|
return response()->json(['message' => ctrans('texts.subdomain_is_not_available')], 401);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!preg_match('/^[A-Za-z0-9](?:[A-Za-z0-9\-]{0,61}[A-Za-z0-9])?$/', request()->input('subdomain'))) {
|
||||||
|
return response()->json(['message' => ctrans('texts.subdomain_is_not_available')], 401);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return response()->json(['message' => 'Domain available'], 200);
|
return response()->json(['message' => 'Domain available'], 200);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,12 @@ use Twilio\Rest\Client;
|
|||||||
|
|
||||||
class TwilioController extends BaseController
|
class TwilioController extends BaseController
|
||||||
{
|
{
|
||||||
|
|
||||||
|
private array $invalid_codes = [
|
||||||
|
'+21',
|
||||||
|
'+17152567760',
|
||||||
|
];
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
@ -36,8 +42,16 @@ class TwilioController extends BaseController
|
|||||||
/** @var \App\Models\User $user */
|
/** @var \App\Models\User $user */
|
||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
|
|
||||||
|
if(!$user->email_verified_at) {
|
||||||
|
return response()->json(['message' => 'Please verify your email address before verifying your phone number'], 400);
|
||||||
|
}
|
||||||
|
|
||||||
$account = $user->company()->account;
|
$account = $user->company()->account;
|
||||||
|
|
||||||
|
if(!$this->checkPhoneValidity($request->phone)) {
|
||||||
|
return response()->json(['message' => 'This phone number is not supported'], 400);
|
||||||
|
}
|
||||||
|
|
||||||
if (MultiDB::hasPhoneNumber($request->phone)) {
|
if (MultiDB::hasPhoneNumber($request->phone)) {
|
||||||
return response()->json(['message' => 'This phone number has already been verified with another account'], 400);
|
return response()->json(['message' => 'This phone number has already been verified with another account'], 400);
|
||||||
}
|
}
|
||||||
@ -65,6 +79,19 @@ class TwilioController extends BaseController
|
|||||||
return response()->json(['message' => 'Code sent.'], 200);
|
return response()->json(['message' => 'Code sent.'], 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function checkPhoneValidity($phone)
|
||||||
|
{
|
||||||
|
foreach($this->invalid_codes as $code){
|
||||||
|
|
||||||
|
if(stripos($phone, $code) !== false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the form for creating a new resource.
|
* Show the form for creating a new resource.
|
||||||
*
|
*
|
||||||
@ -117,12 +144,24 @@ class TwilioController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function generate2faResetCode(Generate2faRequest $request)
|
public function generate2faResetCode(Generate2faRequest $request)
|
||||||
{
|
{
|
||||||
|
nlog($request->all());
|
||||||
|
nlog($request->headers());
|
||||||
|
|
||||||
$user = User::where('email', $request->email)->first();
|
$user = User::where('email', $request->email)->first();
|
||||||
|
|
||||||
if (!$user) {
|
if (!$user) {
|
||||||
return response()->json(['message' => 'Unable to retrieve user.'], 400);
|
return response()->json(['message' => 'Unable to retrieve user.'], 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!$user->email_verified_at) {
|
||||||
|
return response()->json(['message' => 'Please verify your email address before verifying your phone number'], 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(!$user->first_name || !$user->last_name) {
|
||||||
|
return response()->json(['message' => 'Please update your first and/or last name in the User Details before verifying your number.'], 400);
|
||||||
|
}
|
||||||
|
|
||||||
if (!$user->phone || $user->phone == '') {
|
if (!$user->phone || $user->phone == '') {
|
||||||
return response()->json(['message' => 'User found, but no valid phone number on file, please contact support.'], 400);
|
return response()->json(['message' => 'User found, but no valid phone number on file, please contact support.'], 400);
|
||||||
}
|
}
|
||||||
|
@ -196,7 +196,7 @@ class UserController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function destroy(DestroyUserRequest $request, User $user)
|
public function destroy(DestroyUserRequest $request, User $user)
|
||||||
{
|
{
|
||||||
if ($user->isOwner()) {
|
if ($user->hasOwnerFlag()) {
|
||||||
return response()->json(['message', 'Cannot detach owner.'], 401);
|
return response()->json(['message', 'Cannot detach owner.'], 401);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,6 +55,8 @@ class PdfSlot extends Component
|
|||||||
|
|
||||||
public $is_quote = false;
|
public $is_quote = false;
|
||||||
|
|
||||||
|
private $entity_calc;
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
MultiDB::setDb($this->db);
|
MultiDB::setDb($this->db);
|
||||||
@ -123,6 +125,7 @@ class PdfSlot extends Component
|
|||||||
{
|
{
|
||||||
|
|
||||||
$this->entity_type = $this->resolveEntityType();
|
$this->entity_type = $this->resolveEntityType();
|
||||||
|
$this->entity_calc = $this->entity->calc();
|
||||||
|
|
||||||
$this->settings = $this->entity->client ? $this->entity->client->getMergedSettings() : $this->entity->company->settings;
|
$this->settings = $this->entity->client ? $this->entity->client->getMergedSettings() : $this->entity->company->settings;
|
||||||
|
|
||||||
@ -149,6 +152,8 @@ class PdfSlot extends Component
|
|||||||
'services' => $this->getServices(),
|
'services' => $this->getServices(),
|
||||||
'amount' => Number::formatMoney($this->entity->amount, $this->entity->client ?: $this->entity->vendor),
|
'amount' => Number::formatMoney($this->entity->amount, $this->entity->client ?: $this->entity->vendor),
|
||||||
'balance' => Number::formatMoney($this->entity->balance, $this->entity->client ?: $this->entity->vendor),
|
'balance' => Number::formatMoney($this->entity->balance, $this->entity->client ?: $this->entity->vendor),
|
||||||
|
'discount' => $this->entity_calc->getTotalDiscount() > 0 ? Number::formatMoney($this->entity_calc->getTotalDiscount(), $this->entity->client ?: $this->entity->vendor) : false,
|
||||||
|
'taxes' => $this->entity_calc->getTotalTaxes() > 0 ? Number::formatMoney($this->entity_calc->getTotalTaxes(), $this->entity->client ?: $this->entity->vendor) : false,
|
||||||
'company_details' => $this->getCompanyDetails(),
|
'company_details' => $this->getCompanyDetails(),
|
||||||
'company_address' => $this->getCompanyAddress(),
|
'company_address' => $this->getCompanyAddress(),
|
||||||
'entity_details' => $this->getEntityDetails(),
|
'entity_details' => $this->getEntityDetails(),
|
||||||
@ -198,20 +203,20 @@ class PdfSlot extends Component
|
|||||||
|
|
||||||
if($this->entity_type == 'invoice' || $this->entity_type == 'recurring_invoice') {
|
if($this->entity_type == 'invoice' || $this->entity_type == 'recurring_invoice') {
|
||||||
foreach($this->settings->pdf_variables->invoice_details as $variable) {
|
foreach($this->settings->pdf_variables->invoice_details as $variable) {
|
||||||
$entity_details .= "<div class='flex px-5 block'><p class= w-36 block'>{$variable}_label</p><p class='pl-5 w-36 block entity-field'>{$variable}</p></div>";
|
$entity_details .= "<div class='flex px-5 block'><p class= w-36 block'>{$variable}_label</p><p class='ml-5 w-36 block entity-field'>{$variable}</p></div>";
|
||||||
}
|
}
|
||||||
|
|
||||||
} elseif($this->entity_type == 'quote') {
|
} elseif($this->entity_type == 'quote') {
|
||||||
foreach($this->settings->pdf_variables->quote_details ?? [] as $variable) {
|
foreach($this->settings->pdf_variables->quote_details ?? [] as $variable) {
|
||||||
$entity_details .= "<div class='flex px-5 block'><p class= w-36 block'>{$variable}_label</p><p class='pl-5 w-36 block entity-field'>{$variable}</p></div>";
|
$entity_details .= "<div class='flex px-5 block'><p class= w-36 block'>{$variable}_label</p><p class='ml-5 w-36 block entity-field'>{$variable}</p></div>";
|
||||||
}
|
}
|
||||||
} elseif($this->entity_type == 'credit') {
|
} elseif($this->entity_type == 'credit') {
|
||||||
foreach($this->settings->pdf_variables->credit_details ?? [] as $variable) {
|
foreach($this->settings->pdf_variables->credit_details ?? [] as $variable) {
|
||||||
$entity_details .= "<div class='flex px-5 block'><p class= w-36 block'>{$variable}_label</p><p class='pl-5 w-36 block entity-field'>{$variable}</p></div>";
|
$entity_details .= "<div class='flex px-5 block'><p class= w-36 block'>{$variable}_label</p><p class='ml-5 w-36 block entity-field'>{$variable}</p></div>";
|
||||||
}
|
}
|
||||||
} elseif($this->entity_type == 'purchase_order') {
|
} elseif($this->entity_type == 'purchase_order') {
|
||||||
foreach($this->settings->pdf_variables->purchase_order_details ?? [] as $variable) {
|
foreach($this->settings->pdf_variables->purchase_order_details ?? [] as $variable) {
|
||||||
$entity_details .= "<div class='flex px-5 block'><p class= w-36 block'>{$variable}_label</p><p class='pl-5 w-36 block entity-field'>{$variable}</p></div>";
|
$entity_details .= "<div class='flex px-5 block'><p class= w-36 block'>{$variable}_label</p><p class='ml-5 w-36 block entity-field'>{$variable}</p></div>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,6 +310,7 @@ class PdfSlot extends Component
|
|||||||
return 'purchase_order';
|
return 'purchase_order';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,10 @@ class BulkBankIntegrationRequest extends Request
|
|||||||
*/
|
*/
|
||||||
public function authorize() : bool
|
public function authorize() : bool
|
||||||
{
|
{
|
||||||
return auth()->user()->isAdmin();
|
/** @var \App\Models\User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
return $user->isAdmin();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function rules()
|
public function rules()
|
||||||
|
@ -61,7 +61,7 @@ class UpdateCompanyRequest extends Request
|
|||||||
// $rules['client_registration_fields'] = 'array';
|
// $rules['client_registration_fields'] = 'array';
|
||||||
|
|
||||||
if (isset($input['portal_mode']) && ($input['portal_mode'] == 'domain' || $input['portal_mode'] == 'iframe')) {
|
if (isset($input['portal_mode']) && ($input['portal_mode'] == 'domain' || $input['portal_mode'] == 'iframe')) {
|
||||||
$rules['portal_domain'] = 'sometimes|url';
|
$rules['portal_domain'] = 'bail|nullable|sometimes|url';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Ninja::isHosted()) {
|
if (Ninja::isHosted()) {
|
||||||
@ -118,7 +118,7 @@ class UpdateCompanyRequest extends Request
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isset($settings['email_style_custom'])) {
|
if (isset($settings['email_style_custom'])) {
|
||||||
$settings['email_style_custom'] = str_replace(['{{', '}}'], ['', ''], $settings['email_style_custom']);
|
$settings['email_style_custom'] = str_replace(['{!!', '!!}', '{{', '}}', '@if(', '@endif', '@isset', '@unless', '@auth', '@empty', '@guest', '@env', '@section', '@switch', '@foreach', '@while', '@include', '@each', '@once', '@push', '@use', '@forelse', '@verbatim', '<?php', '@php', '@for'], '', $settings['email_style_custom']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$account->isFreeHostedClient()) {
|
if (!$account->isFreeHostedClient()) {
|
||||||
|
@ -60,7 +60,7 @@ class UpdateCreditRequest extends Request
|
|||||||
$rules['file'] = $this->file_validation;
|
$rules['file'] = $this->file_validation;
|
||||||
}
|
}
|
||||||
|
|
||||||
$rules['number'] = ['bail', 'sometimes', Rule::unique('credits')->where('company_id', $user->company()->id)->ignore($this->credit->id)];
|
$rules['number'] = ['bail', 'sometimes', 'nullable', Rule::unique('credits')->where('company_id', $user->company()->id)->ignore($this->credit->id)];
|
||||||
|
|
||||||
$rules['client_id'] = ['bail', 'sometimes',Rule::in([$this->credit->client_id])];
|
$rules['client_id'] = ['bail', 'sometimes',Rule::in([$this->credit->client_id])];
|
||||||
|
|
||||||
|
@ -11,17 +11,37 @@
|
|||||||
|
|
||||||
namespace App\Http\Requests\Email;
|
namespace App\Http\Requests\Email;
|
||||||
|
|
||||||
use App\Http\Requests\Request;
|
|
||||||
use App\Utils\Ninja;
|
use App\Utils\Ninja;
|
||||||
use App\Utils\Traits\MakesHash;
|
|
||||||
use Illuminate\Auth\Access\AuthorizationException;
|
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
use Illuminate\Auth\Access\AuthorizationException;
|
||||||
|
|
||||||
class SendEmailRequest extends Request
|
class SendEmailRequest extends Request
|
||||||
{
|
{
|
||||||
use MakesHash;
|
use MakesHash;
|
||||||
|
|
||||||
|
private string $entity_plural = '';
|
||||||
private string $error_message = '';
|
private string $error_message = '';
|
||||||
|
|
||||||
|
public array $templates = [
|
||||||
|
'email_template_invoice',
|
||||||
|
'email_template_quote',
|
||||||
|
'email_template_credit',
|
||||||
|
'email_template_payment',
|
||||||
|
'email_template_payment_partial',
|
||||||
|
'email_template_statement',
|
||||||
|
'email_template_reminder1',
|
||||||
|
'email_template_reminder2',
|
||||||
|
'email_template_reminder3',
|
||||||
|
'email_template_reminder_endless',
|
||||||
|
'email_template_custom1',
|
||||||
|
'email_template_custom2',
|
||||||
|
'email_template_custom3',
|
||||||
|
'email_template_purchase_order',
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if the user is authorized to make this request.
|
* Determine if the user is authorized to make this request.
|
||||||
*
|
*
|
||||||
@ -39,14 +59,16 @@ class SendEmailRequest extends Request
|
|||||||
*/
|
*/
|
||||||
public function rules()
|
public function rules()
|
||||||
{
|
{
|
||||||
|
/** @var \App\Models\User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'template' => 'bail|required',
|
'template' => 'bail|required|in:'.implode(',', $this->templates),
|
||||||
'entity' => 'bail|required',
|
'entity' => 'bail|required|in:App\Models\Invoice,App\Models\Quote,App\Models\Credit,App\Models\RecurringInvoice,App\Models\PurchaseOrder,App\Models\Payment',
|
||||||
'entity_id' => 'bail|required',
|
'entity_id' => ['bail', 'required', Rule::exists($this->entity_plural, 'id')->where('company_id', $user->company()->id)],
|
||||||
'cc_email.*' => 'bail|sometimes|email',
|
'cc_email.*' => 'bail|sometimes|email',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function prepareForValidation()
|
public function prepareForValidation()
|
||||||
@ -70,6 +92,8 @@ class SendEmailRequest extends Request
|
|||||||
$input['entity_id'] = $this->decodePrimaryKey($input['entity_id']);
|
$input['entity_id'] = $this->decodePrimaryKey($input['entity_id']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->entity_plural = Str::plural($input['entity']) ?? '';
|
||||||
|
|
||||||
if (isset($input['entity'])) {
|
if (isset($input['entity'])) {
|
||||||
$input['entity'] = "App\Models\\".ucfirst(Str::camel($input['entity']));
|
$input['entity'] = "App\Models\\".ucfirst(Str::camel($input['entity']));
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,17 @@ class ImportRequest extends Request
|
|||||||
'column_map' => 'required_with:hash|array',
|
'column_map' => 'required_with:hash|array',
|
||||||
'skip_header' => 'required_with:hash|boolean',
|
'skip_header' => 'required_with:hash|boolean',
|
||||||
'files.*' => 'file|mimes:csv,txt',
|
'files.*' => 'file|mimes:csv,txt',
|
||||||
'bank_integration_id' => 'bail|required_if:column_map,bank_transaction|min:2'
|
'bank_integration_id' => 'bail|required_with:column_map.bank_transaction|min:2'
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function prepareForValidation()
|
||||||
|
{
|
||||||
|
$input = $this->all();
|
||||||
|
|
||||||
|
if(!isset($input['column_map']['bank_transaction']) && array_key_exists('bank_integration_id',$input))
|
||||||
|
unset($input['bank_integration_id']);
|
||||||
|
|
||||||
|
$this->replace($input);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,8 +59,7 @@ class UpdateInvoiceRequest extends Request
|
|||||||
|
|
||||||
$rules['id'] = new LockedInvoiceRule($this->invoice);
|
$rules['id'] = new LockedInvoiceRule($this->invoice);
|
||||||
|
|
||||||
$rules['number'] = ['bail', 'sometimes', Rule::unique('invoices')->where('company_id', $user->company()->id)->ignore($this->invoice->id)];
|
$rules['number'] = ['bail', 'sometimes', 'nullable', Rule::unique('invoices')->where('company_id', $user->company()->id)->ignore($this->invoice->id)];
|
||||||
|
|
||||||
|
|
||||||
$rules['is_amount_discount'] = ['boolean'];
|
$rules['is_amount_discount'] = ['boolean'];
|
||||||
$rules['client_id'] = ['bail', 'sometimes', Rule::in([$this->invoice->client_id])];
|
$rules['client_id'] = ['bail', 'sometimes', Rule::in([$this->invoice->client_id])];
|
||||||
|
@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Nordigen;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
use App\Libraries\MultiDB;
|
||||||
|
use App\Models\Company;
|
||||||
|
use Cache;
|
||||||
|
|
||||||
|
class ConfirmNordigenBankIntegrationRequest extends Request
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'ref' => 'required|string', // nordigen redirects only with the ref-property
|
||||||
|
'lang' => 'string',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
public function getTokenContent()
|
||||||
|
{
|
||||||
|
$input = $this->all();
|
||||||
|
|
||||||
|
$data = Cache::get($input['ref']);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCompany()
|
||||||
|
{
|
||||||
|
MultiDB::findAndSetDbByCompanyKey($this->getTokenContent()['company_key']);
|
||||||
|
|
||||||
|
return Company::where('company_key', $this->getTokenContent()['company_key'])->firstOrFail();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Nordigen;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
use App\Libraries\MultiDB;
|
||||||
|
use App\Models\Company;
|
||||||
|
use Cache;
|
||||||
|
|
||||||
|
class ConnectNordigenBankIntegrationRequest extends Request
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function prepareForValidation()
|
||||||
|
{
|
||||||
|
$input = $this->all();
|
||||||
|
|
||||||
|
$context = $this->getTokenContent();
|
||||||
|
|
||||||
|
$input["redirect"] = isset($context["is_react"]) && $context['is_react'] ? config('ninja.react_url') . "/#/settings/bank_accounts" : config('ninja.app_url');
|
||||||
|
|
||||||
|
$this->replace($input);
|
||||||
|
|
||||||
|
}
|
||||||
|
public function getTokenContent()
|
||||||
|
{
|
||||||
|
if ($this->state) {
|
||||||
|
$this->token = $this->state;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = Cache::get($this->token);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCompany()
|
||||||
|
{
|
||||||
|
MultiDB::findAndSetDbByCompanyKey($this->getTokenContent()['company_key']);
|
||||||
|
|
||||||
|
return Company::where('company_key', $this->getTokenContent()['company_key'])->firstOrFail();
|
||||||
|
}
|
||||||
|
}
|
@ -23,7 +23,10 @@ class StoreProductRequest extends Request
|
|||||||
*/
|
*/
|
||||||
public function authorize() : bool
|
public function authorize() : bool
|
||||||
{
|
{
|
||||||
return auth()->user()->can('create', Product::class);
|
/** @var \App\Models\User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
return $user->can('create', Product::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function rules()
|
public function rules()
|
||||||
@ -54,7 +57,7 @@ class StoreProductRequest extends Request
|
|||||||
{
|
{
|
||||||
$input = $this->all();
|
$input = $this->all();
|
||||||
|
|
||||||
if (! isset($input['quantity']) || $input['quantity'] < 1) {
|
if (! isset($input['quantity'])) {
|
||||||
$input['quantity'] = 1;
|
$input['quantity'] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ class UpdateProductRequest extends Request
|
|||||||
{
|
{
|
||||||
$input = $this->all();
|
$input = $this->all();
|
||||||
|
|
||||||
if (! isset($input['quantity']) || $input['quantity'] < 1) {
|
if (! isset($input['quantity'])) {
|
||||||
$input['quantity'] = 1;
|
$input['quantity'] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ class UpdatePurchaseOrderRequest extends Request
|
|||||||
|
|
||||||
$rules = [];
|
$rules = [];
|
||||||
|
|
||||||
$rules['number'] = ['bail', 'sometimes', Rule::unique('purchase_orders')->where('company_id', $user->company()->id)->ignore($this->purchase_order->id)];
|
$rules['number'] = ['bail', 'sometimes', 'nullable', Rule::unique('purchase_orders')->where('company_id', $user->company()->id)->ignore($this->purchase_order->id)];
|
||||||
$rules['vendor_id'] = ['bail', 'sometimes', Rule::in([$this->purchase_order->vendor_id])];
|
$rules['vendor_id'] = ['bail', 'sometimes', Rule::in([$this->purchase_order->vendor_id])];
|
||||||
|
|
||||||
$rules['line_items'] = 'array';
|
$rules['line_items'] = 'array';
|
||||||
|
@ -55,7 +55,7 @@ class UpdateQuoteRequest extends Request
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$rules['number'] = ['bail', 'sometimes', Rule::unique('quotes')->where('company_id', $user->company()->id)->ignore($this->quote->id)];
|
$rules['number'] = ['bail', 'sometimes', 'nullable', Rule::unique('quotes')->where('company_id', $user->company()->id)->ignore($this->quote->id)];
|
||||||
|
|
||||||
$rules['client_id'] = ['bail', 'sometimes', Rule::in([$this->quote->client_id])];
|
$rules['client_id'] = ['bail', 'sometimes', Rule::in([$this->quote->client_id])];
|
||||||
|
|
||||||
@ -73,6 +73,8 @@ class UpdateQuoteRequest extends Request
|
|||||||
|
|
||||||
$input = $this->decodePrimaryKeys($input);
|
$input = $this->decodePrimaryKeys($input);
|
||||||
|
|
||||||
|
$input['id'] = $this->quote->id;
|
||||||
|
|
||||||
if (isset($input['line_items'])) {
|
if (isset($input['line_items'])) {
|
||||||
$input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : [];
|
$input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : [];
|
||||||
}
|
}
|
||||||
@ -85,7 +87,6 @@ class UpdateQuoteRequest extends Request
|
|||||||
$input['exchange_rate'] = 1;
|
$input['exchange_rate'] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
$input['id'] = $this->quote->id;
|
|
||||||
|
|
||||||
$this->replace($input);
|
$this->replace($input);
|
||||||
}
|
}
|
||||||
|
@ -42,14 +42,14 @@ class StoreSchedulerRequest extends Request
|
|||||||
'template' => 'bail|required|string',
|
'template' => 'bail|required|string',
|
||||||
'parameters' => 'bail|array',
|
'parameters' => 'bail|array',
|
||||||
'parameters.clients' => ['bail','sometimes', 'array', new ValidClientIds()],
|
'parameters.clients' => ['bail','sometimes', 'array', new ValidClientIds()],
|
||||||
'parameters.date_range' => 'bail|sometimes|string|in:last7_days,last30_days,last365_days,this_month,last_month,this_quarter,last_quarter,this_year,last_year,all_time,custom',
|
'parameters.date_range' => 'bail|sometimes|string|in:last7_days,last30_days,last365_days,this_month,last_month,this_quarter,last_quarter,this_year,last_year,all_time,custom,all',
|
||||||
'parameters.start_date' => ['bail', 'sometimes', 'date:Y-m-d', 'required_if:parameters.date_rate,custom'],
|
'parameters.start_date' => ['bail', 'sometimes', 'date:Y-m-d', 'required_if:parameters.date_rate,custom'],
|
||||||
'parameters.end_date' => ['bail', 'sometimes', 'date:Y-m-d', 'required_if:parameters.date_rate,custom', 'after_or_equal:parameters.start_date'],
|
'parameters.end_date' => ['bail', 'sometimes', 'date:Y-m-d', 'required_if:parameters.date_rate,custom', 'after_or_equal:parameters.start_date'],
|
||||||
'parameters.entity' => ['bail', 'sometimes', 'string', 'in:invoice,credit,quote,purchase_order'],
|
'parameters.entity' => ['bail', 'sometimes', 'string', 'in:invoice,credit,quote,purchase_order'],
|
||||||
'parameters.entity_id' => ['bail', 'sometimes', 'string'],
|
'parameters.entity_id' => ['bail', 'sometimes', 'string'],
|
||||||
'parameters.report_name' => ['bail','sometimes', 'string', 'required_if:template,email_report','in:ar_detailed,ar_summary,client_balance,tax_summary,profitloss,client_sales,user_sales,product_sales,clients,client_contacts,credits,documents,expenses,invoices,invoice_items,quotes,quote_items,recurring_invoices,payments,products,tasks'],
|
'parameters.report_name' => ['bail','sometimes', 'string', 'required_if:template,email_report','in:ar_detailed,ar_summary,client_balance,tax_summary,profitloss,client_sales,user_sales,product_sales,activity,client,contact,client_contact,credit,document,expense,invoice,invoice_item,quote,quote_item,recurring_invoice,payment,product,task'],
|
||||||
'parameters.date_key' => ['bail','sometimes', 'string'],
|
'parameters.date_key' => ['bail','sometimes', 'string'],
|
||||||
'parameters.status' => ['bail','sometimes', 'string', 'in:all,draft,paid,unpaid,overdue'],
|
'parameters.status' => ['bail','sometimes', 'string'],
|
||||||
];
|
];
|
||||||
|
|
||||||
return $rules;
|
return $rules;
|
||||||
@ -67,6 +67,18 @@ class StoreSchedulerRequest extends Request
|
|||||||
$input['frequency_id'] = 0;
|
$input['frequency_id'] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(isset($input['parameters']) && !isset($input['parameters']['clients'])) {
|
||||||
|
$input['parameters']['clients'] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isset($input['parameters']['status'])) {
|
||||||
|
|
||||||
|
$input['parameters']['status'] = collect(explode(",", $input['parameters']['status']))
|
||||||
|
->filter(function ($status) {
|
||||||
|
return in_array($status, ['all','draft','paid','unpaid','overdue']);
|
||||||
|
})->implode(",") ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
$this->replace($input);
|
$this->replace($input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,13 +39,14 @@ class UpdateSchedulerRequest extends Request
|
|||||||
'template' => 'bail|required|string',
|
'template' => 'bail|required|string',
|
||||||
'parameters' => 'bail|array',
|
'parameters' => 'bail|array',
|
||||||
'parameters.clients' => ['bail','sometimes', 'array', new ValidClientIds()],
|
'parameters.clients' => ['bail','sometimes', 'array', new ValidClientIds()],
|
||||||
'parameters.date_range' => 'bail|sometimes|string|in:last7_days,last30_days,last365_days,this_month,last_month,this_quarter,last_quarter,this_year,last_year,all_time,custom',
|
'parameters.date_range' => 'bail|sometimes|string|in:last7_days,last30_days,last365_days,this_month,last_month,this_quarter,last_quarter,this_year,last_year,all_time,custom,all',
|
||||||
'parameters.start_date' => ['bail', 'sometimes', 'date:Y-m-d', 'required_if:parameters.date_rate,custom'],
|
'parameters.start_date' => ['bail', 'sometimes', 'date:Y-m-d', 'required_if:parameters.date_rate,custom'],
|
||||||
'parameters.end_date' => ['bail', 'sometimes', 'date:Y-m-d', 'required_if:parameters.date_rate,custom', 'after_or_equal:parameters.start_date'],
|
'parameters.end_date' => ['bail', 'sometimes', 'date:Y-m-d', 'required_if:parameters.date_rate,custom', 'after_or_equal:parameters.start_date'],
|
||||||
'parameters.entity' => ['bail', 'sometimes', 'string', 'in:invoice,credit,quote,purchase_order'],
|
'parameters.entity' => ['bail', 'sometimes', 'string', 'in:invoice,credit,quote,purchase_order'],
|
||||||
'parameters.entity_id' => ['bail', 'sometimes', 'string'],
|
'parameters.entity_id' => ['bail', 'sometimes', 'string'],
|
||||||
'parameters.report_name' => ['bail','sometimes', 'string', 'required_if:template,email_report', 'in:ar_detailed,ar_summary,client_balance,tax_summary,profitloss,client_sales,user_sales,product_sales,clients,client_contacts,credits,documents,expenses,invoices,invoice_items,quotes,quote_items,recurring_invoices,payments,products,tasks'],
|
'parameters.report_name' => ['bail','sometimes', 'string', 'required_if:template,email_report','in:ar_detailed,ar_summary,client_balance,tax_summary,profitloss,client_sales,user_sales,product_sales,activity,client,contact,client_contact,credit,document,expense,invoice,invoice_item,quote,quote_item,recurring_invoice,payment,product,task'],
|
||||||
'parameters.date_key' => ['bail','sometimes', 'string'],
|
'parameters.date_key' => ['bail','sometimes', 'string'],
|
||||||
|
'parameters.status' => ['bail','sometimes', 'string'],
|
||||||
];
|
];
|
||||||
|
|
||||||
return $rules;
|
return $rules;
|
||||||
@ -63,8 +64,21 @@ class UpdateSchedulerRequest extends Request
|
|||||||
$input['frequency_id'] = 0;
|
$input['frequency_id'] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(isset($input['parameters']) && !isset($input['parameters']['clients'])) {
|
||||||
|
$input['parameters']['clients'] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isset($input['parameters']['status'])) {
|
||||||
|
|
||||||
|
$input['parameters']['status'] = collect(explode(",", $input['parameters']['status']))
|
||||||
|
->filter(function ($status) {
|
||||||
|
return in_array($status, ['all','draft','paid','unpaid','overdue']);
|
||||||
|
})->implode(",") ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
$this->replace($input);
|
$this->replace($input);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -11,14 +11,19 @@
|
|||||||
|
|
||||||
namespace App\Http\ValidationRules\Account;
|
namespace App\Http\ValidationRules\Account;
|
||||||
|
|
||||||
use Illuminate\Contracts\Validation\Rule;
|
use Closure;
|
||||||
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class BlackListRule.
|
* Class BlackListRule.
|
||||||
*/
|
*/
|
||||||
class BlackListRule implements Rule
|
class BlackListRule implements ValidationRule
|
||||||
{
|
{
|
||||||
|
/** Bad domains +/- dispoable email domains */
|
||||||
private array $blacklist = [
|
private array $blacklist = [
|
||||||
|
'secure-coinspot.com',
|
||||||
|
'casasotombo.com',
|
||||||
|
'otpku.com',
|
||||||
'ckptr.com',
|
'ckptr.com',
|
||||||
'pretreer.com',
|
'pretreer.com',
|
||||||
'candassociates.com',
|
'candassociates.com',
|
||||||
@ -57,6 +62,8 @@ class BlackListRule implements Rule
|
|||||||
'10dk.email',
|
'10dk.email',
|
||||||
'10mail.com',
|
'10mail.com',
|
||||||
'10mail.org',
|
'10mail.org',
|
||||||
|
'10mail.tk',
|
||||||
|
'10minmail.de',
|
||||||
'10minut.com.pl',
|
'10minut.com.pl',
|
||||||
'10minut.xyz',
|
'10minut.xyz',
|
||||||
'10minutemail.be',
|
'10minutemail.be',
|
||||||
@ -75,6 +82,7 @@ class BlackListRule implements Rule
|
|||||||
'10minutemailbox.com',
|
'10minutemailbox.com',
|
||||||
'10minutemails.in',
|
'10minutemails.in',
|
||||||
'10minutenemail.de',
|
'10minutenemail.de',
|
||||||
|
'10minutenmail.xyz',
|
||||||
'10minutesmail.com',
|
'10minutesmail.com',
|
||||||
'10minutesmail.fr',
|
'10minutesmail.fr',
|
||||||
'10minutmail.pl',
|
'10minutmail.pl',
|
||||||
@ -268,6 +276,7 @@ class BlackListRule implements Rule
|
|||||||
'affinitywe.us',
|
'affinitywe.us',
|
||||||
'affluentwe.us',
|
'affluentwe.us',
|
||||||
'affordablewe.us',
|
'affordablewe.us',
|
||||||
|
'afia.pro',
|
||||||
'afrobacon.com',
|
'afrobacon.com',
|
||||||
'afterhourswe.us',
|
'afterhourswe.us',
|
||||||
'agedmail.com',
|
'agedmail.com',
|
||||||
@ -287,6 +296,8 @@ class BlackListRule implements Rule
|
|||||||
'akapost.com',
|
'akapost.com',
|
||||||
'akerd.com',
|
'akerd.com',
|
||||||
'akgq701.com',
|
'akgq701.com',
|
||||||
|
'akmail.in',
|
||||||
|
'akugu.com',
|
||||||
'al-qaeda.us',
|
'al-qaeda.us',
|
||||||
'albionwe.us',
|
'albionwe.us',
|
||||||
'alchemywe.us',
|
'alchemywe.us',
|
||||||
@ -294,6 +305,7 @@ class BlackListRule implements Rule
|
|||||||
'aliaswe.us',
|
'aliaswe.us',
|
||||||
'alienware13.com',
|
'alienware13.com',
|
||||||
'aligamel.com',
|
'aligamel.com',
|
||||||
|
'alina-schiesser.ch',
|
||||||
'alisongamel.com',
|
'alisongamel.com',
|
||||||
'alivance.com',
|
'alivance.com',
|
||||||
'alivewe.us',
|
'alivewe.us',
|
||||||
@ -376,6 +388,7 @@ class BlackListRule implements Rule
|
|||||||
'antispam.de',
|
'antispam.de',
|
||||||
'antispam24.de',
|
'antispam24.de',
|
||||||
'antispammail.de',
|
'antispammail.de',
|
||||||
|
'any.pink',
|
||||||
'anyalias.com',
|
'anyalias.com',
|
||||||
'aoeuhtns.com',
|
'aoeuhtns.com',
|
||||||
'apfelkorps.de',
|
'apfelkorps.de',
|
||||||
@ -440,10 +453,12 @@ class BlackListRule implements Rule
|
|||||||
'badoop.com',
|
'badoop.com',
|
||||||
'badpotato.tk',
|
'badpotato.tk',
|
||||||
'balaket.com',
|
'balaket.com',
|
||||||
|
'bangban.uk',
|
||||||
'banit.club',
|
'banit.club',
|
||||||
'banit.me',
|
'banit.me',
|
||||||
'bank-opros1.ru',
|
'bank-opros1.ru',
|
||||||
'bareed.ws',
|
'bareed.ws',
|
||||||
|
'barooko.com',
|
||||||
'barryogorman.com',
|
'barryogorman.com',
|
||||||
'bartdevos.be',
|
'bartdevos.be',
|
||||||
'basscode.org',
|
'basscode.org',
|
||||||
@ -451,11 +466,15 @@ class BlackListRule implements Rule
|
|||||||
'bazaaboom.com',
|
'bazaaboom.com',
|
||||||
'bbbbyyzz.info',
|
'bbbbyyzz.info',
|
||||||
'bbhost.us',
|
'bbhost.us',
|
||||||
|
'bbitf.com',
|
||||||
|
'bbitj.com',
|
||||||
|
'bbitq.com',
|
||||||
'bcaoo.com',
|
'bcaoo.com',
|
||||||
'bcast.ws',
|
'bcast.ws',
|
||||||
'bcb.ro',
|
'bcb.ro',
|
||||||
'bccto.me',
|
'bccto.me',
|
||||||
'bdmuzic.pw',
|
'bdmuzic.pw',
|
||||||
|
'beaconmessenger.com',
|
||||||
'bearsarefuzzy.com',
|
'bearsarefuzzy.com',
|
||||||
'beddly.com',
|
'beddly.com',
|
||||||
'beefmilk.com',
|
'beefmilk.com',
|
||||||
@ -477,6 +496,7 @@ class BlackListRule implements Rule
|
|||||||
'betr.co',
|
'betr.co',
|
||||||
'bgtmail.com',
|
'bgtmail.com',
|
||||||
'bgx.ro',
|
'bgx.ro',
|
||||||
|
'bheps.com',
|
||||||
'bidourlnks.com',
|
'bidourlnks.com',
|
||||||
'big1.us',
|
'big1.us',
|
||||||
'bigprofessor.so',
|
'bigprofessor.so',
|
||||||
@ -520,9 +540,11 @@ class BlackListRule implements Rule
|
|||||||
'bouncr.com',
|
'bouncr.com',
|
||||||
'boxformail.in',
|
'boxformail.in',
|
||||||
'boximail.com',
|
'boximail.com',
|
||||||
|
'boxmail.lol',
|
||||||
'boxomail.live',
|
'boxomail.live',
|
||||||
'boxtemp.com.br',
|
'boxtemp.com.br',
|
||||||
'bptfp.net',
|
'bptfp.net',
|
||||||
|
'brand-app.biz',
|
||||||
'brandallday.net',
|
'brandallday.net',
|
||||||
'brasx.org',
|
'brasx.org',
|
||||||
'breakthru.com',
|
'breakthru.com',
|
||||||
@ -543,8 +565,10 @@ class BlackListRule implements Rule
|
|||||||
'budaya-tionghoa.com',
|
'budaya-tionghoa.com',
|
||||||
'budayationghoa.com',
|
'budayationghoa.com',
|
||||||
'buffemail.com',
|
'buffemail.com',
|
||||||
|
'bugfoo.com',
|
||||||
'bugmenever.com',
|
'bugmenever.com',
|
||||||
'bugmenot.com',
|
'bugmenot.com',
|
||||||
|
'bukhariansiddur.com',
|
||||||
'bulrushpress.com',
|
'bulrushpress.com',
|
||||||
'bum.net',
|
'bum.net',
|
||||||
'bumpymail.com',
|
'bumpymail.com',
|
||||||
@ -582,6 +606,7 @@ class BlackListRule implements Rule
|
|||||||
'caseedu.tk',
|
'caseedu.tk',
|
||||||
'cashflow35.com',
|
'cashflow35.com',
|
||||||
'casualdx.com',
|
'casualdx.com',
|
||||||
|
'catgroup.uk',
|
||||||
'cavi.mx',
|
'cavi.mx',
|
||||||
'cbair.com',
|
'cbair.com',
|
||||||
'cbes.net',
|
'cbes.net',
|
||||||
@ -605,6 +630,7 @@ class BlackListRule implements Rule
|
|||||||
'cheaphub.net',
|
'cheaphub.net',
|
||||||
'cheatmail.de',
|
'cheatmail.de',
|
||||||
'chenbot.email',
|
'chenbot.email',
|
||||||
|
'chewydonut.com',
|
||||||
'chibakenma.ml',
|
'chibakenma.ml',
|
||||||
'chickenkiller.com',
|
'chickenkiller.com',
|
||||||
'chielo.com',
|
'chielo.com',
|
||||||
@ -621,6 +647,7 @@ class BlackListRule implements Rule
|
|||||||
'chong-mail.org',
|
'chong-mail.org',
|
||||||
'chumpstakingdumps.com',
|
'chumpstakingdumps.com',
|
||||||
'cigar-auctions.com',
|
'cigar-auctions.com',
|
||||||
|
'civikli.com',
|
||||||
'civx.org',
|
'civx.org',
|
||||||
'ckaazaza.tk',
|
'ckaazaza.tk',
|
||||||
'ckiso.com',
|
'ckiso.com',
|
||||||
@ -637,6 +664,7 @@ class BlackListRule implements Rule
|
|||||||
'clonemoi.tk',
|
'clonemoi.tk',
|
||||||
'cloud-mail.top',
|
'cloud-mail.top',
|
||||||
'cloudns.cx',
|
'cloudns.cx',
|
||||||
|
'clout.wiki',
|
||||||
'clrmail.com',
|
'clrmail.com',
|
||||||
'cmail.club',
|
'cmail.club',
|
||||||
'cmail.com',
|
'cmail.com',
|
||||||
@ -678,6 +706,7 @@ class BlackListRule implements Rule
|
|||||||
'crazymailing.com',
|
'crazymailing.com',
|
||||||
'cream.pink',
|
'cream.pink',
|
||||||
'crepeau12.com',
|
'crepeau12.com',
|
||||||
|
'cringemonster.com',
|
||||||
'cross-law.ga',
|
'cross-law.ga',
|
||||||
'cross-law.gq',
|
'cross-law.gq',
|
||||||
'crossmailjet.com',
|
'crossmailjet.com',
|
||||||
@ -733,6 +762,7 @@ class BlackListRule implements Rule
|
|||||||
'daymailonline.com',
|
'daymailonline.com',
|
||||||
'dayrep.com',
|
'dayrep.com',
|
||||||
'dbunker.com',
|
'dbunker.com',
|
||||||
|
'dcctb.com',
|
||||||
'dcemail.com',
|
'dcemail.com',
|
||||||
'ddcrew.com',
|
'ddcrew.com',
|
||||||
'de-a.org',
|
'de-a.org',
|
||||||
@ -769,6 +799,7 @@ class BlackListRule implements Rule
|
|||||||
'dev-null.ga',
|
'dev-null.ga',
|
||||||
'dev-null.gq',
|
'dev-null.gq',
|
||||||
'dev-null.ml',
|
'dev-null.ml',
|
||||||
|
'developermail.com',
|
||||||
'devnullmail.com',
|
'devnullmail.com',
|
||||||
'deyom.com',
|
'deyom.com',
|
||||||
'dharmatel.net',
|
'dharmatel.net',
|
||||||
@ -800,6 +831,7 @@ class BlackListRule implements Rule
|
|||||||
'discardmail.com',
|
'discardmail.com',
|
||||||
'discardmail.de',
|
'discardmail.de',
|
||||||
'discos4.com',
|
'discos4.com',
|
||||||
|
'dishcatfish.com',
|
||||||
'disign-concept.eu',
|
'disign-concept.eu',
|
||||||
'disign-revelation.com',
|
'disign-revelation.com',
|
||||||
'dispo.in',
|
'dispo.in',
|
||||||
@ -851,10 +883,12 @@ class BlackListRule implements Rule
|
|||||||
'domforfb8.tk',
|
'domforfb8.tk',
|
||||||
'domforfb9.tk',
|
'domforfb9.tk',
|
||||||
'domozmail.com',
|
'domozmail.com',
|
||||||
|
'donebyngle.com',
|
||||||
'donemail.ru',
|
'donemail.ru',
|
||||||
'dongqing365.com',
|
'dongqing365.com',
|
||||||
'dontreg.com',
|
'dontreg.com',
|
||||||
'dontsendmespam.de',
|
'dontsendmespam.de',
|
||||||
|
'doojazz.com',
|
||||||
'doquier.tk',
|
'doquier.tk',
|
||||||
'dotman.de',
|
'dotman.de',
|
||||||
'dotmsg.com',
|
'dotmsg.com',
|
||||||
@ -869,13 +903,17 @@ class BlackListRule implements Rule
|
|||||||
'dred.ru',
|
'dred.ru',
|
||||||
'drevo.si',
|
'drevo.si',
|
||||||
'drivetagdev.com',
|
'drivetagdev.com',
|
||||||
|
'drmail.in',
|
||||||
'droolingfanboy.de',
|
'droolingfanboy.de',
|
||||||
'dropcake.de',
|
'dropcake.de',
|
||||||
'dropjar.com',
|
'dropjar.com',
|
||||||
'droplar.com',
|
'droplar.com',
|
||||||
'dropmail.me',
|
'dropmail.me',
|
||||||
'dropsin.net',
|
'dropsin.net',
|
||||||
|
'drowblock.com',
|
||||||
|
'dsgvo.party',
|
||||||
'dsgvo.ru',
|
'dsgvo.ru',
|
||||||
|
'dshfjdafd.cloud',
|
||||||
'dsiay.com',
|
'dsiay.com',
|
||||||
'dspwebservices.com',
|
'dspwebservices.com',
|
||||||
'duam.net',
|
'duam.net',
|
||||||
@ -944,6 +982,7 @@ class BlackListRule implements Rule
|
|||||||
'emailage.ml',
|
'emailage.ml',
|
||||||
'emailage.tk',
|
'emailage.tk',
|
||||||
'emailate.com',
|
'emailate.com',
|
||||||
|
'emailbin.net',
|
||||||
'emailcu.icu',
|
'emailcu.icu',
|
||||||
'emaildienst.de',
|
'emaildienst.de',
|
||||||
'emaildrop.io',
|
'emaildrop.io',
|
||||||
@ -1017,8 +1056,11 @@ class BlackListRule implements Rule
|
|||||||
'eposta.buzz',
|
'eposta.buzz',
|
||||||
'eposta.work',
|
'eposta.work',
|
||||||
'eqiluxspam.ga',
|
'eqiluxspam.ga',
|
||||||
|
'ereplyzy.com',
|
||||||
'ericjohnson.ml',
|
'ericjohnson.ml',
|
||||||
|
'eripo.net',
|
||||||
'ero-tube.org',
|
'ero-tube.org',
|
||||||
|
'esadverse.com',
|
||||||
'esbano-ru.ru',
|
'esbano-ru.ru',
|
||||||
'esc.la',
|
'esc.la',
|
||||||
'escapehatchapp.com',
|
'escapehatchapp.com',
|
||||||
@ -1043,16 +1085,19 @@ class BlackListRule implements Rule
|
|||||||
'evopo.com',
|
'evopo.com',
|
||||||
'evyush.com',
|
'evyush.com',
|
||||||
'exdonuts.com',
|
'exdonuts.com',
|
||||||
|
'exelica.com',
|
||||||
'existiert.net',
|
'existiert.net',
|
||||||
'exitstageleft.net',
|
'exitstageleft.net',
|
||||||
'explodemail.com',
|
'explodemail.com',
|
||||||
'express.net.ua',
|
'express.net.ua',
|
||||||
|
'extracurricularsociety.com',
|
||||||
'extremail.ru',
|
'extremail.ru',
|
||||||
'eyepaste.com',
|
'eyepaste.com',
|
||||||
'ez.lv',
|
'ez.lv',
|
||||||
'ezehe.com',
|
'ezehe.com',
|
||||||
'ezfill.com',
|
'ezfill.com',
|
||||||
'ezstest.com',
|
'ezstest.com',
|
||||||
|
'ezztt.com',
|
||||||
'f4k.es',
|
'f4k.es',
|
||||||
'f5.si',
|
'f5.si',
|
||||||
'facebook-email.cf',
|
'facebook-email.cf',
|
||||||
@ -1108,12 +1153,14 @@ class BlackListRule implements Rule
|
|||||||
'fbma.tk',
|
'fbma.tk',
|
||||||
'fddns.ml',
|
'fddns.ml',
|
||||||
'fdfdsfds.com',
|
'fdfdsfds.com',
|
||||||
|
'femailtor.com',
|
||||||
'fer-gabon.org',
|
'fer-gabon.org',
|
||||||
'fermaxxi.ru',
|
'fermaxxi.ru',
|
||||||
'fettometern.com',
|
'fettometern.com',
|
||||||
'fexbox.org',
|
'fexbox.org',
|
||||||
'fexbox.ru',
|
'fexbox.ru',
|
||||||
'fexpost.com',
|
'fexpost.com',
|
||||||
|
'fextemp.com',
|
||||||
'ficken.de',
|
'ficken.de',
|
||||||
'fictionsite.com',
|
'fictionsite.com',
|
||||||
'fightallspam.com',
|
'fightallspam.com',
|
||||||
@ -1127,6 +1174,7 @@ class BlackListRule implements Rule
|
|||||||
'filzmail.com',
|
'filzmail.com',
|
||||||
'findemail.info',
|
'findemail.info',
|
||||||
'findu.pl',
|
'findu.pl',
|
||||||
|
'finews.biz',
|
||||||
'fir.hk',
|
'fir.hk',
|
||||||
'firemailbox.club',
|
'firemailbox.club',
|
||||||
'fitnesrezink.ru',
|
'fitnesrezink.ru',
|
||||||
@ -1135,12 +1183,14 @@ class BlackListRule implements Rule
|
|||||||
'fizmail.com',
|
'fizmail.com',
|
||||||
'fleckens.hu',
|
'fleckens.hu',
|
||||||
'flemail.ru',
|
'flemail.ru',
|
||||||
|
'fliegender.fish',
|
||||||
'flowu.com',
|
'flowu.com',
|
||||||
'flu.cc',
|
'flu.cc',
|
||||||
'fluidsoft.us',
|
'fluidsoft.us',
|
||||||
'flurred.com',
|
'flurred.com',
|
||||||
'fly-ts.de',
|
'fly-ts.de',
|
||||||
'flyinggeek.net',
|
'flyinggeek.net',
|
||||||
|
'flymail.tk',
|
||||||
'flyspam.com',
|
'flyspam.com',
|
||||||
'foobarbot.net',
|
'foobarbot.net',
|
||||||
'footard.com',
|
'footard.com',
|
||||||
@ -1158,6 +1208,7 @@ class BlackListRule implements Rule
|
|||||||
'fosil.pro',
|
'fosil.pro',
|
||||||
'foxja.com',
|
'foxja.com',
|
||||||
'foxtrotter.info',
|
'foxtrotter.info',
|
||||||
|
'fr.cr',
|
||||||
'fr.nf',
|
'fr.nf',
|
||||||
'fr33mail.info',
|
'fr33mail.info',
|
||||||
'fragolina2.tk',
|
'fragolina2.tk',
|
||||||
@ -1204,11 +1255,15 @@ class BlackListRule implements Rule
|
|||||||
'fuirio.com',
|
'fuirio.com',
|
||||||
'fukaru.com',
|
'fukaru.com',
|
||||||
'fukurou.ch',
|
'fukurou.ch',
|
||||||
|
'fullangle.org',
|
||||||
'fulvie.com',
|
'fulvie.com',
|
||||||
'fun64.com',
|
'fun64.com',
|
||||||
'funnycodesnippets.com',
|
'funnycodesnippets.com',
|
||||||
'funnymail.de',
|
'funnymail.de',
|
||||||
'furzauflunge.de',
|
'furzauflunge.de',
|
||||||
|
'futuramind.com',
|
||||||
|
'fuwa.be',
|
||||||
|
'fuwa.li',
|
||||||
'fuwamofu.com',
|
'fuwamofu.com',
|
||||||
'fuwari.be',
|
'fuwari.be',
|
||||||
'fux0ringduh.com',
|
'fux0ringduh.com',
|
||||||
@ -1291,6 +1346,7 @@ class BlackListRule implements Rule
|
|||||||
'giveh2o.info',
|
'giveh2o.info',
|
||||||
'givememail.club',
|
'givememail.club',
|
||||||
'givmail.com',
|
'givmail.com',
|
||||||
|
'gixenmixen.com',
|
||||||
'glitch.sx',
|
'glitch.sx',
|
||||||
'globaltouron.com',
|
'globaltouron.com',
|
||||||
'glubex.com',
|
'glubex.com',
|
||||||
@ -1304,6 +1360,7 @@ class BlackListRule implements Rule
|
|||||||
'gnctr-calgary.com',
|
'gnctr-calgary.com',
|
||||||
'go2usa.info',
|
'go2usa.info',
|
||||||
'go2vpn.net',
|
'go2vpn.net',
|
||||||
|
'goatmail.uk',
|
||||||
'goemailgo.com',
|
'goemailgo.com',
|
||||||
'golemico.com',
|
'golemico.com',
|
||||||
'gomail.in',
|
'gomail.in',
|
||||||
@ -1363,6 +1420,7 @@ class BlackListRule implements Rule
|
|||||||
'guerrillamail.net',
|
'guerrillamail.net',
|
||||||
'guerrillamail.org',
|
'guerrillamail.org',
|
||||||
'guerrillamailblock.com',
|
'guerrillamailblock.com',
|
||||||
|
'gufum.com',
|
||||||
'gustr.com',
|
'gustr.com',
|
||||||
'gxemail.men',
|
'gxemail.men',
|
||||||
'gynzi.co.uk',
|
'gynzi.co.uk',
|
||||||
@ -1389,6 +1447,7 @@ class BlackListRule implements Rule
|
|||||||
'haltospam.com',
|
'haltospam.com',
|
||||||
'hamham.uk',
|
'hamham.uk',
|
||||||
'hangxomcuatoilatotoro.ml',
|
'hangxomcuatoilatotoro.ml',
|
||||||
|
'happy2023year.com',
|
||||||
'happydomik.ru',
|
'happydomik.ru',
|
||||||
'harakirimail.com',
|
'harakirimail.com',
|
||||||
'haribu.com',
|
'haribu.com',
|
||||||
@ -1467,6 +1526,7 @@ class BlackListRule implements Rule
|
|||||||
'huskion.net',
|
'huskion.net',
|
||||||
'hvastudiesucces.nl',
|
'hvastudiesucces.nl',
|
||||||
'hwsye.net',
|
'hwsye.net',
|
||||||
|
'hypenated-domain.com',
|
||||||
'i2pmail.org',
|
'i2pmail.org',
|
||||||
'i6.cloudns.cc',
|
'i6.cloudns.cc',
|
||||||
'iaoss.com',
|
'iaoss.com',
|
||||||
@ -1476,6 +1536,7 @@ class BlackListRule implements Rule
|
|||||||
'ichigo.me',
|
'ichigo.me',
|
||||||
'icx.in',
|
'icx.in',
|
||||||
'icx.ro',
|
'icx.ro',
|
||||||
|
'icznn.com',
|
||||||
'idx4.com',
|
'idx4.com',
|
||||||
'idxue.com',
|
'idxue.com',
|
||||||
'ieatspam.eu',
|
'ieatspam.eu',
|
||||||
@ -1498,9 +1559,12 @@ class BlackListRule implements Rule
|
|||||||
'imgof.com',
|
'imgof.com',
|
||||||
'imgv.de',
|
'imgv.de',
|
||||||
'immo-gerance.info',
|
'immo-gerance.info',
|
||||||
|
'imperialcnk.com',
|
||||||
'imstations.com',
|
'imstations.com',
|
||||||
'imul.info',
|
'imul.info',
|
||||||
'in-ulm.de',
|
'in-ulm.de',
|
||||||
|
'in2reach.com',
|
||||||
|
'inactivemachine.com',
|
||||||
'inbax.tk',
|
'inbax.tk',
|
||||||
'inbound.plus',
|
'inbound.plus',
|
||||||
'inbox.si',
|
'inbox.si',
|
||||||
@ -1530,6 +1594,7 @@ class BlackListRule implements Rule
|
|||||||
'ineec.net',
|
'ineec.net',
|
||||||
'infocom.zp.ua',
|
'infocom.zp.ua',
|
||||||
'inggo.org',
|
'inggo.org',
|
||||||
|
'inkiny.com',
|
||||||
'inkomail.com',
|
'inkomail.com',
|
||||||
'inmynetwork.tk',
|
'inmynetwork.tk',
|
||||||
'inoutmail.de',
|
'inoutmail.de',
|
||||||
@ -1540,12 +1605,16 @@ class BlackListRule implements Rule
|
|||||||
'insanumingeniumhomebrew.com',
|
'insanumingeniumhomebrew.com',
|
||||||
'insorg-mail.info',
|
'insorg-mail.info',
|
||||||
'instaddr.ch',
|
'instaddr.ch',
|
||||||
|
'instaddr.uk',
|
||||||
|
'instaddr.win',
|
||||||
'instance-email.com',
|
'instance-email.com',
|
||||||
'instant-mail.de',
|
'instant-mail.de',
|
||||||
'instantblingmail.info',
|
'instantblingmail.info',
|
||||||
'instantemailaddress.com',
|
'instantemailaddress.com',
|
||||||
'instantmail.fr',
|
'instantmail.fr',
|
||||||
|
'instmail.uk',
|
||||||
'internet-v-stavropole.ru',
|
'internet-v-stavropole.ru',
|
||||||
|
'internetkeno.com',
|
||||||
'internetoftags.com',
|
'internetoftags.com',
|
||||||
'interstats.org',
|
'interstats.org',
|
||||||
'intersteller.com',
|
'intersteller.com',
|
||||||
@ -1577,6 +1646,7 @@ class BlackListRule implements Rule
|
|||||||
'italy-mail.com',
|
'italy-mail.com',
|
||||||
'itcompu.com',
|
'itcompu.com',
|
||||||
'itfast.net',
|
'itfast.net',
|
||||||
|
'itsjiff.com',
|
||||||
'itunesgiftcodegenerator.com',
|
'itunesgiftcodegenerator.com',
|
||||||
'iubridge.com',
|
'iubridge.com',
|
||||||
'iuemail.men',
|
'iuemail.men',
|
||||||
@ -1585,6 +1655,7 @@ class BlackListRule implements Rule
|
|||||||
'ixx.io',
|
'ixx.io',
|
||||||
'j-p.us',
|
'j-p.us',
|
||||||
'jafps.com',
|
'jafps.com',
|
||||||
|
'jaga.email',
|
||||||
'jajxz.com',
|
'jajxz.com',
|
||||||
'janproz.com',
|
'janproz.com',
|
||||||
'jaqis.com',
|
'jaqis.com',
|
||||||
@ -1599,11 +1670,15 @@ class BlackListRule implements Rule
|
|||||||
'jetable.net',
|
'jetable.net',
|
||||||
'jetable.org',
|
'jetable.org',
|
||||||
'jetable.pp.ua',
|
'jetable.pp.ua',
|
||||||
|
'ji5.de',
|
||||||
|
'ji6.de',
|
||||||
|
'ji7.de',
|
||||||
'jiooq.com',
|
'jiooq.com',
|
||||||
'jmail.ovh',
|
'jmail.ovh',
|
||||||
'jmail.ro',
|
'jmail.ro',
|
||||||
'jnxjn.com',
|
'jnxjn.com',
|
||||||
'jobbikszimpatizans.hu',
|
'jobbikszimpatizans.hu',
|
||||||
|
'jobbrett.com',
|
||||||
'jobposts.net',
|
'jobposts.net',
|
||||||
'jobs-to-be-done.net',
|
'jobs-to-be-done.net',
|
||||||
'joelpet.com',
|
'joelpet.com',
|
||||||
@ -1660,6 +1735,8 @@ class BlackListRule implements Rule
|
|||||||
'killmail.com',
|
'killmail.com',
|
||||||
'killmail.net',
|
'killmail.net',
|
||||||
'kimsdisk.com',
|
'kimsdisk.com',
|
||||||
|
'kinda.email',
|
||||||
|
'kindamail.com',
|
||||||
'kingsq.ga',
|
'kingsq.ga',
|
||||||
'kino-100.ru',
|
'kino-100.ru',
|
||||||
'kiois.com',
|
'kiois.com',
|
||||||
@ -1668,16 +1745,20 @@ class BlackListRule implements Rule
|
|||||||
'kitnastar.com',
|
'kitnastar.com',
|
||||||
'kjkszpjcompany.com',
|
'kjkszpjcompany.com',
|
||||||
'kkmail.be',
|
'kkmail.be',
|
||||||
|
'kkoup.com',
|
||||||
'kksm.be',
|
'kksm.be',
|
||||||
'klassmaster.com',
|
'klassmaster.com',
|
||||||
'klassmaster.net',
|
'klassmaster.net',
|
||||||
'klick-tipp.us',
|
'klick-tipp.us',
|
||||||
'klipschx12.com',
|
'klipschx12.com',
|
||||||
'kloap.com',
|
'kloap.com',
|
||||||
|
'klovenode.com',
|
||||||
'kludgemush.com',
|
'kludgemush.com',
|
||||||
'klzlk.com',
|
'klzlk.com',
|
||||||
'kmail.li',
|
'kmail.li',
|
||||||
|
'kmail.live',
|
||||||
'kmhow.com',
|
'kmhow.com',
|
||||||
|
'knickerbockerban.de',
|
||||||
'knol-power.nl',
|
'knol-power.nl',
|
||||||
'kobrandly.com',
|
'kobrandly.com',
|
||||||
'kommunity.biz',
|
'kommunity.biz',
|
||||||
@ -1711,6 +1792,7 @@ class BlackListRule implements Rule
|
|||||||
'kwilco.net',
|
'kwilco.net',
|
||||||
'kyal.pl',
|
'kyal.pl',
|
||||||
'kyois.com',
|
'kyois.com',
|
||||||
|
'kzccv.com',
|
||||||
'l-c-a.us',
|
'l-c-a.us',
|
||||||
'l33r.eu',
|
'l33r.eu',
|
||||||
'l6factors.com',
|
'l6factors.com',
|
||||||
@ -1725,9 +1807,12 @@ class BlackListRule implements Rule
|
|||||||
'lak.pp.ua',
|
'lak.pp.ua',
|
||||||
'lakelivingstonrealestate.com',
|
'lakelivingstonrealestate.com',
|
||||||
'lakqs.com',
|
'lakqs.com',
|
||||||
|
'lamasticots.com',
|
||||||
|
'lambsauce.de',
|
||||||
'landmail.co',
|
'landmail.co',
|
||||||
'laoeq.com',
|
'laoeq.com',
|
||||||
'larisia.com',
|
'larisia.com',
|
||||||
|
'larland.com',
|
||||||
'last-chance.pro',
|
'last-chance.pro',
|
||||||
'lastmail.co',
|
'lastmail.co',
|
||||||
'lastmail.com',
|
'lastmail.com',
|
||||||
@ -1757,6 +1842,7 @@ class BlackListRule implements Rule
|
|||||||
'ligsb.com',
|
'ligsb.com',
|
||||||
'lillemap.net',
|
'lillemap.net',
|
||||||
'lilo.me',
|
'lilo.me',
|
||||||
|
'lilspam.com',
|
||||||
'lindenbaumjapan.com',
|
'lindenbaumjapan.com',
|
||||||
'link2mail.net',
|
'link2mail.net',
|
||||||
'linkedintuts2016.pw',
|
'linkedintuts2016.pw',
|
||||||
@ -1802,6 +1888,8 @@ class BlackListRule implements Rule
|
|||||||
'lukop.dk',
|
'lukop.dk',
|
||||||
'luv2.us',
|
'luv2.us',
|
||||||
'lyfestylecreditsolutions.com',
|
'lyfestylecreditsolutions.com',
|
||||||
|
'lyft.live',
|
||||||
|
'lyricspad.net',
|
||||||
'lzoaq.com',
|
'lzoaq.com',
|
||||||
'm21.cc',
|
'm21.cc',
|
||||||
'm4ilweb.info',
|
'm4ilweb.info',
|
||||||
@ -1847,6 +1935,7 @@ class BlackListRule implements Rule
|
|||||||
'mailapp.top',
|
'mailapp.top',
|
||||||
'mailback.com',
|
'mailback.com',
|
||||||
'mailbidon.com',
|
'mailbidon.com',
|
||||||
|
'mailbiscuit.com',
|
||||||
'mailbiz.biz',
|
'mailbiz.biz',
|
||||||
'mailblocks.com',
|
'mailblocks.com',
|
||||||
'mailbox.in.ua',
|
'mailbox.in.ua',
|
||||||
@ -1876,6 +1965,7 @@ class BlackListRule implements Rule
|
|||||||
'mailed.ro',
|
'mailed.ro',
|
||||||
'maileimer.de',
|
'maileimer.de',
|
||||||
'maileme101.com',
|
'maileme101.com',
|
||||||
|
'mailers.edu.pl',
|
||||||
'mailexpire.com',
|
'mailexpire.com',
|
||||||
'mailf5.com',
|
'mailf5.com',
|
||||||
'mailfa.tk',
|
'mailfa.tk',
|
||||||
@ -1943,6 +2033,7 @@ class BlackListRule implements Rule
|
|||||||
'mailonaut.com',
|
'mailonaut.com',
|
||||||
'mailorc.com',
|
'mailorc.com',
|
||||||
'mailorg.org',
|
'mailorg.org',
|
||||||
|
'mailosaur.net',
|
||||||
'mailox.fun',
|
'mailox.fun',
|
||||||
'mailpick.biz',
|
'mailpick.biz',
|
||||||
'mailpluss.com',
|
'mailpluss.com',
|
||||||
@ -2006,18 +2097,22 @@ class BlackListRule implements Rule
|
|||||||
'mcache.net',
|
'mcache.net',
|
||||||
'mciek.com',
|
'mciek.com',
|
||||||
'mdhc.tk',
|
'mdhc.tk',
|
||||||
|
'mdz.email',
|
||||||
'meantinc.com',
|
'meantinc.com',
|
||||||
'mebelnu.info',
|
'mebelnu.info',
|
||||||
'mechanicalresumes.com',
|
'mechanicalresumes.com',
|
||||||
'medkabinet-uzi.ru',
|
'medkabinet-uzi.ru',
|
||||||
'meepsheep.eu',
|
'meepsheep.eu',
|
||||||
|
'meidecn.com',
|
||||||
'meinspamschutz.de',
|
'meinspamschutz.de',
|
||||||
'meltedbrownies.com',
|
'meltedbrownies.com',
|
||||||
'meltmail.com',
|
'meltmail.com',
|
||||||
'memsg.site',
|
'memsg.site',
|
||||||
'mentonit.net',
|
'mentonit.net',
|
||||||
'mepost.pw',
|
'mepost.pw',
|
||||||
|
'merepost.com',
|
||||||
'merry.pink',
|
'merry.pink',
|
||||||
|
'meruado.uk',
|
||||||
'messagebeamer.de',
|
'messagebeamer.de',
|
||||||
'messwiththebestdielikethe.rest',
|
'messwiththebestdielikethe.rest',
|
||||||
'metadownload.org',
|
'metadownload.org',
|
||||||
@ -2043,6 +2138,7 @@ class BlackListRule implements Rule
|
|||||||
'migumail.com',
|
'migumail.com',
|
||||||
'mihep.com',
|
'mihep.com',
|
||||||
'mijnhva.nl',
|
'mijnhva.nl',
|
||||||
|
'minimail.gq',
|
||||||
'ministry-of-silly-walks.de',
|
'ministry-of-silly-walks.de',
|
||||||
'minsmail.com',
|
'minsmail.com',
|
||||||
'mintemail.com',
|
'mintemail.com',
|
||||||
@ -2054,6 +2150,7 @@ class BlackListRule implements Rule
|
|||||||
'mjukglass.nu',
|
'mjukglass.nu',
|
||||||
'mkpfilm.com',
|
'mkpfilm.com',
|
||||||
'ml8.ca',
|
'ml8.ca',
|
||||||
|
'mliok.com',
|
||||||
'mm.my',
|
'mm.my',
|
||||||
'mm5.se',
|
'mm5.se',
|
||||||
'mnode.me',
|
'mnode.me',
|
||||||
@ -2109,6 +2206,7 @@ class BlackListRule implements Rule
|
|||||||
'mucincanon.com',
|
'mucincanon.com',
|
||||||
'muehlacker.tk',
|
'muehlacker.tk',
|
||||||
'muell.icu',
|
'muell.icu',
|
||||||
|
'muell.io',
|
||||||
'muell.monster',
|
'muell.monster',
|
||||||
'muell.xyz',
|
'muell.xyz',
|
||||||
'muellemail.com',
|
'muellemail.com',
|
||||||
@ -2128,16 +2226,19 @@ class BlackListRule implements Rule
|
|||||||
'mycleaninbox.net',
|
'mycleaninbox.net',
|
||||||
'mycorneroftheinter.net',
|
'mycorneroftheinter.net',
|
||||||
'myde.ml',
|
'myde.ml',
|
||||||
|
'mydefipet.live',
|
||||||
'mydemo.equipment',
|
'mydemo.equipment',
|
||||||
'myecho.es',
|
'myecho.es',
|
||||||
'myemailboxy.com',
|
'myemailboxy.com',
|
||||||
'mygeoweb.info',
|
'mygeoweb.info',
|
||||||
'myindohome.services',
|
'myindohome.services',
|
||||||
|
'myinfoinc.com',
|
||||||
'myinterserver.ml',
|
'myinterserver.ml',
|
||||||
'mykickassideas.com',
|
'mykickassideas.com',
|
||||||
'mymail-in.net',
|
'mymail-in.net',
|
||||||
'mymail90.com',
|
'mymail90.com',
|
||||||
'mymailoasis.com',
|
'mymailoasis.com',
|
||||||
|
'mymaily.lol',
|
||||||
'mynetstore.de',
|
'mynetstore.de',
|
||||||
'myopang.com',
|
'myopang.com',
|
||||||
'mypacks.net',
|
'mypacks.net',
|
||||||
@ -2171,10 +2272,12 @@ class BlackListRule implements Rule
|
|||||||
'naslazhdai.ru',
|
'naslazhdai.ru',
|
||||||
'nationalgardeningclub.com',
|
'nationalgardeningclub.com',
|
||||||
'nawmin.info',
|
'nawmin.info',
|
||||||
|
'naymedia.com',
|
||||||
'nbzmr.com',
|
'nbzmr.com',
|
||||||
'negated.com',
|
'negated.com',
|
||||||
'neko2.net',
|
'neko2.net',
|
||||||
'nekochan.fr',
|
'nekochan.fr',
|
||||||
|
'nekosan.uk',
|
||||||
'neomailbox.com',
|
'neomailbox.com',
|
||||||
'neotlozhniy-zaim.ru',
|
'neotlozhniy-zaim.ru',
|
||||||
'nepwk.com',
|
'nepwk.com',
|
||||||
@ -2263,6 +2366,7 @@ class BlackListRule implements Rule
|
|||||||
'nwytg.com',
|
'nwytg.com',
|
||||||
'nwytg.net',
|
'nwytg.net',
|
||||||
'ny7.me',
|
'ny7.me',
|
||||||
|
'nyasan.com',
|
||||||
'nypato.com',
|
'nypato.com',
|
||||||
'nyrmusic.com',
|
'nyrmusic.com',
|
||||||
'o2stk.org',
|
'o2stk.org',
|
||||||
@ -2280,6 +2384,7 @@ class BlackListRule implements Rule
|
|||||||
'oepia.com',
|
'oepia.com',
|
||||||
'oerpub.org',
|
'oerpub.org',
|
||||||
'offshore-proxies.net',
|
'offshore-proxies.net',
|
||||||
|
'ofisher.net',
|
||||||
'ohaaa.de',
|
'ohaaa.de',
|
||||||
'ohi.tw',
|
'ohi.tw',
|
||||||
'oida.icu',
|
'oida.icu',
|
||||||
@ -2305,6 +2410,7 @@ class BlackListRule implements Rule
|
|||||||
'onlatedotcom.info',
|
'onlatedotcom.info',
|
||||||
'online.ms',
|
'online.ms',
|
||||||
'onlineidea.info',
|
'onlineidea.info',
|
||||||
|
'onlyapp.net',
|
||||||
'onqin.com',
|
'onqin.com',
|
||||||
'ontyne.biz',
|
'ontyne.biz',
|
||||||
'oohioo.com',
|
'oohioo.com',
|
||||||
@ -2330,6 +2436,7 @@ class BlackListRule implements Rule
|
|||||||
'ourklips.com',
|
'ourklips.com',
|
||||||
'ourpreviewdomain.com',
|
'ourpreviewdomain.com',
|
||||||
'outlawspam.com',
|
'outlawspam.com',
|
||||||
|
'outlook.edu.pl',
|
||||||
'outmail.win',
|
'outmail.win',
|
||||||
'ovomail.co',
|
'ovomail.co',
|
||||||
'ovpn.to',
|
'ovpn.to',
|
||||||
@ -2337,6 +2444,7 @@ class BlackListRule implements Rule
|
|||||||
'owlpic.com',
|
'owlpic.com',
|
||||||
'ownsyou.de',
|
'ownsyou.de',
|
||||||
'oxopoha.com',
|
'oxopoha.com',
|
||||||
|
'ozatvn.com',
|
||||||
'ozyl.de',
|
'ozyl.de',
|
||||||
'p-banlis.ru',
|
'p-banlis.ru',
|
||||||
'p33.org',
|
'p33.org',
|
||||||
@ -2347,6 +2455,7 @@ class BlackListRule implements Rule
|
|||||||
'pagamenti.tk',
|
'pagamenti.tk',
|
||||||
'paharpurmim.ga',
|
'paharpurmim.ga',
|
||||||
'pakadebu.ga',
|
'pakadebu.ga',
|
||||||
|
'pamaweb.com',
|
||||||
'pancakemail.com',
|
'pancakemail.com',
|
||||||
'papierkorb.me',
|
'papierkorb.me',
|
||||||
'paplease.com',
|
'paplease.com',
|
||||||
@ -2384,6 +2493,8 @@ class BlackListRule implements Rule
|
|||||||
'pisls.com',
|
'pisls.com',
|
||||||
'pitaniezdorovie.ru',
|
'pitaniezdorovie.ru',
|
||||||
'pivo-bar.ru',
|
'pivo-bar.ru',
|
||||||
|
'pixiil.com',
|
||||||
|
'pizzajunk.com',
|
||||||
'pjjkp.com',
|
'pjjkp.com',
|
||||||
'placebomail10.com',
|
'placebomail10.com',
|
||||||
'pleasenoham.org',
|
'pleasenoham.org',
|
||||||
@ -2435,6 +2546,7 @@ class BlackListRule implements Rule
|
|||||||
'prin.be',
|
'prin.be',
|
||||||
'privacy.net',
|
'privacy.net',
|
||||||
'privatdemail.net',
|
'privatdemail.net',
|
||||||
|
'privmail.edu.pl',
|
||||||
'privy-mail.com',
|
'privy-mail.com',
|
||||||
'privy-mail.de',
|
'privy-mail.de',
|
||||||
'privymail.de',
|
'privymail.de',
|
||||||
@ -2454,6 +2566,7 @@ class BlackListRule implements Rule
|
|||||||
'prtz.eu',
|
'prtz.eu',
|
||||||
'psh.me',
|
'psh.me',
|
||||||
'psles.com',
|
'psles.com',
|
||||||
|
'psnator.com',
|
||||||
'psoxs.com',
|
'psoxs.com',
|
||||||
'puglieisi.com',
|
'puglieisi.com',
|
||||||
'puji.pro',
|
'puji.pro',
|
||||||
@ -2464,11 +2577,13 @@ class BlackListRule implements Rule
|
|||||||
'put2.net',
|
'put2.net',
|
||||||
'puttanamaiala.tk',
|
'puttanamaiala.tk',
|
||||||
'putthisinyourspamdatabase.com',
|
'putthisinyourspamdatabase.com',
|
||||||
|
'pwpwa.com',
|
||||||
'pwrby.com',
|
'pwrby.com',
|
||||||
'qasti.com',
|
'qasti.com',
|
||||||
'qbfree.us',
|
'qbfree.us',
|
||||||
'qc.to',
|
'qc.to',
|
||||||
'qibl.at',
|
'qibl.at',
|
||||||
|
'qiott.com',
|
||||||
'qipmail.net',
|
'qipmail.net',
|
||||||
'qiq.us',
|
'qiq.us',
|
||||||
'qisdo.com',
|
'qisdo.com',
|
||||||
@ -2485,6 +2600,7 @@ class BlackListRule implements Rule
|
|||||||
'quickinbox.com',
|
'quickinbox.com',
|
||||||
'quickmail.nl',
|
'quickmail.nl',
|
||||||
'quicksend.ch',
|
'quicksend.ch',
|
||||||
|
'quipas.com',
|
||||||
'ququb.com',
|
'ququb.com',
|
||||||
'qvy.me',
|
'qvy.me',
|
||||||
'qwickmail.com',
|
'qwickmail.com',
|
||||||
@ -2496,6 +2612,7 @@ class BlackListRule implements Rule
|
|||||||
'raetp9.com',
|
'raetp9.com',
|
||||||
'rainbowly.ml',
|
'rainbowly.ml',
|
||||||
'raketenmann.de',
|
'raketenmann.de',
|
||||||
|
'ramenmail.de',
|
||||||
'rancidhome.net',
|
'rancidhome.net',
|
||||||
'randomail.io',
|
'randomail.io',
|
||||||
'randomail.net',
|
'randomail.net',
|
||||||
@ -2512,6 +2629,7 @@ class BlackListRule implements Rule
|
|||||||
're-gister.com',
|
're-gister.com',
|
||||||
'reality-concept.club',
|
'reality-concept.club',
|
||||||
'reallymymail.com',
|
'reallymymail.com',
|
||||||
|
'realquickemail.com',
|
||||||
'realtyalerts.ca',
|
'realtyalerts.ca',
|
||||||
'rebates.stream',
|
'rebates.stream',
|
||||||
'receiveee.com',
|
'receiveee.com',
|
||||||
@ -2542,6 +2660,7 @@ class BlackListRule implements Rule
|
|||||||
'rippb.com',
|
'rippb.com',
|
||||||
'risingsuntouch.com',
|
'risingsuntouch.com',
|
||||||
'riski.cf',
|
'riski.cf',
|
||||||
|
'risu.be',
|
||||||
'rklips.com',
|
'rklips.com',
|
||||||
'rkomo.com',
|
'rkomo.com',
|
||||||
'rm2rf.com',
|
'rm2rf.com',
|
||||||
@ -2578,6 +2697,7 @@ class BlackListRule implements Rule
|
|||||||
's33db0x.com',
|
's33db0x.com',
|
||||||
'sabrestlouis.com',
|
'sabrestlouis.com',
|
||||||
'sackboii.com',
|
'sackboii.com',
|
||||||
|
'saeoil.com',
|
||||||
'safaat.cf',
|
'safaat.cf',
|
||||||
'safermail.info',
|
'safermail.info',
|
||||||
'safersignup.de',
|
'safersignup.de',
|
||||||
@ -2630,10 +2750,13 @@ class BlackListRule implements Rule
|
|||||||
'sexforswingers.com',
|
'sexforswingers.com',
|
||||||
'sexical.com',
|
'sexical.com',
|
||||||
'sexyalwasmi.top',
|
'sexyalwasmi.top',
|
||||||
|
'sfolkar.com',
|
||||||
'shadap.org',
|
'shadap.org',
|
||||||
'shalar.net',
|
'shalar.net',
|
||||||
'sharedmailbox.org',
|
'sharedmailbox.org',
|
||||||
|
'sharkfaces.com',
|
||||||
'sharklasers.com',
|
'sharklasers.com',
|
||||||
|
'shchiba.uk',
|
||||||
'sheryli.com',
|
'sheryli.com',
|
||||||
'shhmail.com',
|
'shhmail.com',
|
||||||
'shhuut.org',
|
'shhuut.org',
|
||||||
@ -2662,6 +2785,7 @@ class BlackListRule implements Rule
|
|||||||
'sify.com',
|
'sify.com',
|
||||||
'sika3.com',
|
'sika3.com',
|
||||||
'sikux.com',
|
'sikux.com',
|
||||||
|
'silenceofthespam.com',
|
||||||
'siliwangi.ga',
|
'siliwangi.ga',
|
||||||
'silvercoin.life',
|
'silvercoin.life',
|
||||||
'sim-simka.ru',
|
'sim-simka.ru',
|
||||||
@ -2681,6 +2805,7 @@ class BlackListRule implements Rule
|
|||||||
'skrx.tk',
|
'skrx.tk',
|
||||||
'sky-inbox.com',
|
'sky-inbox.com',
|
||||||
'sky-ts.de',
|
'sky-ts.de',
|
||||||
|
'skygazerhub.com',
|
||||||
'skyrt.de',
|
'skyrt.de',
|
||||||
'slapsfromlastnight.com',
|
'slapsfromlastnight.com',
|
||||||
'slaskpost.se',
|
'slaskpost.se',
|
||||||
@ -2698,6 +2823,7 @@ class BlackListRule implements Rule
|
|||||||
'smapfree24.eu',
|
'smapfree24.eu',
|
||||||
'smapfree24.info',
|
'smapfree24.info',
|
||||||
'smapfree24.org',
|
'smapfree24.org',
|
||||||
|
'smartnator.com',
|
||||||
'smarttalent.pw',
|
'smarttalent.pw',
|
||||||
'smashmail.de',
|
'smashmail.de',
|
||||||
'smellfear.com',
|
'smellfear.com',
|
||||||
@ -2705,12 +2831,14 @@ class BlackListRule implements Rule
|
|||||||
'smellypotato.tk',
|
'smellypotato.tk',
|
||||||
'smtp99.com',
|
'smtp99.com',
|
||||||
'smwg.info',
|
'smwg.info',
|
||||||
|
'snakebutt.com',
|
||||||
'snakemail.com',
|
'snakemail.com',
|
||||||
'snapwet.com',
|
'snapwet.com',
|
||||||
'sneakmail.de',
|
'sneakmail.de',
|
||||||
'snece.com',
|
'snece.com',
|
||||||
'social-mailer.tk',
|
'social-mailer.tk',
|
||||||
'socialfurry.org',
|
'socialfurry.org',
|
||||||
|
'sociallymediocre.com',
|
||||||
'sofia.re',
|
'sofia.re',
|
||||||
'sofimail.com',
|
'sofimail.com',
|
||||||
'sofort-mail.de',
|
'sofort-mail.de',
|
||||||
@ -2731,6 +2859,7 @@ class BlackListRule implements Rule
|
|||||||
'soodmail.com',
|
'soodmail.com',
|
||||||
'soodomail.com',
|
'soodomail.com',
|
||||||
'soodonims.com',
|
'soodonims.com',
|
||||||
|
'soombo.com',
|
||||||
'soon.it',
|
'soon.it',
|
||||||
'spacebazzar.ru',
|
'spacebazzar.ru',
|
||||||
'spam-be-gone.com',
|
'spam-be-gone.com',
|
||||||
@ -2763,6 +2892,7 @@ class BlackListRule implements Rule
|
|||||||
'spamday.com',
|
'spamday.com',
|
||||||
'spamdecoy.net',
|
'spamdecoy.net',
|
||||||
'spamex.com',
|
'spamex.com',
|
||||||
|
'spamfellas.com',
|
||||||
'spamfighter.cf',
|
'spamfighter.cf',
|
||||||
'spamfighter.ga',
|
'spamfighter.ga',
|
||||||
'spamfighter.gq',
|
'spamfighter.gq',
|
||||||
@ -2791,6 +2921,7 @@ class BlackListRule implements Rule
|
|||||||
'spamobox.com',
|
'spamobox.com',
|
||||||
'spamoff.de',
|
'spamoff.de',
|
||||||
'spamsalad.in',
|
'spamsalad.in',
|
||||||
|
'spamsandwich.com',
|
||||||
'spamslicer.com',
|
'spamslicer.com',
|
||||||
'spamsphere.com',
|
'spamsphere.com',
|
||||||
'spamspot.com',
|
'spamspot.com',
|
||||||
@ -2810,11 +2941,13 @@ class BlackListRule implements Rule
|
|||||||
'spikio.com',
|
'spikio.com',
|
||||||
'spindl-e.com',
|
'spindl-e.com',
|
||||||
'spoofmail.de',
|
'spoofmail.de',
|
||||||
|
'sportrid.com',
|
||||||
'spr.io',
|
'spr.io',
|
||||||
'spritzzone.de',
|
'spritzzone.de',
|
||||||
'spruzme.com',
|
'spruzme.com',
|
||||||
'spybox.de',
|
'spybox.de',
|
||||||
'spymail.com',
|
'spymail.com',
|
||||||
|
'spymail.one',
|
||||||
'squizzy.de',
|
'squizzy.de',
|
||||||
'squizzy.net',
|
'squizzy.net',
|
||||||
'sroff.com',
|
'sroff.com',
|
||||||
@ -2852,10 +2985,12 @@ class BlackListRule implements Rule
|
|||||||
'submic.com',
|
'submic.com',
|
||||||
'suburbanthug.com',
|
'suburbanthug.com',
|
||||||
'suckmyd.com',
|
'suckmyd.com',
|
||||||
|
'sudern.de',
|
||||||
'sueshaw.com',
|
'sueshaw.com',
|
||||||
'suexamplesb.com',
|
'suexamplesb.com',
|
||||||
'suioe.com',
|
'suioe.com',
|
||||||
'super-auswahl.de',
|
'super-auswahl.de',
|
||||||
|
'superblohey.com',
|
||||||
'supergreatmail.com',
|
'supergreatmail.com',
|
||||||
'supermailer.jp',
|
'supermailer.jp',
|
||||||
'superplatyna.com',
|
'superplatyna.com',
|
||||||
@ -2872,6 +3007,7 @@ class BlackListRule implements Rule
|
|||||||
'sweetxxx.de',
|
'sweetxxx.de',
|
||||||
'swift-mail.net',
|
'swift-mail.net',
|
||||||
'swift10minutemail.com',
|
'swift10minutemail.com',
|
||||||
|
'syinxun.com',
|
||||||
'sylvannet.com',
|
'sylvannet.com',
|
||||||
'symphonyresume.com',
|
'symphonyresume.com',
|
||||||
'syosetu.gq',
|
'syosetu.gq',
|
||||||
@ -2891,6 +3027,8 @@ class BlackListRule implements Rule
|
|||||||
'tastrg.com',
|
'tastrg.com',
|
||||||
'taukah.com',
|
'taukah.com',
|
||||||
'tb-on-line.net',
|
'tb-on-line.net',
|
||||||
|
'tcwlm.com',
|
||||||
|
'tcwlx.com',
|
||||||
'tdtda.com',
|
'tdtda.com',
|
||||||
'tech69.com',
|
'tech69.com',
|
||||||
'techblast.ch',
|
'techblast.ch',
|
||||||
@ -2901,6 +3039,7 @@ class BlackListRule implements Rule
|
|||||||
'teewars.org',
|
'teewars.org',
|
||||||
'tefl.ro',
|
'tefl.ro',
|
||||||
'telecomix.pl',
|
'telecomix.pl',
|
||||||
|
'teleg.eu',
|
||||||
'teleworm.com',
|
'teleworm.com',
|
||||||
'teleworm.us',
|
'teleworm.us',
|
||||||
'tellos.xyz',
|
'tellos.xyz',
|
||||||
@ -2965,6 +3104,7 @@ class BlackListRule implements Rule
|
|||||||
'thecloudindex.com',
|
'thecloudindex.com',
|
||||||
'thediamants.org',
|
'thediamants.org',
|
||||||
'thedirhq.info',
|
'thedirhq.info',
|
||||||
|
'theeyeoftruth.com',
|
||||||
'thejoker5.com',
|
'thejoker5.com',
|
||||||
'thelightningmail.net',
|
'thelightningmail.net',
|
||||||
'thelimestones.com',
|
'thelimestones.com',
|
||||||
@ -2974,6 +3114,7 @@ class BlackListRule implements Rule
|
|||||||
'thereddoors.online',
|
'thereddoors.online',
|
||||||
'theroyalweb.club',
|
'theroyalweb.club',
|
||||||
'thescrappermovie.com',
|
'thescrappermovie.com',
|
||||||
|
'thespamfather.com',
|
||||||
'theteastory.info',
|
'theteastory.info',
|
||||||
'thex.ro',
|
'thex.ro',
|
||||||
'thichanthit.com',
|
'thichanthit.com',
|
||||||
@ -3010,9 +3151,13 @@ class BlackListRule implements Rule
|
|||||||
'tkitc.de',
|
'tkitc.de',
|
||||||
'tlpn.org',
|
'tlpn.org',
|
||||||
'tmail.com',
|
'tmail.com',
|
||||||
|
'tmail.io',
|
||||||
'tmail.ws',
|
'tmail.ws',
|
||||||
|
'tmail3.com',
|
||||||
|
'tmail9.com',
|
||||||
'tmailinator.com',
|
'tmailinator.com',
|
||||||
'tmails.net',
|
'tmails.net',
|
||||||
|
'tmmbt.net',
|
||||||
'tmpbox.net',
|
'tmpbox.net',
|
||||||
'tmpemails.com',
|
'tmpemails.com',
|
||||||
'tmpeml.com',
|
'tmpeml.com',
|
||||||
@ -3020,6 +3165,7 @@ class BlackListRule implements Rule
|
|||||||
'tmpjr.me',
|
'tmpjr.me',
|
||||||
'tmpmail.net',
|
'tmpmail.net',
|
||||||
'tmpmail.org',
|
'tmpmail.org',
|
||||||
|
'tmpx.sa.com',
|
||||||
'toddsbighug.com',
|
'toddsbighug.com',
|
||||||
'tofeat.com',
|
'tofeat.com',
|
||||||
'toiea.com',
|
'toiea.com',
|
||||||
@ -3049,6 +3195,7 @@ class BlackListRule implements Rule
|
|||||||
'totoan.info',
|
'totoan.info',
|
||||||
'tourcc.com',
|
'tourcc.com',
|
||||||
'tp-qa-mail.com',
|
'tp-qa-mail.com',
|
||||||
|
'tpwlb.com',
|
||||||
'tqoai.com',
|
'tqoai.com',
|
||||||
'tqosi.com',
|
'tqosi.com',
|
||||||
'tradermail.info',
|
'tradermail.info',
|
||||||
@ -3097,6 +3244,7 @@ class BlackListRule implements Rule
|
|||||||
'trialmail.de',
|
'trialmail.de',
|
||||||
'trickmail.net',
|
'trickmail.net',
|
||||||
'trillianpro.com',
|
'trillianpro.com',
|
||||||
|
'triots.com',
|
||||||
'trixtrux1.ru',
|
'trixtrux1.ru',
|
||||||
'trollproject.com',
|
'trollproject.com',
|
||||||
'tropicalbass.info',
|
'tropicalbass.info',
|
||||||
@ -3112,6 +3260,7 @@ class BlackListRule implements Rule
|
|||||||
'turoid.com',
|
'turoid.com',
|
||||||
'turual.com',
|
'turual.com',
|
||||||
'turuma.com',
|
'turuma.com',
|
||||||
|
'tutuapp.bid',
|
||||||
'tvchd.com',
|
'tvchd.com',
|
||||||
'tverya.com',
|
'tverya.com',
|
||||||
'twinmail.de',
|
'twinmail.de',
|
||||||
@ -3150,6 +3299,7 @@ class BlackListRule implements Rule
|
|||||||
'unit7lahaina.com',
|
'unit7lahaina.com',
|
||||||
'unmail.ru',
|
'unmail.ru',
|
||||||
'uooos.com',
|
'uooos.com',
|
||||||
|
'uorak.com',
|
||||||
'upliftnow.com',
|
'upliftnow.com',
|
||||||
'uplipht.com',
|
'uplipht.com',
|
||||||
'uploadnolimit.com',
|
'uploadnolimit.com',
|
||||||
@ -3268,6 +3418,7 @@ class BlackListRule implements Rule
|
|||||||
'watchever.biz',
|
'watchever.biz',
|
||||||
'watchfull.net',
|
'watchfull.net',
|
||||||
'watchironman3onlinefreefullmovie.com',
|
'watchironman3onlinefreefullmovie.com',
|
||||||
|
'waterisgone.com',
|
||||||
'wazabi.club',
|
'wazabi.club',
|
||||||
'wbdev.tech',
|
'wbdev.tech',
|
||||||
'wbml.net',
|
'wbml.net',
|
||||||
@ -3307,6 +3458,7 @@ class BlackListRule implements Rule
|
|||||||
'wegwrfmail.de',
|
'wegwrfmail.de',
|
||||||
'wegwrfmail.net',
|
'wegwrfmail.net',
|
||||||
'wegwrfmail.org',
|
'wegwrfmail.org',
|
||||||
|
'weizixu.com',
|
||||||
'wekawa.com',
|
'wekawa.com',
|
||||||
'welikecookies.com',
|
'welikecookies.com',
|
||||||
'wellsfargocomcardholders.com',
|
'wellsfargocomcardholders.com',
|
||||||
@ -3316,6 +3468,7 @@ class BlackListRule implements Rule
|
|||||||
'wfgdfhj.tk',
|
'wfgdfhj.tk',
|
||||||
'wg0.com',
|
'wg0.com',
|
||||||
'wh4f.org',
|
'wh4f.org',
|
||||||
|
'whaaaaaaaaaat.com',
|
||||||
'whatiaas.com',
|
'whatiaas.com',
|
||||||
'whatifanalytics.com',
|
'whatifanalytics.com',
|
||||||
'whatpaas.com',
|
'whatpaas.com',
|
||||||
@ -3327,6 +3480,7 @@ class BlackListRule implements Rule
|
|||||||
'wickmail.net',
|
'wickmail.net',
|
||||||
'widaryanto.info',
|
'widaryanto.info',
|
||||||
'widget.gg',
|
'widget.gg',
|
||||||
|
'wiemei.com',
|
||||||
'wierie.tk',
|
'wierie.tk',
|
||||||
'wifimaple.com',
|
'wifimaple.com',
|
||||||
'wifioak.com',
|
'wifioak.com',
|
||||||
@ -3355,6 +3509,7 @@ class BlackListRule implements Rule
|
|||||||
'wudet.men',
|
'wudet.men',
|
||||||
'wuespdj.xyz',
|
'wuespdj.xyz',
|
||||||
'wupics.com',
|
'wupics.com',
|
||||||
|
'wuuvo.com',
|
||||||
'wuzup.net',
|
'wuzup.net',
|
||||||
'wuzupmail.net',
|
'wuzupmail.net',
|
||||||
'wwjmp.com',
|
'wwjmp.com',
|
||||||
@ -3466,6 +3621,7 @@ class BlackListRule implements Rule
|
|||||||
'zebins.eu',
|
'zebins.eu',
|
||||||
'zehnminuten.de',
|
'zehnminuten.de',
|
||||||
'zehnminutenmail.de',
|
'zehnminutenmail.de',
|
||||||
|
'zemzar.net',
|
||||||
'zepp.dk',
|
'zepp.dk',
|
||||||
'zetmail.com',
|
'zetmail.com',
|
||||||
'zfymail.com',
|
'zfymail.com',
|
||||||
@ -3476,6 +3632,7 @@ class BlackListRule implements Rule
|
|||||||
'zhorachu.com',
|
'zhorachu.com',
|
||||||
'zik.dj',
|
'zik.dj',
|
||||||
'zipcad.com',
|
'zipcad.com',
|
||||||
|
'zipcatfish.com',
|
||||||
'zipo1.gq',
|
'zipo1.gq',
|
||||||
'zippymail.info',
|
'zippymail.info',
|
||||||
'zipsendtest.com',
|
'zipsendtest.com',
|
||||||
@ -3497,27 +3654,13 @@ class BlackListRule implements Rule
|
|||||||
'zzz.com',
|
'zzz.com',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
public function validate(string $attribute, mixed $value, Closure $fail): void
|
||||||
* @param string $attribute
|
|
||||||
* @param mixed $value
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function passes($attribute, $value): bool
|
|
||||||
{
|
{
|
||||||
$parts = explode("@", $value);
|
$parts = explode("@", $value);
|
||||||
|
|
||||||
if (is_array($parts)) {
|
if (is_array($parts) && in_array($parts[1], $this->blacklist)) {
|
||||||
return ! in_array($parts[1], $this->blacklist);
|
$fail('This domain is blacklisted, if you think this is in error, please email contact@invoiceninja.com');
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function message(): string
|
|
||||||
{
|
|
||||||
return 'This domain is blacklisted, if you think this is in error, please email contact@invoiceninja.com';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -11,32 +11,26 @@
|
|||||||
|
|
||||||
namespace App\Http\ValidationRules\Account;
|
namespace App\Http\ValidationRules\Account;
|
||||||
|
|
||||||
use Illuminate\Contracts\Validation\Rule;
|
use Closure;
|
||||||
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class EmailBlackListRule.
|
* Class EmailBlackListRule.
|
||||||
*/
|
*/
|
||||||
class EmailBlackListRule implements Rule
|
class EmailBlackListRule implements ValidationRule
|
||||||
{
|
{
|
||||||
public array $blacklist = [
|
public array $blacklist = [
|
||||||
|
'noddy@invoiceninja.com',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $attribute
|
public function validate(string $attribute, mixed $value, Closure $fail): void
|
||||||
* @param mixed $value
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function passes($attribute, $value)
|
|
||||||
{
|
{
|
||||||
return ! in_array($value, $this->blacklist);
|
|
||||||
|
if (in_array($value, $this->blacklist)) {
|
||||||
|
$fail('This email address is blacklisted, if you think this is in error, please email contact@invoiceninja.com');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function message()
|
|
||||||
{
|
|
||||||
return 'This email address is blacklisted, if you think this is in error, please email contact@invoiceninja.com';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -94,7 +94,6 @@ class MatchBankTransactions implements ShouldQueue
|
|||||||
}
|
}
|
||||||
|
|
||||||
$bank_categories = Cache::get('bank_categories');
|
$bank_categories = Cache::get('bank_categories');
|
||||||
|
|
||||||
if (!$bank_categories && $yodlee) {
|
if (!$bank_categories && $yodlee) {
|
||||||
$_categories = $yodlee->getTransactionCategories();
|
$_categories = $yodlee->getTransactionCategories();
|
||||||
$this->categories = collect($_categories->transactionCategory);
|
$this->categories = collect($_categories->transactionCategory);
|
||||||
|
177
app/Jobs/Bank/ProcessBankTransactionsNordigen.php
Normal file
177
app/Jobs/Bank/ProcessBankTransactionsNordigen.php
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Credit Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022. Credit Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Jobs\Bank;
|
||||||
|
|
||||||
|
use App\Helpers\Bank\Nordigen\Nordigen;
|
||||||
|
use App\Libraries\MultiDB;
|
||||||
|
use App\Models\BankIntegration;
|
||||||
|
use App\Models\BankTransaction;
|
||||||
|
use App\Models\Company;
|
||||||
|
use App\Notifications\Ninja\GenericNinjaAdminNotification;
|
||||||
|
use App\Services\Bank\BankMatchingService;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
class ProcessBankTransactionsNordigen implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
private BankIntegration $bank_integration;
|
||||||
|
|
||||||
|
private ?string $from_date;
|
||||||
|
|
||||||
|
public Company $company;
|
||||||
|
public Nordigen $nordigen;
|
||||||
|
public $nordigen_account;
|
||||||
|
private bool $stop_loop = false;
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*/
|
||||||
|
public function __construct(BankIntegration $bank_integration)
|
||||||
|
{
|
||||||
|
$this->bank_integration = $bank_integration;
|
||||||
|
$this->from_date = $bank_integration->from_date ?: now()->subDays(90);
|
||||||
|
$this->company = $this->bank_integration->company;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the job.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
if ($this->bank_integration->integration_type != BankIntegration::INTEGRATION_TYPE_NORDIGEN)
|
||||||
|
throw new \Exception("Invalid BankIntegration Type");
|
||||||
|
|
||||||
|
if (!(config('ninja.nordigen.secret_id') && config('ninja.nordigen.secret_key')))
|
||||||
|
throw new \Exception("Missing credentials for bank_integration service nordigen");
|
||||||
|
|
||||||
|
$this->nordigen = new Nordigen();
|
||||||
|
|
||||||
|
set_time_limit(0);
|
||||||
|
|
||||||
|
nlog("Nordigen: Processing transactions for account: {$this->bank_integration->account->key}");
|
||||||
|
|
||||||
|
// UPDATE ACCOUNT
|
||||||
|
try {
|
||||||
|
$this->updateAccount();
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
nlog("Nordigen: {$this->bank_integration->nordigen_account_id} - exited abnormally => " . $e->getMessage());
|
||||||
|
|
||||||
|
$content = [
|
||||||
|
"Processing transactions for account: {$this->bank_integration->nordigen_account_id} failed",
|
||||||
|
"Exception Details => ",
|
||||||
|
$e->getMessage(),
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->bank_integration->company->notification(new GenericNinjaAdminNotification($content))->ninja();
|
||||||
|
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
if (!$this->nordigen_account)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// UPDATE TRANSACTIONS
|
||||||
|
try {
|
||||||
|
$this->processTransactions();
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
nlog("Nordigen: {$this->bank_integration->nordigen_account_id} - exited abnormally => " . $e->getMessage());
|
||||||
|
|
||||||
|
$content = [
|
||||||
|
"Processing transactions for account: {$this->bank_integration->nordigen_account_id} failed",
|
||||||
|
"Exception Details => ",
|
||||||
|
$e->getMessage(),
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->bank_integration->company->notification(new GenericNinjaAdminNotification($content))->ninja();
|
||||||
|
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform Matching
|
||||||
|
BankMatchingService::dispatch($this->company->id, $this->company->db);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function updateAccount()
|
||||||
|
{
|
||||||
|
if (!$this->nordigen->isAccountActive($this->bank_integration->nordigen_account_id)) {
|
||||||
|
$this->bank_integration->disabled_upstream = true;
|
||||||
|
$this->bank_integration->save();
|
||||||
|
$this->stop_loop = false;
|
||||||
|
nlog("Nordigen: account inactive: " . $this->bank_integration->nordigen_account_id);
|
||||||
|
// @turbo124 @todo send email for expired account
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->nordigen_account = $this->nordigen->getAccount($this->bank_integration->nordigen_account_id);
|
||||||
|
|
||||||
|
$this->bank_integration->disabled_upstream = false;
|
||||||
|
$this->bank_integration->bank_account_status = $this->nordigen_account['account_status'];
|
||||||
|
$this->bank_integration->balance = $this->nordigen_account['current_balance'];
|
||||||
|
|
||||||
|
$this->bank_integration->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function processTransactions()
|
||||||
|
{
|
||||||
|
//Get transaction count object
|
||||||
|
$transactions = $this->nordigen->getTransactions($this->bank_integration->nordigen_account_id, $this->from_date);
|
||||||
|
|
||||||
|
//if no transactions, update the from_date and move on
|
||||||
|
if (count($transactions) == 0) {
|
||||||
|
|
||||||
|
$this->bank_integration->from_date = now()->subDays(5);
|
||||||
|
$this->bank_integration->disabled_upstream = false;
|
||||||
|
$this->bank_integration->save();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Harvest the company
|
||||||
|
|
||||||
|
MultiDB::setDb($this->company->db);
|
||||||
|
|
||||||
|
/*Get the user */
|
||||||
|
$user_id = $this->company->owner()->id;
|
||||||
|
|
||||||
|
/* Unguard the model to perform batch inserts */
|
||||||
|
BankTransaction::unguard();
|
||||||
|
|
||||||
|
$now = now();
|
||||||
|
|
||||||
|
foreach ($transactions as $transaction) {
|
||||||
|
|
||||||
|
if (BankTransaction::where('transaction_id', $transaction['transaction_id'])->where('company_id', $this->company->id)->where('bank_integration_id', $this->bank_integration->id)->withTrashed()->exists())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//this should be much faster to insert than using ::create()
|
||||||
|
\DB::table('bank_transactions')->insert(
|
||||||
|
array_merge($transaction, [
|
||||||
|
'company_id' => $this->company->id,
|
||||||
|
'user_id' => $user_id,
|
||||||
|
'bank_integration_id' => $this->bank_integration->id,
|
||||||
|
'created_at' => $now,
|
||||||
|
'updated_at' => $now,
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->bank_integration->from_date = now()->subDays(5);
|
||||||
|
$this->bank_integration->save();
|
||||||
|
}
|
||||||
|
}
|
@ -14,6 +14,7 @@ namespace App\Jobs\Bank;
|
|||||||
use App\Helpers\Bank\Yodlee\Transformer\AccountTransformer;
|
use App\Helpers\Bank\Yodlee\Transformer\AccountTransformer;
|
||||||
use App\Helpers\Bank\Yodlee\Yodlee;
|
use App\Helpers\Bank\Yodlee\Yodlee;
|
||||||
use App\Libraries\MultiDB;
|
use App\Libraries\MultiDB;
|
||||||
|
use App\Models\Account;
|
||||||
use App\Models\BankIntegration;
|
use App\Models\BankIntegration;
|
||||||
use App\Models\BankTransaction;
|
use App\Models\BankTransaction;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
@ -26,7 +27,7 @@ use Illuminate\Queue\InteractsWithQueue;
|
|||||||
use Illuminate\Queue\Middleware\WithoutOverlapping;
|
use Illuminate\Queue\Middleware\WithoutOverlapping;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
class ProcessBankTransactions implements ShouldQueue
|
class ProcessBankTransactionsYodlee implements ShouldQueue
|
||||||
{
|
{
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
@ -61,21 +62,24 @@ class ProcessBankTransactions implements ShouldQueue
|
|||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
|
if ($this->bank_integration->integration_type != BankIntegration::INTEGRATION_TYPE_YODLEE)
|
||||||
|
throw new \Exception("Invalid BankIntegration Type");
|
||||||
|
|
||||||
set_time_limit(0);
|
set_time_limit(0);
|
||||||
|
|
||||||
//Loop through everything until we are up to date
|
//Loop through everything until we are up to date
|
||||||
$this->from_date = $this->from_date ?: '2021-01-01';
|
$this->from_date = $this->from_date ?: '2021-01-01';
|
||||||
|
|
||||||
nlog("Processing transactions for account: {$this->bank_integration->account->key}");
|
nlog("Yodlee: Processing transactions for account: {$this->bank_integration->account->key}");
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try {
|
try {
|
||||||
$this->processTransactions();
|
$this->processTransactions();
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
nlog("{$this->bank_integration_account_id} - exited abnormally => ". $e->getMessage());
|
nlog("Yodlee: {$this->bank_integration->bank_account_id} - exited abnormally => " . $e->getMessage());
|
||||||
|
|
||||||
$content = [
|
$content = [
|
||||||
"Processing transactions for account: {$this->bank_integration->account->key} failed",
|
"Processing transactions for account: {$this->bank_integration->bank_account_id} failed",
|
||||||
"Exception Details => ",
|
"Exception Details => ",
|
||||||
$e->getMessage(),
|
$e->getMessage(),
|
||||||
];
|
];
|
||||||
@ -158,7 +162,7 @@ class ProcessBankTransactions implements ShouldQueue
|
|||||||
$now = now();
|
$now = now();
|
||||||
|
|
||||||
foreach ($transactions as $transaction) {
|
foreach ($transactions as $transaction) {
|
||||||
if (BankTransaction::query()->where('transaction_id', $transaction['transaction_id'])->where('company_id', $this->company->id)->withTrashed()->exists()) {
|
if (BankTransaction::query()->where('transaction_id', $transaction['transaction_id'])->where('company_id', $this->company->id)->where('bank_integration_id', $this->bank_integration->id)->withTrashed()->exists()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -224,7 +224,7 @@ class CompanyExport implements ShouldQueue
|
|||||||
|
|
||||||
$this->export_data['invoices'] = $this->company->invoices()->orderBy('number', 'DESC')->cursor()->map(function ($invoice) {
|
$this->export_data['invoices'] = $this->company->invoices()->orderBy('number', 'DESC')->cursor()->map(function ($invoice) {
|
||||||
$invoice = $this->transformBasicEntities($invoice);
|
$invoice = $this->transformBasicEntities($invoice);
|
||||||
$invoice = $this->transformArrayOfKeys($invoice, ['recurring_id','client_id', 'vendor_id', 'project_id', 'design_id', 'subscription_id','project_id']);
|
$invoice = $this->transformArrayOfKeys($invoice, ['recurring_id','client_id', 'vendor_id', 'project_id', 'design_id', 'subscription_id']);
|
||||||
$invoice->tax_data = '';
|
$invoice->tax_data = '';
|
||||||
|
|
||||||
return $invoice->makeVisible(['id',
|
return $invoice->makeVisible(['id',
|
||||||
@ -331,7 +331,8 @@ class CompanyExport implements ShouldQueue
|
|||||||
$task = $this->transformBasicEntities($task);
|
$task = $this->transformBasicEntities($task);
|
||||||
$task = $this->transformArrayOfKeys($task, ['client_id', 'invoice_id', 'project_id', 'status_id']);
|
$task = $this->transformArrayOfKeys($task, ['client_id', 'invoice_id', 'project_id', 'status_id']);
|
||||||
|
|
||||||
return $task->makeVisible(['id']);
|
return $task->makeHidden(['hash','meta'])->makeVisible(['id']);
|
||||||
|
// return $task->makeHidden(['hash','meta'])->makeVisible(['id']); //@release v5.7.63
|
||||||
})->all();
|
})->all();
|
||||||
|
|
||||||
$this->export_data['task_statuses'] = $this->company->task_statuses->map(function ($status) {
|
$this->export_data['task_statuses'] = $this->company->task_statuses->map(function ($status) {
|
||||||
@ -387,19 +388,19 @@ class CompanyExport implements ShouldQueue
|
|||||||
})->all();
|
})->all();
|
||||||
|
|
||||||
|
|
||||||
$this->export_data['bank_integrations'] = $this->company->bank_integrations()->orderBy('id', 'ASC')->cursor()->map(function ($bank_integration) {
|
$this->export_data['bank_integrations'] = $this->company->bank_integrations()->withTrashed()->orderBy('id', 'ASC')->cursor()->map(function ($bank_integration) {
|
||||||
$bank_integration = $this->transformArrayOfKeys($bank_integration, ['account_id','company_id', 'user_id']);
|
$bank_integration = $this->transformArrayOfKeys($bank_integration, ['account_id','company_id', 'user_id']);
|
||||||
|
|
||||||
return $bank_integration->makeVisible(['id','user_id','company_id','account_id']);
|
return $bank_integration->makeVisible(['id','user_id','company_id','account_id','hashed_id']);
|
||||||
})->all();
|
})->all();
|
||||||
|
|
||||||
$this->export_data['bank_transactions'] = $this->company->bank_transactions()->orderBy('id', 'ASC')->cursor()->map(function ($bank_transaction) {
|
$this->export_data['bank_transactions'] = $this->company->bank_transactions()->withTrashed()->orderBy('id', 'ASC')->cursor()->map(function ($bank_transaction) {
|
||||||
$bank_transaction = $this->transformArrayOfKeys($bank_transaction, ['company_id', 'user_id','bank_integration_id','expense_id','category_id','ninja_category_id','vendor_id']);
|
$bank_transaction = $this->transformArrayOfKeys($bank_transaction, ['company_id', 'user_id','bank_integration_id','expense_id','ninja_category_id','vendor_id']);
|
||||||
|
|
||||||
return $bank_transaction->makeVisible(['id','user_id','company_id']);
|
return $bank_transaction->makeVisible(['id','user_id','company_id']);
|
||||||
})->all();
|
})->all();
|
||||||
|
|
||||||
$this->export_data['schedulers'] = $this->company->schedulers()->orderBy('id', 'ASC')->cursor()->map(function ($scheduler) {
|
$this->export_data['schedulers'] = $this->company->schedulers()->withTrashed()->orderBy('id', 'ASC')->cursor()->map(function ($scheduler) {
|
||||||
$scheduler = $this->transformArrayOfKeys($scheduler, ['company_id', 'user_id']);
|
$scheduler = $this->transformArrayOfKeys($scheduler, ['company_id', 'user_id']);
|
||||||
|
|
||||||
return $scheduler->makeVisible(['id','user_id','company_id']);
|
return $scheduler->makeVisible(['id','user_id','company_id']);
|
||||||
|
@ -63,14 +63,12 @@ use App\Utils\Ninja;
|
|||||||
use App\Utils\TempFile;
|
use App\Utils\TempFile;
|
||||||
use App\Utils\Traits\GeneratesCounter;
|
use App\Utils\Traits\GeneratesCounter;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
use function GuzzleHttp\json_encode;
|
|
||||||
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\Facades\App;
|
use Illuminate\Support\Facades\App;
|
||||||
use Illuminate\Support\Facades\Cache;
|
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use JsonMachine\JsonDecoder\ExtJsonDecoder;
|
use JsonMachine\JsonDecoder\ExtJsonDecoder;
|
||||||
@ -142,7 +140,6 @@ class CompanyImport implements ShouldQueue
|
|||||||
'recurring_expenses',
|
'recurring_expenses',
|
||||||
'expenses',
|
'expenses',
|
||||||
'tasks',
|
'tasks',
|
||||||
'payments',
|
|
||||||
'company_ledger',
|
'company_ledger',
|
||||||
'designs',
|
'designs',
|
||||||
'documents',
|
'documents',
|
||||||
@ -569,7 +566,7 @@ class CompanyImport implements ShouldQueue
|
|||||||
['expenses' => 'expense_id'],
|
['expenses' => 'expense_id'],
|
||||||
['vendors' => 'vendor_id'],
|
['vendors' => 'vendor_id'],
|
||||||
['expense_categories' => 'ninja_category_id'],
|
['expense_categories' => 'ninja_category_id'],
|
||||||
['expense_categories' => 'category_id'],
|
// ['expense_categories' => 'category_id'],
|
||||||
['bank_integrations' => 'bank_integration_id']
|
['bank_integrations' => 'bank_integration_id']
|
||||||
],
|
],
|
||||||
'bank_transactions',
|
'bank_transactions',
|
||||||
@ -1143,7 +1140,34 @@ class CompanyImport implements ShouldQueue
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$storage_url = (object)$this->getObject('storage_url', true);
|
||||||
|
|
||||||
|
if (!Storage::exists($document->url) && is_string($storage_url)) {
|
||||||
|
$url = $storage_url . $document->url;
|
||||||
|
|
||||||
|
$file = @file_get_contents($url);
|
||||||
|
|
||||||
|
|
||||||
|
if ($file) {
|
||||||
|
try {
|
||||||
|
Storage::disk(config('filesystems.default'))->put($document->url, $file);
|
||||||
|
|
||||||
|
|
||||||
|
} catch(\Exception $e) {
|
||||||
|
nlog($e->getMessage());
|
||||||
|
nlog("I could not upload {$document->url}");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
|
||||||
$new_document = new Document();
|
$new_document = new Document();
|
||||||
|
$new_document->disk = config('filesystems.default');
|
||||||
$new_document->user_id = $this->transformId('users', $document->user_id);
|
$new_document->user_id = $this->transformId('users', $document->user_id);
|
||||||
$new_document->assigned_user_id = $this->transformId('users', $document->assigned_user_id);
|
$new_document->assigned_user_id = $this->transformId('users', $document->assigned_user_id);
|
||||||
$new_document->company_id = $this->company->id;
|
$new_document->company_id = $this->company->id;
|
||||||
@ -1169,26 +1193,6 @@ class CompanyImport implements ShouldQueue
|
|||||||
|
|
||||||
$new_document->save(['timestamps' => false]);
|
$new_document->save(['timestamps' => false]);
|
||||||
|
|
||||||
$storage_url = (object)$this->getObject('storage_url', true);
|
|
||||||
|
|
||||||
if (!Storage::exists($new_document->url) && is_string($storage_url)) {
|
|
||||||
$url = $storage_url . $new_document->url;
|
|
||||||
|
|
||||||
$file = @file_get_contents($url);
|
|
||||||
|
|
||||||
if ($file) {
|
|
||||||
try {
|
|
||||||
Storage::disk(config('filesystems.default'))->put($new_document->url, $file);
|
|
||||||
|
|
||||||
$new_document->disk = config('filesystems.default');
|
|
||||||
$new_document->save();
|
|
||||||
} catch(\Exception $e) {
|
|
||||||
nlog($e->getMessage());
|
|
||||||
nlog("I could not upload {$new_document->url}");
|
|
||||||
$new_document->forceDelete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
@ -1727,7 +1731,9 @@ class CompanyImport implements ShouldQueue
|
|||||||
*/
|
*/
|
||||||
private function transformId(string $resource, ?string $old): ?int
|
private function transformId(string $resource, ?string $old): ?int
|
||||||
{
|
{
|
||||||
if (empty($old)) {
|
|
||||||
|
// WjnegYbwZ1 == 0 return null;
|
||||||
|
if (empty($old) || $old == 'WjnegYbwZ1') {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1736,6 +1742,7 @@ class CompanyImport implements ShouldQueue
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (! array_key_exists($resource, $this->ids)) {
|
if (! array_key_exists($resource, $this->ids)) {
|
||||||
|
|
||||||
$this->sendImportMail("The Import failed due to missing data in the import file. Resource {$resource} not available.");
|
$this->sendImportMail("The Import failed due to missing data in the import file. Resource {$resource} not available.");
|
||||||
|
|
||||||
throw new \Exception("Resource {$resource} not available.");
|
throw new \Exception("Resource {$resource} not available.");
|
||||||
@ -1745,15 +1752,11 @@ class CompanyImport implements ShouldQueue
|
|||||||
// nlog($this->ids[$resource]);
|
// nlog($this->ids[$resource]);
|
||||||
nlog("searching for {$old} in {$resource}");
|
nlog("searching for {$old} in {$resource}");
|
||||||
|
|
||||||
nlog("If we are missing a user - default to the company owner");
|
|
||||||
|
|
||||||
if ($resource == 'users') {
|
if ($resource == 'users') {
|
||||||
return $this->company_owner->id;
|
return $this->company_owner->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->sendImportMail("The Import failed due to missing data in the import file. Resource {$resource} not available.");
|
$this->sendImportMail("The Import failed due to missing data in the import file. Key {$old} not found in {$resource}.");
|
||||||
|
|
||||||
nlog($this->ids[$resource]);
|
|
||||||
|
|
||||||
throw new \Exception("Missing {$resource} key: {$old}");
|
throw new \Exception("Missing {$resource} key: {$old}");
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ class CreateCompany
|
|||||||
$company->settings = $settings;
|
$company->settings = $settings;
|
||||||
$company->db = config('database.default');
|
$company->db = config('database.default');
|
||||||
$company->enabled_modules = config('ninja.enabled_modules');
|
$company->enabled_modules = config('ninja.enabled_modules');
|
||||||
$company->subdomain = isset($this->request['subdomain']) ? $this->request['subdomain'] : '';
|
$company->subdomain = isset($this->request['subdomain']) ? $this->request['subdomain'] : MultiDB::randomSubdomainGenerator();
|
||||||
$company->custom_fields = new \stdClass;
|
$company->custom_fields = new \stdClass;
|
||||||
$company->default_password_timeout = 1800000;
|
$company->default_password_timeout = 1800000;
|
||||||
$company->client_registration_fields = ClientRegistrationFields::generate();
|
$company->client_registration_fields = ClientRegistrationFields::generate();
|
||||||
|
@ -11,14 +11,15 @@
|
|||||||
|
|
||||||
namespace App\Jobs\Cron;
|
namespace App\Jobs\Cron;
|
||||||
|
|
||||||
use App\Jobs\Entity\EmailEntity;
|
|
||||||
use App\Libraries\MultiDB;
|
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
|
use App\Models\Webhook;
|
||||||
|
use App\Libraries\MultiDB;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
|
use App\Jobs\Entity\EmailEntity;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
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\SerializesModels;
|
|
||||||
|
|
||||||
class AutoBill implements ShouldQueue
|
class AutoBill implements ShouldQueue
|
||||||
{
|
{
|
||||||
@ -77,6 +78,8 @@ class AutoBill implements ShouldQueue
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$invoice->sendEvent(Webhook::EVENT_SENT_INVOICE, "client");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -11,13 +11,14 @@
|
|||||||
|
|
||||||
namespace App\Jobs\Invoice;
|
namespace App\Jobs\Invoice;
|
||||||
|
|
||||||
use App\Jobs\Entity\EmailEntity;
|
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
|
use App\Models\Webhook;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
|
use App\Jobs\Entity\EmailEntity;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
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\SerializesModels;
|
|
||||||
|
|
||||||
class BulkInvoiceJob implements ShouldQueue
|
class BulkInvoiceJob implements ShouldQueue
|
||||||
{
|
{
|
||||||
@ -50,6 +51,8 @@ class BulkInvoiceJob implements ShouldQueue
|
|||||||
|
|
||||||
if ($this->invoice->invitations->count() >= 1) {
|
if ($this->invoice->invitations->count() >= 1) {
|
||||||
$this->invoice->entityEmailEvent($this->invoice->invitations->first(), 'invoice', $this->reminder_template);
|
$this->invoice->entityEmailEvent($this->invoice->invitations->first(), 'invoice', $this->reminder_template);
|
||||||
|
$this->invoice->sendEvent(Webhook::EVENT_SENT_INVOICE, "client");
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -549,7 +549,7 @@ class NinjaMailerJob implements ShouldQueue
|
|||||||
/* On the hosted platform if the user has not verified their account we fail here - but still check what they are trying to send! */
|
/* On the hosted platform if the user has not verified their account we fail here - but still check what they are trying to send! */
|
||||||
if (Ninja::isHosted() && $this->company->account && !$this->company->account->account_sms_verified) {
|
if (Ninja::isHosted() && $this->company->account && !$this->company->account->account_sms_verified) {
|
||||||
if (class_exists(\Modules\Admin\Jobs\Account\EmailQuality::class)) {
|
if (class_exists(\Modules\Admin\Jobs\Account\EmailQuality::class)) {
|
||||||
return (new \Modules\Admin\Jobs\Account\EmailQuality($this->nmo, $this->company))->run();
|
(new \Modules\Admin\Jobs\Account\EmailQuality($this->nmo, $this->company))->run();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -105,7 +105,7 @@ class PaymentFailedMailer implements ShouldQueue
|
|||||||
});
|
});
|
||||||
|
|
||||||
//add client payment failures here.
|
//add client payment failures here.
|
||||||
//
|
|
||||||
if ($this->client->contacts()->whereNotNull('email')->exists() && $this->payment_hash) {
|
if ($this->client->contacts()->whereNotNull('email')->exists() && $this->payment_hash) {
|
||||||
$contact = $this->client->contacts()->whereNotNull('email')->first();
|
$contact = $this->client->contacts()->whereNotNull('email')->first();
|
||||||
|
|
||||||
|
@ -11,9 +11,11 @@
|
|||||||
|
|
||||||
namespace App\Jobs\Ninja;
|
namespace App\Jobs\Ninja;
|
||||||
|
|
||||||
use App\Jobs\Bank\ProcessBankTransactions;
|
use App\Jobs\Bank\ProcessBankTransactionsYodlee;
|
||||||
|
use App\Jobs\Bank\ProcessBankTransactionsNordigen;
|
||||||
use App\Libraries\MultiDB;
|
use App\Libraries\MultiDB;
|
||||||
use App\Models\Account;
|
use App\Models\Account;
|
||||||
|
use App\Models\BankIntegration;
|
||||||
use App\Utils\Ninja;
|
use App\Utils\Ninja;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
@ -43,20 +45,52 @@ class BankTransactionSync implements ShouldQueue
|
|||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
//multiDB environment, need to
|
if (config('ninja.db.multi_db_enabled')) {
|
||||||
|
|
||||||
foreach (MultiDB::$dbs as $db) {
|
foreach (MultiDB::$dbs as $db) {
|
||||||
MultiDB::setDB($db);
|
MultiDB::setDB($db);
|
||||||
|
|
||||||
nlog("syncing transactions");
|
$this->processYodlee();
|
||||||
|
$this->processNordigen();
|
||||||
|
}
|
||||||
|
|
||||||
$a = Account::with('bank_integrations')->whereNotNull('bank_integration_account_id')->cursor()->each(function ($account) {
|
} else {
|
||||||
// $queue = Ninja::isHosted() ? 'bank' : 'default';
|
$this->processYodlee();
|
||||||
|
$this->processNordigen();
|
||||||
|
}
|
||||||
|
|
||||||
if ($account->isPaid() && $account->plan == 'enterprise') {
|
nlog("syncing transactions - done");
|
||||||
$account->bank_integrations()->where('auto_sync', true)->cursor()->each(function ($bank_integration) use ($account) {
|
}
|
||||||
(new ProcessBankTransactions($account->bank_integration_account_id, $bank_integration))->handle();
|
|
||||||
|
private function processYodlee()
|
||||||
|
{
|
||||||
|
if (Ninja::isHosted()) {
|
||||||
|
nlog("syncing transactions - yodlee");
|
||||||
|
|
||||||
|
Account::with('bank_integrations')->whereNotNull('bank_integration_account_id')->cursor()->each(function ($account) {
|
||||||
|
|
||||||
|
if ($account->isEnterprisePaidClient()) {
|
||||||
|
$account->bank_integrations()->where('integration_type', BankIntegration::INTEGRATION_TYPE_YODLEE)->where('auto_sync', true)->cursor()->each(function ($bank_integration) use ($account) {
|
||||||
|
(new ProcessBankTransactionsYodlee($account->id, $bank_integration))->handle();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private function processNordigen()
|
||||||
|
{
|
||||||
|
if (config("ninja.nordigen.secret_id") && config("ninja.nordigen.secret_key")) {
|
||||||
|
nlog("syncing transactions - nordigen");
|
||||||
|
|
||||||
|
Account::with('bank_integrations')->cursor()->each(function ($account) {
|
||||||
|
|
||||||
|
if ((Ninja::isSelfHost() || (Ninja::isHosted() && $account->isEnterprisePaidClient()))) {
|
||||||
|
$account->bank_integrations()->where('integration_type', BankIntegration::INTEGRATION_TYPE_NORDIGEN)->where('auto_sync', true)->cursor()->each(function ($bank_integration) {
|
||||||
|
(new ProcessBankTransactionsNordigen($bank_integration))->handle();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,11 +53,19 @@ class CompanySizeCheck implements ShouldQueue
|
|||||||
|
|
||||||
nlog("updating all client credit balances");
|
nlog("updating all client credit balances");
|
||||||
|
|
||||||
Client::where('updated_at', '>', now()->subDay())
|
Client::query()
|
||||||
|
->where('updated_at', '>', now()->subDay())
|
||||||
->cursor()
|
->cursor()
|
||||||
->each(function ($client) {
|
->each(function ($client) {
|
||||||
|
|
||||||
|
$old_credit_balance = $client->credit_balance;
|
||||||
|
$new_credit_balance = $client->service()->getCreditBalance();
|
||||||
|
|
||||||
|
if(floatval($old_credit_balance) !== floatval($new_credit_balance)){
|
||||||
$client->credit_balance = $client->service()->getCreditBalance();
|
$client->credit_balance = $client->service()->getCreditBalance();
|
||||||
$client->save();
|
$client->saveQuietly();
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Ensures lower permissioned users return the correct dataset and refresh responses */
|
/* Ensures lower permissioned users return the correct dataset and refresh responses */
|
||||||
@ -87,11 +95,20 @@ class CompanySizeCheck implements ShouldQueue
|
|||||||
|
|
||||||
nlog("updating all client credit balances");
|
nlog("updating all client credit balances");
|
||||||
|
|
||||||
Client::where('updated_at', '>', now()->subDay())
|
Client::query()->where('updated_at', '>', now()->subDay())
|
||||||
->cursor()
|
->cursor()
|
||||||
->each(function ($client) {
|
->each(function ($client) {
|
||||||
|
|
||||||
|
|
||||||
|
$old_credit_balance = $client->credit_balance;
|
||||||
|
$new_credit_balance = $client->service()->getCreditBalance();
|
||||||
|
|
||||||
|
if(floatval($old_credit_balance) !== floatval($new_credit_balance)) {
|
||||||
$client->credit_balance = $client->service()->getCreditBalance();
|
$client->credit_balance = $client->service()->getCreditBalance();
|
||||||
$client->save();
|
$client->saveQuietly();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Account::where('plan', 'enterprise')
|
Account::where('plan', 'enterprise')
|
||||||
|
@ -215,6 +215,7 @@ class SendReminders implements ShouldQueue
|
|||||||
|
|
||||||
EmailEntity::dispatch($invitation, $invitation->company, $template)->delay(10);
|
EmailEntity::dispatch($invitation, $invitation->company, $template)->delay(10);
|
||||||
event(new InvoiceWasEmailed($invoice->invitations->first(), $invoice->company, Ninja::eventVars(), $template));
|
event(new InvoiceWasEmailed($invoice->invitations->first(), $invoice->company, Ninja::eventVars(), $template));
|
||||||
|
$invoice->sendEvent(Webhook::EVENT_REMIND_INVOICE, "client");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -11,24 +11,26 @@
|
|||||||
|
|
||||||
namespace App\Jobs\PostMark;
|
namespace App\Jobs\PostMark;
|
||||||
|
|
||||||
use App\DataMapper\Analytics\Mail\EmailBounce;
|
use App\Models\Company;
|
||||||
use App\DataMapper\Analytics\Mail\EmailSpam;
|
use App\Models\SystemLog;
|
||||||
use App\Jobs\Util\SystemLogger;
|
|
||||||
use App\Libraries\MultiDB;
|
use App\Libraries\MultiDB;
|
||||||
|
use Postmark\PostmarkClient;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use App\Jobs\Util\SystemLogger;
|
||||||
|
use App\Models\QuoteInvitation;
|
||||||
use App\Models\CreditInvitation;
|
use App\Models\CreditInvitation;
|
||||||
use App\Models\InvoiceInvitation;
|
use App\Models\InvoiceInvitation;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Turbo124\Beacon\Facades\LightLogs;
|
||||||
use App\Models\PurchaseOrderInvitation;
|
use App\Models\PurchaseOrderInvitation;
|
||||||
use App\Models\QuoteInvitation;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use App\Models\RecurringInvoiceInvitation;
|
use App\Models\RecurringInvoiceInvitation;
|
||||||
use App\Models\SystemLog;
|
|
||||||
use App\Notifications\Ninja\EmailSpamNotification;
|
|
||||||
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 App\DataMapper\Analytics\Mail\EmailSpam;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use App\DataMapper\Analytics\Mail\EmailBounce;
|
||||||
use Postmark\PostmarkClient;
|
use App\Notifications\Ninja\EmailSpamNotification;
|
||||||
use Turbo124\Beacon\Facades\LightLogs;
|
use App\Notifications\Ninja\EmailBounceNotification;
|
||||||
|
|
||||||
class ProcessPostmarkWebhook implements ShouldQueue
|
class ProcessPostmarkWebhook implements ShouldQueue
|
||||||
{
|
{
|
||||||
@ -82,9 +84,14 @@ class ProcessPostmarkWebhook implements ShouldQueue
|
|||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
MultiDB::findAndSetDbByCompanyKey($this->request['Tag']);
|
MultiDB::findAndSetDbByCompanyKey($this->request['Tag']);
|
||||||
|
$company = Company::where('company_key', $this->request['Tag'])->first();
|
||||||
|
|
||||||
$this->invitation = $this->discoverInvitation($this->request['MessageID']);
|
$this->invitation = $this->discoverInvitation($this->request['MessageID']);
|
||||||
|
|
||||||
|
if ($company && $this->request['RecordType'] == 'SpamComplaint' && config('ninja.notification.slack')) {
|
||||||
|
$company->notification(new EmailSpamNotification($company))->ninja();
|
||||||
|
}
|
||||||
|
|
||||||
if (!$this->invitation) {
|
if (!$this->invitation) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -97,6 +104,11 @@ class ProcessPostmarkWebhook implements ShouldQueue
|
|||||||
case 'Delivery':
|
case 'Delivery':
|
||||||
return $this->processDelivery();
|
return $this->processDelivery();
|
||||||
case 'Bounce':
|
case 'Bounce':
|
||||||
|
|
||||||
|
if($this->request['Subject'] == ctrans('texts.confirmation_subject')) {
|
||||||
|
$company->notification(new EmailBounceNotification($this->request['Email']))->ninja();
|
||||||
|
}
|
||||||
|
|
||||||
return $this->processBounce();
|
return $this->processBounce();
|
||||||
case 'SpamComplaint':
|
case 'SpamComplaint':
|
||||||
return $this->processSpamComplaint();
|
return $this->processSpamComplaint();
|
||||||
@ -257,8 +269,6 @@ class ProcessPostmarkWebhook implements ShouldQueue
|
|||||||
|
|
||||||
(new SystemLogger($data, SystemLog::CATEGORY_MAIL, SystemLog::EVENT_MAIL_BOUNCED, SystemLog::TYPE_WEBHOOK_RESPONSE, $this->invitation->contact->client, $this->invitation->company))->handle();
|
(new SystemLogger($data, SystemLog::CATEGORY_MAIL, SystemLog::EVENT_MAIL_BOUNCED, SystemLog::TYPE_WEBHOOK_RESPONSE, $this->invitation->contact->client, $this->invitation->company))->handle();
|
||||||
|
|
||||||
// if(config('ninja.notification.slack'))
|
|
||||||
// $this->invitation->company->notification(new EmailBounceNotification($this->invitation->company->account))->ninja();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// {
|
// {
|
||||||
@ -305,14 +315,8 @@ class ProcessPostmarkWebhook implements ShouldQueue
|
|||||||
|
|
||||||
if($sl) {
|
if($sl) {
|
||||||
$this->updateSystemLog($sl, $data);
|
$this->updateSystemLog($sl, $data);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
(new SystemLogger($data, SystemLog::CATEGORY_MAIL, SystemLog::EVENT_MAIL_SPAM_COMPLAINT, SystemLog::TYPE_WEBHOOK_RESPONSE, $this->invitation->contact->client, $this->invitation->company))->handle();
|
|
||||||
|
|
||||||
if (config('ninja.notification.slack')) {
|
|
||||||
$this->invitation->company->notification(new EmailSpamNotification($this->invitation->company->account))->ninja();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function discoverInvitation($message_id)
|
private function discoverInvitation($message_id)
|
||||||
|
@ -11,24 +11,25 @@
|
|||||||
|
|
||||||
namespace App\Jobs\RecurringInvoice;
|
namespace App\Jobs\RecurringInvoice;
|
||||||
|
|
||||||
use App\DataMapper\Analytics\SendRecurringFailure;
|
|
||||||
use App\Events\Invoice\InvoiceWasCreated;
|
|
||||||
use App\Factory\InvoiceInvitationFactory;
|
|
||||||
use App\Factory\RecurringInvoiceToInvoiceFactory;
|
|
||||||
use App\Jobs\Cron\AutoBill;
|
|
||||||
use App\Jobs\Entity\EmailEntity;
|
|
||||||
use App\Models\Invoice;
|
|
||||||
use App\Models\RecurringInvoice;
|
|
||||||
use App\Utils\Ninja;
|
|
||||||
use App\Utils\Traits\GeneratesCounter;
|
|
||||||
use App\Utils\Traits\MakesHash;
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
|
use App\Utils\Ninja;
|
||||||
|
use App\Models\Invoice;
|
||||||
|
use App\Models\Webhook;
|
||||||
|
use App\Jobs\Cron\AutoBill;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use App\Utils\Traits\MakesHash;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use App\Jobs\Entity\EmailEntity;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use App\Models\RecurringInvoice;
|
||||||
|
use App\Utils\Traits\GeneratesCounter;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
use Turbo124\Beacon\Facades\LightLogs;
|
use Turbo124\Beacon\Facades\LightLogs;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use App\Events\Invoice\InvoiceWasCreated;
|
||||||
|
use App\Factory\InvoiceInvitationFactory;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use App\Factory\RecurringInvoiceToInvoiceFactory;
|
||||||
|
use App\DataMapper\Analytics\SendRecurringFailure;
|
||||||
|
|
||||||
class SendRecurring implements ShouldQueue
|
class SendRecurring implements ShouldQueue
|
||||||
{
|
{
|
||||||
@ -117,6 +118,7 @@ class SendRecurring implements ShouldQueue
|
|||||||
//04-08-2023 edge case to support where online payment notifications are not enabled
|
//04-08-2023 edge case to support where online payment notifications are not enabled
|
||||||
if(!$invoice->client->getSetting('client_online_payment_notification')) {
|
if(!$invoice->client->getSetting('client_online_payment_notification')) {
|
||||||
$this->sendRecurringEmails($invoice);
|
$this->sendRecurringEmails($invoice);
|
||||||
|
$invoice->sendEvent(Webhook::EVENT_SENT_INVOICE, "client");
|
||||||
}
|
}
|
||||||
} elseif ($invoice->auto_bill_enabled && $invoice->client->getSetting('auto_bill_date') == 'on_due_date' && $invoice->client->getSetting('auto_email_invoice') && ($invoice->due_date && Carbon::parse($invoice->due_date)->startOfDay()->lte(now()->startOfDay()))) {
|
} elseif ($invoice->auto_bill_enabled && $invoice->client->getSetting('auto_bill_date') == 'on_due_date' && $invoice->client->getSetting('auto_email_invoice') && ($invoice->due_date && Carbon::parse($invoice->due_date)->startOfDay()->lte(now()->startOfDay()))) {
|
||||||
nlog("attempting to autobill {$invoice->number}");
|
nlog("attempting to autobill {$invoice->number}");
|
||||||
@ -125,10 +127,12 @@ class SendRecurring implements ShouldQueue
|
|||||||
//04-08-2023 edge case to support where online payment notifications are not enabled
|
//04-08-2023 edge case to support where online payment notifications are not enabled
|
||||||
if(!$invoice->client->getSetting('client_online_payment_notification')) {
|
if(!$invoice->client->getSetting('client_online_payment_notification')) {
|
||||||
$this->sendRecurringEmails($invoice);
|
$this->sendRecurringEmails($invoice);
|
||||||
|
$invoice->sendEvent(Webhook::EVENT_SENT_INVOICE, "client");
|
||||||
}
|
}
|
||||||
|
|
||||||
} elseif ($invoice->client->getSetting('auto_email_invoice')) {
|
} elseif ($invoice->client->getSetting('auto_email_invoice')) {
|
||||||
$this->sendRecurringEmails($invoice);
|
$this->sendRecurringEmails($invoice);
|
||||||
|
$invoice->sendEvent(Webhook::EVENT_SENT_INVOICE, "client");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -11,22 +11,23 @@
|
|||||||
|
|
||||||
namespace App\Jobs\Util;
|
namespace App\Jobs\Util;
|
||||||
|
|
||||||
|
use App\Utils\Ninja;
|
||||||
|
use App\Models\Invoice;
|
||||||
|
use App\Models\Webhook;
|
||||||
|
use App\Libraries\MultiDB;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Support\Carbon;
|
||||||
use App\DataMapper\InvoiceItem;
|
use App\DataMapper\InvoiceItem;
|
||||||
use App\Factory\InvoiceFactory;
|
use App\Factory\InvoiceFactory;
|
||||||
use App\Jobs\Entity\EmailEntity;
|
use App\Jobs\Entity\EmailEntity;
|
||||||
use App\Libraries\MultiDB;
|
|
||||||
use App\Models\Invoice;
|
|
||||||
use App\Utils\Ninja;
|
|
||||||
use App\Utils\Traits\MakesDates;
|
use App\Utils\Traits\MakesDates;
|
||||||
|
use Illuminate\Support\Facades\App;
|
||||||
use App\Utils\Traits\MakesReminders;
|
use App\Utils\Traits\MakesReminders;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
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\SerializesModels;
|
|
||||||
use Illuminate\Support\Carbon;
|
|
||||||
use Illuminate\Support\Facades\App;
|
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
|
|
||||||
class ReminderJob implements ShouldQueue
|
class ReminderJob implements ShouldQueue
|
||||||
{
|
{
|
||||||
@ -150,6 +151,7 @@ class ReminderJob implements ShouldQueue
|
|||||||
EmailEntity::dispatch($invitation, $invitation->company, $reminder_template);
|
EmailEntity::dispatch($invitation, $invitation->company, $reminder_template);
|
||||||
nlog("Firing reminder email for invoice {$invoice->number} - {$reminder_template}");
|
nlog("Firing reminder email for invoice {$invoice->number} - {$reminder_template}");
|
||||||
$invoice->entityEmailEvent($invitation, $reminder_template);
|
$invoice->entityEmailEvent($invitation, $reminder_template);
|
||||||
|
$invoice->sendEvent(Webhook::EVENT_REMIND_INVOICE, "client");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -220,6 +222,7 @@ class ReminderJob implements ShouldQueue
|
|||||||
EmailEntity::dispatch($invitation, $invitation->company, $reminder_template);
|
EmailEntity::dispatch($invitation, $invitation->company, $reminder_template);
|
||||||
nlog("Firing reminder email for invoice {$invoice->number} - {$reminder_template}");
|
nlog("Firing reminder email for invoice {$invoice->number} - {$reminder_template}");
|
||||||
$invoice->entityEmailEvent($invitation, $reminder_template);
|
$invoice->entityEmailEvent($invitation, $reminder_template);
|
||||||
|
$invoice->sendEvent(Webhook::EVENT_REMIND_INVOICE, "client");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -307,8 +310,6 @@ class ReminderJob implements ShouldQueue
|
|||||||
/**Refresh Invoice values*/
|
/**Refresh Invoice values*/
|
||||||
$invoice = $invoice->calc()->getInvoice();
|
$invoice = $invoice->calc()->getInvoice();
|
||||||
|
|
||||||
// nlog('adjusting client balance and invoice balance by #'.$invoice->number.' '.($invoice->balance - $temp_invoice_balance));
|
|
||||||
// $invoice->client->service()->updateBalance($invoice->balance - $temp_invoice_balance);
|
|
||||||
$invoice->ledger()->updateInvoiceBalance($invoice->balance - $temp_invoice_balance, "Late Fee Adjustment for invoice {$invoice->number}");
|
$invoice->ledger()->updateInvoiceBalance($invoice->balance - $temp_invoice_balance, "Late Fee Adjustment for invoice {$invoice->number}");
|
||||||
$invoice->client->service()->calculateBalance();
|
$invoice->client->service()->calculateBalance();
|
||||||
|
|
||||||
|
@ -11,16 +11,17 @@
|
|||||||
|
|
||||||
namespace App\Libraries;
|
namespace App\Libraries;
|
||||||
|
|
||||||
use App\Models\Account;
|
|
||||||
use App\Models\Client;
|
|
||||||
use App\Models\ClientContact;
|
|
||||||
use App\Models\Company;
|
|
||||||
use App\Models\CompanyToken;
|
|
||||||
use App\Models\Document;
|
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use App\Models\Client;
|
||||||
|
use App\Models\Account;
|
||||||
|
use App\Models\Company;
|
||||||
|
use App\Models\Document;
|
||||||
|
use App\Models\PaymentHash;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use App\Models\CompanyToken;
|
||||||
|
use App\Models\ClientContact;
|
||||||
use App\Models\VendorContact;
|
use App\Models\VendorContact;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class MultiDB.
|
* Class MultiDB.
|
||||||
@ -534,6 +535,27 @@ class MultiDB
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function findAndSetByPaymentHash(string $hash)
|
||||||
|
{
|
||||||
|
if (!config('ninja.db.multi_db_enabled')) {
|
||||||
|
return PaymentHash::with('fee_invoice')->where('hash', $hash)->first();
|
||||||
|
}
|
||||||
|
|
||||||
|
$current_db = config('database.default');
|
||||||
|
|
||||||
|
foreach (self::$dbs as $db) {
|
||||||
|
if ($payment_hash = PaymentHash::on($db)->where('hash', $hash)->first()) {
|
||||||
|
self::setDb($db);
|
||||||
|
|
||||||
|
return $payment_hash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self::setDB($current_db);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public static function findAndSetDbByInvitation($entity, $invitation_key)
|
public static function findAndSetDbByInvitation($entity, $invitation_key)
|
||||||
{
|
{
|
||||||
$class = 'App\Models\\' . ucfirst(Str::camel($entity)) . 'Invitation';
|
$class = 'App\Models\\' . ucfirst(Str::camel($entity)) . 'Invitation';
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user