diff --git a/.env.ci b/.env.ci index 407e82e82624..84d86d4c9ffc 100644 --- a/.env.ci +++ b/.env.ci @@ -6,9 +6,15 @@ APP_URL=http://ninja.test MULTI_DB_ENABLED=false # database DB_CONNECTION=db-ninja-01 +DB_DATABASE1=ninja +DB_USERNAME1=root +DB_PASSWORD1=ninja +DB_HOST1=127.0.0.1 +DB_PORT1=32768 +DB_PORT=32768 DB_DATABASE=ninja DB_USERNAME=root DB_PASSWORD=ninja - +DB_HOST=127.0.0.1 NINJA_ENVIRONMENT=selfhost COMPOSER_AUTH='{"github-oauth": {"github.com": "${{ secrets.GITHUB_TOKEN }}"}}' diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index a2142ddcd5be..d38b735e63ad 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -7,18 +7,48 @@ name: phpunit jobs: phpunit: runs-on: ubuntu-latest - + env: + DB_DATABASE1: ninja + DB_USERNAME1: root + DB_PASSWORD1: ninja + DB_HOST1: '127.0.0.1' + DB_DATABASE: ninja + DB_USERNAME: root + DB_PASSWORD: ninja + DB_HOST: '127.0.0.1' + BROADCAST_DRIVER: log + CACHE_DRIVER: file + QUEUE_CONNECTION: sync + SESSION_DRIVER: file + services: - mysql: - image: mysql:5.7 - env: - MYSQL_ROOT_PASSWORD: ninja - MYSQL_DATABASE: ninja + mariadb: + image: mariadb:latest ports: - - 33306:3306 - options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 + - 3306 + env: + MYSQL_ALLOW_EMPTY_PASSWORD: yes + MYSQL_USER: ninja + MYSQL_PASSWORD: ninja + MYSQL_DATABASE: ninja + MYSQL_ROOT_PASSWORD: ninja + options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3 steps: + - name: Start mysql service + run: | + sudo /etc/init.d/mysql start + + - name: Verify MariaDB connection + env: + DB_PORT: ${{ job.services.mariadb.ports[3306] }} + DB_PORT1: ${{ job.services.mariadb.ports[3306] }} + + run: | + while ! mysqladmin ping -h"127.0.0.1" -P"$DB_PORT" --silent; do + sleep 1 + done + - uses: actions/checkout@v1 with: ref: v2 @@ -37,11 +67,8 @@ jobs: run: | php artisan key:generate php artisan optimize - - - name: Prepare JS/CSS assets - run: | - npm i - npm run production + php artisan cache:clear + php artisan config:cache - name: Create DB and schemas run: | @@ -52,5 +79,13 @@ jobs: run: | php artisan migrate:fresh --seed --force && php artisan db:seed --class=RandomDataSeeder --force + - name: Prepare JS/CSS assets + run: | + npm i + npm run production + - name: Run Testsuite run: vendor/bin/phpunit --testdox + env: + DB_PORT: ${{ job.services.mysql.ports[3306] }} + diff --git a/app/Console/Commands/ArtisanUpgrade.php b/app/Console/Commands/ArtisanUpgrade.php index 0572a0b2bc03..80a856711a64 100644 --- a/app/Console/Commands/ArtisanUpgrade.php +++ b/app/Console/Commands/ArtisanUpgrade.php @@ -62,13 +62,12 @@ class ArtisanUpgrade extends Command try { /* Restart Horizon */ - //Artisan::call('horizon:terminate'); + //Artisan::call('horizon:terminate'); exec('cd '.base_path().' && /usr/bin/php artisan horizon:terminate'); exec('cd '.base_path().' && /usr/bin/php artisan horizon &'); //Artisan::call('horizon'); - } catch (Exception $e) { \Log::error("I wasn't able to start horizon"); } @@ -78,6 +77,5 @@ class ArtisanUpgrade extends Command $application = new Application(); $application->setAutoExit(true); // prevent `$application->run` method from exitting the script $application->run($input); - } } diff --git a/app/Console/Commands/SendTestEmails.php b/app/Console/Commands/SendTestEmails.php index 2f7cc92ca708..a55b1df51c05 100644 --- a/app/Console/Commands/SendTestEmails.php +++ b/app/Console/Commands/SendTestEmails.php @@ -72,7 +72,6 @@ class SendTestEmails extends Command if (!$user) { - $account = factory(\App\Models\Account::class)->create(); $user = factory(\App\Models\User::class)->create([ diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 80c2f209086a..26d8d79d56db 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -44,9 +44,9 @@ class Kernel extends ConsoleKernel $schedule->command('horizon:snapshot')->everyFiveMinutes(); /* Run queue's in shared hosting with this*/ - if(Ninja::isSelfHost()) + if (Ninja::isSelfHost()) { $schedule->command('queue:work')->everyMinute()->withoutOverlapping(); - + } } /** diff --git a/app/DataMapper/EmailTemplateDefaults.php b/app/DataMapper/EmailTemplateDefaults.php index a5dc34aa8bb6..eb831a516f87 100644 --- a/app/DataMapper/EmailTemplateDefaults.php +++ b/app/DataMapper/EmailTemplateDefaults.php @@ -16,12 +16,14 @@ use League\CommonMark\CommonMarkConverter; class EmailTemplateDefaults { - public static function getDefaultTemplate($template, $locale) { App::setLocale($locale); switch ($template) { + + /* Template */ + case 'email_template_invoice': return self::emailInvoiceTemplate(); break; @@ -59,6 +61,45 @@ class EmailTemplateDefaults return self::emailInvoiceTemplate(); break; + /* Subject */ + + case 'email_subject_invoice': + return self::emailInvoiceSubject(); + break; + case 'email_subject_quote': + return self::emailQuoteSubject(); + break; + case 'email_subject_payment': + return self::emailPaymentSubject(); + break; + case 'email_subject_payment_partial': + return self::emailPaymentSubject(); + break; + case 'email_subject_statement': + return self::emailStatementSubject(); + break; + case 'email_subject_reminder1': + return self::emailReminder1Subject(); + break; + case 'email_subject_reminder2': + return self::emailReminder2Subject(); + break; + case 'email_subject_reminder3': + return self::emailReminder3Subject(); + break; + case 'email_subject_reminder_endless': + return self::emailReminderEndlessSubject(); + break; + case 'email_subject_custom1': + return self::emailInvoiceSubject(); + break; + case 'email_subject_custom2': + return self::emailInvoiceSubject(); + break; + case 'email_subject_custom3': + return self::emailInvoiceSubject(); + break; + default: return self::emailInvoiceTemplate(); break; diff --git a/app/Designs/Custom.php b/app/Designs/Custom.php index 317021b0dd48..6c7d46275fe6 100644 --- a/app/Designs/Custom.php +++ b/app/Designs/Custom.php @@ -11,7 +11,7 @@ namespace App\Designs; -class Custom extends AbstractDesign +class Custom { public $includes; diff --git a/app/Designs/Designer.php b/app/Designs/Designer.php index 69d27c51def2..3334218e252d 100644 --- a/app/Designs/Designer.php +++ b/app/Designs/Designer.php @@ -269,13 +269,13 @@ class Designer private function invoiceDetails(Company $company) { $data = [ - '$invoice.invoice_number' => '$invoice_number_label$invoice_number', - '$invoice.po_number' => '$po_number_label$po_number', - '$invoice.invoice_date' => '$invoice_date_label$invoice_date', - '$invoice.due_date' => '$due_date_label$due_date', - '$invoice.balance_due' => '$balance_due_label$balance_due', - '$invoice.invoice_total' => '$invoice_total_label$invoice_total', - '$invoice.partial_due' => '$partial_due_label$partial_due', + '$invoice.invoice_number' => '$invoice.number_label$invoice.number', + '$invoice.po_number' => '$invoice.po_number_label$invoice.po_number', + '$invoice.invoice_date' => '$invoice.date_label$invoice.date', + '$invoice.due_date' => '$invoice.due_date_label$invoice.due_date', + '$invoice.balance_due' => '$invoice.balance_due_label$invoice.balance_due', + '$invoice.invoice_total' => '$invoice.total_label$invoice.total', + '$invoice.partial_due' => '$invoice.partial_due_label$invoice.partial_due', '$invoice.invoice1' => '$invoice1_label$invoice1', '$invoice.invoice2' => '$invoice2_label$invoice2', '$invoice.invoice3' => '$invoice3_label$invoice3', @@ -292,13 +292,13 @@ class Designer private function quoteDetails(Company $company) { $data = [ - '$quote.quote_number' => '$quote_number', - '$quote.po_number' => '$po_number', - '$quote.quote_date' => '$date', - '$quote.valid_until' => '$valid_until', - '$quote.balance_due' => '$balance_due', - '$quote.quote_total' => '$quote_total', - '$quote.partial_due' => '$partial_due', + '$quote.quote_number' => '$quote.number', + '$quote.po_number' => '$quote.po_number', + '$quote.quote_date' => '$quote.date', + '$quote.valid_until' => '$quote.valid_until', + '$quote.balance_due' => '$quote.balance_due', + '$quote.quote_total' => '$quote.total', + '$quote.partial_due' => '$quote.partial_due', '$quote.quote1' => '$quote1', '$quote.quote2' => '$quote2', '$quote.quote3' => '$quote3', @@ -315,16 +315,16 @@ class Designer private function creditDetails(Company $company) { $data = [ - '$credit.credit_number' => '$credit_number', - '$credit.po_number' => '$po_number', - '$credit.credit_date' => '$date', - '$credit.credit_balance' => '$credit_balance', - '$credit.credit_amount' => '$credit_amount', - '$credit.partial_due' => '$partial_due', - '$credit.invoice1' => '$invoice1', - '$credit.invoice2' => '$invoice2', - '$credit.invoice3' => '$invoice3', - '$credit.invoice4' => '$invoice4', + '$credit.credit_number' => '$credit.number', + '$credit.po_number' => '$credit.po_number', + '$credit.credit_date' => '$credit.date', + '$credit.credit_balance' => '$credit.balance', + '$credit.credit_amount' => '$credit.amount', + '$credit.partial_due' => '$credit.partial_due', + '$credit.credit1' => '$credit1', + '$credit.credit2' => '$credit2', + '$credit.credit3' => '$credit3', + '$credit.credit4' => '$credit4', '$credit.surcharge1' => '$surcharge1', '$credit.surcharge2' => '$surcharge2', '$credit.surcharge3' => '$surcharge3', diff --git a/app/Helpers/ClientPortal.php b/app/Helpers/ClientPortal.php index c3a8600e6f82..00cfe939f2bd 100644 --- a/app/Helpers/ClientPortal.php +++ b/app/Helpers/ClientPortal.php @@ -21,11 +21,13 @@ function isActive($page, bool $boolean = false) { $current_page = Route::currentRouteName(); - if ($page == $current_page && $boolean) + if ($page == $current_page && $boolean) { return true; + } - if ($page == $current_page) + if ($page == $current_page) { return 'active-page'; + } return false; } @@ -43,8 +45,9 @@ function render(string $path, array $options = []) if (array_key_exists('root', $options)) { return view( - sprintf('%s.%s.%s', $options['root'], $theme, $path) - , $options); + sprintf('%s.%s.%s', $options['root'], $theme, $path), + $options + ); } return view("portal.$theme.$path", $options); diff --git a/app/Http/Controllers/BaseController.php b/app/Http/Controllers/BaseController.php index 4f8140d0bdfa..2a9f55bf7a28 100644 --- a/app/Http/Controllers/BaseController.php +++ b/app/Http/Controllers/BaseController.php @@ -302,18 +302,19 @@ class BaseController extends Controller public function flutterRoute() { - if (!$this->checkAppSetup()); - return redirect('/setup'); + if ((bool)$this->checkAppSetup() !== false) { + $data = []; - $data = []; + if (Ninja::isSelfHost()) { + $account = Account::all()->first(); + $data['report_errors'] = $account->report_errors; + } else { + $data['report_errors'] = true; + } - if(Ninja::isSelfHost()){ - $account = Account::all()->first(); - $data['report_errors'] = $account->report_errors; + return view('index.index', $data); } - else - $data['report_errors'] = true; - return view('index.index', $data); + return redirect('/setup'); } } diff --git a/app/Http/Controllers/ClientPortal/InvoiceController.php b/app/Http/Controllers/ClientPortal/InvoiceController.php index b7a4a385789f..9ed08fa97b26 100644 --- a/app/Http/Controllers/ClientPortal/InvoiceController.php +++ b/app/Http/Controllers/ClientPortal/InvoiceController.php @@ -95,7 +95,7 @@ class InvoiceController extends Controller // \Log::error($request->all()); $transformed_ids = $this->transformKeys($request->invoices); -//\Log::error($transformed_ids); + //\Log::error($transformed_ids); if ($request->input('action') == 'payment') { return $this->makePayment((array)$transformed_ids); @@ -112,7 +112,7 @@ class InvoiceController extends Controller $invoices = Invoice::whereIn('id', $ids) ->whereClientId(auth()->user()->client->id) ->get(); -//\Log::error($invoices); + //\Log::error($invoices); $total = $invoices->sum('balance'); diff --git a/app/Http/Controllers/ClientPortal/PaymentController.php b/app/Http/Controllers/ClientPortal/PaymentController.php index a89afeee4d02..55fc5abbb3fa 100644 --- a/app/Http/Controllers/ClientPortal/PaymentController.php +++ b/app/Http/Controllers/ClientPortal/PaymentController.php @@ -78,7 +78,7 @@ class PaymentController extends Controller * @return \Illuminate\Http\RedirectResponse|mixed */ public function process() - { + { $invoices = Invoice::whereIn('id', $this->transformKeys(request()->invoices)) ->whereClientId(auth()->user()->client->id) ->get(); diff --git a/app/Http/Controllers/ClientPortal/QuoteController.php b/app/Http/Controllers/ClientPortal/QuoteController.php index 549d8f71fee6..c98080caaac3 100644 --- a/app/Http/Controllers/ClientPortal/QuoteController.php +++ b/app/Http/Controllers/ClientPortal/QuoteController.php @@ -99,7 +99,6 @@ class QuoteController extends Controller } if ($process) { - foreach ($quotes as $quote) { $quote->service()->approve()->save(); } diff --git a/app/Http/Controllers/PingController.php b/app/Http/Controllers/PingController.php index 4c2ece836add..c0b8b13f10ba 100644 --- a/app/Http/Controllers/PingController.php +++ b/app/Http/Controllers/PingController.php @@ -25,5 +25,4 @@ class PingController extends BaseController { return response()->json('success', 200); } - } diff --git a/app/Http/Controllers/SelfUpdateController.php b/app/Http/Controllers/SelfUpdateController.php index 6f955ccd0a28..5a48a5b4601a 100644 --- a/app/Http/Controllers/SelfUpdateController.php +++ b/app/Http/Controllers/SelfUpdateController.php @@ -58,13 +58,12 @@ class SelfUpdateController extends BaseController */ public function update(UpdaterManager $updater) { - if(Ninja::isNinja()) + if (Ninja::isNinja()) { return response()->json(['message' => 'Self update not available on this system.'], 403); + } $res = $updater->update(); return response()->json(['message'=>$res], 200); } - - } diff --git a/app/Http/Controllers/SetupController.php b/app/Http/Controllers/SetupController.php index 02a9d4e42a67..8700c242a7a1 100644 --- a/app/Http/Controllers/SetupController.php +++ b/app/Http/Controllers/SetupController.php @@ -24,12 +24,15 @@ class SetupController extends Controller { public function index() { - $system_health = SystemHealth::check(); + $data = SystemHealth::check(); - if($system_health) + if ($data['system_health'] !== false) { + return view('setup.index', $data); + } + + if ($system_health !== true) { return redirect('/'); - - return view('setup.index'); + } } public function doSetup(StoreSetupRequest $request) @@ -87,4 +90,16 @@ class SetupController extends Controller return view('index.index'); } + + public function check_db() + { + if (Account::count() == 0) { + } + } + + public function check_mail() + { + if (Account::count() == 0) { + } + } } diff --git a/app/Http/Controllers/TemplateController.php b/app/Http/Controllers/TemplateController.php index f780051bd97f..0e70e56c2311 100644 --- a/app/Http/Controllers/TemplateController.php +++ b/app/Http/Controllers/TemplateController.php @@ -12,6 +12,7 @@ namespace App\Http\Controllers; use App\DataMapper\EmailTemplateDefaults; +use App\Utils\TemplateEngine; use App\Utils\Traits\MakesHash; use App\Utils\Traits\MakesInvoiceHtml; use App\Utils\Traits\MakesTemplateData; @@ -106,77 +107,15 @@ class TemplateController extends BaseController */ public function show() { - $entity_obj = null; - - if (request()->has('entity') && request()->has('entity_id')) { - $class = 'App\Models\\'.ucfirst(request()->input('entity')); - $entity_obj = $class::whereId($this->decodePrimaryKey(request()->input('entity_id')))->company()->first(); - } - - if($entity_obj){ - $settings_entity = $entity_obj->client; - } - else{ - $settings_entity = auth()->user()->company(); - } - - - $subject = request()->input('subject') ?: ''; - $body = request()->input('body') ?: ''; - $template = request()->input('template') ?: ''; - - if(strlen($template) >1) { - - $custom_template = $settings_entity->getSetting($template); - - if(strlen($custom_template) > 1){ - $body = $custom_template; - } - else { - $body = EmailTemplateDefaults::getDefaultTemplate($template, $settings_entity->locale()); - } - - } - - $labels = $this->makeFakerLabels(); - $values = $this->makeFakerValues(); - - $body = str_replace(array_keys($labels), array_values($labels), $body); - $body = str_replace(array_keys($values), array_values($values), $body); - - $converter = new CommonMarkConverter([ - 'allow_unsafe_links' => false, - ]); - - $body = $converter->convertToHtml($body); - - /* wrapper */ - $email_style = $settings_entity->getSetting('email_style'); - - $data['title'] = ''; - $data['body'] = $body; - $data['footer'] = ''; - - if($email_style == 'custom') { - - $wrapper = $settings_entity->getSetting('email_style_custom'); - $wrapper = $this->renderView($wrapper, $data); - } - else { - - $wrapper = $this->getTemplate(); - $wrapper = view($this->getTemplatePath($email_style), $data)->render(); - - } - - - - $data = [ - 'subject' => $subject, - 'body' => $body, - 'wrapper' => $wrapper, - ]; + + $entity = request()->has('entity') ? request()->input('entity') : ''; + $entity_id = request()->has('entity_id') ? request()->input('entity_id') : ''; + $subject = request()->has('subject') ? request()->input('subject') : ''; + $body = request()->has('body') ? request()->input('body') : ''; + $template = request()->has('template') ? request()->input('template') : ''; + $data = (new TemplateEngine($body, $subject, $entity, $entity_id, $template))->build(); + return response()->json($data, 200); } } diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index 481f1438efce..b4d5d388a891 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -646,19 +646,19 @@ f * response=200, */ public function detach(DetachCompanyUserRequest $request, User $user) { - $company_user = CompanyUser::whereUserId($user->id) ->whereCompanyId(auth()->user()->companyId())->first(); $token = $company_user->token->where('company_id', $company_user->company_id)->where('user_id', $company_user->user_id)->first(); - if($token) + if ($token) { $token->delete(); + } - if($company_user) + if ($company_user) { $company_user->delete(); + } return response()->json(['message' => 'User detached from company'], 200); - } } diff --git a/app/Jobs/Invoice/EmailInvoice.php b/app/Jobs/Invoice/EmailInvoice.php index cca6b8286e3d..277c3c937817 100644 --- a/app/Jobs/Invoice/EmailInvoice.php +++ b/app/Jobs/Invoice/EmailInvoice.php @@ -57,10 +57,10 @@ class EmailInvoice implements ShouldQueue Mail::to($this->invoice_invitation->contact->email, $this->invoice_invitation->contact->present()->name()) ->send( new TemplateEmail( - $this->email_builder, - $this->invoice_invitation->contact->user, - $this->invoice_invitation->contact->client - ) + $this->email_builder, + $this->invoice_invitation->contact->user, + $this->invoice_invitation->contact->client + ) ); if (count(Mail::failures()) > 0) { diff --git a/app/Jobs/Quote/EmailQuote.php b/app/Jobs/Quote/EmailQuote.php index 503fafc8f541..ebbd5540c83e 100644 --- a/app/Jobs/Quote/EmailQuote.php +++ b/app/Jobs/Quote/EmailQuote.php @@ -50,10 +50,10 @@ class EmailQuote implements ShouldQueue Mail::to($this->quote_invitation->contact->email, $this->quote_invitation->contact->present()->name()) ->send( new TemplateEmail( - $this->email_builder, - $this->quote_invitation->contact->user, - $this->quote_invitation->contact->client - ) + $this->email_builder, + $this->quote_invitation->contact->user, + $this->quote_invitation->contact->client + ) ); if (count(Mail::failures()) > 0) { diff --git a/app/Jobs/Util/Import.php b/app/Jobs/Util/Import.php index edc953db013c..b0ca2ba05f26 100644 --- a/app/Jobs/Util/Import.php +++ b/app/Jobs/Util/Import.php @@ -283,9 +283,9 @@ class Import implements ShouldQueue $client = $client_repository->save( $modified, ClientFactory::create( - $this->company->id, - $modified['user_id'] - ) + $this->company->id, + $modified['user_id'] + ) ); if (array_key_exists('contacts', $resource)) { // need to remove after importing new migration.json @@ -342,9 +342,9 @@ class Import implements ShouldQueue $product_repository->save( $modified, ProductFactory::create( - $this->company->id, - $modified['user_id'] - ) + $this->company->id, + $modified['user_id'] + ) ); } diff --git a/app/Models/ClientContact.php b/app/Models/ClientContact.php index bdc9bda15ce9..7f1d837bd803 100644 --- a/app/Models/ClientContact.php +++ b/app/Models/ClientContact.php @@ -168,8 +168,9 @@ class ClientContact extends Authenticatable implements HasLocalePreference */ public function avatar() { - if($this->avatar) + if ($this->avatar) { return $this->avatar; + } return asset('images/svg/user.svg'); } diff --git a/app/Models/Company.php b/app/Models/Company.php index 4580d0850fcb..6eebd2459a31 100644 --- a/app/Models/Company.php +++ b/app/Models/Company.php @@ -299,13 +299,11 @@ class Company extends BaseModel public function getSetting($setting) { - if (property_exists($this->settings, $setting) != false) { return $this->settings->{$setting}; } return null; - } /** diff --git a/app/Models/Quote.php b/app/Models/Quote.php index 3875a5d4b802..ebd2236015c8 100644 --- a/app/Models/Quote.php +++ b/app/Models/Quote.php @@ -152,8 +152,7 @@ class Quote extends BaseModel { $storage_path = 'storage/' . $this->client->quote_filepath() . $this->number . '.pdf'; - if (Storage::exists($storage_path)) - { + if (Storage::exists($storage_path)) { return $storage_path; } @@ -198,7 +197,7 @@ class Quote extends BaseModel */ public function isApproved() { - if($this->status_id === $this::STATUS_APPROVED) { + if ($this->status_id === $this::STATUS_APPROVED) { return true; } diff --git a/app/Notifications/Admin/NewPartialPaymentNotification.php b/app/Notifications/Admin/NewPartialPaymentNotification.php index 53353cc0afc9..c7dfa01aa813 100644 --- a/app/Notifications/Admin/NewPartialPaymentNotification.php +++ b/app/Notifications/Admin/NewPartialPaymentNotification.php @@ -90,9 +90,9 @@ class NewPartialPaymentNotification extends Notification implements ShouldQueue return (new MailMessage) ->subject( ctrans( - 'texts.notification_partial_payment_paid_subject', - ['client' => $this->payment->client->present()->name()] - ) + 'texts.notification_partial_payment_paid_subject', + ['client' => $this->payment->client->present()->name()] + ) )->markdown('email.admin.generic', $data); } diff --git a/app/Notifications/Admin/NewPaymentNotification.php b/app/Notifications/Admin/NewPaymentNotification.php index c98e1859e634..6f7043aecb79 100644 --- a/app/Notifications/Admin/NewPaymentNotification.php +++ b/app/Notifications/Admin/NewPaymentNotification.php @@ -90,9 +90,9 @@ class NewPaymentNotification extends Notification implements ShouldQueue return (new MailMessage) ->subject( ctrans( - 'texts.notification_payment_paid_subject', - ['client' => $this->payment->client->present()->name(),] - ) + 'texts.notification_payment_paid_subject', + ['client' => $this->payment->client->present()->name(),] + ) )->markdown('email.admin.generic', $data); } diff --git a/app/Repositories/ActivityRepository.php b/app/Repositories/ActivityRepository.php index 88e7b2489011..27e6eb6e85ad 100644 --- a/app/Repositories/ActivityRepository.php +++ b/app/Repositories/ActivityRepository.php @@ -65,11 +65,8 @@ class ActivityRepository extends BaseRepository if (get_class($entity) == Client::class) { $entity->load('company'); - } - else if(get_class($entity) == User::class) { - - } - else { + } elseif (get_class($entity) == User::class) { + } else { $entity->load('company', 'client'); } diff --git a/app/Repositories/UserRepository.php b/app/Repositories/UserRepository.php index f2cfe4967a9c..f211b5f484e9 100644 --- a/app/Repositories/UserRepository.php +++ b/app/Repositories/UserRepository.php @@ -47,7 +47,6 @@ class UserRepository extends BaseRepository */ public function save(array $data, User $user) { - $company = auth()->user()->company(); $account_id = $company->account->id; @@ -56,8 +55,6 @@ class UserRepository extends BaseRepository $user->save(); if (isset($data['company_user'])) { - - $cu = CompanyUser::whereUserId($user->id)->whereCompanyId($company->id)->withTrashed()->first(); /*No company user exists - attach the user*/ @@ -66,7 +63,6 @@ class UserRepository extends BaseRepository $data['company_user']['notifications'] = CompanySettings::notificationDefaults(); $user->companies()->attach($company->id, $data['company_user']); } else { - $cu->fill($data['company_user']); $cu->restore(); $cu->tokens()->restore(); @@ -77,7 +73,6 @@ class UserRepository extends BaseRepository $query->whereCompanyId($company->id) ->whereUserId($user->id); }])->first(); - } $user->restore(); @@ -87,7 +82,6 @@ class UserRepository extends BaseRepository public function destroy(array $data, User $user) { if (array_key_exists('company_user', $data)) { - $this->forced_includes = 'company_users'; $company = auth()->user()->company(); diff --git a/app/Utils/Ninja.php b/app/Utils/Ninja.php index 6da562ad3a9d..5f2f35704fef 100644 --- a/app/Utils/Ninja.php +++ b/app/Utils/Ninja.php @@ -57,8 +57,9 @@ class Ninja public static function boot() { - if(self::isNinjaDev()) + if (self::isNinjaDev()) { return true; + } $data = [ 'license' => config('ninja.license'), diff --git a/app/Utils/SystemHealth.php b/app/Utils/SystemHealth.php index 862ca3f620aa..cb4b70313d26 100644 --- a/app/Utils/SystemHealth.php +++ b/app/Utils/SystemHealth.php @@ -51,12 +51,12 @@ class SystemHealth } return [ - 'system_health' => $system_health, + 'system_health' => (bool)$system_health, 'extensions' => self::extensions(), 'php_version' => phpversion(), 'min_php_version' => self::$php_version, - 'dbs' => self::dbCheck(), - 'mail' => self::testMailServer(), + //'dbs' => self::dbCheck(), + //'mail' => self::testMailServer(), 'env_writable' => self::checkEnvWritable(), ]; } diff --git a/app/Utils/TemplateEngine.php b/app/Utils/TemplateEngine.php new file mode 100644 index 000000000000..cd1d5e6b0220 --- /dev/null +++ b/app/Utils/TemplateEngine.php @@ -0,0 +1,184 @@ +body = $body; + + $this->subject = $subject; + + $this->entity = $entity; + + $this->entity_id = $entity_id; + + $this->template = $template; + + $this->entity_obj = null; + + $this->settings_entity = null; + + } + + public function build() + { + return $this->setEntity() + ->setSettingsObject() + ->setTemplates() + ->replaceValues() + ->renderTemplate(); + } + + private function setEntity() + { + if(strlen($this->entity) > 1 && strlen($this->entity_id) >1) + { + $class = 'App\Models\\'.ucfirst($this->entity); + $this->entity_obj = $class::whereId($this->decodePrimaryKey($this->entity_id))->company()->first(); + } + + return $this; + } + + private function setSettingsObject() + { + if ($this->entity_obj) { + $this->settings_entity = $this->entity_obj->client; + } else { + $this->settings_entity = auth()->user()->company(); + } + + return $this; + } + + /* If the body / subject are not populated we need to get the defaults */ + private function setTemplates() + { + if(strlen($this->subject) == 0 && strlen($this->template) > 1) + { + $subject_template = str_replace("template", "subject", $this->template); + $this->subject = EmailTemplateDefaults::getDefaultTemplate($subject_template, $this->settings_entity->locale()); + } + + if(strlen($this->body) == 0 && strlen($this->template) > 1) + { + $this->body = EmailTemplateDefaults::getDefaultTemplate($this->template, $this->settings_entity->locale()); + } + + return $this; + } + + private function replaceValues() + { + if($this->entity_obj) + $this->entityValues(); + else + $this->fakerValues(); + + return $this; + + } + + private function fakerValues() + { + + $labels = $this->makeFakerLabels(); + $values = $this->makeFakerValues(); + + $this->body = str_replace(array_keys($labels), array_values($labels), $this->body); + $this->body = str_replace(array_keys($values), array_values($values), $this->body); + + $this->subject = str_replace(array_keys($labels), array_values($labels), $this->subject); + $this->subject = str_replace(array_keys($values), array_values($values), $this->subject); + + $converter = new CommonMarkConverter([ + 'allow_unsafe_links' => false, + ]); + + $this->body = $converter->convertToHtml($this->body); + $this->subject = $converter->convertToHtml($this->subject); + + } + + private function entityValues() + { + $labels = $this->entity_obj->makeLabels(); + $values = $this->entity_obj->makeValues(); + + $this->body = str_replace(array_keys($labels), array_values($labels), $this->body); + $this->body = str_replace(array_keys($values), array_values($values), $this->body); + + $this->subject = str_replace(array_keys($labels), array_values($labels), $this->subject); + $this->subject = str_replace(array_keys($values), array_values($values), $this->subject); + + $converter = new CommonMarkConverter([ + 'allow_unsafe_links' => false, + ]); + + $this->body = $converter->convertToHtml($this->body); + $this->subject = $converter->convertToHtml($this->subject); + + } + + private function renderTemplate() + { + /* wrapper */ + $email_style = $this->settings_entity->getSetting('email_style'); + + $data['title'] = ''; + $data['body'] = '$body'; + $data['footer'] = ''; + + if ($email_style == 'custom') { + $wrapper = $this->settings_entity->getSetting('email_style_custom'); + $wrapper = $this->renderView($wrapper, $data); + } else { + $wrapper = $this->getTemplate(); + $wrapper = view($this->getTemplatePath($email_style), $data)->render(); + } + + + $data = [ + 'subject' => $this->subject, + 'body' => $this->body, + 'wrapper' => $wrapper, + ]; + + return $data; + } +} \ No newline at end of file diff --git a/app/Utils/Traits/AppSetup.php b/app/Utils/Traits/AppSetup.php index c880e96f6c25..9b60697b70e7 100644 --- a/app/Utils/Traits/AppSetup.php +++ b/app/Utils/Traits/AppSetup.php @@ -18,12 +18,12 @@ trait AppSetup { public function checkAppSetup() { - if (Ninja::isNinja()) { // Is this the invoice ninja production system? - return true; + if (Ninja::isNinja()) { // Is this the invoice ninja production system? + return Ninja::isNinja(); } + + $check = SystemHealth::check(); -\Log::error(SystemHealth::check()); - - return SystemHealth::check()['system_health']; // Do the system tests pass? + return settype($check['system_health'], "bool"); // Do the system tests pass? } } diff --git a/app/Utils/Traits/MakesInvoiceValues.php b/app/Utils/Traits/MakesInvoiceValues.php index 7d7c856a5c67..ea57ba4067aa 100644 --- a/app/Utils/Traits/MakesInvoiceValues.php +++ b/app/Utils/Traits/MakesInvoiceValues.php @@ -170,6 +170,7 @@ trait MakesInvoiceValues //$data['$paid_to_date'] = ; $data['$invoice.discount'] = ['value' => Number::formatMoney($this->calc()->getTotalDiscount(), $this->client) ?: ' ', 'label' => ctrans('texts.discount')]; + $data['$discount'] = &$data['$invoice.discount']; $data['$subtotal'] = ['value' => Number::formatMoney($this->calc()->getSubTotal(), $this->client) ?: ' ', 'label' => ctrans('texts.subtotal')]; $data['$invoice.subtotal'] = &$data['$subtotal']; $data['$invoice.balance_due'] = ['value' => Number::formatMoney($this->balance, $this->client) ?: ' ', 'label' => ctrans('texts.balance_due')]; @@ -197,12 +198,13 @@ trait MakesInvoiceValues // $data['$quote'] = ; // $data['$your_quote'] = ; // - $data['$quote_date'] = ['value' => $this->date ?: ' ', 'label' => ctrans('texts.quote_date')]; - $data['$quote_number'] = ['value' => $this->number ?: ' ', 'label' => ctrans('texts.quote_number')]; - $data['$quote.quote_number'] = &$data['$quote_number']; - $data['$quote_no'] = &$data['$quote_number']; - $data['$quote.quote_no'] = &$data['$quote_number']; - $data['$valid_until'] = ['value' => $this->due_date, 'label' => ctrans('texts.valid_until')]; + $data['$quote.date'] = ['value' => $this->date ?: ' ', 'label' => ctrans('texts.quote_date')]; + $data['$quote.number'] = ['value' => $this->number ?: ' ', 'label' => ctrans('texts.quote_number')]; + $data['$quote.po_number'] = &$data['$invoice.po_number']; + $data['$quote.quote_number'] = &$data['$quote.number']; + $data['$quote_no'] = &$data['$quote.number']; + $data['$quote.quote_no'] = &$data['$quote.number']; + $data['$quote.valid_until'] = ['value' => $this->due_date, 'label' => ctrans('texts.valid_until')]; $data['$credit_amount'] = ['value' => Number::formatMoney($this->calc()->getTotal(), $this->client) ?: ' ', 'label' => ctrans('texts.credit_amount')]; $data['$credit_balance'] = ['value' => Number::formatMoney($this->balance, $this->client) ?: ' ', 'label' => ctrans('texts.credit_balance')]; ; @@ -308,7 +310,7 @@ trait MakesInvoiceValues $data['$task.tax_name2'] = ['value' => '', 'label' => ctrans('texts.tax')]; $data['$task.tax_name3'] = ['value' => '', 'label' => ctrans('texts.tax')]; $data['$task.line_total'] = ['value' => '', 'label' => ctrans('texts.line_total')]; - //$data['$contact.signature'] + //$data['$contact.signature'] // $data['custom_label1'] = ['value' => '', 'label' => ctrans('texts.')]; // $data['custom_label2'] = ['value' => '', 'label' => ctrans('texts.')]; diff --git a/config/database.php b/config/database.php index d5dc85dbc2aa..1d338edd5dba 100644 --- a/config/database.php +++ b/config/database.php @@ -36,7 +36,7 @@ return [ // single database setup 'mysql' => [ 'driver' => 'mysql', - 'host' => env('DB_HOST1', 'localhost'), + 'host' => env('DB_HOST1', '127.0.0.1'), 'database' => env('DB_DATABASE1', 'forge'), 'username' => env('DB_USERNAME1', 'forge'), 'password' => env('DB_PASSWORD1', ''), @@ -70,7 +70,7 @@ return [ 'sqlsrv' => [ 'driver' => 'sqlsrv', - 'host' => env('DB_HOST', 'localhost'), + 'host' => env('DB_HOST', '127.0.0.1'), 'port' => env('DB_PORT', '1433'), 'database' => env('DB_DATABASE', 'forge'), 'username' => env('DB_USERNAME', 'forge'), @@ -82,7 +82,7 @@ return [ 'db-ninja-01' => [ 'driver' => 'mysql', - 'host' => env('DB_HOST1', env('DB_HOST', 'localhost')), + 'host' => env('DB_HOST1', env('DB_HOST', '127.0.0.1')), 'database' => env('DB_DATABASE1', env('DB_DATABASE', 'forge')), 'username' => env('DB_USERNAME1', env('DB_USERNAME', 'forge')), 'password' => env('DB_PASSWORD1', env('DB_PASSWORD', '')), @@ -97,7 +97,7 @@ return [ 'db-ninja-02' => [ 'driver' => 'mysql', - 'host' => env('DB_HOST2', env('DB_HOST', 'localhost')), + 'host' => env('DB_HOST2', env('DB_HOST', '127.0.0.1')), 'database' => env('DB_DATABASE2', env('DB_DATABASE', 'forge')), 'username' => env('DB_USERNAME2', env('DB_USERNAME', 'forge')), 'password' => env('DB_PASSWORD2', env('DB_PASSWORD', '')), diff --git a/routes/client.php b/routes/client.php index 43ed5c29c0f8..68e6e7bd132e 100644 --- a/routes/client.php +++ b/routes/client.php @@ -14,54 +14,51 @@ Route::post('client/password/reset', 'Auth\ContactResetPasswordController@reset' //todo implement domain DB Route::group(['middleware' => ['auth:contact','locale'], 'prefix' => 'client', 'as' => 'client.'], function () { + Route::get('dashboard', 'ClientPortal\DashboardController@index')->name('dashboard'); // name = (dashboard. index / create / show / update / destroy / edit - Route::get('dashboard', 'ClientPortal\DashboardController@index')->name('dashboard'); // name = (dashboard. index / create / show / update / destroy / edit + Route::get('invoices', 'ClientPortal\InvoiceController@index')->name('invoices.index')->middleware('portal_enabled'); + Route::post('invoices/payment', 'ClientPortal\InvoiceController@bulk')->name('invoices.bulk'); + Route::get('invoices/{invoice}', 'ClientPortal\InvoiceController@show')->name('invoice.show'); + Route::get('invoices/{invoice_invitation}', 'ClientPortal\InvoiceController@show')->name('invoice.show_invitation'); - Route::get('invoices', 'ClientPortal\InvoiceController@index')->name('invoices.index')->middleware('portal_enabled'); - Route::post('invoices/payment', 'ClientPortal\InvoiceController@bulk')->name('invoices.bulk'); - Route::get('invoices/{invoice}', 'ClientPortal\InvoiceController@show')->name('invoice.show'); - Route::get('invoices/{invoice_invitation}', 'ClientPortal\InvoiceController@show')->name('invoice.show_invitation'); + Route::get('recurring_invoices', 'ClientPortal\RecurringInvoiceController@index')->name('recurring_invoices.index')->middleware('portal_enabled'); + Route::get('recurring_invoices/{recurring_invoice}', 'ClientPortal\RecurringInvoiceController@show')->name('recurring_invoices.show'); + Route::get('recurring_invoices/{recurring_invoice}/request_cancellation', 'ClientPortal\RecurringInvoiceController@requestCancellation')->name('recurring_invoices.request_cancellation'); - Route::get('recurring_invoices', 'ClientPortal\RecurringInvoiceController@index')->name('recurring_invoices.index')->middleware('portal_enabled'); - Route::get('recurring_invoices/{recurring_invoice}', 'ClientPortal\RecurringInvoiceController@show')->name('recurring_invoices.show'); - Route::get('recurring_invoices/{recurring_invoice}/request_cancellation', 'ClientPortal\RecurringInvoiceController@requestCancellation')->name('recurring_invoices.request_cancellation'); + Route::post('payments/process', 'ClientPortal\PaymentController@process')->name('payments.process'); + Route::get('payments', 'ClientPortal\PaymentController@index')->name('payments.index')->middleware('portal_enabled'); + Route::get('payments/{payment}', 'ClientPortal\PaymentController@show')->name('payments.show'); + Route::post('payments/process/response', 'ClientPortal\PaymentController@response')->name('payments.response'); + Route::get('payments/process/response', 'ClientPortal\PaymentController@response')->name('payments.response.get'); - Route::post('payments/process', 'ClientPortal\PaymentController@process')->name('payments.process'); - Route::get('payments', 'ClientPortal\PaymentController@index')->name('payments.index')->middleware('portal_enabled'); - Route::get('payments/{payment}', 'ClientPortal\PaymentController@show')->name('payments.show'); - Route::post('payments/process/response', 'ClientPortal\PaymentController@response')->name('payments.response'); - Route::get('payments/process/response', 'ClientPortal\PaymentController@response')->name('payments.response.get'); + Route::get('profile/{client_contact}/edit', 'ClientPortal\ProfileController@edit')->name('profile.edit'); + Route::put('profile/{client_contact}/edit', 'ClientPortal\ProfileController@update')->name('profile.update'); + Route::put('profile/{client_contact}/edit_client', 'ClientPortal\ProfileController@updateClient')->name('profile.edit_client'); + Route::put('profile/{client_contact}/localization', 'ClientPortal\ProfileController@updateClientLocalization')->name('profile.edit_localization'); - Route::get('profile/{client_contact}/edit', 'ClientPortal\ProfileController@edit')->name('profile.edit'); - Route::put('profile/{client_contact}/edit', 'ClientPortal\ProfileController@update')->name('profile.update'); - Route::put('profile/{client_contact}/edit_client', 'ClientPortal\ProfileController@updateClient')->name('profile.edit_client'); - Route::put('profile/{client_contact}/localization', 'ClientPortal\ProfileController@updateClientLocalization')->name('profile.edit_localization'); - - Route::resource('payment_methods', 'ClientPortal\PaymentMethodController');// name = (payment_methods. index / create / show / update / destroy / edit + Route::resource('payment_methods', 'ClientPortal\PaymentMethodController');// name = (payment_methods. index / create / show / update / destroy / edit Route::match(['GET', 'POST'], 'quotes/approve', 'ClientPortal\QuoteController@bulk')->name('quotes.bulk'); Route::resource('quotes', 'ClientPortal\QuoteController')->only('index', 'show'); Route::resource('credits', 'ClientPortal\CreditController')->only('index', 'show'); - Route::post('document', 'ClientPortal\DocumentController@store')->name('document.store'); - Route::delete('document', 'ClientPortal\DocumentController@destroy')->name('document.destroy'); + Route::post('document', 'ClientPortal\DocumentController@store')->name('document.store'); + Route::delete('document', 'ClientPortal\DocumentController@destroy')->name('document.destroy'); - Route::get('logout', 'Auth\ContactLoginController@logout')->name('logout'); + Route::get('logout', 'Auth\ContactLoginController@logout')->name('logout'); }); Route::group(['middleware' => ['invite_db'], 'prefix' => 'client', 'as' => 'client.'], function () { + Route::get('invoice/{invitation_key}/download_pdf', 'InvoiceController@downloadPdf'); + Route::get('quote/{invitation_key}/download_pdf', 'QuoteController@downloadPdf'); + Route::get('credit/{invitation_key}/download_pdf', 'CreditController@downloadPdf'); + Route::get('{entity}/{invitation_key}/download', 'ClientPortal\InvitationController@routerForDownload'); - Route::get('invoice/{invitation_key}/download_pdf', 'InvoiceController@downloadPdf'); - Route::get('quote/{invitation_key}/download_pdf', 'QuoteController@downloadPdf'); - Route::get('credit/{invitation_key}/download_pdf', 'CreditController@downloadPdf'); - Route::get('{entity}/{invitation_key}/download', 'ClientPortal\InvitationController@routerForDownload'); - - /*Invitation catches*/ - Route::get('{entity}/{invitation_key}','ClientPortal\InvitationController@router'); - Route::get('{entity}/{client_hash}/{invitation_key}','ClientPortal\InvitationController@routerForIframe'); //should never need this - Route::get('payment_hook/{company_gateway_id}/{gateway_type_id}','ClientPortal\PaymentHookController@process'); - + /*Invitation catches*/ + Route::get('{entity}/{invitation_key}', 'ClientPortal\InvitationController@router'); + Route::get('{entity}/{client_hash}/{invitation_key}', 'ClientPortal\InvitationController@routerForIframe'); //should never need this + Route::get('payment_hook/{company_gateway_id}/{gateway_type_id}', 'ClientPortal\PaymentHookController@process'); }); Route::fallback('BaseController@notFoundClient'); diff --git a/routes/web.php b/routes/web.php index d48524d2109a..9e745cf350b2 100644 --- a/routes/web.php +++ b/routes/web.php @@ -5,6 +5,8 @@ Route::get('/', 'BaseController@flutterRoute')->middleware('guest'); Route::get('setup', 'SetupController@index')->middleware('guest'); +Route::post('setup/check_db', 'SetupController@check_db')->middleware('guest'); +Route::post('setup/check_mail', 'SetupController@check_mail')->middleware('guest'); Route::post('setup', 'SetupController@doSetup')->middleware('guest'); /* diff --git a/tests/Unit/GeneratesCounterTest.php b/tests/Unit/GeneratesCounterTest.php index 2dcf971ecf3d..99e569510afe 100644 --- a/tests/Unit/GeneratesCounterTest.php +++ b/tests/Unit/GeneratesCounterTest.php @@ -287,7 +287,7 @@ class GeneratesCounterTest extends TestCase $this->assertEquals($client_number, date('Y') . '-' . str_pad($this->client->user_id, 2, '0', STR_PAD_LEFT) . '-0002'); } /* - + public function testClientNextNumber() { $this->assertEquals($this->getNextNumber($this->client),1); @@ -296,7 +296,7 @@ class GeneratesCounterTest extends TestCase { //$this->assertEquals($this->getNextNumber(RecurringInvoice::class), 'R1'); $this->assertEquals($this->getCounter($this->client), 1); - + } public function testClientIncrementer() { @@ -319,7 +319,7 @@ class GeneratesCounterTest extends TestCase $this->assertEquals($this->getCounter(RecurringInvoice::class), 3); $this->assertEquals($this->getCounter(Credit::class), 2); } - + public function testClientNumberPattern() { $settings = $this->client->getSettingsByKey('client_number_pattern'); @@ -329,7 +329,7 @@ class GeneratesCounterTest extends TestCase $this->assertEquals($company->settings->client_number_counter,1); $this->assertEquals($this->getNextNumber($this->client), date('y').'-1'); $this->assertEquals($this->getNextNumber($this->client), date('y').'-2'); - + $company = Company::find($this->client->company_id); $this->assertEquals($company->settings->client_number_counter,2); $this->assertEquals($this->client->settings->client_number_counter,1); @@ -340,7 +340,7 @@ class GeneratesCounterTest extends TestCase $settings = $this->client->getSettingsByKey('client_number_pattern'); $settings->client_number_pattern = '{$date:j}-{$counter}'; $this->client->setSettingsByEntity(Client::class, $settings); - + $this->assertEquals($this->getNextNumber($this->client), date('j') . '-1'); } public function testClientNumberPatternWithDate2() @@ -349,7 +349,7 @@ class GeneratesCounterTest extends TestCase $settings = $this->client->getSettingsByKey('client_number_pattern'); $settings->client_number_pattern = '{$date:d M Y}-{$counter}'; $this->client->setSettingsByEntity(Client::class, $settings); - + $this->assertEquals($this->getNextNumber($this->client), date('d M Y') . '-1'); } */ diff --git a/tests/Unit/MakesInvoiceValuesTest.php b/tests/Unit/MakesInvoiceValuesTest.php index e7b4d339a4c4..ecd5dde41ea0 100644 --- a/tests/Unit/MakesInvoiceValuesTest.php +++ b/tests/Unit/MakesInvoiceValuesTest.php @@ -15,16 +15,16 @@ class MakesInvoiceValuesTest extends TestCase $columns = ['custom_invoice_label3']; $columns = str_replace( - ['custom_invoice_label1', + ['custom_invoice_label1', 'custom_invoice_label2', 'custom_invoice_label3', 'custom_invoice_label4'], - ['custom_invoice_value1', + ['custom_invoice_value1', 'custom_invoice_value2', 'custom_invoice_value3', 'custom_invoice_value4'], - $columns - ); + $columns + ); $this->assertTrue(in_array("custom_invoice_value3", $columns));