Fixes for v5-dev merge

This commit is contained in:
David Bomba 2023-11-13 15:50:08 +11:00
commit 3b4ff74c1a
868 changed files with 748646 additions and 665529 deletions

View File

@ -47,13 +47,9 @@ jobs:
npm i npm i
npm run build npm run build
for file in dist/react/* ; do mkdir -p ../public/react/${{ github.event.release.tag_name }}/
filename=$(basename -- "$file") cp -r dist/react/* ../public/react/${{ github.event.release.tag_name }}/
extension="${filename##*.}" cp -r dist/react/* ../public/react/
filename="${filename%.*}"
version=${{ github.event.release.tag_name }}
cp dist/react/$file ../public/react/$filename"."$version"."$extension
done
mkdir -p ../public/tinymce_6.4.2/tinymce/js/ mkdir -p ../public/tinymce_6.4.2/tinymce/js/
cp -r node_modules/tinymce ../public/tinymce_6.4.2/tinymce/js/ cp -r node_modules/tinymce ../public/tinymce_6.4.2/tinymce/js/

View File

@ -50,8 +50,7 @@ We offer a $30 per year white-label license to remove the Invoice Ninja branding
## Quick Hosting Setup ## Quick Hosting Setup
```sh ```sh
git clone https://github.com/invoiceninja/invoiceninja.git git clone --single-branch --branch v5-stable https://github.com/invoiceninja/invoiceninja.git
git checkout v5-stable
cp .env.example .env cp .env.example .env
composer i -o --no-dev composer i -o --no-dev
php artisan key:generate php artisan key:generate

View File

@ -1 +1 @@
5.7.11 5.7.47

View File

@ -11,13 +11,13 @@
namespace App\Console\Commands; namespace App\Console\Commands;
use App\Utils\Ninja; use App\Libraries\MultiDB;
use App\Models\Backup; use App\Models\Backup;
use App\Models\Client; use App\Models\Client;
use App\Models\Company; use App\Models\Company;
use App\Models\Document; use App\Models\Document;
use App\Libraries\MultiDB;
use App\Models\GroupSetting; use App\Models\GroupSetting;
use App\Utils\Ninja;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
@ -56,8 +56,9 @@ class BackupUpdate extends Command
{ {
//always return state to first DB //always return state to first DB
if(Ninja::isSelfHost()) if(Ninja::isSelfHost()) {
return; return;
}
$current_db = config('database.default'); $current_db = config('database.default');

View File

@ -12,38 +12,37 @@
namespace App\Console\Commands; namespace App\Console\Commands;
use App; use App;
use Exception;
use App\Models\User;
use App\Utils\Ninja;
use App\Models\Quote;
use App\Models\Client;
use App\Models\Credit;
use App\Models\Vendor;
use App\Models\Account;
use App\Models\Company;
use App\Models\Contact;
use App\Models\Invoice;
use App\Models\Payment;
use App\Models\CompanyUser;
use Illuminate\Support\Str;
use App\Models\CompanyToken;
use App\Models\ClientContact;
use App\Models\CompanyLedger;
use App\Models\PurchaseOrder;
use App\Models\VendorContact;
use App\Models\BankTransaction;
use App\Models\QuoteInvitation;
use Illuminate\Console\Command;
use App\Models\CreditInvitation;
use App\Models\RecurringInvoice;
use App\Models\InvoiceInvitation;
use App\DataMapper\ClientSettings; use App\DataMapper\ClientSettings;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Mail;
use App\Factory\ClientContactFactory; use App\Factory\ClientContactFactory;
use App\Factory\VendorContactFactory; use App\Factory\VendorContactFactory;
use App\Jobs\Company\CreateCompanyToken; use App\Jobs\Company\CreateCompanyToken;
use App\Models\Account;
use App\Models\BankTransaction;
use App\Models\Client;
use App\Models\ClientContact;
use App\Models\Company;
use App\Models\CompanyLedger;
use App\Models\CompanyToken;
use App\Models\CompanyUser;
use App\Models\Contact;
use App\Models\Credit;
use App\Models\CreditInvitation;
use App\Models\Invoice;
use App\Models\InvoiceInvitation;
use App\Models\Payment;
use App\Models\PurchaseOrder;
use App\Models\Quote;
use App\Models\QuoteInvitation;
use App\Models\RecurringInvoice;
use App\Models\RecurringInvoiceInvitation; use App\Models\RecurringInvoiceInvitation;
use App\Models\User;
use App\Models\Vendor;
use App\Models\VendorContact;
use App\Utils\Ninja;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Str;
use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputOption;
/* /*
@ -185,8 +184,7 @@ class CheckData extends Command
if ($cu->company && $cu->user) { if ($cu->company && $cu->user) {
(new CreateCompanyToken($cu->company, $cu->user, 'System'))->handle(); (new CreateCompanyToken($cu->company, $cu->user, 'System'))->handle();
} } else {
else {
// $cu->forceDelete(); // $cu->forceDelete();
} }
} }
@ -906,26 +904,6 @@ class CheckData extends Command
public function checkClientSettings() public function checkClientSettings()
{ {
if ($this->option('fix') == 'true') { if ($this->option('fix') == 'true') {
// Client::query()->whereNull('settings->currency_id')->cursor()->each(function ($client){
// if(is_array($client->settings) && count($client->settings) == 0)
// {
// $settings = ClientSettings::defaults();
// $settings->currency_id = $client->company->settings->currency_id;
// }
// else {
// $settings = $client->settings;
// $settings->currency_id = $client->company->settings->currency_id;
// }
// $client->settings = $settings;
// $client->save();
// $this->logMessage("Fixing currency for # {$client->id}");
// });
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->save();

View File

@ -20,7 +20,6 @@ use App\Models\Account;
use App\Models\Company; use App\Models\Company;
use App\Models\CompanyToken; use App\Models\CompanyToken;
use App\Models\User; use App\Models\User;
use App\Repositories\InvoiceRepository;
use App\Utils\Traits\GeneratesCounter; use App\Utils\Traits\GeneratesCounter;
use App\Utils\Traits\MakesHash; use App\Utils\Traits\MakesHash;
use Illuminate\Console\Command; use Illuminate\Console\Command;
@ -63,17 +62,25 @@ class CreateAccount extends Command
private function createAccount() private function createAccount()
{ {
$settings = CompanySettings::defaults();
$settings->name = "Untitled Company";
$settings->currency_id = '1';
$settings->language_id = '1';
$account = Account::factory()->create(); $account = Account::factory()->create();
$company = Company::factory()->create([ $company = Company::factory()->create([
'account_id' => $account->id, 'account_id' => $account->id,
'portal_domain' => config('ninja.app_url'), 'portal_domain' => config('ninja.app_url'),
'portal_mode' => 'domain', 'portal_mode' => 'domain',
'settings' => $settings,
]); ]);
$company->client_registration_fields = ClientRegistrationFields::generate(); $company->client_registration_fields = ClientRegistrationFields::generate();
$company->save(); $company->save();
$account->default_company_id = $company->id; $account->default_company_id = $company->id;
$account->set_react_as_default_ap = true;
$account->save(); $account->save();
$email = $this->option('email') ?? 'admin@example.com'; $email = $this->option('email') ?? 'admin@example.com';

View File

@ -11,52 +11,52 @@
namespace App\Console\Commands; namespace App\Console\Commands;
use stdClass; use App\DataMapper\ClientRegistrationFields;
use Carbon\Carbon; use App\DataMapper\CompanySettings;
use Faker\Factory; use App\DataMapper\FeesAndLimits;
use App\Models\Task; use App\Events\Invoice\InvoiceWasCreated;
use App\Models\User; use App\Events\RecurringInvoice\RecurringInvoiceWasCreated;
use App\Utils\Ninja; use App\Factory\GroupSettingFactory;
use App\Models\Quote; use App\Factory\InvoiceFactory;
use App\Models\Client; use App\Factory\InvoiceItemFactory;
use App\Models\Credit; use App\Factory\RecurringInvoiceFactory;
use App\Models\Vendor; use App\Factory\SubscriptionFactory;
use App\Helpers\Invoice\InvoiceSum;
use App\Jobs\Company\CreateCompanyTaskStatuses;
use App\Libraries\MultiDB;
use App\Models\Account; use App\Models\Account;
use App\Models\BankIntegration;
use App\Models\BankTransaction;
use App\Models\BankTransactionRule;
use App\Models\Client;
use App\Models\ClientContact;
use App\Models\Company; use App\Models\Company;
use App\Models\CompanyGateway;
use App\Models\CompanyToken;
use App\Models\Country; use App\Models\Country;
use App\Models\Credit;
use App\Models\Expense; use App\Models\Expense;
use App\Models\Invoice; use App\Models\Invoice;
use App\Models\Product; use App\Models\Product;
use App\Models\Project; use App\Models\Project;
use App\Models\TaxRate; use App\Models\Quote;
use App\Libraries\MultiDB;
use App\Models\CompanyToken;
use App\Models\ClientContact;
use App\Models\VendorContact;
use App\Models\CompanyGateway;
use App\Factory\InvoiceFactory;
use App\Models\BankIntegration;
use App\Models\BankTransaction;
use App\Utils\Traits\MakesHash;
use Illuminate\Console\Command;
use App\Models\RecurringInvoice; use App\Models\RecurringInvoice;
use App\DataMapper\FeesAndLimits; use App\Models\Task;
use App\DataMapper\CompanySettings; use App\Models\TaxRate;
use App\Factory\InvoiceItemFactory; use App\Models\User;
use App\Helpers\Invoice\InvoiceSum; use App\Models\Vendor;
use App\Models\BankTransactionRule; use App\Models\VendorContact;
use App\Factory\GroupSettingFactory;
use App\Factory\SubscriptionFactory;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Cache;
use App\Utils\Traits\GeneratesCounter;
use Illuminate\Support\Facades\Schema;
use App\Repositories\InvoiceRepository; use App\Repositories\InvoiceRepository;
use App\Factory\RecurringInvoiceFactory; use App\Utils\Ninja;
use App\Events\Invoice\InvoiceWasCreated; use App\Utils\Traits\GeneratesCounter;
use App\DataMapper\ClientRegistrationFields; use App\Utils\Traits\MakesHash;
use App\Jobs\Company\CreateCompanyTaskStatuses; use Carbon\Carbon;
use App\Events\RecurringInvoice\RecurringInvoiceWasCreated; use Faker\Factory;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Schema;
use stdClass;
class CreateSingleAccount extends Command class CreateSingleAccount extends Command
{ {
@ -349,15 +349,17 @@ class CreateSingleAccount extends Command
}); });
Project::query()->cursor()->each(function ($p) { Project::query()->with('client')->whereNotNull('client_id')->cursor()->each(function ($p) {
if(!isset($p->number)) { if($p && $p->client && !isset($p->number)) {
$p->number = $this->getNextProjectNumber($p); $p->number = $this->getNextProjectNumber($p);
$p->save(); $p->save();
} }
}); });
$this->info("finished");
} }
private function createSubsData($company, $user) private function createSubsData($company, $user)
@ -940,11 +942,11 @@ class CreateSingleAccount extends Command
} }
} }
private function createRecurringInvoice($client) private function createRecurringInvoice(Client $client)
{ {
$faker = Factory::create(); $faker = Factory::create();
$invoice = RecurringInvoiceFactory::create($client->company->id, $client->user->id); //stub the company and user_id $invoice = RecurringInvoiceFactory::create($client->company_id, $client->user_id); //stub the company and user_id
$invoice->client_id = $client->id; $invoice->client_id = $client->id;
$dateable = Carbon::now()->subDays(rand(0, 90)); $dateable = Carbon::now()->subDays(rand(0, 90));
$invoice->date = $dateable; $invoice->date = $dateable;

View File

@ -61,6 +61,8 @@ class CreateTestData extends Command
protected $invoice_repo; protected $invoice_repo;
protected $count;
/** /**
* Execute the console command. * Execute the console command.
* *

View File

@ -18,7 +18,6 @@ use App\Exceptions\ProcessingMigrationArchiveFailed;
use App\Exceptions\ResourceDependencyMissing; use App\Exceptions\ResourceDependencyMissing;
use App\Exceptions\ResourceNotAvailableForMigration; use App\Exceptions\ResourceNotAvailableForMigration;
use App\Jobs\Util\Import; use App\Jobs\Util\Import;
use App\Jobs\Util\StartMigration;
use App\Mail\MigrationFailed; use App\Mail\MigrationFailed;
use App\Models\Account; use App\Models\Account;
use App\Models\Company; use App\Models\Company;

View File

@ -63,6 +63,7 @@ class MobileLocalization extends Command
{ {
$resources = $this->getResources(); $resources = $this->getResources();
if(is_iterable($resources)){
foreach ($resources as $key => $val) { foreach ($resources as $key => $val) {
$transKey = "texts.{$key}"; $transKey = "texts.{$key}";
if (trans($transKey) == $transKey) { if (trans($transKey) == $transKey) {
@ -70,6 +71,7 @@ class MobileLocalization extends Command
} }
} }
} }
}
private function flutterResources() private function flutterResources()
{ {

View File

@ -48,7 +48,14 @@ class ReactBuilder extends Command
{ {
$includes = ''; $includes = '';
$directoryIterator = new \RecursiveDirectoryIterator(public_path('react'), \RecursiveDirectoryIterator::SKIP_DOTS); $directoryIterator = false;
try {
$directoryIterator = new \RecursiveDirectoryIterator(public_path('react/v'.config('ninja.app_version').'/'), \RecursiveDirectoryIterator::SKIP_DOTS);
} catch (\Exception $e) {
$this->error('React files not found');
return;
}
foreach (new \RecursiveIteratorIterator($directoryIterator) as $file) { foreach (new \RecursiveIteratorIterator($directoryIterator) as $file) {
if ($file->getExtension() == 'js') { if ($file->getExtension() == 'js') {

View File

@ -172,18 +172,13 @@ class SendRemindersCron extends Command
/**Refresh Invoice values*/ /**Refresh Invoice values*/
$invoice->calc()->getInvoice()->save(); $invoice->calc()->getInvoice()->save();
$invoice->fresh(); $invoice = $invoice->fresh();
// $invoice->service()->deletePdf()->save();
if ($invoice->client->getSetting('enable_e_invoice')){
$invoice->service()->deleteEInvoice()->save();
}
/* Refresh the client here to ensure the balance is fresh */ /* Refresh the client here to ensure the balance is fresh */
$client = $invoice->client; $client = $invoice->client;
$client = $client->fresh(); $client = $client->fresh();
nlog('adjusting client balance and invoice balance by '.($invoice->balance - $temp_invoice_balance)); $client->service()->calculateBalance();
$client->service()->updateBalance($invoice->balance - $temp_invoice_balance)->save();
$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}");
return $invoice; return $invoice;

View File

@ -11,16 +11,11 @@
namespace App\Console\Commands; namespace App\Console\Commands;
use App\DataMapper\CompanySettings;
use App\DataMapper\DefaultSettings;
use App\Jobs\Mail\NinjaMailerJob;
use App\Jobs\Mail\NinjaMailerObject; use App\Jobs\Mail\NinjaMailerObject;
use App\Mail\Migration\MaxCompanies; use App\Mail\TestMailServer;
use App\Models\Account;
use App\Models\Company;
use App\Models\User; use App\Models\User;
use Faker\Factory;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Support\Facades\Mail;
class SendTestEmails extends Command class SendTestEmails extends Command
{ {
@ -55,39 +50,26 @@ class SendTestEmails extends Command
*/ */
public function handle() public function handle()
{ {
$faker = Factory::create();
$account = Account::factory()->create(); $to_user = User::first();
$user = User::factory()->create([
'account_id' => $account->id,
'confirmation_code' => '123',
'email' => $faker->safeEmail(),
'first_name' => 'John',
'last_name' => 'Doe',
]);
$company = Company::factory()->create([
'account_id' => $account->id,
]);
$user->companies()->attach($company->id, [
'account_id' => $account->id,
'is_owner' => 1,
'is_admin' => 1,
'is_locked' => 0,
'permissions' => '',
'notifications' => CompanySettings::notificationDefaults(),
//'settings' => DefaultSettings::userSettings(),
'settings' => null,
]);
$nmo = new NinjaMailerObject; $nmo = new NinjaMailerObject;
$nmo->mailable = new MaxCompanies($user->account->companies()->first()); $nmo->mailable = new TestMailServer('Email Server Works!', config('mail.from.address'));
$nmo->company = $user->account->companies()->first(); $nmo->company = $to_user->account->companies()->first();
$nmo->settings = $user->account->companies()->first()->settings; $nmo->settings = $to_user->account->companies()->first()->settings;
$nmo->to_user = $user; $nmo->to_user = $to_user;
(new NinjaMailerJob($nmo))->handle(); try {
Mail::raw("Test Message", function ($message) {
$message->to(config('mail.from.address'))
->from(config('mail.from.address'), config('mail.from.name'))
->subject('Test Email');
});
} catch(\Exception $e) {
$this->info("Error sending email: " . $e->getMessage());
}
} }
} }

View File

@ -19,6 +19,7 @@ use App\Jobs\Cron\UpdateCalculatedFields;
use App\Jobs\Invoice\InvoiceCheckLateWebhook; use App\Jobs\Invoice\InvoiceCheckLateWebhook;
use App\Jobs\Ninja\AdjustEmailQuota; use App\Jobs\Ninja\AdjustEmailQuota;
use App\Jobs\Ninja\BankTransactionSync; use App\Jobs\Ninja\BankTransactionSync;
use App\Jobs\Ninja\CheckACHStatus;
use App\Jobs\Ninja\CompanySizeCheck; use App\Jobs\Ninja\CompanySizeCheck;
use App\Jobs\Ninja\QueueSize; use App\Jobs\Ninja\QueueSize;
use App\Jobs\Ninja\SystemMaintenance; use App\Jobs\Ninja\SystemMaintenance;
@ -109,6 +110,9 @@ class Kernel extends ConsoleKernel
/* Pulls in bank transactions from third party services */ /* Pulls in bank transactions from third party services */
$schedule->job(new BankTransactionSync)->everyFourHours()->withoutOverlapping()->name('bank-trans-sync-job')->onOneServer(); $schedule->job(new BankTransactionSync)->everyFourHours()->withoutOverlapping()->name('bank-trans-sync-job')->onOneServer();
/* Checks ACH verification status and updates state to authorize when verified */
$schedule->job(new CheckACHStatus)->everySixHours()->withoutOverlapping()->name('ach-status-job')->onOneServer();
$schedule->command('ninja:check-data --database=db-ninja-01')->dailyAt('02:10')->withoutOverlapping()->name('check-data-db-1-job')->onOneServer(); $schedule->command('ninja:check-data --database=db-ninja-01')->dailyAt('02:10')->withoutOverlapping()->name('check-data-db-1-job')->onOneServer();
$schedule->command('ninja:check-data --database=db-ninja-02')->dailyAt('02:20')->withoutOverlapping()->name('check-data-db-2-job')->onOneServer(); $schedule->command('ninja:check-data --database=db-ninja-02')->dailyAt('02:20')->withoutOverlapping()->name('check-data-db-2-job')->onOneServer();

View File

@ -69,8 +69,15 @@ class EmailSuccess extends GenericMixedMetric
*/ */
public $string_metric7 = ''; public $string_metric7 = '';
public function __construct($string_metric7) /**
* Subject
* @var string
*/
public $string_metric8 = '';
public function __construct($string_metric7 = '', $string_metric8 = '')
{ {
$this->string_metric7 = $string_metric7; $this->string_metric7 = $string_metric7;
$this->string_metric8 = $string_metric8;
} }
} }

View File

@ -498,6 +498,7 @@ class CompanySettings extends BaseSettings
'payment_refund_design_id' => 'string', 'payment_refund_design_id' => 'string',
'classification' => 'string', 'classification' => 'string',
'enable_e_invoice' => 'bool', 'enable_e_invoice' => 'bool',
'classification' => 'string',
'default_expense_payment_type_id' => 'string', 'default_expense_payment_type_id' => 'string',
'e_invoice_type' => 'string', 'e_invoice_type' => 'string',
'mailgun_endpoint' => 'string', 'mailgun_endpoint' => 'string',
@ -855,11 +856,30 @@ class CompanySettings extends BaseSettings
{ {
$notification = new stdClass; $notification = new stdClass;
$notification->email = []; $notification->email = [];
$notification->email = ['invoice_sent_all'];
// $notification->email = ['all_notifications']; // $notification->email = ['all_notifications'];
return $notification; return $notification;
} }
/**
* Stubs the notification defaults
*
* @return stdClass
*/
public static function notificationAdminDefaults() :stdClass
{
$notification = new stdClass;
$notification->email = [];
$notification->email = ['invoice_sent_all'];
return $notification;
}
/** /**
* Defines entity variables for PDF generation * Defines entity variables for PDF generation
* *

View File

@ -0,0 +1,516 @@
<?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\DataMapper\Settings;
class SettingsData
{
public bool $auto_archive_invoice = false; // @implemented
public string $qr_iban = ''; //@implemented
public string $besr_id = ''; //@implemented
public string $lock_invoices = 'off'; // off, when_sent, when_paid //@implemented
public bool $enable_client_portal_tasks = false; //@ben to implement
public string $show_all_tasks_client_portal = 'invoiced'; // all, uninvoiced, invoiced
public bool $enable_client_portal_password = false; //@implemented
public bool $enable_client_portal = true; //@implemented
public bool $enable_client_portal_dashboard = false; // @TODO There currently is no dashboard, so this is pending
public bool $signature_on_pdf = false; //@implemented
public bool $document_email_attachment = false; //@TODO I assume this is 3rd party attachments on the entity to be included
public string $portal_design_id = '1'; //? @deprecated
public string $timezone_id = ''; //@implemented
public string $date_format_id = ''; //@implemented
public bool $military_time = false; // @TODO Implemented in Tasks only?
public string $language_id = ''; //@implemented
public bool $show_currency_code = false; //@implemented
public string $company_gateway_ids = ''; //@implemented
public string $currency_id = '1'; //@implemented
public string $custom_value1 = ''; //@implemented
public string $custom_value2 = ''; //@implemented
public string $custom_value3 = ''; //@implemented
public string $custom_value4 = ''; //@implemented
public float $default_task_rate = 0; // @TODO Where do we inject this?
public string $payment_terms = ''; //@implemented
public bool $send_reminders = true; //@TODO
public string $custom_message_dashboard = ''; // @TODO There currently is no dashboard, so this is pending
public string $custom_message_unpaid_invoice = '';
public string $custom_message_paid_invoice = '';
public string $custom_message_unapproved_quote = '';
public bool $auto_archive_quote = false; //@implemented
public bool $auto_convert_quote = true; //@implemented
public bool $auto_email_invoice = true; //@only used for Recurring Invoices, if set to false, we never send?
public int $entity_send_time = 6;
public bool $inclusive_taxes = false; //@implemented
public string $quote_footer = ''; //@implemented
public object $translations;
public string $counter_number_applied = 'when_saved'; // when_saved, when_sent //@implemented
public string $quote_number_applied = 'when_saved'; // when_saved, when_sent //@implemented
public string $invoice_number_pattern = ''; //@implemented
public int $invoice_number_counter = 1; //@implemented
public string $recurring_invoice_number_pattern = ''; //@implemented
public int $recurring_invoice_number_counter = 1; //@implemented
public string $quote_number_pattern = ''; //@implemented
public int $quote_number_counter = 1; //@implemented
public string $client_number_pattern = ''; //@implemented
public int $client_number_counter = 1; //@implemented
public string $credit_number_pattern = ''; //@implemented
public int $credit_number_counter = 1; //@implemented
public string $task_number_pattern = ''; //@implemented
public int $task_number_counter = 1; //@implemented
public string $expense_number_pattern = ''; //@implemented
public int $expense_number_counter = 1; //@implemented
public string $recurring_expense_number_pattern = '';
public int $recurring_expense_number_counter = 1;
public string $recurring_quote_number_pattern = '';
public int $recurring_quote_number_counter = 1;
public string $vendor_number_pattern = ''; //@implemented
public int $vendor_number_counter = 1; //@implemented
public string $ticket_number_pattern = ''; //@implemented
public int $ticket_number_counter = 1; //@implemented
public string $payment_number_pattern = ''; //@implemented
public int $payment_number_counter = 1; //@implemented
public string $project_number_pattern = ''; //@implemented
public int $project_number_counter = 1; //@implemented
public string $purchase_order_number_pattern = ''; //@implemented
public int $purchase_order_number_counter = 1; //@implemented
public bool $shared_invoice_quote_counter = false; //@implemented
public bool $shared_invoice_credit_counter = false; //@implemented
public string $recurring_number_prefix = ''; //@implemented
public string $reset_counter_frequency_id = '0'; //@implemented
public string $reset_counter_date = ''; //@implemented
public int $counter_padding = 4; //@implemented
public string $auto_bill = 'off'; // off, always, opt-in, opt-out //@implemented
public string $auto_bill_date = 'on_due_date'; // on_due_date, on_send_date //@implemented
public string $invoice_terms = ''; //@implemented
public string $quote_terms = ''; //@implemented
public int $invoice_taxes = 0; // ? used in AP only?
public string $invoice_design_id = 'Wpmbk5ezJn'; //@implemented
public string $quote_design_id = 'Wpmbk5ezJn'; //@implemented
public string $credit_design_id = 'Wpmbk5ezJn'; //@implemented
public string $purchase_order_design_id = 'Wpmbk5ezJn';
public string $purchase_order_footer = ''; //@implemented
public string $purchase_order_terms = ''; //@implemented
public string $purchase_order_public_notes = ''; //@implemented
public bool $require_purchase_order_signature = false; //@TODO ben to confirm
public string $invoice_footer = ''; //@implemented
public string $credit_footer = ''; //@implemented
public string $credit_terms = ''; //@implemented
public string $invoice_labels = ''; //@TODO used in AP only?
public string $tax_name1 = ''; //@TODO where do we use this?
public float $tax_rate1 = 0; //@TODO where do we use this?
public string $tax_name2 = ''; //@TODO where do we use this?
public float $tax_rate2 = 0; //@TODO where do we use this?
public string $tax_name3 = ''; //@TODO where do we use this?
public float $tax_rate3 = 0; //@TODO where do we use this?
public string $payment_type_id = '0'; //@TODO where do we use this?
public string $valid_until = ''; //@implemented
public bool $show_accept_invoice_terms = false; //@TODO ben to confirm
public bool $show_accept_quote_terms = false; //@TODO ben to confirm
public string $email_sending_method = 'default'; // enum 'default', 'gmail', 'office365', 'client_postmark', 'client_mailgun' //@implemented
public string $gmail_sending_user_id = '0'; //@implemented
public string $reply_to_email = ''; //@implemented
public string $reply_to_name = ''; //@implemented
public string $bcc_email = ''; //@TODO
public bool $pdf_email_attachment = false; //@implemented
public bool $ubl_email_attachment = false; //@implemented
public string $email_style = 'light'; // plain, light, dark, custom //@implemented
public string $email_style_custom = ''; // the template itself //@implemented
public string $email_subject_invoice = ''; //@implemented
public string $email_subject_quote = ''; //@implemented
public string $email_subject_credit = ''; //@implemented
public string $email_subject_payment = ''; //@implemented
public string $email_subject_payment_partial = ''; //@implemented
public string $email_subject_statement = ''; //@implemented
public string $email_subject_purchase_order = ''; //@implemented
public string $email_template_purchase_order = ''; //@implemented
public string $email_template_invoice = ''; //@implemented
public string $email_template_credit = ''; //@implemented
public string $email_template_quote = ''; //@implemented
public string $email_template_payment = ''; //@implemented
public string $email_template_payment_partial = ''; //@implemented
public string $email_template_statement = ''; //@implemented
public string $email_subject_reminder1 = ''; //@implemented
public string $email_subject_reminder2 = ''; //@implemented
public string $email_subject_reminder3 = ''; //@implemented
public string $email_subject_reminder_endless = ''; //@implemented
public string $email_template_reminder1 = ''; //@implemented
public string $email_template_reminder2 = ''; //@implemented
public string $email_template_reminder3 = ''; //@implemented
public string $email_template_reminder_endless = ''; //@implemented
public string $email_signature = ''; //@implemented
public bool $enable_email_markup = true; //@TODO -
public string $email_subject_custom1 = ''; //@TODO
public string $email_subject_custom2 = ''; //@TODO
public string $email_subject_custom3 = ''; //@TODO
public string $email_template_custom1 = ''; //@TODO
public string $email_template_custom2 = ''; //@TODO
public string $email_template_custom3 = ''; //@TODO
public bool $enable_reminder1 = false; //@implmemented
public bool $enable_reminder2 = false; //@implmemented
public bool $enable_reminder3 = false; //@implmemented
public bool $enable_reminder_endless = false; //@implmemented
public int $num_days_reminder1 = 0; //@implmemented
public int $num_days_reminder2 = 0; //@implmemented
public int $num_days_reminder3 = 0; //@implmemented
public string $schedule_reminder1 = ''; // (enum: after_invoice_date, before_due_date, after_due_date) implmemented
public string $schedule_reminder2 = ''; // (enum: after_invoice_date, before_due_date, after_due_date) implmemented
public string $schedule_reminder3 = ''; // (enum: after_invoice_date, before_due_date, after_due_date) implmemented
public int $reminder_send_time = 0; // number of seconds from UTC +0 to send reminders @TODO
public float $late_fee_amount1 = 0; //@implemented
public float $late_fee_amount2 = 0; //@implemented
public float $late_fee_amount3 = 0; //@implemented
public float $late_fee_percent1 = 0; //@implemented
public float $late_fee_percent2 = 0; //@implemented
public float $late_fee_percent3 = 0; //@implemented
public string $endless_reminder_frequency_id = '0'; //@implemented
public float $late_fee_endless_amount = 0; //@implemented
public float $late_fee_endless_percent = 0; //@implemented
public bool $client_online_payment_notification = true; //@todo implement in notifications check this bool prior to sending payment notification to client
public bool $client_manual_payment_notification = true; //@todo implement in notifications check this bool prior to sending manual payment notification to client
public string $name = ''; //@implemented
public string $company_logo = ''; //@implemented
public string $website = ''; //@implemented
public string $address1 = ''; //@implemented
public string $address2 = ''; //@implemented
public string $city = ''; //@implemented
public string $state = ''; //@implemented
public string $postal_code = ''; //@implemented
public string $phone = ''; //@implemented
public string $email = ''; //@implemented
public string $country_id = ''; //@implemented
public string $vat_number = ''; //@implemented
public string $id_number = ''; //@implemented
public string $page_size = 'A4'; // Letter, Legal, Tabloid, Ledger, A0, A1, A2, A3, A4, A5, A6
public string $page_layout = 'portrait';
public int $font_size = 16; //@implemented
public string $primary_font = 'Roboto';
public string $secondary_font = 'Roboto';
public string $primary_color = '#298AAB';
public string $secondary_color = '#7081e0';
public bool $page_numbering = false;
public string $page_numbering_alignment = 'C'; // C, R, L
public bool $hide_paid_to_date = false; //@TODO where?
public bool $embed_documents = false; //@TODO where?
public bool $all_pages_header = false; //@deprecated 31-05-2021
public bool $all_pages_footer = false; //@deprecated 31-05-2021
public string $pdf_variables = ''; //@implemented
public string $portal_custom_head = ''; //@TODO @BEN
public string $portal_custom_css = ''; //@TODO @BEN
public string $portal_custom_footer = ''; //@TODO @BEN
public string $portal_custom_js = ''; //@TODO @BEN
public bool $client_can_register = false; //@deprecated 04/06/2021
public string $client_portal_terms = ''; //@TODO @BEN
public string $client_portal_privacy_policy = ''; //@TODO @BEN
public bool $client_portal_enable_uploads = false; //@implemented
public bool $client_portal_allow_under_payment = false; //@implemented
public float $client_portal_under_payment_minimum = 0; //@implemented
public bool $client_portal_allow_over_payment = false; //@implemented
public string $use_credits_payment = 'off'; // always, option, off //@implemented
public bool $hide_empty_columns_on_pdf = false;
public string $email_from_name = '';
public bool $auto_archive_invoice_cancelled = false;
public bool $vendor_portal_enable_uploads = false;
public bool $send_email_on_mark_paid = false;
public string $postmark_secret = '';
public string $custom_sending_email = '';
public string $mailgun_secret = '';
public string $mailgun_domain = '';
public string $mailgun_endpoint = 'api.mailgun.net'; // api.eu.mailgun.net
public bool $auto_bill_standard_invoices = false;
public string $email_alignment = 'center'; // center, left, right
public bool $show_email_footer = true;
public string $company_logo_size = '';
public bool $show_paid_stamp = false;
public bool $show_shipping_address = false;
public bool $accept_client_input_quote_approval = false;
public bool $allow_billable_task_items = true;
public bool $show_task_item_description = false;
public bool $client_initiated_payments = false;
public float $client_initiated_payments_minimum = 0;
public bool $sync_invoice_quote_columns = true;
public string $e_invoice_type = 'EN16931';
public string $default_expense_payment_type_id = '0';
public bool $enable_e_invoice = false;
public string $classification = '';
private mixed $object;
public function cast(mixed $object)
{
if(is_array($object)) {
$object = (object)$object;
}
if (is_object($object)) {
foreach ($object as $key => $value) {
try {
settype($object->{$key}, gettype($this->{$key}));
} catch(\Exception | \Error | \Throwable $e) {
if(property_exists($this, $key)) {
$object->{$key} = $this->{$key};
} else {
unset($object->{$key});
}
}
// if(!property_exists($this, $key)) {
// unset($object->{$key});
// }
// elseif(is_array($object->{$key}) && gettype($this->{$key} != 'array')){
// $object->{$key} = $this->{$key};
// }
// else {
// settype($object->{$key}, gettype($this->{$key}));
// }
}
}
$this->object = $object;
return $this;
}
public function toObject(): object
{
return (object)$this->object;
}
public function toArray(): array
{
return (array)$this->object;
}
}

View File

@ -62,7 +62,7 @@ class Rule extends BaseRule implements RuleInterface
public function taxByType($item): self public function taxByType($item): self
{ {
if ($this->client->is_tax_exempt) { if ($this->client->is_tax_exempt || !property_exists($item, 'tax_id')) {
return $this->taxExempt($item); return $this->taxExempt($item);
} }

View File

@ -11,11 +11,11 @@
namespace App\DataMapper\Tax; namespace App\DataMapper\Tax;
use App\DataMapper\Tax\ZipTax\Response;
use App\DataProviders\USStates;
use App\Models\Client; use App\Models\Client;
use App\Models\Invoice; use App\Models\Invoice;
use App\Models\Product; use App\Models\Product;
use App\DataProviders\USStates;
use App\DataMapper\Tax\ZipTax\Response;
class BaseRule implements RuleInterface class BaseRule implements RuleInterface
{ {
@ -147,8 +147,9 @@ class BaseRule implements RuleInterface
$this->resolveRegions(); $this->resolveRegions();
if(!$this->isTaxableRegion()) if(!$this->isTaxableRegion()) {
return $this; return $this;
}
$this->configTaxData(); $this->configTaxData();
@ -173,8 +174,9 @@ class BaseRule implements RuleInterface
/** Harvest the client_region */ /** Harvest the client_region */
/** If the tax data is already set and the invoice is marked as sent, do not adjust the rates */ /** If the tax data is already set and the invoice is marked as sent, do not adjust the rates */
if($this->invoice->tax_data && $this->invoice->status_id > 1) if($this->invoice->tax_data && $this->invoice->status_id > 1) {
return $this; return $this;
}
/** /**
* Origin - Company Tax Data * Origin - Company Tax Data
@ -190,8 +192,7 @@ class BaseRule implements RuleInterface
/** If no company tax data has been configured, lets do that now. */ /** If no company tax data has been configured, lets do that now. */
/** We should never encounter this scenario */ /** We should never encounter this scenario */
if(!$company->origin_tax_data) if(!$company->origin_tax_data) {
{
$this->should_calc_tax = false; $this->should_calc_tax = false;
return $this; return $this;
} }
@ -201,8 +202,7 @@ class BaseRule implements RuleInterface
$tax_data = $company->origin_tax_data; $tax_data = $company->origin_tax_data;
} } elseif($this->client->tax_data) {
elseif($this->client->tax_data){
$tax_data = $this->client->tax_data; $tax_data = $this->client->tax_data;
@ -215,8 +215,14 @@ class BaseRule implements RuleInterface
$this->invoice->tax_data = $tax_data; $this->invoice->tax_data = $tax_data;
if(\DB::transactionLevel() == 0) if(\DB::transactionLevel() == 0) {
try {
$this->invoice->saveQuietly(); $this->invoice->saveQuietly();
}catch(\Exception $e) {
}
}
} }
return $this; return $this;
@ -251,8 +257,9 @@ class BaseRule implements RuleInterface
$states = USStates::$states; $states = USStates::$states;
if(isset($states[$this->client->state])) if(isset($states[$this->client->state])) {
return $this->client->state; return $this->client->state;
}
return USStates::getState(strlen($this->client->postal_code) > 1 ? $this->client->postal_code : $this->client->shipping_postal_code); return USStates::getState(strlen($this->client->postal_code) > 1 ? $this->client->postal_code : $this->client->shipping_postal_code);
@ -277,8 +284,7 @@ class BaseRule implements RuleInterface
return $this; return $this;
} } elseif($this->client_region == 'AU') { //these are defaults and are only stubbed out for now, for AU we can actually remove these
elseif($this->client_region == 'AU'){ //these are defaults and are only stubbed out for now, for AU we can actually remove these
$this->tax_rate1 = $this->client->company->tax_data->regions->AU->subregions->AU->tax_rate; $this->tax_rate1 = $this->client->company->tax_data->regions->AU->subregions->AU->tax_rate;
$this->tax_name1 = $this->client->company->tax_data->regions->AU->subregions->AU->tax_name; $this->tax_name1 = $this->client->company->tax_data->regions->AU->subregions->AU->tax_name;
@ -297,7 +303,7 @@ class BaseRule implements RuleInterface
public function tax($item = null): self public function tax($item = null): self
{ {
if ($this->client->is_tax_exempt) { if ($this->client->is_tax_exempt || !property_exists($item, 'tax_id')) {
return $this->taxExempt($item); return $this->taxExempt($item);

View File

@ -11,9 +11,9 @@
namespace App\DataMapper\Tax\DE; namespace App\DataMapper\Tax\DE;
use App\Models\Product;
use App\DataMapper\Tax\BaseRule; use App\DataMapper\Tax\BaseRule;
use App\DataMapper\Tax\RuleInterface; use App\DataMapper\Tax\RuleInterface;
use App\Models\Product;
class Rule extends BaseRule implements RuleInterface class Rule extends BaseRule implements RuleInterface
{ {
@ -63,7 +63,7 @@ class Rule extends BaseRule implements RuleInterface
public function taxByType($item): self public function taxByType($item): self
{ {
if ($this->client->is_tax_exempt) { if ($this->client->is_tax_exempt || !property_exists($item, 'tax_id')) {
return $this->taxExempt($item); return $this->taxExempt($item);
} }
@ -220,39 +220,28 @@ class Rule extends BaseRule implements RuleInterface
// nlog("tax exempt"); // nlog("tax exempt");
$this->tax_rate = 0; $this->tax_rate = 0;
$this->reduced_tax_rate = 0; $this->reduced_tax_rate = 0;
} } elseif($this->client_subregion != $this->client->company->tax_data->seller_subregion && in_array($this->client_subregion, $this->eu_country_codes) && $this->client->vat_number && $this->eu_business_tax_exempt) {
elseif($this->client_subregion != $this->client->company->tax_data->seller_subregion && in_array($this->client_subregion, $this->eu_country_codes) && $this->client->vat_number && $this->eu_business_tax_exempt)
// elseif($this->client_subregion != $this->client->company->tax_data->seller_subregion && in_array($this->client_subregion, $this->eu_country_codes) && $this->client->has_valid_vat_number && $this->eu_business_tax_exempt) // elseif($this->client_subregion != $this->client->company->tax_data->seller_subregion && in_array($this->client_subregion, $this->eu_country_codes) && $this->client->has_valid_vat_number && $this->eu_business_tax_exempt)
{
// nlog("euro zone and tax exempt"); // nlog("euro zone and tax exempt");
$this->tax_rate = 0; $this->tax_rate = 0;
$this->reduced_tax_rate = 0; $this->reduced_tax_rate = 0;
} } elseif(!in_array($this->client_subregion, $this->eu_country_codes) && ($this->foreign_consumer_tax_exempt || $this->foreign_business_tax_exempt)) { //foreign + tax exempt
elseif(!in_array($this->client_subregion, $this->eu_country_codes) && ($this->foreign_consumer_tax_exempt || $this->foreign_business_tax_exempt)) //foreign + tax exempt
{
// nlog("foreign and tax exempt"); // nlog("foreign and tax exempt");
$this->tax_rate = 0; $this->tax_rate = 0;
$this->reduced_tax_rate = 0; $this->reduced_tax_rate = 0;
} } elseif(!in_array($this->client_subregion, $this->eu_country_codes)) {
elseif(!in_array($this->client_subregion, $this->eu_country_codes))
{
$this->defaultForeign(); $this->defaultForeign();
} } elseif(in_array($this->client_subregion, $this->eu_country_codes) && !$this->client->vat_number) { //eu country / no valid vat
elseif(in_array($this->client_subregion, $this->eu_country_codes) && !$this->client->vat_number) //eu country / no valid vat if(($this->client->company->tax_data->seller_subregion != $this->client_subregion) && $this->client->company->tax_data->regions->EU->has_sales_above_threshold) {
{
if(($this->client->company->tax_data->seller_subregion != $this->client_subregion) && $this->client->company->tax_data->regions->EU->has_sales_above_threshold)
{
// nlog("eu zone with sales above threshold"); // nlog("eu zone with sales above threshold");
$this->tax_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->country->iso_3166_2}->tax_rate; $this->tax_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->country->iso_3166_2}->tax_rate;
$this->reduced_tax_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->country->iso_3166_2}->reduced_tax_rate; $this->reduced_tax_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->country->iso_3166_2}->reduced_tax_rate;
} } else {
else {
// nlog("EU with intra-community supply ie DE to DE"); // nlog("EU with intra-community supply ie DE to DE");
$this->tax_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->company->country()->iso_3166_2}->tax_rate; $this->tax_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->company->country()->iso_3166_2}->tax_rate;
$this->reduced_tax_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->company->country()->iso_3166_2}->reduced_tax_rate; $this->reduced_tax_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->company->country()->iso_3166_2}->reduced_tax_rate;
} }
} } else {
else {
// nlog("default tax"); // nlog("default tax");
$this->tax_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->company->country()->iso_3166_2}->tax_rate; $this->tax_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->company->country()->iso_3166_2}->tax_rate;
$this->reduced_tax_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->company->country()->iso_3166_2}->reduced_tax_rate; $this->reduced_tax_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->company->country()->iso_3166_2}->reduced_tax_rate;

View File

@ -32,10 +32,11 @@ class TaxModel
public function __construct(public ?TaxModel $model = null) public function __construct(public ?TaxModel $model = null)
{ {
if(!$this->model) if(!$this->model) {
$this->regions = $this->init(); $this->regions = $this->init();
else } else {
$this->regions = $model; $this->regions = $model;
}
} }

View File

@ -119,8 +119,7 @@ class Rule extends BaseRule implements RuleInterface
{ {
if(in_array($this->tax_data?->txbService, ['Y','L'])) { if(in_array($this->tax_data?->txbService, ['Y','L'])) {
$this->default($item); $this->default($item);
} } else {
else {
$this->taxExempt($item); $this->taxExempt($item);
} }

View File

@ -114,4 +114,3 @@ class Response
} }
} }

View File

@ -33868,18 +33868,21 @@ class USStates
public static function getState(?string $zip = '90210'): string public static function getState(?string $zip = '90210'): string
{ {
if(isset(self::$zip_code_map[$zip])) if(isset(self::$zip_code_map[$zip])) {
return self::$zip_code_map[$zip]; return self::$zip_code_map[$zip];
}
$prefix_state = self::getStateFromThreeDigitPrefix($zip); $prefix_state = self::getStateFromThreeDigitPrefix($zip);
if($prefix_state) if($prefix_state) {
return $prefix_state; return $prefix_state;
}
$zippo_response = self::getStateFromZippo($zip); $zippo_response = self::getStateFromZippo($zip);
if($zippo_response) if($zippo_response) {
return $zippo_response; return $zippo_response;
}
throw new \Exception('Zip code not found'); throw new \Exception('Zip code not found');
} }
@ -33905,8 +33908,9 @@ class USStates
$response = Http::get("https://api.zippopotam.us/us/{$zip}"); $response = Http::get("https://api.zippopotam.us/us/{$zip}");
if($response->failed()) if($response->failed()) {
return false; return false;
}
$data = $response->object(); $data = $response->object();

View File

@ -12,11 +12,9 @@
namespace App\Events\Account; namespace App\Events\Account;
use App\Models\Company; use App\Models\Company;
use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
/** /**
* Class StripeConnectFailure. * Class StripeConnectFailure.

View File

@ -15,7 +15,6 @@ use App\Models\Client;
use App\Models\Company; use App\Models\Company;
use Illuminate\Broadcasting\Channel; use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;

View File

@ -14,7 +14,6 @@ namespace App\Events\Company;
use App\Models\Company; use App\Models\Company;
use Illuminate\Broadcasting\Channel; use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;

View File

@ -14,7 +14,6 @@ namespace App\Events\Contact;
use App\Models\ClientContact; use App\Models\ClientContact;
use Illuminate\Broadcasting\Channel; use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;

View File

@ -15,7 +15,6 @@ use App\Models\Company;
use App\Models\Design; use App\Models\Design;
use Illuminate\Broadcasting\Channel; use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;

View File

@ -11,10 +11,10 @@
namespace App\Events\Design; namespace App\Events\Design;
use App\Models\Design;
use App\Models\Company; use App\Models\Company;
use Illuminate\Queue\SerializesModels; use App\Models\Design;
use Illuminate\Broadcasting\PrivateChannel; use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Queue\SerializesModels;
/** /**
* Class DesignWasCreated. * Class DesignWasCreated.

View File

@ -11,10 +11,10 @@
namespace App\Events\Design; namespace App\Events\Design;
use App\Models\Design;
use App\Models\Company; use App\Models\Company;
use Illuminate\Queue\SerializesModels; use App\Models\Design;
use Illuminate\Broadcasting\PrivateChannel; use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Queue\SerializesModels;
/** /**
* Class DesignWasDeleted. * Class DesignWasDeleted.

View File

@ -11,10 +11,10 @@
namespace App\Events\Design; namespace App\Events\Design;
use App\Models\Design;
use App\Models\Company; use App\Models\Company;
use Illuminate\Queue\SerializesModels; use App\Models\Design;
use Illuminate\Broadcasting\PrivateChannel; use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Queue\SerializesModels;
/** /**
* Class DesignWasRestored. * Class DesignWasRestored.

View File

@ -11,10 +11,10 @@
namespace App\Events\Design; namespace App\Events\Design;
use App\Models\Design;
use App\Models\Company; use App\Models\Company;
use Illuminate\Queue\SerializesModels; use App\Models\Design;
use Illuminate\Broadcasting\PrivateChannel; use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Queue\SerializesModels;
/** /**
* Class DesignWasUpdated. * Class DesignWasUpdated.

View File

@ -15,7 +15,6 @@ use App\Models\Company;
use App\Models\Document; use App\Models\Document;
use Illuminate\Broadcasting\Channel; use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;

View File

@ -15,7 +15,6 @@ use App\Models\ClientGatewayToken;
use App\Models\Company; use App\Models\Company;
use Illuminate\Broadcasting\Channel; use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;

View File

@ -11,12 +11,12 @@
namespace App\Events\Payment; namespace App\Events\Payment;
use App\Models\ClientContact;
use App\Models\Company; use App\Models\Company;
use App\Models\Payment; use App\Models\Payment;
use App\Models\ClientContact;
use Illuminate\Queue\SerializesModels;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
/** /**
* Class PaymentWasEmailed. * Class PaymentWasEmailed.

View File

@ -12,7 +12,6 @@
namespace App\Events\PurchaseOrder; namespace App\Events\PurchaseOrder;
use App\Models\Company; use App\Models\Company;
use App\Models\PurchaseOrder;
use App\Models\PurchaseOrderInvitation; use App\Models\PurchaseOrderInvitation;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;

View File

@ -12,7 +12,6 @@
namespace App\Events\Quote; namespace App\Events\Quote;
use App\Models\Company; use App\Models\Company;
use App\Models\Quote;
use App\Models\QuoteInvitation; use App\Models\QuoteInvitation;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;

View File

@ -5,7 +5,6 @@ namespace App\Events\Subscription;
use App\Models\Company; use App\Models\Company;
use App\Models\Subscription; use App\Models\Subscription;
use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;

View File

@ -15,7 +15,6 @@ use App\Models\Company;
use App\Models\User; use App\Models\User;
use Illuminate\Broadcasting\Channel; use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;

View File

@ -15,7 +15,6 @@ use App\Models\Company;
use App\Models\User; use App\Models\User;
use Illuminate\Broadcasting\Channel; use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;

View File

@ -15,7 +15,6 @@ use App\Models\Company;
use App\Models\User; use App\Models\User;
use Illuminate\Broadcasting\Channel; use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
@ -26,7 +25,7 @@ class UserWasCreated
{ {
use Dispatchable, InteractsWithSockets, SerializesModels; use Dispatchable, InteractsWithSockets, SerializesModels;
public function __construct(public User $user, public User $creating_user, public Company $company, public array $event_vars) public function __construct(public User $user, public User $creating_user, public Company $company, public array $event_vars, public $is_react = true)
{ {
} }

View File

@ -15,7 +15,6 @@ use App\Models\Company;
use App\Models\User; use App\Models\User;
use Illuminate\Broadcasting\Channel; use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;

View File

@ -15,7 +15,6 @@ use App\Models\Company;
use App\Models\User; use App\Models\User;
use Illuminate\Broadcasting\Channel; use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;

View File

@ -15,7 +15,6 @@ use App\Models\Company;
use App\Models\User; use App\Models\User;
use Illuminate\Broadcasting\Channel; use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;

View File

@ -14,9 +14,9 @@ namespace App\Events\Vendor;
use App\Models\Company; use App\Models\Company;
use App\Models\VendorContact; use App\Models\VendorContact;
use Illuminate\Broadcasting\Channel; use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
/** /**
* Class VendorContactLoggedIn. * Class VendorContactLoggedIn.

View File

@ -11,31 +11,31 @@
namespace App\Exceptions; namespace App\Exceptions;
use Throwable;
use PDOException;
use App\Utils\Ninja; use App\Utils\Ninja;
use Sentry\State\Scope;
use Illuminate\Support\Arr;
use Illuminate\Http\Request;
use InvalidArgumentException;
use Sentry\Laravel\Integration;
use Illuminate\Support\Facades\Schema;
use Aws\Exception\CredentialsException; use Aws\Exception\CredentialsException;
use GuzzleHttp\Exception\ConnectException; use GuzzleHttp\Exception\ConnectException;
use Illuminate\Auth\AuthenticationException;
use League\Flysystem\UnableToCreateDirectory;
use Illuminate\Session\TokenMismatchException;
use Illuminate\Validation\ValidationException;
use Illuminate\Auth\Access\AuthorizationException; use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Queue\MaxAttemptsExceededException; use Illuminate\Auth\AuthenticationException;
use Illuminate\Http\Exceptions\ThrottleRequestsException; use Illuminate\Database\Eloquent\ModelNotFoundException as ModelNotFoundException;
use Symfony\Component\Process\Exception\RuntimeException;
use Illuminate\Database\Eloquent\RelationNotFoundException; use Illuminate\Database\Eloquent\RelationNotFoundException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Http\Exceptions\ThrottleRequestsException;
use Illuminate\Http\Request;
use Illuminate\Queue\MaxAttemptsExceededException;
use Illuminate\Session\TokenMismatchException;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Schema;
use Illuminate\Validation\ValidationException;
use InvalidArgumentException;
use League\Flysystem\UnableToCreateDirectory;
use PDOException;
use Sentry\Laravel\Integration;
use Sentry\State\Scope;
use Symfony\Component\Console\Exception\CommandNotFoundException; use Symfony\Component\Console\Exception\CommandNotFoundException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException; use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
use Illuminate\Database\Eloquent\ModelNotFoundException as ModelNotFoundException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Process\Exception\RuntimeException;
use Throwable;
class Handler extends ExceptionHandler class Handler extends ExceptionHandler
{ {

View File

@ -13,8 +13,8 @@
namespace App\Exceptions; namespace App\Exceptions;
use Exception; use Exception;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class PaymentRefundFailed extends Exception class PaymentRefundFailed extends Exception
{ {

View File

@ -13,8 +13,8 @@
namespace App\Exceptions; namespace App\Exceptions;
use Exception; use Exception;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class QuoteConversion extends Exception class QuoteConversion extends Exception
{ {

View File

@ -13,8 +13,8 @@
namespace App\Exceptions; namespace App\Exceptions;
use Exception; use Exception;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class YodleeApiException extends Exception class YodleeApiException extends Exception
{ {

View File

@ -11,17 +11,17 @@
namespace App\Export\CSV; namespace App\Export\CSV;
use App\Models\Task;
use App\Utils\Ninja;
use League\Csv\Writer;
use App\Models\Company;
use App\Models\Activity;
use App\Libraries\MultiDB; use App\Libraries\MultiDB;
use App\Models\Activity;
use App\Models\Company;
use App\Models\DateFormat; use App\Models\DateFormat;
use App\Models\Task;
use App\Transformers\ActivityTransformer;
use App\Utils\Ninja;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Carbon; use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\App;
use Illuminate\Database\Eloquent\Builder; use League\Csv\Writer;
use App\Transformers\ActivityTransformer;
class ActivityExport extends BaseExport class ActivityExport extends BaseExport
{ {
@ -54,12 +54,14 @@ class ActivityExport extends BaseExport
$headerdisplay = $this->buildHeader(); $headerdisplay = $this->buildHeader();
$header = collect($this->input['report_keys'])->map(function ($key, $value) use ($headerdisplay) { $header = collect($this->input['report_keys'])->map(function ($key, $value) use ($headerdisplay) {
return ['identifier' => $value, 'display_value' => $headerdisplay[$value]]; return ['identifier' => $key, 'display_value' => $headerdisplay[$value]];
})->toArray(); })->toArray();
$report = $query->cursor() $report = $query->cursor()
->map(function ($credit) { ->map(function ($resource) {
return $this->buildActivityRow($credit); $row = $this->buildActivityRow($resource);
return $this->processMetaData($row, $resource);
})->toArray(); })->toArray();
return array_merge(['columns' => $header], $report); return array_merge(['columns' => $header], $report);
@ -70,6 +72,8 @@ class ActivityExport extends BaseExport
return [ return [
Carbon::parse($activity->created_at)->format($this->date_format), Carbon::parse($activity->created_at)->format($this->date_format),
ctrans("texts.activity_{$activity->activity_type_id}", [ ctrans("texts.activity_{$activity->activity_type_id}", [
'payment_amount' => $activity->payment ? $activity->payment->amount : '',
'adjustment' => $activity->payment ? $activity->payment->refunded : '',
'client' => $activity->client ? $activity->client->present()->name() : '', 'client' => $activity->client ? $activity->client->present()->name() : '',
'contact' => $activity->contact ? $activity->contact->present()->name() : '', 'contact' => $activity->contact ? $activity->contact->present()->name() : '',
'quote' => $activity->quote ? $activity->quote->number : '', 'quote' => $activity->quote ? $activity->quote->number : '',
@ -101,7 +105,7 @@ class ActivityExport extends BaseExport
$this->date_format = DateFormat::find($this->company->settings->date_format_id)->format; $this->date_format = DateFormat::find($this->company->settings->date_format_id)->format;
ksort($this->entity_keys); // ksort($this->entity_keys);
if (count($this->input['report_keys']) == 0) { if (count($this->input['report_keys']) == 0) {
$this->input['report_keys'] = array_values($this->entity_keys); $this->input['report_keys'] = array_values($this->entity_keys);
@ -146,4 +150,25 @@ class ActivityExport extends BaseExport
{ {
return $entity; return $entity;
} }
public function processMetaData(array $row, $resource): array
{
$clean_row = [];
foreach (array_values($this->input['report_keys']) as $key => $value) {
$clean_row[$key]['entity'] = 'activity';
$clean_row[$key]['id'] = $key;
$clean_row[$key]['hashed_id'] = null;
$clean_row[$key]['value'] = $row[$key];
$clean_row[$key]['identifier'] = $value;
$clean_row[$key]['display_value'] = $row[$key];
}
return $clean_row;
}
} }

View File

@ -11,19 +11,27 @@
namespace App\Export\CSV; namespace App\Export\CSV;
use App\Utils\Number;
use App\Models\Client; use App\Models\Client;
use App\Utils\Helpers; use App\Models\ClientContact;
use App\Models\Company; use App\Models\Company;
use App\Models\Credit;
use App\Models\Document;
use App\Models\Expense; use App\Models\Expense;
use App\Models\Invoice; use App\Models\Invoice;
use App\Models\Payment; use App\Models\Payment;
use League\Fractal\Manager; use App\Models\Product;
use Illuminate\Support\Carbon; use App\Models\PurchaseOrder;
use App\Utils\Traits\MakesHash; use App\Models\Quote;
use App\Transformers\TaskTransformer; use App\Models\RecurringInvoice;
use App\Models\Task;
use App\Models\Vendor;
use App\Transformers\PaymentTransformer; use App\Transformers\PaymentTransformer;
use App\Transformers\TaskTransformer;
use App\Utils\Helpers;
use App\Utils\Traits\MakesHash;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Carbon;
use League\Fractal\Manager;
use League\Fractal\Serializer\ArraySerializer; use League\Fractal\Serializer\ArraySerializer;
class BaseExport class BaseExport
@ -56,7 +64,7 @@ class BaseExport
'id_number' => 'vendor.id_number', 'id_number' => 'vendor.id_number',
'name' => 'vendor.name', 'name' => 'vendor.name',
'number' => 'vendor.number', 'number' => 'vendor.number',
'client_phone' => 'vendor.phone', 'phone' => 'vendor.phone',
'postal_code' => 'vendor.postal_code', 'postal_code' => 'vendor.postal_code',
'private_notes' => 'vendor.private_notes', 'private_notes' => 'vendor.private_notes',
'public_notes' => 'vendor.public_notes', 'public_notes' => 'vendor.public_notes',
@ -73,10 +81,12 @@ class BaseExport
'contact_custom_value4' => 'vendor_contact.custom_value4', 'contact_custom_value4' => 'vendor_contact.custom_value4',
'email' => 'vendor_contact.email', 'email' => 'vendor_contact.email',
'status' => 'vendor.status', 'status' => 'vendor.status',
'classification' => 'vendor.classification',
]; ];
protected array $client_report_keys = [ protected array $client_report_keys = [
"name" => "client.name", "name" => "client.name",
"number" => "client.number",
"user" => "client.user", "user" => "client.user",
"assigned_user" => "client.assigned_user", "assigned_user" => "client.assigned_user",
"balance" => "client.balance", "balance" => "client.balance",
@ -115,10 +125,13 @@ class BaseExport
"contact_custom_value2" => "contact.custom_value2", "contact_custom_value2" => "contact.custom_value2",
"contact_custom_value3" => "contact.custom_value3", "contact_custom_value3" => "contact.custom_value3",
"contact_custom_value4" => "contact.custom_value4", "contact_custom_value4" => "contact.custom_value4",
'payment_balance' => 'client.payment_balance',
'credit_balance' => 'client.credit_balance',
'classification' => 'client.classification',
]; ];
protected array $invoice_report_keys = [ protected array $invoice_report_keys = [
'name' => 'client.name',
"invoice_number" => "invoice.number", "invoice_number" => "invoice.number",
"amount" => "invoice.amount", "amount" => "invoice.amount",
"balance" => "invoice.balance", "balance" => "invoice.balance",
@ -154,6 +167,8 @@ class BaseExport
'tax_rate1' => 'invoice.tax_rate1', 'tax_rate1' => 'invoice.tax_rate1',
'tax_rate2' => 'invoice.tax_rate2', 'tax_rate2' => 'invoice.tax_rate2',
'tax_rate3' => 'invoice.tax_rate3', 'tax_rate3' => 'invoice.tax_rate3',
'recurring_invoice' => 'invoice.recurring_id',
'auto_bill' => 'invoice.auto_bill_enabled',
]; ];
protected array $recurring_invoice_report_keys = [ protected array $recurring_invoice_report_keys = [
@ -194,6 +209,9 @@ class BaseExport
'tax_rate1' => 'recurring_invoice.tax_rate1', 'tax_rate1' => 'recurring_invoice.tax_rate1',
'tax_rate2' => 'recurring_invoice.tax_rate2', 'tax_rate2' => 'recurring_invoice.tax_rate2',
'tax_rate3' => 'recurring_invoice.tax_rate3', 'tax_rate3' => 'recurring_invoice.tax_rate3',
'auto_bill' => 'recurring_invoice.auto_bill',
'auto_bill_enabled' => 'recurring_invoice.auto_bill_enabled',
]; ];
protected array $purchase_order_report_keys = [ protected array $purchase_order_report_keys = [
@ -216,7 +234,7 @@ class BaseExport
'po_number' => 'purchase_order.po_number', 'po_number' => 'purchase_order.po_number',
'private_notes' => 'purchase_order.private_notes', 'private_notes' => 'purchase_order.private_notes',
'public_notes' => 'purchase_order.public_notes', 'public_notes' => 'purchase_order.public_notes',
'status' => 'purchase_order.status_id', 'status' => 'purchase_order.status',
'tax_name1' => 'purchase_order.tax_name1', 'tax_name1' => 'purchase_order.tax_name1',
'tax_name2' => 'purchase_order.tax_name2', 'tax_name2' => 'purchase_order.tax_name2',
'tax_name3' => 'purchase_order.tax_name3', 'tax_name3' => 'purchase_order.tax_name3',
@ -229,8 +247,8 @@ class BaseExport
]; ];
protected array $product_report_keys = [ protected array $product_report_keys = [
'project' => 'project_id', // 'project' => 'project_id',
'vendor' => 'vendor_id', // 'vendor' => 'vendor_id',
'custom_value1' => 'custom_value1', 'custom_value1' => 'custom_value1',
'custom_value2' => 'custom_value2', 'custom_value2' => 'custom_value2',
'custom_value3' => 'custom_value3', 'custom_value3' => 'custom_value3',
@ -246,6 +264,10 @@ class BaseExport
'tax_name1' => 'tax_name1', 'tax_name1' => 'tax_name1',
'tax_name2' => 'tax_name2', 'tax_name2' => 'tax_name2',
'tax_name3' => 'tax_name3', 'tax_name3' => 'tax_name3',
'image' => 'product_image',
'tax_category' => 'tax_id',
'max_quantity' => 'max_quantity',
'in_stock_quantity' => 'in_stock_quantity',
]; ];
protected array $item_report_keys = [ protected array $item_report_keys = [
@ -269,6 +291,7 @@ class BaseExport
'is_amount_discount' => 'item.is_amount_discount', 'is_amount_discount' => 'item.is_amount_discount',
'line_total' => 'item.line_total', 'line_total' => 'item.line_total',
'gross_line_total' => 'item.gross_line_total', 'gross_line_total' => 'item.gross_line_total',
'tax_amount' => 'item.tax_amount',
]; ];
protected array $quote_report_keys = [ protected array $quote_report_keys = [
@ -359,12 +382,13 @@ class BaseExport
"custom_value4" => "payment.custom_value4", "custom_value4" => "payment.custom_value4",
"user" => "payment.user_id", "user" => "payment.user_id",
"assigned_user" => "payment.assigned_user_id", "assigned_user" => "payment.assigned_user_id",
]; ];
protected array $expense_report_keys = [ protected array $expense_report_keys = [
'amount' => 'expense.amount', 'amount' => 'expense.amount',
'category' => 'expense.category_id', 'category' => 'expense.category_id',
'client' => 'expense.client_id', // 'client' => 'expense.client_id',
'custom_value1' => 'expense.custom_value1', 'custom_value1' => 'expense.custom_value1',
'custom_value2' => 'expense.custom_value2', 'custom_value2' => 'expense.custom_value2',
'custom_value3' => 'expense.custom_value3', 'custom_value3' => 'expense.custom_value3',
@ -411,14 +435,21 @@ class BaseExport
'project' => 'task.project_id', 'project' => 'task.project_id',
]; ];
protected array $forced_client_fields = [
"client.name",
];
protected array $forced_vendor_fields = [
"vendor.name",
];
protected function filterByClients($query) protected function filterByClients($query)
{ {
if (isset($this->input['client_id']) && $this->input['client_id'] != 'all') { if (isset($this->input['client_id']) && $this->input['client_id'] != 'all') {
$client = Client::withTrashed()->find($this->input['client_id']); $client = Client::withTrashed()->find($this->input['client_id']);
$this->client_description = $client->present()->name; $this->client_description = $client->present()->name;
return $query->where('client_id', $this->input['client_id']); return $query->where('client_id', $this->input['client_id']);
} } elseif(isset($this->input['clients']) && count($this->input['clients']) > 0) {
elseif(isset($this->input['clients']) && count($this->input['clients']) > 0) {
$this->client_description = 'Multiple Clients'; $this->client_description = 'Multiple Clients';
return $query->whereIn('client_id', $this->input['clients']); return $query->whereIn('client_id', $this->input['clients']);
@ -430,8 +461,9 @@ class BaseExport
{ {
$parts = explode(".", $key); $parts = explode(".", $key);
if(!is_array($parts) || count($parts) < 2) if(!is_array($parts) || count($parts) < 2) {
return ''; return '';
}
$value = ''; $value = '';
@ -468,8 +500,9 @@ class BaseExport
private function resolveVendorContactKey($column, $entity, $transformer) private function resolveVendorContactKey($column, $entity, $transformer)
{ {
if(!$entity->vendor) if(!$entity->vendor) {
return ""; return "";
}
$primary_contact = $entity->vendor->primary_contact()->first() ?? $entity->vendor->contacts()->first(); $primary_contact = $entity->vendor->primary_contact()->first() ?? $entity->vendor->contacts()->first();
@ -481,18 +514,21 @@ class BaseExport
private function resolveExpenseKey($column, $entity, $transformer) private function resolveExpenseKey($column, $entity, $transformer)
{ {
if($column == 'user' && $entity?->expense?->user) if($column == 'user' && $entity?->expense?->user) {
return $entity->expense->user->present()->name() ?? ' '; return $entity->expense->user->present()->name() ?? ' ';
}
if($column == 'assigned_user' && $entity?->expense?->assigned_user) if($column == 'assigned_user' && $entity?->expense?->assigned_user) {
return $entity->expense->assigned_user->present()->name() ?? ' '; return $entity->expense->assigned_user->present()->name() ?? ' ';
}
if($column == 'category' && $entity->expense) { if($column == 'category' && $entity->expense) {
return $entity->expense->category?->name ?? ' '; return $entity->expense->category?->name ?? ' ';
} }
if($entity instanceof Expense) if($entity instanceof Expense) {
return ''; return '';
}
$transformed_entity = $transformer->includeExpense($entity); $transformed_entity = $transformer->includeExpense($entity);
@ -500,11 +536,13 @@ class BaseExport
$manager->setSerializer(new ArraySerializer()); $manager->setSerializer(new ArraySerializer());
$transformed_entity = $manager->createData($transformed_entity)->toArray(); $transformed_entity = $manager->createData($transformed_entity)->toArray();
if(array_key_exists($column, $transformed_entity)) if(array_key_exists($column, $transformed_entity)) {
return $transformed_entity[$column]; return $transformed_entity[$column];
}
if(property_exists($entity, $column)) if(property_exists($entity, $column)) {
return $entity?->{$column} ?? ''; return $entity?->{$column} ?? '';
}
nlog("export: Could not resolve expense key: {$column}"); nlog("export: Could not resolve expense key: {$column}");
@ -531,8 +569,9 @@ class BaseExport
private function resolveVendorKey($column, $entity, $transformer) private function resolveVendorKey($column, $entity, $transformer)
{ {
if(!$entity->vendor) if(!$entity->vendor) {
return ''; return '';
}
$transformed_entity = $transformer->includeVendor($entity); $transformed_entity = $transformer->includeVendor($entity);
@ -540,24 +579,29 @@ class BaseExport
$manager->setSerializer(new ArraySerializer()); $manager->setSerializer(new ArraySerializer());
$transformed_entity = $manager->createData($transformed_entity)->toArray(); $transformed_entity = $manager->createData($transformed_entity)->toArray();
if($column == 'name') if($column == 'name') {
return $entity->vendor->present()->name() ?: ''; return $entity->vendor->present()->name() ?: '';
}
if($column == 'user_id') if($column == 'user_id') {
return $entity->vendor->user->present()->name() ?: ''; return $entity->vendor->user->present()->name() ?: '';
}
if($column == 'country_id') if($column == 'country_id') {
return $entity->vendor->country ? ctrans("texts.country_{$entity->vendor->country->name}") : ''; return $entity->vendor->country ? ctrans("texts.country_{$entity->vendor->country->name}") : '';
}
if ($column == 'currency_id') { if ($column == 'currency_id') {
return $entity->vendor->currency() ? $entity->vendor->currency()->code : $entity->company->currency()->code; return $entity->vendor->currency() ? $entity->vendor->currency()->code : $entity->company->currency()->code;
} }
if($column == 'status') if($column == 'status') {
return $entity->stringStatus($entity->status_id) ?: ''; return $entity->stringStatus($entity->status_id) ?: '';
}
if(array_key_exists($column, $transformed_entity)) if(array_key_exists($column, $transformed_entity)) {
return $transformed_entity[$column]; return $transformed_entity[$column];
}
// nlog("export: Could not resolve vendor key: {$column}"); // nlog("export: Could not resolve vendor key: {$column}");
@ -569,8 +613,9 @@ class BaseExport
private function resolveClientKey($column, $entity, $transformer) private function resolveClientKey($column, $entity, $transformer)
{ {
if(!$entity->client) if(!$entity->client) {
return ''; return '';
}
$transformed_client = $transformer->includeClient($entity); $transformed_client = $transformer->includeClient($entity);
@ -578,34 +623,46 @@ class BaseExport
$manager->setSerializer(new ArraySerializer()); $manager->setSerializer(new ArraySerializer());
$transformed_client = $manager->createData($transformed_client)->toArray(); $transformed_client = $manager->createData($transformed_client)->toArray();
if($column == 'name') if(in_array($column, ['client.name', 'name'])) {
return $transformed_client['display_name']; return $transformed_client['display_name'];
}
if($column == 'user_id') if(in_array($column, ['client.user_id', 'user_id'])) {
return $entity->client->user->present()->name(); return $entity->client->user->present()->name();
}
if($column == 'country_id') if(in_array($column, ['client.assigned_user_id', 'assigned_user_id'])) {
return $entity->client->assigned_user->present()->name();
}
if(in_array($column, ['client.country_id', 'country_id'])) {
return $entity->client->country ? ctrans("texts.country_{$entity->client->country->name}") : ''; return $entity->client->country ? ctrans("texts.country_{$entity->client->country->name}") : '';
}
if($column == 'shipping_country_id') if(in_array($column, ['client.shipping_country_id', 'shipping_country_id'])) {
return $entity->client->shipping_country ? ctrans("texts.country_{$entity->client->shipping_country->name}") : ''; return $entity->client->shipping_country ? ctrans("texts.country_{$entity->client->shipping_country->name}") : '';
}
if($column == 'size_id') if(in_array($column, ['client.size_id', 'size_id'])) {
return $entity->client->size?->name ?? ''; return $entity->client->size?->name ?? '';
}
if($column == 'industry_id') if(in_array($column, ['client.industry_id', 'industry_id'])) {
return $entity->client->industry?->name ?? ''; return $entity->client->industry?->name ?? '';
}
if ($column == 'currency_id') { if (in_array($column, ['client.currency_id', 'currency_id'])) {
return $entity->client->currency() ? $entity->client->currency()->code : $entity->company->currency()->code; return $entity->client->currency() ? $entity->client->currency()->code : $entity->company->currency()->code;
} }
if($column == 'client.payment_terms') { if(in_array($column, ['payment_terms', 'client.payment_terms'])) {
return $entity->client->getSetting('payment_terms'); return $entity->client->getSetting('payment_terms');
} }
if(array_key_exists($column, $transformed_client))
if(array_key_exists($column, $transformed_client)) {
return $transformed_client[$column]; return $transformed_client[$column];
}
// nlog("export: Could not resolve client key: {$column}"); // nlog("export: Could not resolve client key: {$column}");
@ -619,8 +676,9 @@ class BaseExport
$transformed_entity = $transformer->transform($entity); $transformed_entity = $transformer->transform($entity);
if($column == 'status') if($column == 'status') {
return $entity->stringStatus($entity->status_id); return $entity->stringStatus($entity->status_id);
}
return ''; return '';
} }
@ -644,33 +702,37 @@ class BaseExport
// nlog("searching for {$column}"); // nlog("searching for {$column}");
$transformed_invoice = false; $transformed_invoice = false;
if($transformer instanceof PaymentTransformer) { if($transformer instanceof PaymentTransformer && ($entity->invoices ?? false)) {
$transformed_invoices = $transformer->includeInvoices($entity); $transformed_invoices = $transformer->includeInvoices($entity);
$manager = new Manager(); $manager = new Manager();
$manager->setSerializer(new ArraySerializer()); $manager->setSerializer(new ArraySerializer());
$transformed_invoices = $manager->createData($transformed_invoices)->toArray(); $transformed_invoices = $manager->createData($transformed_invoices)->toArray();
if(!isset($transformed_invoices['App\\Models\\Invoice'])) if(!isset($transformed_invoices['App\\Models\\Invoice'])) {
return ''; return '';
}
$transformed_invoices = $transformed_invoices['App\\Models\\Invoice']; $transformed_invoices = $transformed_invoices['App\\Models\\Invoice'];
if(count($transformed_invoices) == 1 && array_key_exists($column, $transformed_invoices[0])) if(count($transformed_invoices) == 1 && array_key_exists($column, $transformed_invoices[0])) {
return $transformed_invoices[0][$column]; return $transformed_invoices[0][$column];
}
if(count($transformed_invoices) > 1 && array_key_exists($column, $transformed_invoices[0])) if(count($transformed_invoices) > 1 && array_key_exists($column, $transformed_invoices[0])) {
return implode(', ', array_column($transformed_invoices, $column)); return implode(', ', array_column($transformed_invoices, $column));
}
return ""; return "";
} }
if($transformer instanceof TaskTransformer) { if($transformer instanceof TaskTransformer && ($entity->invoice ?? false)) {
$transformed_invoice = $transformer->includeInvoice($entity); $transformed_invoice = $transformer->includeInvoice($entity);
if(!$transformed_invoice) if(!$transformed_invoice) {
return ''; return '';
}
$manager = new Manager(); $manager = new Manager();
$manager->setSerializer(new ArraySerializer()); $manager->setSerializer(new ArraySerializer());
@ -706,8 +768,9 @@ class BaseExport
} }
if($column == 'amount') if($column == 'amount') {
return $entity->payments()->exists() ? $entity->payments()->withoutTrashed()->sum('paymentables.amount') : ctrans('texts.unpaid'); return $entity->payments()->exists() ? $entity->payments()->withoutTrashed()->sum('paymentables.amount') : ctrans('texts.unpaid');
}
if($column == 'refunded') { if($column == 'refunded') {
return $entity->payments()->exists() ? $entity->payments()->withoutTrashed()->sum('paymentables.refunded') : ''; return $entity->payments()->exists() ? $entity->payments()->withoutTrashed()->sum('paymentables.refunded') : '';
@ -722,14 +785,17 @@ class BaseExport
$payment = $entity->payments()->withoutTrashed()->first(); $payment = $entity->payments()->withoutTrashed()->first();
if(!$payment) if(!$payment) {
return ''; return '';
}
if($column == 'method') if($column == 'method') {
return $payment->translatedType(); return $payment->translatedType();
}
if($column == 'currency') if($column == 'currency') {
return $payment?->currency?->code ?? ''; return $payment?->currency?->code ?? '';
}
$payment_transformer = new PaymentTransformer(); $payment_transformer = new PaymentTransformer();
$transformed_payment = $payment_transformer->transform($payment); $transformed_payment = $payment_transformer->transform($payment);
@ -738,21 +804,41 @@ class BaseExport
return $payment->stringStatus($transformed_payment['status_id']); return $payment->stringStatus($transformed_payment['status_id']);
} }
if(array_key_exists($column, $transformed_payment)) if(array_key_exists($column, $transformed_payment)) {
return $transformed_payment[$column]; return $transformed_payment[$column];
}
return ''; return '';
} }
public function applyFilters(Builder $query): Builder
{
if(isset($this->input['product_key'])) {
$products = explode(",", $this->input['product_key']);
$query->where(function ($q) use ($products) {
foreach($products as $product) {
$q->orWhereJsonContains('line_items', ['product_key' => $product]);
}
});
}
return $query;
}
protected function addInvoiceStatusFilter($query, $status): Builder protected function addInvoiceStatusFilter($query, $status): Builder
{ {
$status_parameters = explode(',', $status); $status_parameters = explode(',', $status);
if(in_array('all', $status_parameters)) if(in_array('all', $status_parameters)) {
return $query; return $query;
}
$query->where(function ($nested) use ($status_parameters) { $query->where(function ($nested) use ($status_parameters) {
@ -801,6 +887,8 @@ class BaseExport
protected function addDateRange($query) protected function addDateRange($query)
{ {
$query = $this->applyFilters($query);
$date_range = $this->input['date_range']; $date_range = $this->input['date_range'];
if (array_key_exists('date_key', $this->input) && strlen($this->input['date_key']) > 1) { if (array_key_exists('date_key', $this->input) && strlen($this->input['date_key']) > 1) {
@ -853,8 +941,9 @@ class BaseExport
$first_month_of_year = $this->company->getSetting('first_month_of_year') ?? 1; $first_month_of_year = $this->company->getSetting('first_month_of_year') ?? 1;
$fin_year_start = now()->createFromDate(now()->year, $first_month_of_year, 1); $fin_year_start = now()->createFromDate(now()->year, $first_month_of_year, 1);
if(now()->lt($fin_year_start)) if(now()->lt($fin_year_start)) {
$fin_year_start->subYearNoOverflow(); $fin_year_start->subYearNoOverflow();
}
$this->start_date = $fin_year_start->format('Y-m-d'); $this->start_date = $fin_year_start->format('Y-m-d');
$this->end_date = $fin_year_start->copy()->addYear()->subDay()->format('Y-m-d'); $this->end_date = $fin_year_start->copy()->addYear()->subDay()->format('Y-m-d');
@ -865,8 +954,9 @@ class BaseExport
$fin_year_start = now()->createFromDate(now()->year, $first_month_of_year, 1); $fin_year_start = now()->createFromDate(now()->year, $first_month_of_year, 1);
$fin_year_start->subYearNoOverflow(); $fin_year_start->subYearNoOverflow();
if(now()->subYear()->lt($fin_year_start)) if(now()->subYear()->lt($fin_year_start)) {
$fin_year_start->subYearNoOverflow(); $fin_year_start->subYearNoOverflow();
}
$this->start_date = $fin_year_start->format('Y-m-d'); $this->start_date = $fin_year_start->format('Y-m-d');
$this->end_date = $fin_year_start->copy()->addYear()->subDay()->format('Y-m-d'); $this->end_date = $fin_year_start->copy()->addYear()->subDay()->format('Y-m-d');
@ -900,7 +990,7 @@ class BaseExport
$helper = new Helpers(); $helper = new Helpers();
$header = []; $header = [];
// nlog("header");
foreach ($this->input['report_keys'] as $value) { foreach ($this->input['report_keys'] as $value) {
$key = array_search($value, $this->entity_keys); $key = array_search($value, $this->entity_keys);
@ -947,6 +1037,10 @@ class BaseExport
if(!$key) { if(!$key) {
$prefix = ctrans('texts.expense')." "; $prefix = ctrans('texts.expense')." ";
$key = array_search($value, $this->expense_report_keys); $key = array_search($value, $this->expense_report_keys);
if(!$key && $value == 'expense.category') {
$key = 'category';
}
} }
if(!$key) { if(!$key) {
@ -973,6 +1067,8 @@ class BaseExport
$prefix = ''; $prefix = '';
} }
// nlog("key => {$key}");
$key = str_replace('item.', '', $key); $key = str_replace('item.', '', $key);
$key = str_replace('recurring_invoice.', '', $key); $key = str_replace('recurring_invoice.', '', $key);
$key = str_replace('purchase_order.', '', $key); $key = str_replace('purchase_order.', '', $key);
@ -986,9 +1082,9 @@ class BaseExport
$key = str_replace('payment.', '', $key); $key = str_replace('payment.', '', $key);
$key = str_replace('expense.', '', $key); $key = str_replace('expense.', '', $key);
$key = str_replace('product.', '', $key); $key = str_replace('product.', '', $key);
$key = str_replace('task.', '', $key);
if(stripos($value, 'custom_value') !== false) if(stripos($value, 'custom_value') !== false) {
{
$parts = explode(".", $value); $parts = explode(".", $value);
if(count($parts) == 2 && in_array($parts[0], ['credit','quote','invoice','purchase_order','recurring_invoice'])) { if(count($parts) == 2 && in_array($parts[0], ['credit','quote','invoice','purchase_order','recurring_invoice'])) {
@ -997,29 +1093,27 @@ class BaseExport
$fallback = "custom_value".substr($parts[1], -1); $fallback = "custom_value".substr($parts[1], -1);
$custom_field_label = $helper->makeCustomField($this->company->custom_fields, $entity); $custom_field_label = $helper->makeCustomField($this->company->custom_fields, $entity);
if(strlen($custom_field_label) > 1) if(strlen($custom_field_label) > 1) {
$header[] = $custom_field_label; $header[] = $custom_field_label;
else { } else {
$header[] = $prefix . " ". ctrans("texts.{$fallback}"); $header[] = $prefix . " ". ctrans("texts.{$fallback}");
} }
} } elseif(count($parts) == 2 && (stripos($parts[0], 'vendor_contact') !== false || stripos($parts[0], 'contact') !== false)) {
elseif(count($parts) == 2 && stripos($parts[0], 'contact') !== false) { $parts[0] = str_replace('vendor_contact', 'contact', $parts[0]);
$entity = "contact".substr($parts[1], -1); $entity = "contact".substr($parts[1], -1);
$custom_field_string = strlen($helper->makeCustomField($this->company->custom_fields, $entity)) > 1 ? $helper->makeCustomField($this->company->custom_fields, $entity) : ctrans("texts.{$parts[1]}"); $custom_field_string = strlen($helper->makeCustomField($this->company->custom_fields, $entity)) > 1 ? $helper->makeCustomField($this->company->custom_fields, $entity) : ctrans("texts.{$parts[1]}");
$header[] = ctrans("texts.{$parts[0]}") . " " . $custom_field_string; $header[] = ctrans("texts.{$parts[0]}") . " " . $custom_field_string;
}
elseif(count($parts) == 2 && in_array(substr($original_key, 0, -1), ['credit','quote','invoice','purchase_order','recurring_invoice'])){ } elseif(count($parts) == 2 && in_array(substr($original_key, 0, -1), ['credit','quote','invoice','purchase_order','recurring_invoice','task'])) {
$custom_field_string = strlen($helper->makeCustomField($this->company->custom_fields, "product".substr($original_key, -1))) > 1 ? $helper->makeCustomField($this->company->custom_fields, "product".substr($original_key, -1)) : ctrans("texts.{$parts[1]}"); $custom_field_string = strlen($helper->makeCustomField($this->company->custom_fields, "product".substr($original_key, -1))) > 1 ? $helper->makeCustomField($this->company->custom_fields, "product".substr($original_key, -1)) : ctrans("texts.{$parts[1]}");
$header[] = ctrans("texts.{$parts[0]}") . " " . $custom_field_string; $header[] = ctrans("texts.{$parts[0]}") . " " . $custom_field_string;
} } else {
else{
$header[] = "{$prefix}" . ctrans("texts.{$key}"); $header[] = "{$prefix}" . ctrans("texts.{$key}");
} }
} } else {
else
{
$header[] = "{$prefix}" . ctrans("texts.{$key}"); $header[] = "{$prefix}" . ctrans("texts.{$key}");
} }
} }
@ -1028,4 +1122,102 @@ class BaseExport
return $header; return $header;
} }
public function processMetaData(array $row, $resource): array
{
$class = get_class($resource);
$entity = '';
match ($class) {
Invoice::class => $entity = 'invoice',
RecurringInvoice::class => $entity = 'recurring_invoice',
Quote::class => $entity = 'quote',
Credit::class => $entity = 'credit',
Expense::class => $entity = 'expense',
Document::class => $entity = 'document',
ClientContact::class => $entity = 'contact',
PurchaseOrder::class => $entity = 'purchase_order',
Payment::class => $entity = 'payment',
Product::class => $entity = 'product',
Task::class => $entity = 'task',
Vendor::class => $entity = 'vendor',
default => $entity = 'invoice',
};
$clean_row = [];
foreach (array_values($this->input['report_keys']) as $key => $value) {
$report_keys = explode(".", $value);
$column_key = $value;
if($value == 'product_image') {
$column_key = 'image';
$value = 'image';
}
if($value == 'tax_id') {
$column_key = 'tax_category';
$value = 'tax_category';
}
$clean_row[$key]['entity'] = $report_keys[0];
$clean_row[$key]['id'] = $report_keys[1] ?? $report_keys[0];
$clean_row[$key]['hashed_id'] = $report_keys[0] == $entity ? null : $resource->{$report_keys[0]}->hashed_id ?? null;
$clean_row[$key]['value'] = $row[$column_key];
$clean_row[$key]['identifier'] = $value;
$clean_row[$key]['display_value'] = $row[$column_key];
}
return $clean_row;
}
public function processItemMetaData(array $row, $resource): array
{
$class = get_class($resource);
$entity = '';
match ($class) {
Invoice::class => $entity = 'invoice',
Quote::class => $entity = 'quote',
Credit::class => $entity = 'credit',
Expense::class => $entity = 'expense',
Document::class => $entity = 'document',
ClientContact::class => $entity = 'contact',
PurchaseOrder::class => $entity = 'purchase_order',
default => $entity = 'invoice',
};
$clean_row = [];
foreach (array_values($this->input['report_keys']) as $key => $value) {
$report_keys = explode(".", $value);
$column_key = $value;
if($value == 'type_id' || $value == 'item.type_id') {
$column_key = 'type';
}
if($value == 'tax_id' || $value == 'item.tax_id') {
$column_key = 'tax_category';
}
$clean_row[$key]['entity'] = $report_keys[0];
$clean_row[$key]['id'] = $report_keys[1] ?? $report_keys[0];
$clean_row[$key]['hashed_id'] = $report_keys[0] == $entity ? null : $resource->{$report_keys[0]}->hashed_id ?? null;
$clean_row[$key]['value'] = isset($row[$column_key]) ? $row[$column_key] : $row[$value];
$clean_row[$key]['identifier'] = $value;
$clean_row[$key]['display_value'] = isset($row[$column_key]) ? $row[$column_key] : $row[$value];
}
return $clean_row;
}
} }

View File

@ -17,6 +17,7 @@ use App\Models\Company;
use App\Transformers\ClientContactTransformer; use App\Transformers\ClientContactTransformer;
use App\Transformers\ClientTransformer; use App\Transformers\ClientTransformer;
use App\Utils\Ninja; use App\Utils\Ninja;
use App\Utils\Number;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\App;
use League\Csv\Writer; use League\Csv\Writer;
@ -70,7 +71,11 @@ class ClientExport extends BaseExport
'contact_custom_value3' => 'contact.custom_value3', 'contact_custom_value3' => 'contact.custom_value3',
'contact_custom_value4' => 'contact.custom_value4', 'contact_custom_value4' => 'contact.custom_value4',
'email' => 'contact.email', 'email' => 'contact.email',
'status' => 'status' 'status' => 'status',
'payment_balance' => 'client.payment_balance',
'credit_balance' => 'client.credit_balance',
'classification' => 'client.classification',
]; ];
public function __construct(Company $company, array $input) public function __construct(Company $company, array $input)
@ -88,12 +93,13 @@ class ClientExport extends BaseExport
$headerdisplay = $this->buildHeader(); $headerdisplay = $this->buildHeader();
$header = collect($this->input['report_keys'])->map(function ($key, $value) use ($headerdisplay) { $header = collect($this->input['report_keys'])->map(function ($key, $value) use ($headerdisplay) {
return ['identifier' => $value, 'display_value' => $headerdisplay[$value]]; return ['identifier' => $key, 'display_value' => $headerdisplay[$value]];
})->toArray(); })->toArray();
$report = $query->cursor() $report = $query->cursor()
->map(function ($client) { ->map(function ($client) {
return $this->buildRow($client); $row = $this->buildRow($client);
return $this->processMetaData($row, $client);
})->toArray(); })->toArray();
return array_merge(['columns' => $header], $report); return array_merge(['columns' => $header], $report);
@ -171,6 +177,31 @@ class ClientExport extends BaseExport
return $this->decorateAdvancedFields($client, $entity); return $this->decorateAdvancedFields($client, $entity);
} }
public function processMetaData(array $row, $resource): array
{
$clean_row = [];
foreach (array_values($this->input['report_keys']) as $key => $value) {
$report_keys = explode(".", $value);
$column_key = $value;
$clean_row[$key]['entity'] = $report_keys[0];
$clean_row[$key]['id'] = $report_keys[1] ?? $report_keys[0];
$clean_row[$key]['hashed_id'] = $report_keys[0] == 'client' ? null : $resource->{$report_keys[0]}->hashed_id ?? null;
$clean_row[$key]['value'] = $row[$column_key];
$clean_row[$key]['identifier'] = $value;
if(in_array($clean_row[$key]['id'], ['paid_to_date', 'balance', 'credit_balance','payment_balance'])) {
$clean_row[$key]['display_value'] = Number::formatMoney($row[$column_key], $resource);
} else {
$clean_row[$key]['display_value'] = $row[$column_key];
}
}
return $clean_row;
}
private function decorateAdvancedFields(Client $client, array $entity) :array private function decorateAdvancedFields(Client $client, array $entity) :array
{ {
if (in_array('client.user', $this->input['report_keys'])) { if (in_array('client.user', $this->input['report_keys'])) {
@ -197,6 +228,10 @@ class ClientExport 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.classification', $this->input['report_keys']) && isset($client->classification)) {
$entity['client.classification'] = ctrans("texts.{$client->classification}") ?? '';
}
return $entity; return $entity;
} }

View File

@ -89,12 +89,13 @@ class ContactExport extends BaseExport
$headerdisplay = $this->buildHeader(); $headerdisplay = $this->buildHeader();
$header = collect($this->input['report_keys'])->map(function ($key, $value) use ($headerdisplay) { $header = collect($this->input['report_keys'])->map(function ($key, $value) use ($headerdisplay) {
return ['identifier' => $value, 'display_value' => $headerdisplay[$value]]; return ['identifier' => $key, 'display_value' => $headerdisplay[$value]];
})->toArray(); })->toArray();
$report = $query->cursor() $report = $query->cursor()
->map(function ($contact) { ->map(function ($contact) {
return $this->buildRow($contact); $row = $this->buildRow($contact);
return $this->processMetaData($row, $contact);
})->toArray(); })->toArray();
return array_merge(['columns' => $header], $report); return array_merge(['columns' => $header], $report);

View File

@ -11,15 +11,15 @@
namespace App\Export\CSV; namespace App\Export\CSV;
use App\Libraries\MultiDB;
use App\Models\Company;
use App\Models\Credit;
use App\Transformers\CreditTransformer;
use App\Utils\Ninja; use App\Utils\Ninja;
use App\Utils\Number; use App\Utils\Number;
use App\Models\Credit; use Illuminate\Database\Eloquent\Builder;
use League\Csv\Writer;
use App\Models\Company;
use App\Libraries\MultiDB;
use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\App;
use App\Transformers\CreditTransformer; use League\Csv\Writer;
use Illuminate\Contracts\Database\Eloquent\Builder;
class CreditExport extends BaseExport class CreditExport extends BaseExport
{ {
@ -44,7 +44,7 @@ class CreditExport extends BaseExport
$headerdisplay = $this->buildHeader(); $headerdisplay = $this->buildHeader();
$header = collect($this->input['report_keys'])->map(function ($key, $value) use ($headerdisplay) { $header = collect($this->input['report_keys'])->map(function ($key, $value) use ($headerdisplay) {
return ['identifier' => $value, 'display_value' => $headerdisplay[$value]]; return ['identifier' => $key, 'display_value' => $headerdisplay[$value]];
})->toArray(); })->toArray();
$report = $query->cursor() $report = $query->cursor()
@ -56,7 +56,7 @@ class CreditExport extends BaseExport
return array_merge(['columns' => $header], $report); return array_merge(['columns' => $header], $report);
} }
private function processMetaData(array $row, Credit $credit): array public function processMetaData(array $row, $resource): array
{ {
$clean_row = []; $clean_row = [];
foreach (array_values($this->input['report_keys']) as $key => $value) { foreach (array_values($this->input['report_keys']) as $key => $value) {
@ -66,14 +66,15 @@ class CreditExport extends BaseExport
$column_key = $value; $column_key = $value;
$clean_row[$key]['entity'] = $report_keys[0]; $clean_row[$key]['entity'] = $report_keys[0];
$clean_row[$key]['id'] = $report_keys[1] ?? $report_keys[0]; $clean_row[$key]['id'] = $report_keys[1] ?? $report_keys[0];
$clean_row[$key]['hashed_id'] = $report_keys[0] == 'credit' ? null : $credit->{$report_keys[0]}->hashed_id ?? null; $clean_row[$key]['hashed_id'] = $report_keys[0] == 'credit' ? null : $resource->{$report_keys[0]}->hashed_id ?? null;
$clean_row[$key]['value'] = $row[$column_key]; $clean_row[$key]['value'] = $row[$column_key];
$clean_row[$key]['identifier'] = $value; $clean_row[$key]['identifier'] = $value;
if(in_array($clean_row[$key]['id'], ['paid_to_date','total_taxes','amount', 'balance', 'partial', 'refunded', 'applied','unit_cost','cost','price'])) if(in_array($clean_row[$key]['id'], ['paid_to_date','total_taxes','amount', 'balance', 'partial', 'refunded', 'applied','unit_cost','cost','price'])) {
$clean_row[$key]['display_value'] = Number::formatMoney($row[$column_key], $credit->client); $clean_row[$key]['display_value'] = Number::formatMoney($row[$column_key], $resource->client);
else } else {
$clean_row[$key]['display_value'] = $row[$column_key]; $clean_row[$key]['display_value'] = $row[$column_key];
}
} }
@ -93,6 +94,8 @@ class CreditExport extends BaseExport
$this->input['report_keys'] = array_values($this->credit_report_keys); $this->input['report_keys'] = array_values($this->credit_report_keys);
} }
$this->input['report_keys'] = array_merge($this->input['report_keys'], array_diff($this->forced_client_fields, $this->input['report_keys']));
$query = Credit::query() $query = Credit::query()
->withTrashed() ->withTrashed()
->with('client') ->with('client')
@ -139,8 +142,7 @@ class CreditExport extends BaseExport
$entity[$keyval] = $transformed_credit[$keyval]; $entity[$keyval] = $transformed_credit[$keyval];
} elseif(isset($transformed_credit[$searched_credit_key])) { } elseif(isset($transformed_credit[$searched_credit_key])) {
$entity[$keyval] = $transformed_credit[$searched_credit_key]; $entity[$keyval] = $transformed_credit[$searched_credit_key];
} } else {
else {
$entity[$keyval] = $this->resolveKey($keyval, $credit, $this->credit_transformer); $entity[$keyval] = $this->resolveKey($keyval, $credit, $this->credit_transformer);
} }

View File

@ -16,7 +16,7 @@ use App\Models\Company;
use App\Models\Document; use App\Models\Document;
use App\Transformers\DocumentTransformer; use App\Transformers\DocumentTransformer;
use App\Utils\Ninja; use App\Utils\Ninja;
use Illuminate\Contracts\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\App;
use League\Csv\Writer; use League\Csv\Writer;
@ -50,12 +50,13 @@ class DocumentExport extends BaseExport
$headerdisplay = $this->buildHeader(); $headerdisplay = $this->buildHeader();
$header = collect($this->input['report_keys'])->map(function ($key, $value) use ($headerdisplay) { $header = collect($this->input['report_keys'])->map(function ($key, $value) use ($headerdisplay) {
return ['identifier' => $value, 'display_value' => $headerdisplay[$value]]; return ['identifier' => $key, 'display_value' => $headerdisplay[$value]];
})->toArray(); })->toArray();
$report = $query->cursor() $report = $query->cursor()
->map(function ($document) { ->map(function ($document) {
$row = $this->buildRow($document); $row = $this->buildRow($document);
return $this->processMetaData($row, $document);
})->toArray(); })->toArray();
return array_merge(['columns' => $header], $report); return array_merge(['columns' => $header], $report);

View File

@ -44,12 +44,13 @@ class ExpenseExport extends BaseExport
$headerdisplay = $this->buildHeader(); $headerdisplay = $this->buildHeader();
$header = collect($this->input['report_keys'])->map(function ($key, $value) use ($headerdisplay) { $header = collect($this->input['report_keys'])->map(function ($key, $value) use ($headerdisplay) {
return ['identifier' => $value, 'display_value' => $headerdisplay[$value]]; return ['identifier' => $key, 'display_value' => $headerdisplay[$value]];
})->toArray(); })->toArray();
$report = $query->cursor() $report = $query->cursor()
->map(function ($resource) { ->map(function ($resource) {
return $this->buildRow($resource); $row = $this->buildRow($resource);
return $this->processMetaData($row, $resource);
})->toArray(); })->toArray();
return array_merge(['columns' => $header], $report); return array_merge(['columns' => $header], $report);
@ -158,6 +159,10 @@ class ExpenseExport extends BaseExport
$entity['expense.assigned_user'] = $expense->assigned_user ? $expense->assigned_user->present()->name() : ''; $entity['expense.assigned_user'] = $expense->assigned_user ? $expense->assigned_user->present()->name() : '';
} }
if (in_array('expense.category_id', $this->input['report_keys'])) {
$entity['expense.category_id'] = $expense->category ? $expense->category->name : '';
}
return $entity; return $entity;
} }
} }

View File

@ -11,16 +11,14 @@
namespace App\Export\CSV; namespace App\Export\CSV;
use App\Utils\Ninja; use App\Libraries\MultiDB;
use App\Utils\Number;
use League\Csv\Writer;
use App\Models\Company; use App\Models\Company;
use App\Models\Invoice; use App\Models\Invoice;
use App\Libraries\MultiDB;
use App\Export\CSV\BaseExport;
use Illuminate\Support\Facades\App;
use App\Transformers\InvoiceTransformer; use App\Transformers\InvoiceTransformer;
use Illuminate\Contracts\Database\Eloquent\Builder; use App\Utils\Ninja;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\App;
use League\Csv\Writer;
class InvoiceExport extends BaseExport class InvoiceExport extends BaseExport
{ {
@ -50,6 +48,8 @@ class InvoiceExport extends BaseExport
$this->input['report_keys'] = array_values($this->invoice_report_keys); $this->input['report_keys'] = array_values($this->invoice_report_keys);
} }
$this->input['report_keys'] = array_merge($this->input['report_keys'], array_diff($this->forced_client_fields, $this->input['report_keys']));
$query = Invoice::query() $query = Invoice::query()
->withTrashed() ->withTrashed()
->with('client') ->with('client')
@ -73,12 +73,13 @@ class InvoiceExport extends BaseExport
$headerdisplay = $this->buildHeader(); $headerdisplay = $this->buildHeader();
$header = collect($this->input['report_keys'])->map(function ($key, $value) use ($headerdisplay) { $header = collect($this->input['report_keys'])->map(function ($key, $value) use ($headerdisplay) {
return ['identifier' => $value, 'display_value' => $headerdisplay[$value]]; return ['identifier' => $key, 'display_value' => $headerdisplay[$value]];
})->toArray(); })->toArray();
$report = $query->cursor() $report = $query->cursor()
->map(function ($resource) { ->map(function ($resource) {
return $this->buildRow($resource); $row = $this->buildRow($resource);
return $this->processMetaData($row, $resource);
})->toArray(); })->toArray();
return array_merge(['columns' => $header], $report); return array_merge(['columns' => $header], $report);
@ -94,7 +95,6 @@ class InvoiceExport extends BaseExport
//insert the header //insert the header
$this->csv->insertOne($this->buildHeader()); $this->csv->insertOne($this->buildHeader());
$query->cursor() $query->cursor()
->each(function ($invoice) { ->each(function ($invoice) {
$this->csv->insertOne($this->buildRow($invoice)); $this->csv->insertOne($this->buildRow($invoice));
@ -143,6 +143,15 @@ class InvoiceExport extends BaseExport
$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'])) {
$entity['invoice.recurring_id'] = $invoice->recurring_invoice->number ?? '';
}
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');
}
return $entity; return $entity;
} }
} }

View File

@ -16,7 +16,7 @@ use App\Models\Company;
use App\Models\Invoice; use App\Models\Invoice;
use App\Transformers\InvoiceTransformer; use App\Transformers\InvoiceTransformer;
use App\Utils\Ninja; use App\Utils\Ninja;
use Illuminate\Contracts\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\App;
use League\Csv\Writer; use League\Csv\Writer;
@ -33,6 +33,8 @@ class InvoiceItemExport extends BaseExport
private array $storage_array = []; private array $storage_array = [];
private array $storage_item_array = [];
private array $decorate_keys = [ private array $decorate_keys = [
'client', 'client',
'currency_id', 'currency_id',
@ -60,13 +62,18 @@ class InvoiceItemExport extends BaseExport
$this->input['report_keys'] = array_values($this->mergeItemsKeys('invoice_report_keys')); $this->input['report_keys'] = array_values($this->mergeItemsKeys('invoice_report_keys'));
} }
$this->input['report_keys'] = array_merge($this->input['report_keys'], array_diff($this->forced_client_fields, $this->input['report_keys']));
$query = Invoice::query() $query = Invoice::query()
->withTrashed() ->withTrashed()
->with('client')->where('company_id', $this->company->id) ->with('client')
->where('company_id', $this->company->id)
->where('is_deleted', 0); ->where('is_deleted', 0);
$query = $this->addDateRange($query); $query = $this->addDateRange($query);
$query = $this->applyFilters($query);
return $query; return $query;
} }
@ -78,15 +85,24 @@ class InvoiceItemExport extends BaseExport
$headerdisplay = $this->buildHeader(); $headerdisplay = $this->buildHeader();
$header = collect($this->input['report_keys'])->map(function ($key, $value) use ($headerdisplay) { $header = collect($this->input['report_keys'])->map(function ($key, $value) use ($headerdisplay) {
return ['identifier' => $value, 'display_value' => $headerdisplay[$value]]; return ['identifier' => $key, 'display_value' => $headerdisplay[$value]];
})->toArray(); })->toArray();
$query->cursor() $query->cursor()
->each(function ($resource) { ->each(function ($resource) {
$this->iterateItems($resource); $this->iterateItems($resource);
foreach($this->storage_array as $row) {
$this->storage_item_array[] = $this->processItemMetaData($row, $resource);
}
$this->storage_array = [];
}); });
return array_merge(['columns' => $header], $this->storage_array); return array_merge(['columns' => $header], $this->storage_item_array);
} }
@ -123,18 +139,19 @@ class InvoiceItemExport extends BaseExport
if (str_contains($key, "item.")) { if (str_contains($key, "item.")) {
$key = str_replace("item.", "", $key); $tmp_key = str_replace("item.", "", $key);
if($key == 'type_id') if($tmp_key == 'type_id') {
$key = 'type'; $tmp_key = 'type';
if($key == 'tax_id')
$key = 'tax_category';
if (property_exists($item, $key)) {
$item_array[$key] = $item->{$key};
} }
else {
if($tmp_key == 'tax_id') {
$tmp_key = 'tax_category';
}
if (property_exists($item, $tmp_key)) {
$item_array[$key] = $item->{$tmp_key};
} else {
$item_array[$key] = ''; $item_array[$key] = '';
} }
} }
@ -143,6 +160,8 @@ class InvoiceItemExport extends BaseExport
$transformed_items = array_merge($transformed_invoice, $item_array); $transformed_items = array_merge($transformed_invoice, $item_array);
$entity = $this->decorateAdvancedFields($invoice, $transformed_items); $entity = $this->decorateAdvancedFields($invoice, $transformed_items);
$entity = array_merge(array_flip(array_values($this->input['report_keys'])), $entity);
$this->storage_array[] = $entity; $this->storage_array[] = $entity;
} }
@ -158,15 +177,15 @@ class InvoiceItemExport extends BaseExport
$parts = explode('.', $key); $parts = explode('.', $key);
if(is_array($parts) && $parts[0] == 'item') if(is_array($parts) && $parts[0] == 'item') {
continue; continue;
}
if (is_array($parts) && $parts[0] == 'invoice' && array_key_exists($parts[1], $transformed_invoice)) { if (is_array($parts) && $parts[0] == 'invoice' && array_key_exists($parts[1], $transformed_invoice)) {
$entity[$key] = $transformed_invoice[$parts[1]]; $entity[$key] = $transformed_invoice[$parts[1]];
} elseif (array_key_exists($key, $transformed_invoice)) { } elseif (array_key_exists($key, $transformed_invoice)) {
$entity[$key] = $transformed_invoice[$key]; $entity[$key] = $transformed_invoice[$key];
} } else {
else {
$entity[$key] = $this->resolveKey($key, $invoice, $this->invoice_transformer); $entity[$key] = $this->resolveKey($key, $invoice, $this->invoice_transformer);
} }
} }
@ -188,13 +207,28 @@ class InvoiceItemExport extends BaseExport
$entity['tax_category'] = $invoice->taxTypeString($entity['tax_category']); $entity['tax_category'] = $invoice->taxTypeString($entity['tax_category']);
} }
// if($this->force_keys) { if (in_array('invoice.country_id', $this->input['report_keys'])) {
// $entity['client'] = $invoice->client->present()->name(); $entity['invoice.country_id'] = $invoice->client->country ? ctrans("texts.country_{$invoice->client->country->name}") : '';
// $entity['client_id_number'] = $invoice->client->id_number; }
// $entity['client_number'] = $invoice->client->number;
// $entity['status'] = $invoice->stringStatus($invoice->status_id); 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;
}
if (in_array('invoice.client_id', $this->input['report_keys'])) {
$entity['invoice.client_id'] = $invoice->client->present()->name();
}
if (in_array('invoice.status', $this->input['report_keys'])) {
$entity['invoice.status'] = $invoice->stringStatus($invoice->status_id);
}
if (in_array('invoice.recurring_id', $this->input['report_keys'])) {
$entity['invoice.recurring_id'] = $invoice->recurring_invoice->number ?? '';
}
return $entity; return $entity;
} }
} }

View File

@ -16,7 +16,7 @@ use App\Models\Company;
use App\Models\Payment; use App\Models\Payment;
use App\Transformers\PaymentTransformer; use App\Transformers\PaymentTransformer;
use App\Utils\Ninja; use App\Utils\Ninja;
use Illuminate\Contracts\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\App;
use League\Csv\Writer; use League\Csv\Writer;
@ -28,40 +28,6 @@ class PaymentExport extends BaseExport
public Writer $csv; public Writer $csv;
// public array $entity_keys = [
// 'amount' => 'amount',
// 'applied' => 'applied',
// 'client' => 'client_id',
// 'currency' => 'currency_id',
// 'custom_value1' => 'custom_value1',
// 'custom_value2' => 'custom_value2',
// 'custom_value3' => 'custom_value3',
// 'custom_value4' => 'custom_value4',
// 'date' => 'date',
// 'exchange_currency' => 'exchange_currency_id',
// 'gateway' => 'gateway_type_id',
// 'number' => 'number',
// 'private_notes' => 'private_notes',
// 'project' => 'project_id',
// 'refunded' => 'refunded',
// 'status' => 'status_id',
// 'transaction_reference' => 'transaction_reference',
// 'type' => 'type_id',
// 'vendor' => 'vendor_id',
// 'invoices' => 'invoices',
// ];
// private array $decorate_keys = [
// 'vendor',
// 'status',
// 'project',
// 'client',
// 'currency',
// 'exchange_currency',
// 'type',
// 'invoices',
// ];
public function __construct(Company $company, array $input) public function __construct(Company $company, array $input)
{ {
$this->company = $company; $this->company = $company;
@ -82,6 +48,8 @@ class PaymentExport extends BaseExport
$this->input['report_keys'] = array_values($this->payment_report_keys); $this->input['report_keys'] = array_values($this->payment_report_keys);
} }
$this->input['report_keys'] = array_merge($this->input['report_keys'], array_diff($this->forced_client_fields, $this->input['report_keys']));
$query = Payment::query() $query = Payment::query()
->withTrashed() ->withTrashed()
->where('company_id', $this->company->id) ->where('company_id', $this->company->id)
@ -100,17 +68,17 @@ class PaymentExport extends BaseExport
$headerdisplay = $this->buildHeader(); $headerdisplay = $this->buildHeader();
$header = collect($this->input['report_keys'])->map(function ($key, $value) use ($headerdisplay) { $header = collect($this->input['report_keys'])->map(function ($key, $value) use ($headerdisplay) {
return ['identifier' => $value, 'display_value' => $headerdisplay[$value]]; return ['identifier' => $key, 'display_value' => $headerdisplay[$value]];
})->toArray(); })->toArray();
$report = $query->cursor() $report = $query->cursor()
->map(function ($resource) { ->map(function ($resource) {
return $this->buildRow($resource); $row = $this->buildRow($resource);
return $this->processMetaData($row, $resource);
})->toArray(); })->toArray();
return array_merge(['columns' => $header], $report); return array_merge(['columns' => $header], $report);
} }
public function run() public function run()

View File

@ -13,11 +13,10 @@ namespace App\Export\CSV;
use App\Libraries\MultiDB; use App\Libraries\MultiDB;
use App\Models\Company; use App\Models\Company;
use App\Models\Document;
use App\Models\Product; use App\Models\Product;
use App\Transformers\ProductTransformer; use App\Transformers\ProductTransformer;
use App\Utils\Ninja; use App\Utils\Ninja;
use Illuminate\Contracts\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\App;
use League\Csv\Writer; use League\Csv\Writer;
@ -43,12 +42,13 @@ class ProductExport extends BaseExport
$headerdisplay = $this->buildHeader(); $headerdisplay = $this->buildHeader();
$header = collect($this->input['report_keys'])->map(function ($key, $value) use ($headerdisplay) { $header = collect($this->input['report_keys'])->map(function ($key, $value) use ($headerdisplay) {
return ['identifier' => $value, 'display_value' => $headerdisplay[$value]]; return ['identifier' => $key, 'display_value' => $headerdisplay[$value]];
})->toArray(); })->toArray();
$report = $query->cursor() $report = $query->cursor()
->map(function ($resource) { ->map(function ($resource) {
return $this->buildRow($resource); $row = $this->buildRow($resource);
return $this->processMetaData($row, $resource);
})->toArray(); })->toArray();
return array_merge(['columns' => $header], $report); return array_merge(['columns' => $header], $report);

View File

@ -11,15 +11,14 @@
namespace App\Export\CSV; namespace App\Export\CSV;
use App\Utils\Ninja;
use App\Utils\Number;
use League\Csv\Writer;
use App\Models\Company;
use App\Libraries\MultiDB; use App\Libraries\MultiDB;
use App\Models\Company;
use App\Models\PurchaseOrder; use App\Models\PurchaseOrder;
use Illuminate\Support\Facades\App;
use App\Transformers\PurchaseOrderTransformer; use App\Transformers\PurchaseOrderTransformer;
use Illuminate\Contracts\Database\Eloquent\Builder; use App\Utils\Ninja;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\App;
use League\Csv\Writer;
class PurchaseOrderExport extends BaseExport class PurchaseOrderExport extends BaseExport
{ {
@ -54,7 +53,7 @@ class PurchaseOrderExport extends BaseExport
'po_number' => 'purchase_order.po_number', 'po_number' => 'purchase_order.po_number',
'private_notes' => 'purchase_order.private_notes', 'private_notes' => 'purchase_order.private_notes',
'public_notes' => 'purchase_order.public_notes', 'public_notes' => 'purchase_order.public_notes',
'status' => 'purchase_order.status_id', 'status' => 'purchase_order.status',
'tax_name1' => 'purchase_order.tax_name1', 'tax_name1' => 'purchase_order.tax_name1',
'tax_name2' => 'purchase_order.tax_name2', 'tax_name2' => 'purchase_order.tax_name2',
'tax_name3' => 'purchase_order.tax_name3', 'tax_name3' => 'purchase_order.tax_name3',
@ -95,6 +94,9 @@ class PurchaseOrderExport extends BaseExport
if (count($this->input['report_keys']) == 0) { if (count($this->input['report_keys']) == 0) {
$this->input['report_keys'] = array_values($this->purchase_order_report_keys); $this->input['report_keys'] = array_values($this->purchase_order_report_keys);
} }
$this->input['report_keys'] = array_merge($this->input['report_keys'], array_diff($this->forced_vendor_fields, $this->input['report_keys']));
$query = PurchaseOrder::query() $query = PurchaseOrder::query()
->withTrashed() ->withTrashed()
->with('vendor') ->with('vendor')
@ -114,12 +116,13 @@ class PurchaseOrderExport extends BaseExport
$headerdisplay = $this->buildHeader(); $headerdisplay = $this->buildHeader();
$header = collect($this->input['report_keys'])->map(function ($key, $value) use ($headerdisplay) { $header = collect($this->input['report_keys'])->map(function ($key, $value) use ($headerdisplay) {
return ['identifier' => $value, 'display_value' => $headerdisplay[$value]]; return ['identifier' => $key, 'display_value' => $headerdisplay[$value]];
})->toArray(); })->toArray();
$report = $query->cursor() $report = $query->cursor()
->map(function ($resource) { ->map(function ($resource) {
return $this->buildRow($resource); $row = $this->buildRow($resource);
return $this->processMetaData($row, $resource);
})->toArray(); })->toArray();
return array_merge(['columns' => $header], $report); return array_merge(['columns' => $header], $report);
@ -180,8 +183,8 @@ class PurchaseOrderExport extends BaseExport
$entity['vendor'] = $purchase_order->vendor->present()->name(); $entity['vendor'] = $purchase_order->vendor->present()->name();
} }
if (in_array('status_id', $this->input['report_keys'])) { if (in_array('purchase_order.status', $this->input['report_keys'])) {
$entity['status'] = $purchase_order->stringStatus($purchase_order->status_id); $entity['purchase_order.status'] = $purchase_order->stringStatus($purchase_order->status_id);
} }
return $entity; return $entity;

View File

@ -16,7 +16,7 @@ use App\Models\Company;
use App\Models\PurchaseOrder; use App\Models\PurchaseOrder;
use App\Transformers\PurchaseOrderTransformer; use App\Transformers\PurchaseOrderTransformer;
use App\Utils\Ninja; use App\Utils\Ninja;
use Illuminate\Contracts\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\App;
use League\Csv\Writer; use League\Csv\Writer;
@ -33,6 +33,8 @@ class PurchaseOrderItemExport extends BaseExport
private array $storage_array = []; private array $storage_array = [];
private array $storage_item_array = [];
public function __construct(Company $company, array $input) public function __construct(Company $company, array $input)
{ {
$this->company = $company; $this->company = $company;
@ -50,10 +52,11 @@ class PurchaseOrderItemExport extends BaseExport
$t->replace(Ninja::transformTranslations($this->company->settings)); $t->replace(Ninja::transformTranslations($this->company->settings));
if (count($this->input['report_keys']) == 0) { if (count($this->input['report_keys']) == 0) {
// $this->force_keys = true;
$this->input['report_keys'] = array_values($this->mergeItemsKeys('purchase_order_report_keys')); $this->input['report_keys'] = array_values($this->mergeItemsKeys('purchase_order_report_keys'));
} }
$this->input['report_keys'] = array_merge($this->input['report_keys'], array_diff($this->forced_vendor_fields, $this->input['report_keys']));
$query = PurchaseOrder::query() $query = PurchaseOrder::query()
->withTrashed() ->withTrashed()
->with('vendor')->where('company_id', $this->company->id) ->with('vendor')->where('company_id', $this->company->id)
@ -72,15 +75,22 @@ class PurchaseOrderItemExport extends BaseExport
$headerdisplay = $this->buildHeader(); $headerdisplay = $this->buildHeader();
$header = collect($this->input['report_keys'])->map(function ($key, $value) use ($headerdisplay) { $header = collect($this->input['report_keys'])->map(function ($key, $value) use ($headerdisplay) {
return ['identifier' => $value, 'display_value' => $headerdisplay[$value]]; return ['identifier' => $key, 'display_value' => $headerdisplay[$value]];
})->toArray(); })->toArray();
$query->cursor() $query->cursor()
->each(function ($resource) { ->each(function ($resource) {
$this->iterateItems($resource); $this->iterateItems($resource);
foreach($this->storage_array as $row) {
$this->storage_item_array[] = $this->processItemMetaData($row, $resource);
}
$this->storage_array = [];
}); });
return array_merge(['columns' => $header], $this->storage_array); return array_merge(['columns' => $header], $this->storage_item_array);
} }
public function run() public function run()
@ -113,22 +123,22 @@ class PurchaseOrderItemExport extends BaseExport
foreach ($purchase_order->line_items as $item) { foreach ($purchase_order->line_items as $item) {
$item_array = []; $item_array = [];
foreach (array_values($this->input['report_keys']) as $key) { //items iterator produces item array foreach (array_values(array_intersect($this->input['report_keys'], $this->item_report_keys)) as $key) { //items iterator produces item array
if (str_contains($key, "item.")) { if (str_contains($key, "item.")) {
$key = str_replace("item.", "", $key); $tmp_key = str_replace("item.", "", $key);
if($key == 'type_id') { if($tmp_key == 'type_id') {
$keyval = 'type'; $tmp_key = 'type';
} }
if($key == 'tax_id') { if($tmp_key == 'tax_id') {
$keyval = 'tax_category'; $tmp_key = 'tax_category';
} }
if (property_exists($item, $key)) { if (property_exists($item, $tmp_key)) {
$item_array[$key] = $item->{$key}; $item_array[$key] = $item->{$tmp_key};
} else { } else {
$item_array[$key] = ''; $item_array[$key] = '';
} }
@ -137,6 +147,7 @@ class PurchaseOrderItemExport extends BaseExport
$transformed_items = array_merge($transformed_purchase_order, $item_array); $transformed_items = array_merge($transformed_purchase_order, $item_array);
$entity = $this->decorateAdvancedFields($purchase_order, $transformed_items); $entity = $this->decorateAdvancedFields($purchase_order, $transformed_items);
$entity = array_merge(array_flip(array_values($this->input['report_keys'])), $entity);
$this->storage_array[] = $entity; $this->storage_array[] = $entity;
} }
@ -190,4 +201,5 @@ class PurchaseOrderItemExport extends BaseExport
return $entity; return $entity;
} }
} }

View File

@ -16,7 +16,7 @@ use App\Models\Company;
use App\Models\Quote; use App\Models\Quote;
use App\Transformers\QuoteTransformer; use App\Transformers\QuoteTransformer;
use App\Utils\Ninja; use App\Utils\Ninja;
use Illuminate\Contracts\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\App;
use League\Csv\Writer; use League\Csv\Writer;
@ -56,6 +56,8 @@ class QuoteExport extends BaseExport
$this->input['report_keys'] = array_values($this->quote_report_keys); $this->input['report_keys'] = array_values($this->quote_report_keys);
} }
$this->input['report_keys'] = array_merge($this->input['report_keys'], array_diff($this->forced_client_fields, $this->input['report_keys']));
$query = Quote::query() $query = Quote::query()
->withTrashed() ->withTrashed()
->with('client') ->with('client')
@ -75,12 +77,13 @@ class QuoteExport extends BaseExport
$headerdisplay = $this->buildHeader(); $headerdisplay = $this->buildHeader();
$header = collect($this->input['report_keys'])->map(function ($key, $value) use ($headerdisplay) { $header = collect($this->input['report_keys'])->map(function ($key, $value) use ($headerdisplay) {
return ['identifier' => $value, 'display_value' => $headerdisplay[$value]]; return ['identifier' => $key, 'display_value' => $headerdisplay[$value]];
})->toArray(); })->toArray();
$report = $query->cursor() $report = $query->cursor()
->map(function ($resource) { ->map(function ($resource) {
return $this->buildRow($resource); $row = $this->buildRow($resource);
return $this->processMetaData($row, $resource);
})->toArray(); })->toArray();
return array_merge(['columns' => $header], $report); return array_merge(['columns' => $header], $report);

View File

@ -16,7 +16,7 @@ use App\Models\Company;
use App\Models\Quote; use App\Models\Quote;
use App\Transformers\QuoteTransformer; use App\Transformers\QuoteTransformer;
use App\Utils\Ninja; use App\Utils\Ninja;
use Illuminate\Contracts\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\App;
use League\Csv\Writer; use League\Csv\Writer;
@ -29,7 +29,8 @@ class QuoteItemExport extends BaseExport
public Writer $csv; public Writer $csv;
private array $storage_array; private array $storage_array = [];
private array $storage_item_array = [];
private array $decorate_keys = [ private array $decorate_keys = [
'client', 'client',
@ -56,6 +57,8 @@ class QuoteItemExport extends BaseExport
$this->input['report_keys'] = array_values($this->mergeItemsKeys('quote_report_keys')); $this->input['report_keys'] = array_values($this->mergeItemsKeys('quote_report_keys'));
} }
$this->input['report_keys'] = array_merge($this->input['report_keys'], array_diff($this->forced_client_fields, $this->input['report_keys']));
$query = Quote::query() $query = Quote::query()
->withTrashed() ->withTrashed()
->with('client')->where('company_id', $this->company->id) ->with('client')->where('company_id', $this->company->id)
@ -74,15 +77,23 @@ class QuoteItemExport extends BaseExport
$headerdisplay = $this->buildHeader(); $headerdisplay = $this->buildHeader();
$header = collect($this->input['report_keys'])->map(function ($key, $value) use ($headerdisplay) { $header = collect($this->input['report_keys'])->map(function ($key, $value) use ($headerdisplay) {
return ['identifier' => $value, 'display_value' => $headerdisplay[$value]]; return ['identifier' => $key, 'display_value' => $headerdisplay[$value]];
})->toArray(); })->toArray();
$query->cursor() $query->cursor()
->each(function ($resource) { ->each(function ($resource) {
$this->iterateItems($resource); $this->iterateItems($resource);
foreach($this->storage_array as $row) {
$this->storage_item_array[] = $this->processItemMetaData($row, $resource);
}
$this->storage_array = [];
}); });
return array_merge(['columns' => $header], $this->storage_array); return array_merge(['columns' => $header], $this->storage_item_array);
} }
@ -122,18 +133,19 @@ class QuoteItemExport extends BaseExport
if (str_contains($key, "item.")) { if (str_contains($key, "item.")) {
$key = str_replace("item.", "", $key); $tmp_key = str_replace("item.", "", $key);
if($key == 'type_id') if($tmp_key == 'type_id') {
$key = 'type'; $tmp_key = 'type';
if($key == 'tax_id')
$key = 'tax_category';
if (property_exists($item, $key)) {
$item_array[$key] = $item->{$key};
} }
else {
if($tmp_key == 'tax_id') {
$tmp_key = 'tax_category';
}
if (property_exists($item, $tmp_key)) {
$item_array[$key] = $item->{$tmp_key};
} else {
$item_array[$key] = ''; $item_array[$key] = '';
} }
} }
@ -141,6 +153,7 @@ class QuoteItemExport extends BaseExport
$transformed_items = array_merge($transformed_quote, $item_array); $transformed_items = array_merge($transformed_quote, $item_array);
$entity = $this->decorateAdvancedFields($quote, $transformed_items); $entity = $this->decorateAdvancedFields($quote, $transformed_items);
$entity = array_merge(array_flip(array_values($this->input['report_keys'])), $entity);
$this->storage_array[] = $entity; $this->storage_array[] = $entity;
} }

View File

@ -16,6 +16,7 @@ use App\Models\Company;
use App\Models\RecurringInvoice; use App\Models\RecurringInvoice;
use App\Transformers\RecurringInvoiceTransformer; use App\Transformers\RecurringInvoiceTransformer;
use App\Utils\Ninja; use App\Utils\Ninja;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\App;
use League\Csv\Writer; use League\Csv\Writer;
@ -28,55 +29,6 @@ class RecurringInvoiceExport extends BaseExport
public Writer $csv; public Writer $csv;
public array $entity_keys = [
'amount' => 'amount',
'balance' => 'balance',
'client' => 'client_id',
// 'custom_surcharge1' => 'custom_surcharge1',
// 'custom_surcharge2' => 'custom_surcharge2',
// 'custom_surcharge3' => 'custom_surcharge3',
// 'custom_surcharge4' => 'custom_surcharge4',
'custom_value1' => 'custom_value1',
'custom_value2' => 'custom_value2',
'custom_value3' => 'custom_value3',
'custom_value4' => 'custom_value4',
'date' => 'date',
'discount' => 'discount',
'due_date' => 'due_date',
'exchange_rate' => 'exchange_rate',
'footer' => 'footer',
'number' => 'number',
'paid_to_date' => 'paid_to_date',
'partial' => 'partial',
'partial_due_date' => 'partial_due_date',
'po_number' => 'po_number',
'private_notes' => 'private_notes',
'public_notes' => 'public_notes',
'next_send_date' => 'next_send_date',
'status' => 'status_id',
'tax_name1' => 'tax_name1',
'tax_name2' => 'tax_name2',
'tax_name3' => 'tax_name3',
'tax_rate1' => 'tax_rate1',
'tax_rate2' => 'tax_rate2',
'tax_rate3' => 'tax_rate3',
'terms' => 'terms',
'total_taxes' => 'total_taxes',
'currency' => 'currency_id',
'vendor' => 'vendor_id',
'project' => 'project_id',
'frequency_id' => 'frequency_id',
];
private array $decorate_keys = [
'country',
'client',
'currency',
'status',
'vendor',
'project',
];
public function __construct(Company $company, array $input) public function __construct(Company $company, array $input)
{ {
$this->company = $company; $this->company = $company;
@ -84,7 +36,7 @@ class RecurringInvoiceExport extends BaseExport
$this->invoice_transformer = new RecurringInvoiceTransformer(); $this->invoice_transformer = new RecurringInvoiceTransformer();
} }
public function run() public function init(): Builder
{ {
MultiDB::setDb($this->company->db); MultiDB::setDb($this->company->db);
App::forgetInstance('translator'); App::forgetInstance('translator');
@ -92,23 +44,35 @@ class RecurringInvoiceExport extends BaseExport
$t = app('translator'); $t = app('translator');
$t->replace(Ninja::transformTranslations($this->company->settings)); $t->replace(Ninja::transformTranslations($this->company->settings));
//load the CSV document from a string
$this->csv = Writer::createFromString();
if (count($this->input['report_keys']) == 0) { if (count($this->input['report_keys']) == 0) {
$this->input['report_keys'] = array_values($this->entity_keys); $this->input['report_keys'] = array_values($this->recurring_invoice_report_keys);
} }
//insert the header $this->input['report_keys'] = array_merge($this->input['report_keys'], array_diff($this->forced_client_fields, $this->input['report_keys']));
$this->csv->insertOne($this->buildHeader());
$query = RecurringInvoice::query() $query = RecurringInvoice::query()
->withTrashed() ->withTrashed()
->with('client')->where('company_id', $this->company->id) ->with('client')
->where('company_id', $this->company->id)
->where('is_deleted', 0); ->where('is_deleted', 0);
$query = $this->addDateRange($query); $query = $this->addDateRange($query);
return $query;
}
public function run()
{
$query = $this->init();
//load the CSV document from a string
$this->csv = Writer::createFromString();
//insert the header
$this->csv->insertOne($this->buildHeader());
$query->cursor() $query->cursor()
->each(function ($invoice) { ->each(function ($invoice) {
$this->csv->insertOne($this->buildRow($invoice)); $this->csv->insertOne($this->buildRow($invoice));
@ -117,6 +81,27 @@ class RecurringInvoiceExport extends BaseExport
return $this->csv->toString(); return $this->csv->toString();
} }
public function returnJson()
{
$query = $this->init();
$headerdisplay = $this->buildHeader();
$header = collect($this->input['report_keys'])->map(function ($key, $value) use ($headerdisplay) {
return ['identifier' => $key, 'display_value' => $headerdisplay[$value]];
})->toArray();
$report = $query->cursor()
->map(function ($resource) {
$row = $this->buildRow($resource);
return $this->processMetaData($row, $resource);
})->toArray();
return array_merge(['columns' => $header], $report);
}
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);
@ -124,22 +109,13 @@ class RecurringInvoiceExport extends BaseExport
$entity = []; $entity = [];
foreach (array_values($this->input['report_keys']) as $key) { foreach (array_values($this->input['report_keys']) as $key) {
$keyval = array_search($key, $this->entity_keys);
if(!$keyval) { $parts = explode('.', $key);
$keyval = array_search(str_replace("recurring_invoice.", "", $key), $this->entity_keys) ?? $key;
}
if(!$keyval) { if (is_array($parts) && $parts[0] == 'recurring_invoice' && array_key_exists($parts[1], $transformed_invoice)) {
$keyval = $key; $entity[$key] = $transformed_invoice[$parts[1]];
}
if (array_key_exists($key, $transformed_invoice)) {
$entity[$keyval] = $transformed_invoice[$key];
} elseif (array_key_exists($keyval, $transformed_invoice)) {
$entity[$keyval] = $transformed_invoice[$keyval];
} else { } else {
$entity[$keyval] = $this->resolveKey($keyval, $invoice, $this->invoice_transformer); $entity[$key] = $this->resolveKey($key, $invoice, $this->invoice_transformer);
} }
} }
@ -161,8 +137,8 @@ class RecurringInvoiceExport extends BaseExport
$entity['client'] = $invoice->client->present()->name(); $entity['client'] = $invoice->client->present()->name();
} }
if (in_array('status_id', $this->input['report_keys'])) { if (in_array('recurring_invoice.status', $this->input['report_keys'])) {
$entity['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'])) {
@ -174,7 +150,11 @@ class RecurringInvoiceExport extends BaseExport
} }
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['frequency_id'] = $invoice->frequencyForKey($invoice->frequency_id); $entity['recurring_invoice.frequency_id'] = $invoice->frequencyForKey($invoice->frequency_id);
}
if (in_array('recurring_invoice.auto_bill_enabled', $this->input['report_keys'])) {
$entity['recurring_invoice.auto_bill_enabled'] = $invoice->auto_bill_enabled ? ctrans('texts.yes') : ctrans('texts.no');
} }
return $entity; return $entity;

View File

@ -18,6 +18,7 @@ use App\Models\Task;
use App\Models\Timezone; use App\Models\Timezone;
use App\Transformers\TaskTransformer; use App\Transformers\TaskTransformer;
use App\Utils\Ninja; use App\Utils\Ninja;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Carbon; use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\App;
use League\Csv\Writer; use League\Csv\Writer;
@ -33,30 +34,9 @@ class TaskExport extends BaseExport
public Writer $csv; public Writer $csv;
public array $entity_keys = [ private array $storage_array = [];
'start_date' => 'start_date',
'end_date' => 'end_date',
'duration' => 'duration',
'rate' => 'rate',
'number' => 'number',
'description' => 'description',
'custom_value1' => 'custom_value1',
'custom_value2' => 'custom_value2',
'custom_value3' => 'custom_value3',
'custom_value4' => 'custom_value4',
'status' => 'status_id',
'project' => 'project_id',
];
private array $decorate_keys = [ private array $storage_item_array = [];
'status',
'project',
'client',
'invoice',
'start_date',
'end_date',
'duration',
];
public function __construct(Company $company, array $input) public function __construct(Company $company, array $input)
{ {
@ -65,7 +45,7 @@ class TaskExport extends BaseExport
$this->entity_transformer = new TaskTransformer(); $this->entity_transformer = new TaskTransformer();
} }
public function run() public function init(): Builder
{ {
MultiDB::setDb($this->company->db); MultiDB::setDb($this->company->db);
App::forgetInstance('translator'); App::forgetInstance('translator');
@ -74,18 +54,13 @@ class TaskExport extends BaseExport
$t->replace(Ninja::transformTranslations($this->company->settings)); $t->replace(Ninja::transformTranslations($this->company->settings));
$this->date_format = DateFormat::find($this->company->settings->date_format_id)->format; $this->date_format = DateFormat::find($this->company->settings->date_format_id)->format;
//load the CSV document from a string
$this->csv = Writer::createFromString();
ksort($this->entity_keys); ksort($this->entity_keys);
if (count($this->input['report_keys']) == 0) { if (count($this->input['report_keys']) == 0) {
$this->input['report_keys'] = array_values($this->entity_keys); $this->input['report_keys'] = array_values($this->task_report_keys);
} }
//insert the header $this->input['report_keys'] = array_merge($this->input['report_keys'], array_diff($this->forced_client_fields, $this->input['report_keys']));
$this->csv->insertOne($this->buildHeader());
$query = Task::query() $query = Task::query()
->withTrashed() ->withTrashed()
@ -94,52 +69,86 @@ class TaskExport extends BaseExport
$query = $this->addDateRange($query); $query = $this->addDateRange($query);
return $query;
}
public function run()
{
$query = $this->init();
//load the CSV document from a string
$this->csv = Writer::createFromString();
//insert the header
$this->csv->insertOne($this->buildHeader());
$query->cursor() $query->cursor()
->each(function ($entity) { ->each(function ($entity) {
$this->buildRow($entity); $this->buildRow($entity);
}); });
$this->csv->insertAll($this->storage_array);
return $this->csv->toString(); return $this->csv->toString();
} }
public function returnJson()
{
$query = $this->init();
$headerdisplay = $this->buildHeader();
$header = collect($this->input['report_keys'])->map(function ($key, $value) use ($headerdisplay) {
return ['identifier' => $key, 'display_value' => $headerdisplay[$value]];
})->toArray();
$query->cursor()
->each(function ($resource) {
$this->buildRow($resource);
foreach($this->storage_array as $row) {
$this->storage_item_array[] = $this->processMetaData($row, $resource);
}
$this->storage_array = [];
});
// nlog($this->storage_item_array);
return array_merge(['columns' => $header], $this->storage_item_array);
}
private function buildRow(Task $task) private function buildRow(Task $task)
{ {
$entity = []; $entity = [];
$transformed_entity = $this->entity_transformer->transform($task); $transformed_entity = $this->entity_transformer->transform($task);
foreach (array_values($this->input['report_keys']) as $key) { foreach (array_values($this->input['report_keys']) as $key) {
$keyval = array_search($key, $this->entity_keys);
if(!$keyval) { $parts = explode('.', $key);
$keyval = array_search(str_replace("task.", "", $key), $this->entity_keys) ?? $key;
if (is_array($parts) && $parts[0] == 'task' && array_key_exists($parts[1], $transformed_entity)) {
$entity[$key] = $transformed_entity[$parts[1]];
} elseif (array_key_exists($key, $transformed_entity)) {
$entity[$key] = $transformed_entity[$key];
} else {
$entity[$key] = $this->resolveKey($key, $task, $this->entity_transformer);
} }
if(!$keyval) {
$keyval = $key;
} }
if (array_key_exists($key, $transformed_entity)) { $entity['task.start_date'] = '';
$entity[$keyval] = $transformed_entity[$key]; $entity['task.end_date'] = '';
} elseif (array_key_exists($keyval, $transformed_entity)) { $entity['task.duration'] = '';
$entity[$keyval] = $transformed_entity[$keyval];
}
else {
$entity[$keyval] = $this->resolveKey($keyval, $task, $this->entity_transformer);
}
}
$entity['start_date'] = '';
$entity['end_date'] = '';
$entity['duration'] = '';
if (is_null($task->time_log) || (is_array(json_decode($task->time_log, 1)) && count(json_decode($task->time_log, 1)) == 0)) { if (is_null($task->time_log) || (is_array(json_decode($task->time_log, 1)) && count(json_decode($task->time_log, 1)) == 0)) {
$this->csv->insertOne($entity); $this->storage_array[] = $entity;
} else { } else {
$this->iterateLogs($task, $entity); $this->iterateLogs($task, $entity);
} }
} }
private function iterateLogs(Task $task, array $entity) private function iterateLogs(Task $task, array $entity)
@ -163,39 +172,40 @@ class TaskExport extends BaseExport
foreach ($logs as $key => $item) { foreach ($logs as $key => $item) {
if (in_array('task.start_date', $this->input['report_keys']) || in_array('start_date', $this->input['report_keys'])) { if (in_array('task.start_date', $this->input['report_keys']) || in_array('start_date', $this->input['report_keys'])) {
$entity['start_date'] = Carbon::createFromTimeStamp($item[0])->setTimezone($timezone_name)->format($date_format_default); $entity['task.start_date'] = Carbon::createFromTimeStamp($item[0])->setTimezone($timezone_name)->format($date_format_default);
} }
if ((in_array('task.end_date', $this->input['report_keys']) || in_array('end_date', $this->input['report_keys'])) && $item[1] > 0) { if ((in_array('task.end_date', $this->input['report_keys']) || in_array('end_date', $this->input['report_keys'])) && $item[1] > 0) {
$entity['end_date'] = Carbon::createFromTimeStamp($item[1])->setTimezone($timezone_name)->format($date_format_default); $entity['task.end_date'] = Carbon::createFromTimeStamp($item[1])->setTimezone($timezone_name)->format($date_format_default);
} }
if ((in_array('task.end_date', $this->input['report_keys']) || in_array('end_date', $this->input['report_keys'])) && $item[1] == 0) { if ((in_array('task.end_date', $this->input['report_keys']) || in_array('end_date', $this->input['report_keys'])) && $item[1] == 0) {
$entity['end_date'] = ctrans('texts.is_running'); $entity['task.end_date'] = ctrans('texts.is_running');
} }
if (in_array('task.duration', $this->input['report_keys']) || in_array('duration', $this->input['report_keys'])) { if (in_array('task.duration', $this->input['report_keys']) || in_array('duration', $this->input['report_keys'])) {
$entity['duration'] = $task->calcDuration(); $entity['task.duration'] = $task->calcDuration();
} }
$entity = $this->decorateAdvancedFields($task, $entity); $entity = $this->decorateAdvancedFields($task, $entity);
$this->csv->insertOne($entity); $this->storage_array[] = $entity;
unset($entity['start_date']); unset($entity['task.start_date']);
unset($entity['end_date']); unset($entity['task.end_date']);
unset($entity['duration']); unset($entity['task.duration']);
} }
} }
private function decorateAdvancedFields(Task $task, array $entity) :array private function decorateAdvancedFields(Task $task, array $entity) :array
{ {
if (in_array('status_id', $this->input['report_keys'])) { if (in_array('task.status_id', $this->input['report_keys'])) {
$entity['status'] = $task->status()->exists() ? $task->status->name : ''; $entity['task.status_id'] = $task->status()->exists() ? $task->status->name : '';
} }
if (in_array('project_id', $this->input['report_keys'])) { if (in_array('task.project_id', $this->input['report_keys'])) {
$entity['project'] = $task->project()->exists() ? $task->project->name : ''; $entity['task.project_id'] = $task->project()->exists() ? $task->project->name : '';
} }
return $entity; return $entity;

View File

@ -12,11 +12,12 @@
namespace App\Export\CSV; namespace App\Export\CSV;
use App\Libraries\MultiDB; use App\Libraries\MultiDB;
use App\Models\Vendor;
use App\Models\Company; use App\Models\Company;
use App\Models\Vendor;
use App\Transformers\VendorContactTransformer; use App\Transformers\VendorContactTransformer;
use App\Transformers\VendorTransformer; use App\Transformers\VendorTransformer;
use App\Utils\Ninja; use App\Utils\Ninja;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\App;
use League\Csv\Writer; use League\Csv\Writer;
@ -31,42 +32,6 @@ class VendorExport extends BaseExport
public string $date_key = 'created_at'; public string $date_key = 'created_at';
public array $entity_keys = [
'address1' => 'vendor.address1',
'address2' => 'vendor.address2',
'city' => 'vendor.city',
'country' => 'vendor.country_id',
'custom_value1' => 'vendor.custom_value1',
'custom_value2' => 'vendor.custom_value2',
'custom_value3' => 'vendor.custom_value3',
'custom_value4' => 'vendor.custom_value4',
'id_number' => 'vendor.id_number',
'name' => 'vendor.name',
'number' => 'vendor.number',
'phone' => 'vendor.phone',
'postal_code' => 'vendor.postal_code',
'private_notes' => 'vendor.private_notes',
'public_notes' => 'vendor.public_notes',
'state' => 'vendor.state',
'vat_number' => 'vendor.vat_number',
'website' => 'vendor.website',
'currency' => 'vendor.currency',
'first_name' => 'vendor_contact.first_name',
'last_name' => 'vendor_contact.last_name',
'contact_phone' => 'vendor_contact.phone',
'contact_custom_value1' => 'vendor_contact.custom_value1',
'contact_custom_value2' => 'vendor_contact.custom_value2',
'contact_custom_value3' => 'vendor_contact.custom_value3',
'contact_custom_value4' => 'vendor_contact.custom_value4',
'email' => 'vendor_contact.email',
'status' => 'vendor.status'
];
private array $decorate_keys = [
'vendor.country_id',
'vendor.currency',
];
public function __construct(Company $company, array $input) public function __construct(Company $company, array $input)
{ {
$this->company = $company; $this->company = $company;
@ -75,8 +40,9 @@ class VendorExport extends BaseExport
$this->contact_transformer = new VendorContactTransformer(); $this->contact_transformer = new VendorContactTransformer();
} }
public function run() public function init(): Builder
{ {
MultiDB::setDb($this->company->db); MultiDB::setDb($this->company->db);
App::forgetInstance('translator'); App::forgetInstance('translator');
App::setLocale($this->company->locale()); App::setLocale($this->company->locale());
@ -87,12 +53,9 @@ class VendorExport extends BaseExport
$this->csv = Writer::createFromString(); $this->csv = Writer::createFromString();
if (count($this->input['report_keys']) == 0) { if (count($this->input['report_keys']) == 0) {
$this->input['report_keys'] = array_values($this->entity_keys); $this->input['report_keys'] = array_values($this->vendor_report_keys);
} }
//insert the header
$this->csv->insertOne($this->buildHeader());
$query = Vendor::query()->with('contacts') $query = Vendor::query()->with('contacts')
->withTrashed() ->withTrashed()
->where('company_id', $this->company->id) ->where('company_id', $this->company->id)
@ -100,6 +63,37 @@ class VendorExport extends BaseExport
$query = $this->addDateRange($query); $query = $this->addDateRange($query);
return $query;
}
public function returnJson()
{
$query = $this->init();
$headerdisplay = $this->buildHeader();
$header = collect($this->input['report_keys'])->map(function ($key, $value) use ($headerdisplay) {
return ['identifier' => $key, 'display_value' => $headerdisplay[$value]];
})->toArray();
$report = $query->cursor()
->map(function ($resource) {
$row = $this->buildRow($resource);
return $this->processMetaData($row, $resource);
})->toArray();
return array_merge(['columns' => $header], $report);
}
public function run()
{
$query = $this->init();
//insert the header
$this->csv->insertOne($this->buildHeader());
$query->cursor() $query->cursor()
->each(function ($vendor) { ->each(function ($vendor) {
$this->csv->insertOne($this->buildRow($vendor)); $this->csv->insertOne($this->buildRow($vendor));
@ -110,7 +104,7 @@ class VendorExport extends BaseExport
private function buildRow(Vendor $vendor) :array private function buildRow(Vendor $vendor) :array
{ {
$transformed_contact = []; $transformed_contact = false;
$transformed_vendor = $this->vendor_transformer->transform($vendor); $transformed_vendor = $this->vendor_transformer->transform($vendor);
@ -123,14 +117,12 @@ class VendorExport extends BaseExport
foreach (array_values($this->input['report_keys']) as $key) { foreach (array_values($this->input['report_keys']) as $key) {
$parts = explode('.', $key); $parts = explode('.', $key);
$keyval = array_search($key, $this->entity_keys);
if (is_array($parts) && $parts[0] == 'vendor' && array_key_exists($parts[1], $transformed_vendor)) { if (is_array($parts) && $parts[0] == 'vendor' && array_key_exists($parts[1], $transformed_vendor)) {
$entity[$keyval] = $transformed_vendor[$parts[1]]; $entity[$key] = $transformed_vendor[$parts[1]];
} elseif (is_array($parts) && $parts[0] == 'vendor_contact' && array_key_exists($parts[1], $transformed_contact)) { } elseif (is_array($parts) && $parts[0] == 'vendor_contact' && isset($transformed_contact[$parts[1]])) {
$entity[$keyval] = $transformed_contact[$parts[1]]; $entity[$key] = $transformed_contact[$parts[1]];
} else { } else {
$entity[$keyval] = ''; $entity[$key] = $this->resolveKey($key, $vendor, $this->vendor_transformer);
} }
} }
@ -147,7 +139,11 @@ class VendorExport extends BaseExport
$entity['currency'] = $vendor->currency() ? $vendor->currency()->code : $vendor->company->currency()->code; $entity['currency'] = $vendor->currency() ? $vendor->currency()->code : $vendor->company->currency()->code;
} }
$entity['status'] = $this->calculateStatus($vendor); if (in_array('vendor.classification', $this->input['report_keys']) && isset($vendor->classification)) {
$entity['vendor.classification'] = ctrans("texts.{$vendor->classification}") ?? '';
}
// $entity['status'] = $this->calculateStatus($vendor);
return $entity; return $entity;
} }

View File

@ -30,6 +30,7 @@ class BankIntegrationFactory
$bank_integration->bank_account_type = ''; $bank_integration->bank_account_type = '';
$bank_integration->balance = 0; $bank_integration->balance = 0;
$bank_integration->currency = ''; $bank_integration->currency = '';
$bank_integration->auto_sync = 1;
return $bank_integration; return $bank_integration;
} }

View File

@ -32,6 +32,7 @@ class ClientFactory
$client->is_deleted = 0; $client->is_deleted = 0;
$client->client_hash = Str::random(40); $client->client_hash = Str::random(40);
$client->settings = ClientSettings::defaults(); $client->settings = ClientSettings::defaults();
$client->classification = '';
return $client; return $client;
} }

View File

@ -11,13 +11,13 @@
namespace App\Factory; namespace App\Factory;
use App\Utils\Ninja;
use App\Models\Company;
use App\Libraries\MultiDB;
use App\Utils\Traits\MakesHash;
use App\DataMapper\Tax\TaxModel;
use App\DataMapper\CompanySettings;
use App\DataMapper\ClientRegistrationFields; use App\DataMapper\ClientRegistrationFields;
use App\DataMapper\CompanySettings;
use App\DataMapper\Tax\TaxModel;
use App\Libraries\MultiDB;
use App\Models\Company;
use App\Utils\Ninja;
use App\Utils\Traits\MakesHash;
class CompanyFactory class CompanyFactory
{ {

View File

@ -34,7 +34,7 @@ class ProductFactory
$product->custom_value2 = ''; $product->custom_value2 = '';
$product->custom_value3 = ''; $product->custom_value3 = '';
$product->custom_value4 = ''; $product->custom_value4 = '';
$product->is_deleted = 0; $product->is_deleted = false;
$product->tax_id = 1; $product->tax_id = 1;
return $product; return $product;

View File

@ -20,7 +20,6 @@ class ProjectFactory
$project = new Project; $project = new Project;
$project->company_id = $company_id; $project->company_id = $company_id;
$project->user_id = $user_id; $project->user_id = $user_id;
$project->public_notes = ''; $project->public_notes = '';
$project->private_notes = ''; $project->private_notes = '';
$project->budgeted_hours = 0; $project->budgeted_hours = 0;
@ -30,7 +29,7 @@ class ProjectFactory
$project->custom_value2 = ''; $project->custom_value2 = '';
$project->custom_value3 = ''; $project->custom_value3 = '';
$project->custom_value4 = ''; $project->custom_value4 = '';
$project->is_deleted = 0; $project->is_deleted = false;
return $project; return $project;
} }

View File

@ -34,7 +34,9 @@ class RecurringExpenseFactory
$recurring_expense->tax_amount1 = 0; $recurring_expense->tax_amount1 = 0;
$recurring_expense->tax_amount2 = 0; $recurring_expense->tax_amount2 = 0;
$recurring_expense->tax_amount3 = 0; $recurring_expense->tax_amount3 = 0;
$recurring_expense->date = null; $recurring_expense->date = now()->format('Y-m-d');
$recurring_expense->next_send_date = now()->format('Y-m-d');
$recurring_expense->next_send_date_client = now()->format('Y-m-d');
$recurring_expense->payment_date = null; $recurring_expense->payment_date = null;
$recurring_expense->amount = 0; $recurring_expense->amount = 0;
$recurring_expense->foreign_amount = 0; $recurring_expense->foreign_amount = 0;
@ -47,6 +49,7 @@ class RecurringExpenseFactory
$recurring_expense->custom_value4 = ''; $recurring_expense->custom_value4 = '';
$recurring_expense->uses_inclusive_taxes = true; $recurring_expense->uses_inclusive_taxes = true;
$recurring_expense->calculate_tax_by_amount = true; $recurring_expense->calculate_tax_by_amount = true;
$recurring_expense->remaining_cycles = -1;
return $recurring_expense; return $recurring_expense;
} }

View File

@ -28,6 +28,7 @@ class UserFactory
$user->failed_logins = 0; $user->failed_logins = 0;
$user->signature = ''; $user->signature = '';
$user->theme_id = 0; $user->theme_id = 0;
$user->user_logged_in_notification = true;
return $user; return $user;
} }

View File

@ -28,6 +28,7 @@ class VendorFactory
$vendor->country_id = 4; $vendor->country_id = 4;
$vendor->is_deleted = 0; $vendor->is_deleted = 0;
$vendor->vendor_hash = Str::random(40); $vendor->vendor_hash = Str::random(40);
// $vendor->classification = '';
return $vendor; return $vendor;
} }

View File

@ -48,6 +48,10 @@ class CreditFilters extends QueryFilters
$credit_filters[] = Credit::STATUS_DRAFT; $credit_filters[] = Credit::STATUS_DRAFT;
} }
if (in_array('sent', $status_parameters)) {
$credit_filters[] = Credit::STATUS_SENT;
}
if (in_array('partial', $status_parameters)) { if (in_array('partial', $status_parameters)) {
$credit_filters[] = Credit::STATUS_PARTIAL; $credit_filters[] = Credit::STATUS_PARTIAL;
} }
@ -97,6 +101,21 @@ class CreditFilters extends QueryFilters
}); });
} }
public function applicable(string $value = ''): Builder
{
if (strlen($value) == 0) {
return $this->builder;
}
return $this->builder->where(function ($query){
$query->whereIn('status_id', [Credit::STATUS_SENT, Credit::STATUS_PARTIAL])
->where('balance', '>', 0)
->where(function ($q){
$q->whereNull('due_date')->orWhere('due_date', '>', now());
});
});
}
public function number(string $number = ''): Builder public function number(string $number = ''): Builder
{ {
if (strlen($number) == 0) { if (strlen($number) == 0) {

View File

@ -41,6 +41,9 @@ class ExpenseFilters extends QueryFilters
->orWhere('custom_value4', 'like', '%'.$filter.'%') ->orWhere('custom_value4', 'like', '%'.$filter.'%')
->orWhereHas('category', function ($q) use ($filter) { ->orWhereHas('category', function ($q) use ($filter) {
$q->where('name', 'like', '%'.$filter.'%'); $q->where('name', 'like', '%'.$filter.'%');
})
->orWhereHas('vendor', function ($q) use ($filter) {
$q->where('name', 'like', '%'.$filter.'%');
}); });
}); });
} }

View File

@ -25,7 +25,8 @@ class GroupSettingFilters extends QueryFilters
* @return Builder * @return Builder
*/ */
public function name(string $name = ''): Builder public function name(string $name = ''): Builder
{nlog("filter"); {
if (strlen($name) == 0) { if (strlen($name) == 0) {
return $this->builder; return $this->builder;
} }

View File

@ -11,14 +11,13 @@
namespace App\Filters; namespace App\Filters;
use RuntimeException;
use App\Models\Client; use App\Models\Client;
use App\Models\Invoice; use App\Models\Invoice;
use App\Filters\QueryFilters;
use InvalidArgumentException;
use Illuminate\Support\Carbon;
use App\Utils\Traits\MakesHash; use App\Utils\Traits\MakesHash;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Carbon;
use InvalidArgumentException;
use RuntimeException;
/** /**
* InvoiceFilters. * InvoiceFilters.
@ -247,9 +246,7 @@ class InvoiceFilters extends QueryFilters
$end_date = Carbon::parse($parts[2]); $end_date = Carbon::parse($parts[2]);
return $this->builder->whereBetween($parts[0], [$start_date, $end_date]); return $this->builder->whereBetween($parts[0], [$start_date, $end_date]);
} } catch(\Exception $e) {
catch(\Exception $e){
return $this->builder; return $this->builder;
} }

View File

@ -12,9 +12,8 @@
namespace App\Filters; namespace App\Filters;
use App\Models\Payment; use App\Models\Payment;
use Illuminate\Support\Carbon;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
use Illuminate\Contracts\Database\Eloquent\Builder as EloquentBuilder; use Illuminate\Support\Carbon;
/** /**
* PaymentFilters. * PaymentFilters.
@ -114,7 +113,7 @@ class PaymentFilters extends QueryFilters
} }
if(in_array('partially_unapplied', $status_parameters)) { if(in_array('partially_unapplied', $status_parameters)) {
$query->where('amount', '>', 'applied')->where('refunded', 0); $query->whereColumn('amount', '>', 'applied')->where('refunded', 0);
} }
}); });
@ -196,9 +195,7 @@ class PaymentFilters extends QueryFilters
$end_date = Carbon::parse($parts[2]); $end_date = Carbon::parse($parts[2]);
return $this->builder->whereBetween($parts[0], [$start_date, $end_date]); return $this->builder->whereBetween($parts[0], [$start_date, $end_date]);
} } catch(\Exception $e) {
catch(\Exception $e){
return $this->builder; return $this->builder;
} }

View File

@ -112,6 +112,12 @@ class QuoteFilters extends QueryFilters
->orderBy('due_date', 'DESC'); ->orderBy('due_date', 'DESC');
}); });
} }
if(in_array('converted', $status_parameters)) {
$query->orWhere(function ($q) {
$q->whereNotNull('invoice_id');
});
}
}); });
return $this->builder; return $this->builder;

View File

@ -60,6 +60,7 @@ class TaskFilters extends QueryFilters
* Statuses we need to handle * Statuses we need to handle
* - all * - all
* - invoiced * - invoiced
* - uninvoiced
* *
* @param string $value The invoice status as seen by the client * @param string $value The invoice status as seen by the client
* @return Builder * @return Builder
@ -80,6 +81,10 @@ class TaskFilters extends QueryFilters
$this->builder->whereNotNull('invoice_id'); $this->builder->whereNotNull('invoice_id');
} }
if (in_array('uninvoiced', $status_parameters)) {
$this->builder->whereNull('invoice_id');
}
return $this->builder; return $this->builder;
} }
@ -136,8 +141,13 @@ class TaskFilters extends QueryFilters
$status_parameters = explode(',', $value); $status_parameters = explode(',', $value);
if(count($status_parameters) >= 1) if(count($status_parameters) >= 1) {
$this->builder->whereIn('status_id', $this->transformKeys($status_parameters));
$this->builder->where(function ($query) use ($status_parameters) {
$query->whereIn('status_id', $this->transformKeys($status_parameters))->whereNull('invoice_id');
});
}
return $this->builder; return $this->builder;
} }

View File

@ -130,4 +130,42 @@ class UserFilters extends QueryFilters
$query->whereNotIn('id', $user_array); $query->whereNotIn('id', $user_array);
}); });
} }
/**
* Filters the list based on the status
* archived, active, deleted.
*
* @param string $filter
* @return Builder
*/
public function status(string $filter = ''): Builder
{
if (strlen($filter) == 0) {
return $this->builder;
}
$filters = explode(',', $filter);
return $this->builder->where(function ($query) use ($filters) {
/** @var \App\Models\User $user */
$user = auth()->user();
if (in_array(self::STATUS_ACTIVE, $filters)) {
$query->orWhereNull('deleted_at');
}
if (in_array(self::STATUS_ARCHIVED, $filters)) {
$query->orWhereNotNull('deleted_at')->where('is_deleted', 0);
}
if (in_array(self::STATUS_DELETED, $filters)) {
$query->orWhere('is_deleted', 1);
}
});
}
} }

View File

@ -11,10 +11,9 @@
namespace App\Helpers\Bank\Yodlee\DTO; namespace App\Helpers\Bank\Yodlee\DTO;
use Spatie\LaravelData\Data;
use Spatie\LaravelData\Attributes\MapInputName;
use Spatie\LaravelData\Attributes\MapOutputName;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Spatie\LaravelData\Attributes\MapInputName;
use Spatie\LaravelData\Data;
/** /**
* [ * [

View File

@ -88,8 +88,7 @@ class AccountTransformer implements AccountTransformerInterface
if(property_exists($account, 'currentBalance')) { if(property_exists($account, 'currentBalance')) {
$current_balance = $account->currentBalance->amount ?? 0; $current_balance = $account->currentBalance->amount ?? 0;
$account_currency = $account->currentBalance->currency ?? ''; $account_currency = $account->currentBalance->currency ?? '';
} } elseif(property_exists($account, 'balance')) {
elseif(property_exists($account, 'balance')){
$current_balance = $account->balance->amount ?? 0; $current_balance = $account->balance->amount ?? 0;
$account_currency = $account->balance->currency ?? ''; $account_currency = $account->balance->currency ?? '';
} }
@ -129,8 +128,7 @@ class AccountTransformer implements AccountTransformerInterface
if($status && $update) { if($status && $update) {
$account_status = $status . ' - ' . $update; $account_status = $status . ' - ' . $update;
} } elseif($update) {
elseif($update){
$account_status = $update; $account_status = $update;
} }
@ -140,7 +138,7 @@ class AccountTransformer implements AccountTransformerInterface
'id' => $account->id, 'id' => $account->id,
'account_type' => $account->CONTAINER, 'account_type' => $account->CONTAINER,
// 'account_name' => $account->accountName, // 'account_name' => $account->accountName,
'account_name' => property_exists($account, 'accountName') ? $account->accountName : $account->nickname, 'account_name' => property_exists($account, 'accountName') ? $account->accountName : ($account->nickname ?? 'Unknown Account'),
'account_status' => $account_status, 'account_status' => $account_status,
'account_number' => property_exists($account, 'accountNumber') ? '**** ' . substr($account?->accountNumber, -7) : '', 'account_number' => property_exists($account, 'accountNumber') ? '**** ' . substr($account?->accountNumber, -7) : '',
'provider_account_id' => $account->providerAccountId, 'provider_account_id' => $account->providerAccountId,

View File

@ -127,12 +127,14 @@ class IncomeTransformer implements BankRevenueInterface
foreach ($transaction->transaction as $transaction) { foreach ($transaction->transaction as $transaction) {
//do not store duplicate / pending transactions //do not store duplicate / pending transactions
if (property_exists($transaction, 'status') && $transaction->status == 'PENDING') if (property_exists($transaction, 'status') && $transaction->status == 'PENDING') {
continue; continue;
}
//some object do no store amounts ignore these //some object do no store amounts ignore these
if(!property_exists($transaction, 'amount')) if(!property_exists($transaction, 'amount')) {
continue; continue;
}
$data[] = $this->transformTransaction($transaction); $data[] = $this->transformTransaction($transaction);
} }

View File

@ -15,6 +15,7 @@ use App\Models\Company;
use App\Models\Invoice; use App\Models\Invoice;
use App\Models\RecurringInvoice; use App\Models\RecurringInvoice;
use App\Utils\Ninja; use App\Utils\Ninja;
use BaconQrCode\Exception\InvalidArgumentException;
use BaconQrCode\Renderer\Image\SvgImageBackEnd; use BaconQrCode\Renderer\Image\SvgImageBackEnd;
use BaconQrCode\Renderer\ImageRenderer; use BaconQrCode\Renderer\ImageRenderer;
use BaconQrCode\Renderer\RendererStyle\RendererStyle; use BaconQrCode\Renderer\RendererStyle\RendererStyle;
@ -41,6 +42,9 @@ class EpcQrGenerator
public function getQrCode() public function getQrCode()
{ {
$qr = '';
try {
$renderer = new ImageRenderer( $renderer = new ImageRenderer(
new RendererStyle(200), new RendererStyle(200),
new SvgImageBackEnd() new SvgImageBackEnd()
@ -49,14 +53,23 @@ class EpcQrGenerator
$this->validateFields(); $this->validateFields();
try {
$qr = $writer->writeString($this->encodeMessage(), 'utf-8'); $qr = $writer->writeString($this->encodeMessage(), 'utf-8');
} catch(\Throwable $e) {
return '';
}
return "<svg viewBox='0 0 200 200' width='200' height='200' x='0' y='0' xmlns='http://www.w3.org/2000/svg'> return "<svg viewBox='0 0 200 200' width='200' height='200' x='0' y='0' xmlns='http://www.w3.org/2000/svg'>
<rect x='0' y='0' width='100%'' height='100%' />{$qr}</svg>"; <rect x='0' y='0' width='100%'' height='100%' />{$qr}</svg>";
} catch(\Throwable $e) {
nlog("EPC QR failure => ".$e->getMessage());
return '';
} catch(\Exception $e) {
nlog("EPC QR failure => ".$e->getMessage());
return '';
} catch(InvalidArgumentException $e) {
nlog("EPC QR failure => ".$e->getMessage());
return '';
}
} }
public function encodeMessage() public function encodeMessage()
@ -86,6 +99,7 @@ class EpcQrGenerator
if (Ninja::isSelfHost() && isset($this->company?->custom_fields?->company1)) { if (Ninja::isSelfHost() && isset($this->company?->custom_fields?->company1)) {
nlog('The IBAN field is required'); nlog('The IBAN field is required');
} }
} }
private function formatMoney($value) private function formatMoney($value)

View File

@ -11,16 +11,16 @@
namespace App\Helpers\Invoice; namespace App\Helpers\Invoice;
use App\Models\Quote; use App\DataMapper\BaseSettings;
use App\DataMapper\InvoiceItem;
use App\DataMapper\Tax\RuleInterface;
use App\Models\Client; use App\Models\Client;
use App\Models\Credit; use App\Models\Credit;
use App\Models\Invoice; use App\Models\Invoice;
use App\Models\PurchaseOrder; use App\Models\PurchaseOrder;
use App\Models\RecurringQuote; use App\Models\Quote;
use App\DataMapper\InvoiceItem;
use App\DataMapper\BaseSettings;
use App\Models\RecurringInvoice; use App\Models\RecurringInvoice;
use App\DataMapper\Tax\RuleInterface; use App\Models\RecurringQuote;
use App\Utils\Traits\NumberFormatter; use App\Utils\Traits\NumberFormatter;
class InvoiceItemSum class InvoiceItemSum
@ -144,7 +144,7 @@ class InvoiceItemSum
public function process(): self public function process(): self
{ {
if (!$this->invoice->line_items || !is_array($this->invoice->line_items)) { if (!$this->invoice->line_items || !is_iterable($this->invoice->line_items)) {
$this->items = []; $this->items = [];
return $this; return $this;
} }
@ -181,8 +181,9 @@ class InvoiceItemSum
$this->rule = new $class(); $this->rule = new $class();
if($this->rule->regionWithNoTaxCoverage($this->client->country->iso_3166_2)) if($this->rule->regionWithNoTaxCoverage($this->client->country->iso_3166_2)) {
return $this; return $this;
}
$this->rule $this->rule
->setEntity($this->invoice) ->setEntity($this->invoice)
@ -391,15 +392,20 @@ class InvoiceItemSum
{ {
$this->setGroupedTaxes(collect([])); $this->setGroupedTaxes(collect([]));
$item_tax = 0; foreach ($this->line_items as $key => $this->item) {
foreach ($this->line_items as $this->item) {
if ($this->item->line_total == 0) { if ($this->item->line_total == 0) {
continue; continue;
} }
//$amount = $this->item->line_total - ($this->item->line_total * ($this->invoice->discount / $this->sub_total)); $item_tax = 0;
$amount = ($this->sub_total > 0) ? $this->item->line_total - ($this->item->line_total * ($this->invoice->discount / $this->sub_total)) : 0;
try {
$amount = $this->item->line_total - ($this->item->line_total * ($this->invoice->discount / $this->sub_total));
} catch(\DivisionByZeroError $e) {
$amount = $this->item->line_total;
}
//$amount = ($this->sub_total > 0) ? $this->item->line_total - ($this->invoice->discount * ($this->item->line_total / $this->sub_total)) : 0;
$item_tax_rate1_total = $this->calcAmountLineTax($this->item->tax_rate1, $amount); $item_tax_rate1_total = $this->calcAmountLineTax($this->item->tax_rate1, $amount);
@ -424,9 +430,19 @@ class InvoiceItemSum
if ($item_tax_rate3_total != 0) { if ($item_tax_rate3_total != 0) {
$this->groupTax($this->item->tax_name3, $this->item->tax_rate3, $item_tax_rate3_total); $this->groupTax($this->item->tax_name3, $this->item->tax_rate3, $item_tax_rate3_total);
} }
$this->item->gross_line_total = $this->getLineTotal() + $item_tax;
$this->item->tax_amount = $item_tax;
$this->line_items[$key] = $this->item;
$this->setTotalTaxes($this->getTotalTaxes() + $item_tax);
} }
$this->setTotalTaxes($item_tax);
return $this;
} }
/** /**

View File

@ -11,14 +11,14 @@
namespace App\Helpers\Invoice; namespace App\Helpers\Invoice;
use App\Models\Quote; use App\DataMapper\Tax\RuleInterface;
use App\Models\Client; use App\Models\Client;
use App\Models\Credit; use App\Models\Credit;
use App\Models\Invoice; use App\Models\Invoice;
use App\Models\PurchaseOrder; use App\Models\PurchaseOrder;
use App\Models\RecurringQuote; use App\Models\Quote;
use App\Models\RecurringInvoice; use App\Models\RecurringInvoice;
use App\DataMapper\Tax\RuleInterface; use App\Models\RecurringQuote;
use App\Utils\Traits\NumberFormatter; use App\Utils\Traits\NumberFormatter;
class InvoiceItemSumInclusive class InvoiceItemSumInclusive
@ -131,8 +131,7 @@ class InvoiceItemSumInclusive
public function process() public function process()
{ {
if (! $this->invoice->line_items || ! is_array($this->invoice->line_items) || count($this->invoice->line_items) == 0) { if (!$this->invoice->line_items || ! is_iterable($this->invoice->line_items) || count($this->invoice->line_items) == 0) {
return $this; return $this;
} }
@ -349,15 +348,17 @@ class InvoiceItemSumInclusive
{ {
$this->setGroupedTaxes(collect([])); $this->setGroupedTaxes(collect([]));
$item_tax = 0;
foreach ($this->line_items as $this->item) { foreach ($this->line_items as $this->item) {
if ($this->sub_total == 0) { if ($this->sub_total == 0) {
$amount = $this->item->line_total; $amount = $this->item->line_total;
} else { } else {
$amount = $this->item->line_total - ($this->item->line_total * ($this->invoice->discount / $this->sub_total)); $amount = $this->item->line_total - ($this->invoice->discount * ($this->item->line_total / $this->sub_total));
// $amount = $this->item->line_total - ($this->item->line_total * ($this->invoice->discount / $this->sub_total));
} }
$item_tax = 0;
$item_tax_rate1_total = $this->calcInclusiveLineTax($this->item->tax_rate1, $amount); $item_tax_rate1_total = $this->calcInclusiveLineTax($this->item->tax_rate1, $amount);
$item_tax += $item_tax_rate1_total; $item_tax += $item_tax_rate1_total;
@ -381,9 +382,17 @@ class InvoiceItemSumInclusive
if ($item_tax_rate3_total != 0) { if ($item_tax_rate3_total != 0) {
$this->groupTax($this->item->tax_name3, $this->item->tax_rate3, $item_tax_rate3_total); $this->groupTax($this->item->tax_name3, $this->item->tax_rate3, $item_tax_rate3_total);
} }
$this->setTotalTaxes($this->getTotalTaxes() + $item_tax);
$this->item->gross_line_total = $this->getLineTotal();
$this->item->tax_amount = $item_tax;
} }
$this->setTotalTaxes($item_tax); return $this;
// $this->setTotalTaxes($item_tax);
} }
@ -401,8 +410,9 @@ class InvoiceItemSumInclusive
$this->rule = new $class(); $this->rule = new $class();
if($this->rule->regionWithNoTaxCoverage($this->client->country->iso_3166_2)) if($this->rule->regionWithNoTaxCoverage($this->client->country->iso_3166_2)) {
return $this; return $this;
}
$this->rule $this->rule
->setEntity($this->invoice) ->setEntity($this->invoice)

View File

@ -11,15 +11,15 @@
namespace App\Helpers\Invoice; namespace App\Helpers\Invoice;
use App\Models\Quote;
use App\Utils\Number;
use App\Models\Credit; use App\Models\Credit;
use App\Models\Invoice; use App\Models\Invoice;
use App\Models\PurchaseOrder; use App\Models\PurchaseOrder;
use App\Models\RecurringQuote; use App\Models\Quote;
use App\Models\RecurringInvoice; use App\Models\RecurringInvoice;
use Illuminate\Support\Collection; use App\Models\RecurringQuote;
use App\Utils\Number;
use App\Utils\Traits\NumberFormatter; use App\Utils\Traits\NumberFormatter;
use Illuminate\Support\Collection;
class InvoiceSum class InvoiceSum
{ {
@ -308,8 +308,9 @@ class InvoiceSum
public function setTaxMap(): self public function setTaxMap(): self
{ {
if ($this->invoice->is_amount_discount == true) { if ($this->invoice->is_amount_discount) {
$this->invoice_items->calcTaxesWithAmountDiscount(); $this->invoice_items->calcTaxesWithAmountDiscount();
$this->invoice->line_items = $this->invoice_items->getLineItems();
} }
$this->tax_map = collect(); $this->tax_map = collect();
@ -327,8 +328,6 @@ class InvoiceSum
return $value['key'] == $key; return $value['key'] == $key;
})->sum('total'); })->sum('total');
//$total_line_tax -= $this->discount($total_line_tax);
$this->tax_map[] = ['name' => $tax_name, 'total' => $total_line_tax]; $this->tax_map[] = ['name' => $tax_name, 'total' => $total_line_tax];
$this->total_taxes += $total_line_tax; $this->total_taxes += $total_line_tax;
@ -377,16 +376,6 @@ class InvoiceSum
public function purgeTaxes(): self public function purgeTaxes(): self
{ {
// $this->tax_rate1 = 0;
// $this->tax_name1 = '';
// $this->tax_rate2 = 0;
// $this->tax_name2 = '';
// $this->tax_rate3 = 0;
// $this->tax_name3 = '';
// $this->discount = 0;
$line_items = collect($this->invoice->line_items); $line_items = collect($this->invoice->line_items);

View File

@ -11,15 +11,14 @@
namespace App\Helpers\Invoice; namespace App\Helpers\Invoice;
use App\Models\Quote;
use App\Models\Credit; use App\Models\Credit;
use App\Models\Invoice; use App\Models\Invoice;
use App\Models\PurchaseOrder; use App\Models\PurchaseOrder;
use App\Models\RecurringQuote; use App\Models\Quote;
use App\Models\RecurringInvoice; use App\Models\RecurringInvoice;
use Illuminate\Support\Collection; use App\Models\RecurringQuote;
use App\Utils\Traits\NumberFormatter; use App\Utils\Traits\NumberFormatter;
use App\Helpers\Invoice\InvoiceItemSumInclusive; use Illuminate\Support\Collection;
class InvoiceSumInclusive class InvoiceSumInclusive
{ {
@ -315,8 +314,9 @@ class InvoiceSumInclusive
public function setTaxMap() public function setTaxMap()
{ {
if ($this->invoice->is_amount_discount == true) { if ($this->invoice->is_amount_discount) {
$this->invoice_items->calcTaxesWithAmountDiscount(); $this->invoice_items->calcTaxesWithAmountDiscount();
$this->invoice->line_items = $this->invoice_items->getLineItems();
} }
$this->tax_map = collect(); $this->tax_map = collect();

View File

@ -166,7 +166,7 @@ class SwissQrGenerator
// Now get the QR code image and save it as a file. // Now get the QR code image and save it as a file.
try { try {
$output = new QrBill\PaymentPart\Output\HtmlOutput\HtmlOutput($qrBill, $this->client->locale() ?: 'en'); $output = new QrBill\PaymentPart\Output\HtmlOutput\HtmlOutput($qrBill, $this->resolveLanguage());
$html = $output $html = $output
->setPrintable(false) ->setPrintable(false)
@ -174,15 +174,44 @@ class SwissQrGenerator
return $html; return $html;
} catch (\Exception $e) { } catch (\Exception $e) {
if(is_iterable($qrBill->getViolations())) {
foreach ($qrBill->getViolations() as $key => $violation) { foreach ($qrBill->getViolations() as $key => $violation) {
nlog("qr"); nlog("qr");
nlog($violation); nlog($violation);
} }
}
nlog($e->getMessage()); nlog($e->getMessage());
return ''; return '';
// return $e->getMessage(); // return $e->getMessage();
} }
} }
private function resolveLanguage(): string
{
$language = $this->client->locale() ?: 'en';
switch ($language) {
case 'de':
return 'de';
case 'en':
case 'en_GB':
return 'en';
case 'it':
return 'it';
case 'fr':
case 'fr_CA':
case 'fr_CH':
return 'fr';
default:
return 'en';
}
}
} }

View File

@ -11,17 +11,17 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Models\Account;
use App\Libraries\MultiDB;
use App\Utils\TruthSource;
use App\Models\CompanyUser;
use Illuminate\Http\Response;
use App\Jobs\Account\CreateAccount;
use App\Transformers\AccountTransformer;
use App\Transformers\CompanyUserTransformer;
use Illuminate\Foundation\Bus\DispatchesJobs;
use App\Http\Requests\Account\CreateAccountRequest; use App\Http\Requests\Account\CreateAccountRequest;
use App\Http\Requests\Account\UpdateAccountRequest; use App\Http\Requests\Account\UpdateAccountRequest;
use App\Jobs\Account\CreateAccount;
use App\Libraries\MultiDB;
use App\Models\Account;
use App\Models\CompanyUser;
use App\Transformers\AccountTransformer;
use App\Transformers\CompanyUserTransformer;
use App\Utils\TruthSource;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Http\Response;
class AccountController extends BaseController class AccountController extends BaseController
{ {

View File

@ -11,19 +11,19 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use stdClass;
use App\Utils\Ninja;
use App\Models\Activity;
use Illuminate\Http\Request;
use App\Utils\Traits\MakesHash;
use App\Utils\PhantomJS\Phantom;
use App\Utils\HostedPDF\NinjaPdf;
use App\Utils\Traits\Pdf\PdfMaker;
use App\Utils\Traits\Pdf\PageNumbering;
use Illuminate\Support\Facades\Storage;
use App\Transformers\ActivityTransformer;
use App\Http\Requests\Activity\ShowActivityRequest;
use App\Http\Requests\Activity\DownloadHistoricalEntityRequest; use App\Http\Requests\Activity\DownloadHistoricalEntityRequest;
use App\Http\Requests\Activity\ShowActivityRequest;
use App\Models\Activity;
use App\Transformers\ActivityTransformer;
use App\Utils\HostedPDF\NinjaPdf;
use App\Utils\Ninja;
use App\Utils\PhantomJS\Phantom;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\Pdf\PageNumbering;
use App\Utils\Traits\Pdf\PdfMaker;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use stdClass;
class ActivityController extends BaseController class ActivityController extends BaseController
{ {

View File

@ -80,6 +80,7 @@ class ContactForgotPasswordController extends Controller
'passwordEmailRoute' => 'client.password.email', 'passwordEmailRoute' => 'client.password.email',
'account' => $account, 'account' => $account,
'company' => $company, 'company' => $company,
'is_react' => false,
]); ]);
} }

View File

@ -11,13 +11,13 @@
namespace App\Http\Controllers\Auth; namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Libraries\MultiDB;
use App\Models\Account; use App\Models\Account;
use App\Models\Company; use App\Models\Company;
use App\Libraries\MultiDB;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Password;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails; use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Password;
class ForgotPasswordController extends Controller class ForgotPasswordController extends Controller
{ {
@ -90,6 +90,8 @@ class ForgotPasswordController extends Controller
$account = Account::find($account_id); $account = Account::find($account_id);
} }
return $this->render('auth.passwords.request', ['root' => 'themes', 'account' => $account]); $is_react = request()->has('react') ? true : false;
return $this->render('auth.passwords.request', ['root' => 'themes', 'account' => $account, 'is_react' => $is_react]);
} }
} }

View File

@ -12,37 +12,37 @@
namespace App\Http\Controllers\Auth; namespace App\Http\Controllers\Auth;
use Google_Client;
use App\Models\User;
use App\Utils\Ninja;
use App\Models\Account;
use App\Libraries\MultiDB;
use App\Utils\TruthSource;
use Microsoft\Graph\Model;
use App\Models\CompanyUser;
use App\Models\CompanyToken;
use Illuminate\Http\Request;
use App\Libraries\OAuth\OAuth;
use App\Events\User\UserLoggedIn;
use Illuminate\Http\JsonResponse;
use PragmaRX\Google2FA\Google2FA;
use App\Jobs\Account\CreateAccount;
use Illuminate\Support\Facades\Auth;
use App\Utils\Traits\User\LoginCache;
use Illuminate\Support\Facades\Cache;
use Turbo124\Beacon\Facades\LightLogs;
use App\Http\Controllers\BaseController;
use App\Jobs\Company\CreateCompanyToken;
use Illuminate\Support\Facades\Response;
use Laravel\Socialite\Facades\Socialite;
use App\Http\Requests\Login\LoginRequest;
use App\Libraries\OAuth\Providers\Google;
use Illuminate\Database\Eloquent\Builder;
use App\DataMapper\Analytics\LoginFailure; use App\DataMapper\Analytics\LoginFailure;
use App\DataMapper\Analytics\LoginSuccess; use App\DataMapper\Analytics\LoginSuccess;
use App\Utils\Traits\UserSessionAttributes; use App\Events\User\UserLoggedIn;
use App\Http\Controllers\BaseController;
use App\Http\Requests\Login\LoginRequest;
use App\Jobs\Account\CreateAccount;
use App\Jobs\Company\CreateCompanyToken;
use App\Libraries\MultiDB;
use App\Libraries\OAuth\OAuth;
use App\Libraries\OAuth\Providers\Google;
use App\Models\Account;
use App\Models\CompanyToken;
use App\Models\CompanyUser;
use App\Models\User;
use App\Transformers\CompanyUserTransformer; use App\Transformers\CompanyUserTransformer;
use App\Utils\Ninja;
use App\Utils\Traits\User\LoginCache;
use App\Utils\Traits\UserSessionAttributes;
use App\Utils\TruthSource;
use Google_Client;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Foundation\Auth\AuthenticatesUsers; use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Response;
use Laravel\Socialite\Facades\Socialite;
use Microsoft\Graph\Model;
use PragmaRX\Google2FA\Google2FA;
use Turbo124\Beacon\Facades\LightLogs;
class LoginController extends BaseController class LoginController extends BaseController
{ {
@ -418,10 +418,12 @@ class LoginController extends BaseController
->setReturnType(Model\User::class) ->setReturnType(Model\User::class)
->execute(); ->execute();
nlog($user);
if ($user) { if ($user) {
$account = request()->input('account'); $account = request()->input('account');
$email = $user->getMail() ?: $user->getUserPrincipalName(); $email = $user->getUserPrincipalName() ?? false;
$query = [ $query = [
'oauth_user_id' => $user->getId(), 'oauth_user_id' => $user->getId(),
@ -437,7 +439,7 @@ class LoginController extends BaseController
} }
// If this is a result user/email combo - lets add their OAuth details details // If this is a result user/email combo - lets add their OAuth details details
if ($existing_login_user = MultiDB::hasUser(['email' => $email])) { if ($email && $existing_login_user = MultiDB::hasUser(['email' => $email])) {
if (!$existing_login_user->account) { if (!$existing_login_user->account) {
return response()->json(['message' => 'User exists, but not attached to any companies! Orphaned user!'], 400); return response()->json(['message' => 'User exists, but not attached to any companies! Orphaned user!'], 400);
} }
@ -447,7 +449,6 @@ class LoginController extends BaseController
return $this->existingLoginUser($user->getId(), 'microsoft'); return $this->existingLoginUser($user->getId(), 'microsoft');
} }
// Signup! // Signup!
if (request()->has('create') && request()->input('create') == 'true') { if (request()->has('create') && request()->input('create') == 'true') {
$new_account = [ $new_account = [
@ -640,8 +641,9 @@ class LoginController extends BaseController
$parameters = ['response_type' => 'code', 'redirect_uri' => config('ninja.app_url') . "/auth/microsoft"]; $parameters = ['response_type' => 'code', 'redirect_uri' => config('ninja.app_url') . "/auth/microsoft"];
} }
if(request()->hasHeader('X-REACT') || request()->query('react')) if(request()->hasHeader('X-REACT') || request()->query('react')) {
Cache::put("react_redir:".auth()->user()?->account->key, 'true', 300); Cache::put("react_redir:".auth()->user()?->account->key, 'true', 300);
}
if (request()->has('code')) { if (request()->has('code')) {
return $this->handleProviderCallback($provider); return $this->handleProviderCallback($provider);

View File

@ -25,4 +25,3 @@ class PasswordTimeoutController extends Controller
return $cached ? response()->json(['message' => 'Password is valid'], 200) : response()->json(['message' => 'Invalid Password'], 412); return $cached ? response()->json(['message' => 'Password is valid'], 200) : response()->json(['message' => 'Invalid Password'], 412);
} }
} }

View File

@ -70,6 +70,7 @@ class ResetPasswordController extends Controller
$account = Account::first(); $account = Account::first();
} }
return $this->render('auth.passwords.reset', ['root' => 'themes', 'token' => $token, 'account' => $account, 'email' => $request->email]); return $this->render('auth.passwords.reset', ['root' => 'themes', 'token' => $token, 'account' => $account, 'email' => $request->email]);
} }
@ -110,6 +111,10 @@ class ResetPasswordController extends Controller
{ {
auth()->logout(); auth()->logout();
if(request()->has('react') || request()->hasHeader('X-React')) {
return redirect(config('ninja.react_url').'/#/login');
}
return redirect('/'); return redirect('/');
} }
@ -126,11 +131,11 @@ class ResetPasswordController extends Controller
return new JsonResponse(['message' => trans($response)], 200); return new JsonResponse(['message' => trans($response)], 200);
} }
if(Ninja::isHosted() && $request->hasHeader('X-React')){ if($request->hasHeader('X-REACT') || $request->has('react')) {
return redirect('https://app.invoicing.co/#/login'); return redirect(config('ninja.react_url').'/#/login');
} } else {
elseif($request->hasHeader('X-React'))
return redirect('/#/login'); return redirect('/#/login');
}
return redirect($this->redirectPath()) return redirect($this->redirectPath())
->with('status', trans($response)); ->with('status', trans($response));

Some files were not shown because too many files have changed in this diff Show More