Implement Github actions (#3547)

* Update phpunit.yml

* Update phpunit.yml

* Update .env.ci

* Update phpunit.yml

* Update .env.ci

* Update phpunit.yml

* Update phpunit.yml

* Update phpunit.yml

* Update phpunit.yml

* Update .env.ci

* Update phpunit.yml

* Update phpunit.yml

* Update phpunit.yml

* Update phpunit.yml

* Force /setup if system requirements are not met

* Update .env.ci

* Update phpunit.yml

* Minor changes for github actions"

* Fixes for github actions

* Fixes for github actions

* Fixes for github actions

* Fixes for github actions

* Fixes for github actions

* Fixes for github actions

* Fixes for github actions

* Fixes for github actions

* cs-fixer

* cs-fixer

* Fixes for github actions

* db ports github actions

* Refactor the template engine
This commit is contained in:
David Bomba 2020-03-26 14:23:57 +11:00 committed by GitHub
parent 4729a3841b
commit 6a7079b0be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 453 additions and 244 deletions

View File

@ -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 }}"}}'

View File

@ -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] }}

View File

@ -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);
}
}

View File

@ -72,7 +72,6 @@ class SendTestEmails extends Command
if (!$user) {
$account = factory(\App\Models\Account::class)->create();
$user = factory(\App\Models\User::class)->create([

View File

@ -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();
}
}
/**

View File

@ -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;

View File

@ -11,7 +11,7 @@
namespace App\Designs;
class Custom extends AbstractDesign
class Custom
{
public $includes;

View File

@ -269,13 +269,13 @@ class Designer
private function invoiceDetails(Company $company)
{
$data = [
'$invoice.invoice_number' => '<span>$invoice_number_label</span><span>$invoice_number</span>',
'$invoice.po_number' => '<span>$po_number_label</span><span>$po_number</span>',
'$invoice.invoice_date' => '<span>$invoice_date_label</span><span>$invoice_date</span>',
'$invoice.due_date' => '<span>$due_date_label</span><span>$due_date</span>',
'$invoice.balance_due' => '<span>$balance_due_label</span><span>$balance_due</span>',
'$invoice.invoice_total' => '<span>$invoice_total_label</span><span>$invoice_total</span>',
'$invoice.partial_due' => '<span>$partial_due_label</span><span>$partial_due</span>',
'$invoice.invoice_number' => '<span>$invoice.number_label</span><span>$invoice.number</span>',
'$invoice.po_number' => '<span>$invoice.po_number_label</span><span>$invoice.po_number</span>',
'$invoice.invoice_date' => '<span>$invoice.date_label</span><span>$invoice.date</span>',
'$invoice.due_date' => '<span>$invoice.due_date_label</span><span>$invoice.due_date</span>',
'$invoice.balance_due' => '<span>$invoice.balance_due_label</span><span>$invoice.balance_due</span>',
'$invoice.invoice_total' => '<span>$invoice.total_label</span><span>$invoice.total</span>',
'$invoice.partial_due' => '<span>$invoice.partial_due_label</span><span>$invoice.partial_due</span>',
'$invoice.invoice1' => '<span>$invoice1_label</span><span>$invoice1</span>',
'$invoice.invoice2' => '<span>$invoice2_label</span><span>$invoice2</span>',
'$invoice.invoice3' => '<span>$invoice3_label</span><span>$invoice3</span>',
@ -292,13 +292,13 @@ class Designer
private function quoteDetails(Company $company)
{
$data = [
'$quote.quote_number' => '<span>$quote_number</span>',
'$quote.po_number' => '<span>$po_number</span>',
'$quote.quote_date' => '<span>$date</span>',
'$quote.valid_until' => '<span>$valid_until</span>',
'$quote.balance_due' => '<span>$balance_due</span>',
'$quote.quote_total' => '<span>$quote_total</span>',
'$quote.partial_due' => '<span>$partial_due</span>',
'$quote.quote_number' => '<span>$quote.number</span>',
'$quote.po_number' => '<span>$quote.po_number</span>',
'$quote.quote_date' => '<span>$quote.date</span>',
'$quote.valid_until' => '<span>$quote.valid_until</span>',
'$quote.balance_due' => '<span>$quote.balance_due</span>',
'$quote.quote_total' => '<span>$quote.total</span>',
'$quote.partial_due' => '<span>$quote.partial_due</span>',
'$quote.quote1' => '<span>$quote1</span>',
'$quote.quote2' => '<span>$quote2</span>',
'$quote.quote3' => '<span>$quote3</span>',
@ -315,16 +315,16 @@ class Designer
private function creditDetails(Company $company)
{
$data = [
'$credit.credit_number' => '<span>$credit_number</span>',
'$credit.po_number' => '<span>$po_number</span>',
'$credit.credit_date' => '<span>$date</span>',
'$credit.credit_balance' => '<span>$credit_balance</span>',
'$credit.credit_amount' => '<span>$credit_amount</span>',
'$credit.partial_due' => '<span>$partial_due</span>',
'$credit.invoice1' => '<span>$invoice1</span>',
'$credit.invoice2' => '<span>$invoice2</span>',
'$credit.invoice3' => '<span>$invoice3</span>',
'$credit.invoice4' => '<span>$invoice4</span>',
'$credit.credit_number' => '<span>$credit.number</span>',
'$credit.po_number' => '<span>$credit.po_number</span>',
'$credit.credit_date' => '<span>$credit.date</span>',
'$credit.credit_balance' => '<span>$credit.balance</span>',
'$credit.credit_amount' => '<span>$credit.amount</span>',
'$credit.partial_due' => '<span>$credit.partial_due</span>',
'$credit.credit1' => '<span>$credit1</span>',
'$credit.credit2' => '<span>$credit2</span>',
'$credit.credit3' => '<span>$credit3</span>',
'$credit.credit4' => '<span>$credit4</span>',
'$credit.surcharge1' => '<span>$surcharge1</span>',
'$credit.surcharge2' => '<span>$surcharge2</span>',
'$credit.surcharge3' => '<span>$surcharge3</span>',

View File

@ -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);

View File

@ -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');
}
}

View File

@ -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');

View File

@ -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();

View File

@ -99,7 +99,6 @@ class QuoteController extends Controller
}
if ($process) {
foreach ($quotes as $quote) {
$quote->service()->approve()->save();
}

View File

@ -25,5 +25,4 @@ class PingController extends BaseController
{
return response()->json('success', 200);
}
}

View File

@ -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);
}
}

View File

@ -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) {
}
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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) {

View File

@ -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) {

View File

@ -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']
)
);
}

View File

@ -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');
}

View File

@ -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;
}
/**

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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');
}

View File

@ -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();

View File

@ -57,8 +57,9 @@ class Ninja
public static function boot()
{
if(self::isNinjaDev())
if (self::isNinjaDev()) {
return true;
}
$data = [
'license' => config('ninja.license'),

View File

@ -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(),
];
}

View File

@ -0,0 +1,184 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com)
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Utils;
use App\DataMapper\EmailTemplateDefaults;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\MakesInvoiceHtml;
use App\Utils\Traits\MakesTemplateData;
use League\CommonMark\CommonMarkConverter;
class TemplateEngine
{
use MakesHash;
use MakesTemplateData;
use MakesInvoiceHtml;
public $body;
public $subject;
public $entity;
public $entity_id;
public $template;
private $entity_obj;
private $settings_entity;
function __construct($body, $subject, $entity, $entity_id, $template)
{
$this->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;
}
}

View File

@ -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?
}
}

View File

@ -170,6 +170,7 @@ trait MakesInvoiceValues
//$data['$paid_to_date'] = ;
$data['$invoice.discount'] = ['value' => Number::formatMoney($this->calc()->getTotalDiscount(), $this->client) ?: '&nbsp;', 'label' => ctrans('texts.discount')];
$data['$discount'] = &$data['$invoice.discount'];
$data['$subtotal'] = ['value' => Number::formatMoney($this->calc()->getSubTotal(), $this->client) ?: '&nbsp;', 'label' => ctrans('texts.subtotal')];
$data['$invoice.subtotal'] = &$data['$subtotal'];
$data['$invoice.balance_due'] = ['value' => Number::formatMoney($this->balance, $this->client) ?: '&nbsp;', 'label' => ctrans('texts.balance_due')];
@ -197,12 +198,13 @@ trait MakesInvoiceValues
// $data['$quote'] = ;
// $data['$your_quote'] = ;
//
$data['$quote_date'] = ['value' => $this->date ?: '&nbsp;', 'label' => ctrans('texts.quote_date')];
$data['$quote_number'] = ['value' => $this->number ?: '&nbsp;', '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 ?: '&nbsp;', 'label' => ctrans('texts.quote_date')];
$data['$quote.number'] = ['value' => $this->number ?: '&nbsp;', '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) ?: '&nbsp;', 'label' => ctrans('texts.credit_amount')];
$data['$credit_balance'] = ['value' => Number::formatMoney($this->balance, $this->client) ?: '&nbsp;', '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.')];

View File

@ -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', '')),

View File

@ -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');

View File

@ -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');
/*

View File

@ -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');
}
*/

View File

@ -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));