diff --git a/.env.ci b/.env.ci index ef00aa84d077..8379aa8781e6 100644 --- a/.env.ci +++ b/.env.ci @@ -18,3 +18,4 @@ DB_PASSWORD=ninja DB_HOST=127.0.0.1 NINJA_ENVIRONMENT=development COMPOSER_AUTH='{"github-oauth": {"github.com": "${{ secrets.GITHUB_TOKEN }}"}}' +TRAVIS=true \ No newline at end of file diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index bb0c4f6f83b5..b3ea42dc829e 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -22,7 +22,8 @@ jobs: SESSION_DRIVER: file NINJA_ENVIRONMENT: development MULTI_DB_ENABLED: false - + TRAVIS: true + services: mariadb: image: mariadb:latest diff --git a/app/Designs/Designer.php b/app/Designs/Designer.php index 4c5a3ab00d76..73bf62c9b5f1 100644 --- a/app/Designs/Designer.php +++ b/app/Designs/Designer.php @@ -235,7 +235,7 @@ class Designer private function companyDetails(Company $company) { $data = [ - '$company.company_name' => '$company.company_name', + '$company.name' => '$company.name', '$company.id_number' => '$company.id_number', '$company.vat_number' => '$company.vat_number', '$company.website' => '$company.website', diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index e139bd9d6723..5c9357ca75d2 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -23,6 +23,8 @@ use Symfony\Component\Debug\Exception\FatalThrowableError; use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Illuminate\Database\Eloquent\RelationNotFoundException; +use Sentry\State\Scope; +use function Sentry\configureScope; class Handler extends ExceptionHandler { @@ -53,8 +55,23 @@ class Handler extends ExceptionHandler */ public function report(Exception $exception) { + if (app()->bound('sentry') && $this->shouldReport($exception)) { + + app('sentry')->configureScope(function (Scope $scope): void { + + if (auth()->user() && auth()->user()->account->report_errors) { + $scope->setUser([ + 'id' => auth()->user()->account->key, + 'email' => auth()->user()->email, + 'name' => "Anonymous User", + ]); + } + + }); + app('sentry')->captureException($exception); + } parent::report($exception); diff --git a/app/Factory/InvoiceItemFactory.php b/app/Factory/InvoiceItemFactory.php index edf3e19f8d05..cdb29f3247ff 100644 --- a/app/Factory/InvoiceItemFactory.php +++ b/app/Factory/InvoiceItemFactory.php @@ -34,7 +34,6 @@ class InvoiceItemFactory $item->tax_rate3 = 0; $item->sort_id = 0; $item->line_total = 0; - $item->date = Carbon::now(); $item->custom_value1 = null; $item->custom_value2 = null; $item->custom_value3 = null; diff --git a/app/Http/Controllers/EmailController.php b/app/Http/Controllers/EmailController.php index 3832d25d71af..bb573a764fcd 100644 --- a/app/Http/Controllers/EmailController.php +++ b/app/Http/Controllers/EmailController.php @@ -11,7 +11,10 @@ namespace App\Http\Controllers; +use App\Helpers\Email\InvoiceEmail; use App\Http\Requests\Email\SendEmailRequest; +use App\Jobs\Invoice\EmailInvoice; +use App\Notifications\SendGenericNotification; use App\Utils\Traits\MakesHash; class EmailController extends BaseController @@ -94,6 +97,24 @@ class EmailController extends BaseController */ public function send(SendEmailRequest $request) { + $entity = $request->input('entity'); + $entity_obj = $entity::find($request->input('entity_id')); + $subject = $request->input('subject'); + $body = $request->input('body'); + $entity_string = strtolower(class_basename($entity_obj)); + + $entity_obj->invitations->each(function ($invitation) use($subject, $body, $entity_string, $entity_obj) { + + if ($invitation->contact->send_email && $invitation->contact->email) { + + $when = now()->addSeconds(1); + + $invitation->contact->notify((new SendGenericNotification($invitation, $entity_string, $subject, $body))->delay($when)); + + } + + }); + $data = []; return response()->json($data, 200); diff --git a/app/Http/Controllers/SetupController.php b/app/Http/Controllers/SetupController.php index 2113127fffb8..e03a365b47e0 100644 --- a/app/Http/Controllers/SetupController.php +++ b/app/Http/Controllers/SetupController.php @@ -128,10 +128,11 @@ class SetupController extends Controller try { SystemHealth::testMailServer(); - $randomStatus = rand(0, 1); + $randomStatus = rand(0, 1); - if ($randomStatus) { - return response([], 200); + if ($randomStatus) + return response([], 200); + } catch (\Exception $e) { info(['action' => 'SetupController::checkMail()', 'message' => $e->getMessage(),]); diff --git a/app/Http/Requests/Email/SendEmailRequest.php b/app/Http/Requests/Email/SendEmailRequest.php index 55ba254f2a59..b7bab220cca2 100644 --- a/app/Http/Requests/Email/SendEmailRequest.php +++ b/app/Http/Requests/Email/SendEmailRequest.php @@ -12,9 +12,11 @@ namespace App\Http\Requests\Email; use App\Http\Requests\Request; +use App\Utils\Traits\MakesHash; class SendEmailRequest extends Request { + use MakesHash; /** * Determine if the user is authorized to make this request. @@ -48,9 +50,15 @@ class SendEmailRequest extends Request $settings = auth()->user()->company()->settings; - if(!property_exists($settings, $template)) + if(empty($input['template'])) + $input['template'] = ''; + + if(!property_exists($settings, $input['template'])) unset($input['template']); + $input['entity_id'] = $this->decodePrimaryKey($input['entity_id']); + $input['entity'] = "App\Models\\". ucfirst($input['entity']); + $this->replace($input); } @@ -66,16 +74,14 @@ class SendEmailRequest extends Request $input = $this->all(); /*Make sure we have all the require ingredients to send a template*/ - if(array_key_exists('entity', $input) && array_key_exists('entity_id', $input) && is_string($input['entity']) && is_string($input['entity_id'])) { + if(array_key_exists('entity', $input) && array_key_exists('entity_id', $input) && is_string($input['entity']) && $input['entity_id']) { $company = auth()->user()->company(); - $entity = ucfirst($input['entity']); - - $class = "App\Models\\$entity"; + $entity = $input['entity']; /* Harvest the entity*/ - $entity_obj = $class::whereId($this->decodePrimaryKey($input['entity_id']))->company()->first(); + $entity_obj = $entity::whereId($input['entity_id'])->company()->first(); /* Check object, check user and company id is same as users, and check user can edit the object */ if($entity_obj && ($company->id == $entity_obj->company_id) && auth()->user()->can('edit', $entity_obj)) diff --git a/app/Jobs/Account/CreateAccount.php b/app/Jobs/Account/CreateAccount.php index 1bdbeb0abac9..65c6a4ccbd44 100644 --- a/app/Jobs/Account/CreateAccount.php +++ b/app/Jobs/Account/CreateAccount.php @@ -35,6 +35,10 @@ class CreateAccount } $sp794f3f = Account::create($this->request); $sp794f3f->referral_code = Str::random(32); + + if(!$sp794f3f->key) + $sp794f3f->key = Str::random(32); + $sp794f3f->save(); $sp035a66 = CreateCompany::dispatchNow($this->request, $sp794f3f); diff --git a/app/Models/ClientContact.php b/app/Models/ClientContact.php index 7f1d837bd803..5b82b489c2cc 100644 --- a/app/Models/ClientContact.php +++ b/app/Models/ClientContact.php @@ -149,6 +149,10 @@ class ClientContact extends Authenticatable implements HasLocalePreference //return $lang->locale; } + public function routeNotificationForMail($notification) + { + return $this->email; + } /** * Retrieve the model for a bound value. diff --git a/app/Models/Credit.php b/app/Models/Credit.php index efe3b91b77de..d9203a462c2b 100644 --- a/app/Models/Credit.php +++ b/app/Models/Credit.php @@ -41,6 +41,7 @@ class Credit extends BaseModel 'po_number', 'date', 'due_date', + 'partial_due_date', 'terms', 'public_notes', 'private_notes', @@ -54,7 +55,6 @@ class Credit extends BaseModel 'is_amount_discount', 'footer', 'partial', - 'partial_due_date', 'custom_value1', 'custom_value2', 'custom_value3', @@ -78,6 +78,30 @@ class Credit extends BaseModel const STATUS_PARTIAL = 3; const STATUS_APPLIED = 4; + public function getDateAttribute($value) { + if (!$value) { + //$value format 'Y:m:d H:i:s' to 'Y-m-d H:i' + return (new Carbon($value))->format('Y-m-d'); + } + return $value; + } + + public function getDueDateAttribute($value) { + if (!$value) { + //$value format 'Y:m:d H:i:s' to 'Y-m-d H:i' + return (new Carbon($value))->format('Y-m-d'); + } + return $value; + } + + public function getPartialDueDateAttribute($value) { + if (!$value) { + //$value format 'Y:m:d H:i:s' to 'Y-m-d H:i' + return (new Carbon($value))->format('Y-m-d'); + } + return $value; + } + public function assigned_user() { return $this->belongsTo(User::class, 'assigned_user_id', 'id'); diff --git a/app/Models/CreditInvitation.php b/app/Models/CreditInvitation.php index 5462c797d29b..aabd03b3a6a9 100644 --- a/app/Models/CreditInvitation.php +++ b/app/Models/CreditInvitation.php @@ -33,6 +33,34 @@ class CreditInvitation extends BaseModel // 'company', ]; + public function getSignatureDateAttribute($value) { + if (!$value) { + return (new Carbon($value))->format('Y-m-d'); + } + return $value; + } + + public function getSentDateAttribute($value) { + if (!$value) { + return (new Carbon($value))->format('Y-m-d'); + } + return $value; + } + + public function getViewedDateAttribute($value) { + if (!$value) { + return (new Carbon($value))->format('Y-m-d'); + } + return $value; + } + + public function getOpenedDateAttribute($value) { + if (!$value) { + return (new Carbon($value))->format('Y-m-d'); + } + return $value; + } + public function entityType() { return Credit::class; diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php index f2debf5f29e4..b16eb8ccd7a5 100644 --- a/app/Models/Invoice.php +++ b/app/Models/Invoice.php @@ -128,6 +128,27 @@ class Invoice extends BaseModel const STATUS_UNPAID = -2; const STATUS_REVERSED = -3; + public function getDateAttribute($value) { + if (!$value) { + return (new Carbon($value))->format('Y-m-d'); + } + return $value; + } + + public function getDueDateAttribute($value) { + if (!$value) { + return (new Carbon($value))->format('Y-m-d'); + } + return $value; + } + + public function getPartialDueDateAttribute($value) { + if (!$value) { + return (new Carbon($value))->format('Y-m-d'); + } + return $value; + } + public function company() { return $this->belongsTo(Company::class); diff --git a/app/Models/InvoiceInvitation.php b/app/Models/InvoiceInvitation.php index 2eb907aa56e1..95cea4b983fb 100644 --- a/app/Models/InvoiceInvitation.php +++ b/app/Models/InvoiceInvitation.php @@ -33,6 +33,35 @@ class InvoiceInvitation extends BaseModel // 'company', ]; + + public function getSignatureDateAttribute($value) { + if (!$value) { + return (new Carbon($value))->format('Y-m-d'); + } + return $value; + } + + public function getSentDateAttribute($value) { + if (!$value) { + return (new Carbon($value))->format('Y-m-d'); + } + return $value; + } + + public function getViewedDateAttribute($value) { + if (!$value) { + return (new Carbon($value))->format('Y-m-d'); + } + return $value; + } + + public function getOpenedDateAttribute($value) { + if (!$value) { + return (new Carbon($value))->format('Y-m-d'); + } + return $value; + } + public function entityType() { return Invoice::class ; diff --git a/app/Models/Quote.php b/app/Models/Quote.php index ebd2236015c8..54d0d8bbed37 100644 --- a/app/Models/Quote.php +++ b/app/Models/Quote.php @@ -70,6 +70,9 @@ class Quote extends BaseModel ]; protected $casts = [ + 'date' => 'date:Y-m-d', + 'due_date' => 'date:Y-m-d', + 'partial_due_date' => 'date:Y-m-d', 'line_items' => 'object', 'updated_at' => 'timestamp', 'created_at' => 'timestamp', @@ -81,6 +84,27 @@ class Quote extends BaseModel const STATUS_APPROVED = 3; const STATUS_EXPIRED = -1; + public function getDateAttribute($value) { + if (!$value) { + return (new Carbon($value))->format('Y-m-d'); + } + return $value; + } + + public function getDueDateAttribute($value) { + if (!$value) { + return (new Carbon($value))->format('Y-m-d'); + } + return $value; + } + + public function getPartialDueDateAttribute($value) { + if (!$value) { + return (new Carbon($value))->format('Y-m-d'); + } + return $value; + } + public function company() { return $this->belongsTo(Company::class); diff --git a/app/Models/QuoteInvitation.php b/app/Models/QuoteInvitation.php index 97b0c19bc01b..f23b75ae7e24 100644 --- a/app/Models/QuoteInvitation.php +++ b/app/Models/QuoteInvitation.php @@ -15,6 +15,7 @@ use App\Models\Quote; use App\Utils\Traits\Inviteable; use App\Utils\Traits\MakesDates; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Carbon; class QuoteInvitation extends BaseModel { @@ -26,6 +27,34 @@ class QuoteInvitation extends BaseModel 'client_contact_id', ]; + public function getSignatureDateAttribute($value) { + if (!$value) { + return (new Carbon($value))->format('Y-m-d'); + } + return $value; + } + + public function getSentDateAttribute($value) { + if (!$value) { + return (new Carbon($value))->format('Y-m-d'); + } + return $value; + } + + public function getViewedDateAttribute($value) { + if (!$value) { + return (new Carbon($value))->format('Y-m-d'); + } + return $value; + } + + public function getOpenedDateAttribute($value) { + if (!$value) { + return (new Carbon($value))->format('Y-m-d'); + } + return $value; + } + public function entityType() { return Quote::class; diff --git a/app/Models/RecurringInvoice.php b/app/Models/RecurringInvoice.php index 88bf81552441..0cc36d640e2f 100644 --- a/app/Models/RecurringInvoice.php +++ b/app/Models/RecurringInvoice.php @@ -111,6 +111,27 @@ class RecurringInvoice extends BaseModel 'status' ]; + public function getDateAttribute($value) { + if (!$value) { + return (new Carbon($value))->format('Y-m-d'); + } + return $value; + } + + public function getDueDateAttribute($value) { + if (!$value) { + return (new Carbon($value))->format('Y-m-d'); + } + return $value; + } + + public function getPartialDueDateAttribute($value) { + if (!$value) { + return (new Carbon($value))->format('Y-m-d'); + } + return $value; + } + public function company() { return $this->belongsTo(Company::class); diff --git a/app/Models/RecurringQuote.php b/app/Models/RecurringQuote.php index 0b85f99de54b..add31149da69 100644 --- a/app/Models/RecurringQuote.php +++ b/app/Models/RecurringQuote.php @@ -15,6 +15,7 @@ use App\Models\Filterable; use App\Utils\Traits\MakesHash; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; +use Illuminate\Support\Carbon; /** * Class for Recurring Invoices. @@ -81,6 +82,7 @@ class RecurringQuote extends BaseModel ]; protected $casts = [ + 'line_items' => 'object', 'settings' => 'object', 'updated_at' => 'timestamp', 'created_at' => 'timestamp', @@ -92,6 +94,27 @@ class RecurringQuote extends BaseModel // 'company', ]; + public function getDateAttribute($value) { + if (!$value) { + return (new Carbon($value))->format('Y-m-d'); + } + return $value; + } + + public function getDueDateAttribute($value) { + if (!$value) { + return (new Carbon($value))->format('Y-m-d'); + } + return $value; + } + + public function getPartialDueDateAttribute($value) { + if (!$value) { + return (new Carbon($value))->format('Y-m-d'); + } + return $value; + } + public function company() { return $this->belongsTo(Company::class); diff --git a/app/Notifications/Admin/InvoiceViewedNotification.php b/app/Notifications/Admin/InvoiceViewedNotification.php index c2b4bff14b11..0ee1deb4aca5 100644 --- a/app/Notifications/Admin/InvoiceViewedNotification.php +++ b/app/Notifications/Admin/InvoiceViewedNotification.php @@ -87,6 +87,14 @@ class InvoiceViewedNotification extends Notification implements ShouldQueue 'logo' => $this->company->present()->logo(), ]; + // if($this->settings->email_style == 'custom'){ + + // $subject = + + // return (new MailMessage) + // ->subject($subject) + // ->view('email.template.custom', ['body' => ]); + // } return (new MailMessage) ->subject($subject) diff --git a/app/Notifications/SendGenericNotification.php b/app/Notifications/SendGenericNotification.php new file mode 100644 index 000000000000..46c3b232d10d --- /dev/null +++ b/app/Notifications/SendGenericNotification.php @@ -0,0 +1,135 @@ +entity = $invitation->{$entity_string}; + $this->contact = $invitation->contact; + $this->settings = $this->entity->client->getMergedSettings(); + $this->subject = $subject; + $this->body = $body; + } + + /** + * Get the notification's delivery channels. + * + * @param mixed $notifiable + * @return array + */ + public function via($notifiable) + {\Log::error("via"); + return ['slack','mail']; + } + + /** + * Get the mail representation of the notification. + * + * @param mixed $notifiable + * @return \Illuminate\Notifications\Messages\MailMessage + */ + public function toMail($notifiable) + { +\Log::error("to mail"); + $subject = $this->generateEmailEntityHtml($this->entity, $this->subject, $this->contact); + $body = $this->generateEmailEntityHtml($this->entity, $this->body, $this->contact); + + $design_style = $this->settings->email_style; + + if($design_style == 'custom') { + $email_style_custom = $this->settings->email_style_custom; + $body = str_replace("$body", $body, $email_style_custom); + } + + $data = [ + 'body' => $body, + 'design' => $design_style, + 'footer' => '', + 'title' => '', + 'settings' => '', + 'company' => '', + 'logo' => $this->entity->company->present()->logo(), + 'signature' => '', + + ]; + + return (new MailMessage) + ->subject($subject) + ->markdown('email.admin.generic_email', $data); + + } + + /** + * Get the array representation of the notification. + * + * @param mixed $notifiable + * @return array + */ + public function toArray($notifiable) + { + return [ + // + ]; + } + + public function toSlack($notifiable) + { +\Log::error("slack"); + return ''; + // $logo = $this->company->present()->logo(); + // $amount = Number::formatMoney($this->invoice->amount, $this->invoice->client); + + // return (new SlackMessage) + // ->success() + // ->from(ctrans('texts.notification_bot')) + // ->image($logo) + // ->content(ctrans( + // 'texts.notification_invoice_viewed', + // [ + // 'amount' => $amount, + // 'client' => $this->contact->present()->name(), + // 'invoice' => $this->invoice->number + // ] + // )); + } +} diff --git a/app/Providers/HorizonServiceProvider.php b/app/Providers/HorizonServiceProvider.php deleted file mode 100644 index 08881175e5ce..000000000000 --- a/app/Providers/HorizonServiceProvider.php +++ /dev/null @@ -1,42 +0,0 @@ -email, [ - // - ]); - }); - } -} diff --git a/app/Utils/Traits/MakesInvoiceHtml.php b/app/Utils/Traits/MakesInvoiceHtml.php index e428c85292d6..c45b1732d734 100644 --- a/app/Utils/Traits/MakesInvoiceHtml.php +++ b/app/Utils/Traits/MakesInvoiceHtml.php @@ -62,6 +62,21 @@ trait MakesInvoiceHtml return $html; } + public function generateEmailEntityHtml($entity, $content, $contact = null) :string + { + $entity->load('client'); + + $client = $entity->client; + + App::setLocale($client->preferredLocale()); + + $labels = $entity->makeLabels(); + $values = $entity->makeValues($contact); + + return $this->parseLabelsAndValues($labels, $values, $content); + + } + private function parseLabelsAndValues($labels, $values, $section) :string { $section = str_replace(array_keys($labels), array_values($labels), $section); diff --git a/app/Utils/Traits/MakesInvoiceValues.php b/app/Utils/Traits/MakesInvoiceValues.php index 6db15143efd0..21a7fa226502 100644 --- a/app/Utils/Traits/MakesInvoiceValues.php +++ b/app/Utils/Traits/MakesInvoiceValues.php @@ -271,8 +271,7 @@ trait MakesInvoiceValues $data['$contact.email'] = ['value' => $contact->email, 'label' => ctrans('texts.email')]; $data['$contact.phone'] = ['value' => $contact->phone, 'label' => ctrans('texts.phone')]; - $data['$contact_name'] = - $data['$contact.name'] = ['value' => isset($contact) ? $contact->present()->name() : 'no contact name on record', 'label' => ctrans('texts.contact_name')]; + $data['$contact.name'] = ['value' => isset($contact) ? $contact->present()->name() : 'no contact name on record', 'label' => ctrans('texts.contact_name')]; $data['$contact.custom1'] = ['value' => isset($contact) ? $contact->custom_value1 : ' ', 'label' => $this->makeCustomField('contact1')]; $data['$contact.custom2'] = ['value' => isset($contact) ? $contact->custom_value2 : ' ', 'label' => $this->makeCustomField('contact1')]; $data['$contact.custom3'] = ['value' => isset($contact) ? $contact->custom_value3 : ' ', 'label' => $this->makeCustomField('contact1')]; @@ -281,7 +280,6 @@ trait MakesInvoiceValues $data['$company.city_state_postal'] = ['value' => $this->company->present()->cityStateZip($settings->city, $settings->state, $settings->postal_code, false) ?: ' ', 'label' => ctrans('texts.city_state_postal')]; $data['$company.postal_city_state'] = ['value' => $this->company->present()->cityStateZip($settings->city, $settings->state, $settings->postal_code, true) ?: ' ', 'label' => ctrans('texts.postal_city_state')]; $data['$company.name'] = ['value' => $this->company->present()->name() ?: ' ', 'label' => ctrans('texts.company_name')]; - $data['$company.company_name'] = &$data['$company.name']; $data['$company.address1'] = ['value' => $settings->address1 ?: ' ', 'label' => ctrans('texts.address1')]; $data['$company.address2'] = ['value' => $settings->address2 ?: ' ', 'label' => ctrans('texts.address2')]; $data['$company.city'] = ['value' => $settings->city ?: ' ', 'label' => ctrans('texts.city')]; @@ -311,6 +309,7 @@ trait MakesInvoiceValues $data['$product.cost'] = ['value' => '', 'label' => ctrans('texts.cost')]; $data['$product.quantity'] = ['value' => '', 'label' => ctrans('texts.quantity')]; $data['$product.tax_name1'] = ['value' => '', 'label' => ctrans('texts.tax')]; + $data['$product.tax'] = ['value' => '', 'label' => ctrans('texts.tax')]; $data['$product.tax_name2'] = ['value' => '', 'label' => ctrans('texts.tax')]; $data['$product.tax_name3'] = ['value' => '', 'label' => ctrans('texts.tax')]; $data['$product.line_total'] = ['value' => '', 'label' => ctrans('texts.line_total')]; @@ -321,6 +320,7 @@ trait MakesInvoiceValues $data['$task.notes'] = ['value' => '', 'label' => ctrans('texts.notes')]; $data['$task.cost'] = ['value' => '', 'label' => ctrans('texts.cost')]; $data['$task.quantity'] = ['value' => '', 'label' => ctrans('texts.quantity')]; + $data['$task.tax'] = ['value' => '', 'label' => ctrans('texts.tax')]; $data['$task.tax_name1'] = ['value' => '', 'label' => ctrans('texts.tax')]; $data['$task.tax_name2'] = ['value' => '', 'label' => ctrans('texts.tax')]; $data['$task.tax_name3'] = ['value' => '', 'label' => ctrans('texts.tax')]; diff --git a/database/factories/AccountFactory.php b/database/factories/AccountFactory.php index 868f3c1867b3..67868546c159 100644 --- a/database/factories/AccountFactory.php +++ b/database/factories/AccountFactory.php @@ -1,9 +1,11 @@ define(App\Models\Account::class, function (Faker $faker) { return [ - 'default_company_id' => 1 + 'default_company_id' => 1, + 'key' => Str::random(32), ]; }); diff --git a/database/migrations/2014_10_13_000000_create_users_table.php b/database/migrations/2014_10_13_000000_create_users_table.php index ed1c888165f1..5d99b3563d66 100644 --- a/database/migrations/2014_10_13_000000_create_users_table.php +++ b/database/migrations/2014_10_13_000000_create_users_table.php @@ -104,6 +104,7 @@ class CreateUsersTable extends Migration $table->date('plan_paid')->nullable(); $table->date('plan_expires')->nullable(); $table->string('user_agent')->nullable(); + $table->string('key')->nullable(); $table->unsignedInteger('payment_id')->nullable()->index(); $table->unsignedInteger('default_company_id'); @@ -517,9 +518,9 @@ class CreateUsersTable extends Migration $t->string('po_number')->nullable(); $t->date('date')->nullable(); - $t->date('last_sent_date')->nullable(); + $t->datetime('last_sent_date')->nullable(); - $t->datetime('due_date')->nullable(); + $t->date('due_date')->nullable(); $t->boolean('is_deleted')->default(false); $t->mediumText('line_items')->nullable(); diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index 64fc61829c98..106a9c1c4c1c 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -3147,7 +3147,7 @@ return [ 'email_link_not_working' => 'If button above isn\'t working for you, please click on the link', 'credit_terms' => 'Credit Terms', 'display_log' => 'Display Log', - 'send_fail_logs_to_our_server' => 'Send error logs to our servers for analysis', + 'send_fail_logs_to_our_server' => 'Report errors in realtime', 'setup' => 'Setup', 'quick_overview_statistics' => 'Quick overview & statistics', @@ -3179,8 +3179,8 @@ return [ 'remove_payment_method' => 'Remove payment method', 'warning_action_cannot_be_reversed' => 'Warning! This action can\'t be reversed!', 'confirmation' => 'Confirmation', - 'list_of_quotes' => 'List of quotes', + 'list_of_quotes' => 'Quotes', 'waiting_for_approval' => 'Waiting for approval', 'quote_still_not_approved' => 'This quote is still not approved', - 'list_of_credits' => 'List of credits', + 'list_of_credits' => 'Credits', ]; diff --git a/resources/views/email/admin/generic_email.blade.php b/resources/views/email/admin/generic_email.blade.php new file mode 100644 index 000000000000..ae8d87338f7a --- /dev/null +++ b/resources/views/email/admin/generic_email.blade.php @@ -0,0 +1,22 @@ +@component('email.template.master', ['design' => 'light']) + +@slot('header') + @component('email.components.header', ['p' => $title, 'logo' => $logo]) + @endcomponent +@endslot + +@slot('greeting') + @lang($body) +@endslot + +@slot('signature') + {{ $signature }} +@endslot + +@slot('footer') + @component('email.components.footer', ['url' => 'https://invoiceninja.com', 'url_text' => '© InvoiceNinja']) + For any info, please visit InvoiceNinja. + @endcomponent +@endslot + +@endcomponent \ No newline at end of file diff --git a/resources/views/setup/_database.blade.php b/resources/views/setup/_database.blade.php index 88b356fe8dd8..e3f6f40ec97d 100644 --- a/resources/views/setup/_database.blade.php +++ b/resources/views/setup/_database.blade.php @@ -4,7 +4,6 @@ {{ ctrans('texts.database_connection') }}
- To store data, we need database. Here's how you can create one.