mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-08-07 10:01:47 -04:00
commit
c9521da75f
@ -19,3 +19,5 @@ MAIL_USERNAME
|
|||||||
MAIL_FROM_ADDRESS
|
MAIL_FROM_ADDRESS
|
||||||
MAIL_FROM_NAME
|
MAIL_FROM_NAME
|
||||||
MAIL_PASSWORD
|
MAIL_PASSWORD
|
||||||
|
|
||||||
|
ALLOW_NEW_ACCOUNTS
|
23
.gitignore
vendored
23
.gitignore
vendored
@ -13,18 +13,19 @@
|
|||||||
/bootstrap/environment.php
|
/bootstrap/environment.php
|
||||||
/vendor
|
/vendor
|
||||||
/node_modules
|
/node_modules
|
||||||
.env
|
|
||||||
/.DS_Store
|
/.DS_Store
|
||||||
/Thumbs.db
|
/Thumbs.db
|
||||||
.env.development.php
|
/.env
|
||||||
.env.php
|
/.env.development.php
|
||||||
.idea
|
/.env.php
|
||||||
.project
|
|
||||||
error_log
|
/error_log
|
||||||
public/error_log
|
/auth.json
|
||||||
|
/public/error_log
|
||||||
|
|
||||||
/ninja.sublime-project
|
/ninja.sublime-project
|
||||||
/ninja.sublime-workspace
|
/ninja.sublime-workspace
|
||||||
auth.json
|
/.phpstorm.meta.php
|
||||||
|
/_ide_helper.php
|
||||||
.phpstorm.meta.php
|
/.idea
|
||||||
_ide_helper.php
|
/.project
|
5
.htaccess
Normal file
5
.htaccess
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<IfModule mod_rewrite.c>
|
||||||
|
RewriteEngine On
|
||||||
|
RewriteRule "^.env" - [F,L]
|
||||||
|
RewriteRule "^storage" - [F,L]
|
||||||
|
</IfModule>
|
22
Gruntfile.js
22
Gruntfile.js
@ -51,7 +51,17 @@ module.exports = function(grunt) {
|
|||||||
'public/vendor/knockout-mapping/build/output/knockout.mapping-latest.js',
|
'public/vendor/knockout-mapping/build/output/knockout.mapping-latest.js',
|
||||||
'public/vendor/knockout-sortable/build/knockout-sortable.min.js',
|
'public/vendor/knockout-sortable/build/knockout-sortable.min.js',
|
||||||
'public/vendor/underscore/underscore.js',
|
'public/vendor/underscore/underscore.js',
|
||||||
'public/vendor/bootstrap-datepicker/js/bootstrap-datepicker.js',
|
'public/vendor/bootstrap-datepicker/dist/js/bootstrap-datepicker.min.js',
|
||||||
|
'public/vendor/bootstrap-datepicker/dist/locales/bootstrap-datepicker.de.min.js',
|
||||||
|
'public/vendor/bootstrap-datepicker/dist/locales/bootstrap-datepicker.da.min.js',
|
||||||
|
'public/vendor/bootstrap-datepicker/dist/locales/bootstrap-datepicker.pt-BR.min.js',
|
||||||
|
'public/vendor/bootstrap-datepicker/dist/locales/bootstrap-datepicker.nl.min.js',
|
||||||
|
'public/vendor/bootstrap-datepicker/dist/locales/bootstrap-datepicker.fr.min.js',
|
||||||
|
'public/vendor/bootstrap-datepicker/dist/locales/bootstrap-datepicker.it.min.js',
|
||||||
|
'public/vendor/bootstrap-datepicker/dist/locales/bootstrap-datepicker.lt.min.js',
|
||||||
|
'public/vendor/bootstrap-datepicker/dist/locales/bootstrap-datepicker.no.min.js',
|
||||||
|
'public/vendor/bootstrap-datepicker/dist/locales/bootstrap-datepicker.es.min.js',
|
||||||
|
'public/vendor/bootstrap-datepicker/dist/locales/bootstrap-datepicker.sv.min.js',
|
||||||
'public/vendor/typeahead.js/dist/typeahead.min.js',
|
'public/vendor/typeahead.js/dist/typeahead.min.js',
|
||||||
'public/vendor/accounting/accounting.min.js',
|
'public/vendor/accounting/accounting.min.js',
|
||||||
'public/vendor/spectrum/spectrum.js',
|
'public/vendor/spectrum/spectrum.js',
|
||||||
@ -65,7 +75,7 @@ module.exports = function(grunt) {
|
|||||||
'public/js/lightbox.min.js',
|
'public/js/lightbox.min.js',
|
||||||
'public/js/bootstrap-combobox.js',
|
'public/js/bootstrap-combobox.js',
|
||||||
'public/js/script.js',
|
'public/js/script.js',
|
||||||
'public/js/pdf.pdfmake.js'
|
'public/js/pdf.pdfmake.js',
|
||||||
],
|
],
|
||||||
dest: 'public/js/built.js',
|
dest: 'public/js/built.js',
|
||||||
nonull: true
|
nonull: true
|
||||||
@ -79,8 +89,8 @@ module.exports = function(grunt) {
|
|||||||
'public/js/simpleexpand.js',
|
'public/js/simpleexpand.js',
|
||||||
*/
|
*/
|
||||||
'public/vendor/bootstrap/dist/js/bootstrap.min.js',
|
'public/vendor/bootstrap/dist/js/bootstrap.min.js',
|
||||||
'public/js/bootstrap-combobox.js',
|
'public/js/bootstrap-combobox.js',
|
||||||
|
|
||||||
],
|
],
|
||||||
dest: 'public/js/built.public.js',
|
dest: 'public/js/built.public.js',
|
||||||
nonull: true
|
nonull: true
|
||||||
@ -91,7 +101,7 @@ module.exports = function(grunt) {
|
|||||||
'public/vendor/datatables/media/css/jquery.dataTables.css',
|
'public/vendor/datatables/media/css/jquery.dataTables.css',
|
||||||
'public/vendor/datatables-bootstrap3/BS3/assets/css/datatables.css',
|
'public/vendor/datatables-bootstrap3/BS3/assets/css/datatables.css',
|
||||||
'public/vendor/font-awesome/css/font-awesome.min.css',
|
'public/vendor/font-awesome/css/font-awesome.min.css',
|
||||||
'public/vendor/bootstrap-datepicker/css/datepicker3.css',
|
'public/vendor/bootstrap-datepicker/dist/css/bootstrap-datepicker3.css',
|
||||||
'public/vendor/spectrum/spectrum.css',
|
'public/vendor/spectrum/spectrum.css',
|
||||||
'public/css/bootstrap-combobox.css',
|
'public/css/bootstrap-combobox.css',
|
||||||
'public/css/typeahead.js-bootstrap.css',
|
'public/css/typeahead.js-bootstrap.css',
|
||||||
@ -115,7 +125,7 @@ module.exports = function(grunt) {
|
|||||||
*/
|
*/
|
||||||
'public/css/bootstrap-combobox.css',
|
'public/css/bootstrap-combobox.css',
|
||||||
'public/vendor/datatables/media/css/jquery.dataTables.css',
|
'public/vendor/datatables/media/css/jquery.dataTables.css',
|
||||||
'public/vendor/datatables-bootstrap3/BS3/assets/css/datatables.css',
|
'public/vendor/datatables-bootstrap3/BS3/assets/css/datatables.css',
|
||||||
],
|
],
|
||||||
dest: 'public/css/built.public.css',
|
dest: 'public/css/built.public.css',
|
||||||
nonull: true,
|
nonull: true,
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
<?php namespace App\Exceptions;
|
<?php namespace App\Exceptions;
|
||||||
|
|
||||||
|
use Redirect;
|
||||||
use Utils;
|
use Utils;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
||||||
|
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||||
|
|
||||||
class Handler extends ExceptionHandler {
|
class Handler extends ExceptionHandler {
|
||||||
|
|
||||||
@ -39,7 +41,12 @@ class Handler extends ExceptionHandler {
|
|||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\Response
|
||||||
*/
|
*/
|
||||||
public function render($request, Exception $e)
|
public function render($request, Exception $e)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if ($e instanceof ModelNotFoundException) {
|
||||||
|
return Redirect::to('/');
|
||||||
|
}
|
||||||
|
|
||||||
if (Utils::isNinjaProd()) {
|
if (Utils::isNinjaProd()) {
|
||||||
$data = [
|
$data = [
|
||||||
'error' => get_class($e),
|
'error' => get_class($e),
|
||||||
|
@ -77,14 +77,17 @@ class AccountController extends BaseController
|
|||||||
{
|
{
|
||||||
if (Auth::check()) {
|
if (Auth::check()) {
|
||||||
return Redirect::to('invoices/create');
|
return Redirect::to('invoices/create');
|
||||||
} elseif (!Utils::isNinja() && Account::count() > 0) {
|
|
||||||
return Redirect::to('/login');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!Utils::isNinja() && !Utils::allowNewAccounts() && Account::count() > 0) {
|
||||||
|
return Redirect::to('/login');
|
||||||
|
}
|
||||||
|
|
||||||
$user = false;
|
$user = false;
|
||||||
$guestKey = Input::get('guest_key');
|
$guestKey = Input::get('guest_key'); // local storage key to login until registered
|
||||||
|
$prevUserId = Session::pull(PREV_USER_ID); // last user id used to link to new account
|
||||||
|
|
||||||
if ($guestKey) {
|
if ($guestKey && !$prevUserId) {
|
||||||
$user = User::where('password', '=', $guestKey)->first();
|
$user = User::where('password', '=', $guestKey)->first();
|
||||||
|
|
||||||
if ($user && $user->registered) {
|
if ($user && $user->registered) {
|
||||||
@ -97,6 +100,11 @@ class AccountController extends BaseController
|
|||||||
$user = $account->users()->first();
|
$user = $account->users()->first();
|
||||||
|
|
||||||
Session::forget(RECENTLY_VIEWED);
|
Session::forget(RECENTLY_VIEWED);
|
||||||
|
|
||||||
|
if ($prevUserId) {
|
||||||
|
$users = $this->accountRepo->associateAccounts($user->id, $prevUserId);
|
||||||
|
Session::put(SESSION_USER_ACCOUNTS, $users);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Auth::login($user, true);
|
Auth::login($user, true);
|
||||||
@ -152,6 +160,7 @@ class AccountController extends BaseController
|
|||||||
'currencies' => Cache::get('currencies'),
|
'currencies' => Cache::get('currencies'),
|
||||||
'languages' => Cache::get('languages'),
|
'languages' => Cache::get('languages'),
|
||||||
'showUser' => Auth::user()->id === Auth::user()->account->users()->first()->id,
|
'showUser' => Auth::user()->id === Auth::user()->account->users()->first()->id,
|
||||||
|
'title' => trans('texts.company_details'),
|
||||||
];
|
];
|
||||||
|
|
||||||
return View::make('accounts.details', $data);
|
return View::make('accounts.details', $data);
|
||||||
@ -164,26 +173,33 @@ class AccountController extends BaseController
|
|||||||
if ($count == 0) {
|
if ($count == 0) {
|
||||||
return Redirect::to('gateways/create');
|
return Redirect::to('gateways/create');
|
||||||
} else {
|
} else {
|
||||||
return View::make('accounts.payments', ['showAdd' => $count < 3]);
|
return View::make('accounts.payments', [
|
||||||
|
'showAdd' => $count < 3,
|
||||||
|
'title' => trans('texts.online_payments')
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
} elseif ($section == ACCOUNT_NOTIFICATIONS) {
|
} elseif ($section == ACCOUNT_NOTIFICATIONS) {
|
||||||
$data = [
|
$data = [
|
||||||
'account' => Account::with('users')->findOrFail(Auth::user()->account_id),
|
'account' => Account::with('users')->findOrFail(Auth::user()->account_id),
|
||||||
|
'title' => trans('texts.notifications'),
|
||||||
];
|
];
|
||||||
|
|
||||||
return View::make('accounts.notifications', $data);
|
return View::make('accounts.notifications', $data);
|
||||||
} elseif ($section == ACCOUNT_IMPORT_EXPORT) {
|
} elseif ($section == ACCOUNT_IMPORT_EXPORT) {
|
||||||
return View::make('accounts.import_export');
|
return View::make('accounts.import_export', ['title' => trans('texts.import_export')]);
|
||||||
} elseif ($section == ACCOUNT_ADVANCED_SETTINGS) {
|
} elseif ($section == ACCOUNT_ADVANCED_SETTINGS) {
|
||||||
$account = Auth::user()->account;
|
$account = Auth::user()->account->load('country');
|
||||||
$data = [
|
$data = [
|
||||||
'account' => $account,
|
'account' => $account,
|
||||||
'feature' => $subSection,
|
'feature' => $subSection,
|
||||||
|
'title' => trans('texts.invoice_settings'),
|
||||||
];
|
];
|
||||||
|
|
||||||
if ($subSection == ACCOUNT_INVOICE_DESIGN) {
|
if ($subSection == ACCOUNT_INVOICE_DESIGN
|
||||||
|
|| $subSection == ACCOUNT_CUSTOMIZE_DESIGN) {
|
||||||
$invoice = new stdClass();
|
$invoice = new stdClass();
|
||||||
$client = new stdClass();
|
$client = new stdClass();
|
||||||
|
$contact = new stdClass();
|
||||||
$invoiceItem = new stdClass();
|
$invoiceItem = new stdClass();
|
||||||
|
|
||||||
$client->name = 'Sample Client';
|
$client->name = 'Sample Client';
|
||||||
@ -194,11 +210,17 @@ class AccountController extends BaseController
|
|||||||
$client->work_phone = '';
|
$client->work_phone = '';
|
||||||
$client->work_email = '';
|
$client->work_email = '';
|
||||||
|
|
||||||
$invoice->invoice_number = Auth::user()->account->getNextInvoiceNumber();
|
$invoice->invoice_number = $account->getNextInvoiceNumber();
|
||||||
$invoice->invoice_date = date_create()->format('Y-m-d');
|
$invoice->invoice_date = date_create()->format('Y-m-d');
|
||||||
$invoice->account = json_decode(Auth::user()->account->toJson());
|
$invoice->account = json_decode($account->toJson());
|
||||||
$invoice->amount = $invoice->balance = 100;
|
$invoice->amount = $invoice->balance = 100;
|
||||||
|
|
||||||
|
$invoice->terms = trim($account->invoice_terms);
|
||||||
|
$invoice->invoice_footer = trim($account->invoice_footer);
|
||||||
|
|
||||||
|
$contact->email = 'contact@gmail.com';
|
||||||
|
$client->contacts = [$contact];
|
||||||
|
|
||||||
$invoiceItem->cost = 100;
|
$invoiceItem->cost = 100;
|
||||||
$invoiceItem->qty = 1;
|
$invoiceItem->qty = 1;
|
||||||
$invoiceItem->notes = 'Notes';
|
$invoiceItem->notes = 'Notes';
|
||||||
@ -207,20 +229,38 @@ class AccountController extends BaseController
|
|||||||
$invoice->client = $client;
|
$invoice->client = $client;
|
||||||
$invoice->invoice_items = [$invoiceItem];
|
$invoice->invoice_items = [$invoiceItem];
|
||||||
|
|
||||||
|
$data['account'] = $account;
|
||||||
$data['invoice'] = $invoice;
|
$data['invoice'] = $invoice;
|
||||||
$data['invoiceDesigns'] = InvoiceDesign::availableDesigns();
|
|
||||||
$data['invoiceLabels'] = json_decode($account->invoice_labels) ?: [];
|
$data['invoiceLabels'] = json_decode($account->invoice_labels) ?: [];
|
||||||
|
$data['title'] = trans('texts.invoice_design');
|
||||||
|
$data['invoiceDesigns'] = InvoiceDesign::getDesigns($subSection == ACCOUNT_CUSTOMIZE_DESIGN);
|
||||||
|
|
||||||
|
$design = false;
|
||||||
|
foreach ($data['invoiceDesigns'] as $item) {
|
||||||
|
if ($item->id == $account->invoice_design_id) {
|
||||||
|
$design = $item->javascript;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($subSection == ACCOUNT_CUSTOMIZE_DESIGN) {
|
||||||
|
$data['customDesign'] = ($account->custom_design && !$design) ? $account->custom_design : $design;
|
||||||
|
}
|
||||||
} else if ($subSection == ACCOUNT_EMAIL_TEMPLATES) {
|
} else if ($subSection == ACCOUNT_EMAIL_TEMPLATES) {
|
||||||
$data['invoiceEmail'] = $account->getEmailTemplate(ENTITY_INVOICE);
|
$data['invoiceEmail'] = $account->getEmailTemplate(ENTITY_INVOICE);
|
||||||
$data['quoteEmail'] = $account->getEmailTemplate(ENTITY_QUOTE);
|
$data['quoteEmail'] = $account->getEmailTemplate(ENTITY_QUOTE);
|
||||||
$data['paymentEmail'] = $account->getEmailTemplate(ENTITY_PAYMENT);
|
$data['paymentEmail'] = $account->getEmailTemplate(ENTITY_PAYMENT);
|
||||||
$data['emailFooter'] = $account->getEmailFooter();
|
$data['emailFooter'] = $account->getEmailFooter();
|
||||||
|
$data['title'] = trans('texts.email_templates');
|
||||||
|
} else if ($subSection == ACCOUNT_USER_MANAGEMENT) {
|
||||||
|
$data['title'] = trans('texts.users_and_tokens');
|
||||||
}
|
}
|
||||||
|
|
||||||
return View::make("accounts.{$subSection}", $data);
|
return View::make("accounts.{$subSection}", $data);
|
||||||
} elseif ($section == ACCOUNT_PRODUCTS) {
|
} elseif ($section == ACCOUNT_PRODUCTS) {
|
||||||
$data = [
|
$data = [
|
||||||
'account' => Auth::user()->account,
|
'account' => Auth::user()->account,
|
||||||
|
'title' => trans('texts.product_library'),
|
||||||
];
|
];
|
||||||
|
|
||||||
return View::make('accounts.products', $data);
|
return View::make('accounts.products', $data);
|
||||||
@ -244,6 +284,8 @@ class AccountController extends BaseController
|
|||||||
return AccountController::saveInvoiceSettings();
|
return AccountController::saveInvoiceSettings();
|
||||||
} elseif ($subSection == ACCOUNT_INVOICE_DESIGN) {
|
} elseif ($subSection == ACCOUNT_INVOICE_DESIGN) {
|
||||||
return AccountController::saveInvoiceDesign();
|
return AccountController::saveInvoiceDesign();
|
||||||
|
} elseif ($subSection == ACCOUNT_CUSTOMIZE_DESIGN) {
|
||||||
|
return AccountController::saveCustomizeDesign();
|
||||||
} elseif ($subSection == ACCOUNT_EMAIL_TEMPLATES) {
|
} elseif ($subSection == ACCOUNT_EMAIL_TEMPLATES) {
|
||||||
return AccountController::saveEmailTemplates();
|
return AccountController::saveEmailTemplates();
|
||||||
}
|
}
|
||||||
@ -252,6 +294,24 @@ class AccountController extends BaseController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function saveCustomizeDesign() {
|
||||||
|
if (Auth::user()->account->isPro()) {
|
||||||
|
$account = Auth::user()->account;
|
||||||
|
$account->custom_design = Input::get('custom_design');
|
||||||
|
$account->invoice_design_id = CUSTOM_DESIGN;
|
||||||
|
|
||||||
|
if (!$account->utf8_invoices) {
|
||||||
|
$account->utf8_invoices = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$account->save();
|
||||||
|
|
||||||
|
Session::flash('message', trans('texts.updated_settings'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Redirect::to('company/advanced_settings/customize_design');
|
||||||
|
}
|
||||||
|
|
||||||
private function saveEmailTemplates()
|
private function saveEmailTemplates()
|
||||||
{
|
{
|
||||||
if (Auth::user()->account->isPro()) {
|
if (Auth::user()->account->isPro()) {
|
||||||
@ -628,6 +688,9 @@ class AccountController extends BaseController
|
|||||||
$user->username = trim(Input::get('email'));
|
$user->username = trim(Input::get('email'));
|
||||||
$user->email = trim(strtolower(Input::get('email')));
|
$user->email = trim(strtolower(Input::get('email')));
|
||||||
$user->phone = trim(Input::get('phone'));
|
$user->phone = trim(Input::get('phone'));
|
||||||
|
if (Utils::isNinja()) {
|
||||||
|
$user->dark_mode = Input::get('dark_mode') ? true : false;
|
||||||
|
}
|
||||||
$user->save();
|
$user->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -635,17 +698,21 @@ class AccountController extends BaseController
|
|||||||
if ($file = Input::file('logo')) {
|
if ($file = Input::file('logo')) {
|
||||||
$path = Input::file('logo')->getRealPath();
|
$path = Input::file('logo')->getRealPath();
|
||||||
File::delete('logo/'.$account->account_key.'.jpg');
|
File::delete('logo/'.$account->account_key.'.jpg');
|
||||||
|
File::delete('logo/'.$account->account_key.'.png');
|
||||||
|
|
||||||
$image = Image::make($path);
|
$image = Image::make($path);
|
||||||
$mimeType = $file->getMimeType();
|
$mimeType = $file->getMimeType();
|
||||||
|
|
||||||
if ($image->width() == 200 && $mimeType == 'image/jpeg') {
|
if ($mimeType == 'image/jpeg' && $account->utf8_invoices) {
|
||||||
$file->move('logo/', $account->account_key . '.jpg');
|
$file->move('logo/', $account->account_key . '.jpg');
|
||||||
|
} else if ($mimeType == 'image/png' && $account->utf8_invoices) {
|
||||||
|
$file->move('logo/', $account->account_key . '.png');
|
||||||
} else {
|
} else {
|
||||||
$image->resize(200, 120, function ($constraint) {
|
$image->resize(200, 120, function ($constraint) {
|
||||||
$constraint->aspectRatio();
|
$constraint->aspectRatio();
|
||||||
});
|
});
|
||||||
Image::canvas($image->width(), $image->height(), '#FFFFFF')->insert($image)->save($account->getLogoPath());
|
Image::canvas($image->width(), $image->height(), '#FFFFFF')
|
||||||
|
->insert($image)->save('logo/'.$account->account_key.'.jpg');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -659,6 +726,7 @@ class AccountController extends BaseController
|
|||||||
public function removeLogo()
|
public function removeLogo()
|
||||||
{
|
{
|
||||||
File::delete('logo/'.Auth::user()->account->account_key.'.jpg');
|
File::delete('logo/'.Auth::user()->account->account_key.'.jpg');
|
||||||
|
File::delete('logo/'.Auth::user()->account->account_key.'.png');
|
||||||
|
|
||||||
Session::flash('message', trans('texts.removed_logo'));
|
Session::flash('message', trans('texts.removed_logo'));
|
||||||
|
|
||||||
@ -702,8 +770,6 @@ class AccountController extends BaseController
|
|||||||
|
|
||||||
if (Utils::isNinja()) {
|
if (Utils::isNinja()) {
|
||||||
$this->userMailer->sendConfirmation($user);
|
$this->userMailer->sendConfirmation($user);
|
||||||
} else {
|
|
||||||
$this->accountRepo->registerUser($user);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$activities = Activity::scope()->get();
|
$activities = Activity::scope()->get();
|
||||||
@ -725,10 +791,16 @@ class AccountController extends BaseController
|
|||||||
{
|
{
|
||||||
$affiliate = Affiliate::where('affiliate_key', '=', SELF_HOST_AFFILIATE_KEY)->first();
|
$affiliate = Affiliate::where('affiliate_key', '=', SELF_HOST_AFFILIATE_KEY)->first();
|
||||||
|
|
||||||
|
$email = trim(Input::get('email'));
|
||||||
|
|
||||||
|
if (!$email || $email == 'user@example.com') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
$license = new License();
|
$license = new License();
|
||||||
$license->first_name = Input::get('first_name');
|
$license->first_name = Input::get('first_name');
|
||||||
$license->last_name = Input::get('last_name');
|
$license->last_name = Input::get('last_name');
|
||||||
$license->email = Input::get('email');
|
$license->email = $email;
|
||||||
$license->transaction_reference = Request::getClientIp();
|
$license->transaction_reference = Request::getClientIp();
|
||||||
$license->license_key = Utils::generateLicense();
|
$license->license_key = Utils::generateLicense();
|
||||||
$license->affiliate_id = $affiliate->id;
|
$license->affiliate_id = $affiliate->id;
|
||||||
@ -753,9 +825,11 @@ class AccountController extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
$account = Auth::user()->account;
|
$account = Auth::user()->account;
|
||||||
|
$this->accountRepo->unlinkAccount($account);
|
||||||
$account->forceDelete();
|
$account->forceDelete();
|
||||||
|
|
||||||
Auth::logout();
|
Auth::logout();
|
||||||
|
Session::flush();
|
||||||
|
|
||||||
return Redirect::to('/')->with('clearGuestKey', true);
|
return Redirect::to('/')->with('clearGuestKey', true);
|
||||||
}
|
}
|
||||||
|
@ -200,7 +200,7 @@ class AccountGatewayController extends BaseController
|
|||||||
$fields = $gateway->getFields();
|
$fields = $gateway->getFields();
|
||||||
$optional = array_merge(Gateway::$hiddenFields, Gateway::$optionalFields);
|
$optional = array_merge(Gateway::$hiddenFields, Gateway::$optionalFields);
|
||||||
|
|
||||||
if (Utils::isNinja() && $gatewayId == GATEWAY_DWOLLA) {
|
if ($gatewayId == GATEWAY_DWOLLA) {
|
||||||
$optional = array_merge($optional, ['key', 'secret']);
|
$optional = array_merge($optional, ['key', 'secret']);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,6 +257,8 @@ class AccountGatewayController extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
$accountGateway->accepted_credit_cards = $cardCount;
|
$accountGateway->accepted_credit_cards = $cardCount;
|
||||||
|
$accountGateway->show_address = Input::get('show_address') ? true : false;
|
||||||
|
$accountGateway->update_address = Input::get('update_address') ? true : false;
|
||||||
$accountGateway->config = json_encode($config);
|
$accountGateway->config = json_encode($config);
|
||||||
|
|
||||||
if ($accountGatewayPublicId) {
|
if ($accountGatewayPublicId) {
|
||||||
@ -278,7 +280,7 @@ class AccountGatewayController extends BaseController
|
|||||||
|
|
||||||
Session::flash('message', $message);
|
Session::flash('message', $message);
|
||||||
|
|
||||||
return Redirect::to('company/payments');
|
return Redirect::to("gateways/{$accountGateway->public_id}/edit");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,8 @@ use Session;
|
|||||||
use Cookie;
|
use Cookie;
|
||||||
use Response;
|
use Response;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use App\Models\Account;
|
||||||
|
use App\Models\Industry;
|
||||||
use App\Ninja\Mailers\Mailer;
|
use App\Ninja\Mailers\Mailer;
|
||||||
use App\Ninja\Repositories\AccountRepository;
|
use App\Ninja\Repositories\AccountRepository;
|
||||||
use Redirect;
|
use Redirect;
|
||||||
@ -32,24 +34,16 @@ class AppController extends BaseController
|
|||||||
|
|
||||||
public function showSetup()
|
public function showSetup()
|
||||||
{
|
{
|
||||||
if (Utils::isNinja() || Utils::isDatabaseSetup()) {
|
if (Utils::isNinja() || (Utils::isDatabaseSetup() && Account::count() > 0)) {
|
||||||
return Redirect::to('/');
|
return Redirect::to('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
$view = View::make('setup');
|
return View::make('setup');
|
||||||
|
|
||||||
/*
|
|
||||||
$cookie = Cookie::forget('ninja_session', '/', 'www.ninja.dev');
|
|
||||||
Cookie::queue($cookie);
|
|
||||||
return Response::make($view)->withCookie($cookie);
|
|
||||||
*/
|
|
||||||
|
|
||||||
return Response::make($view);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function doSetup()
|
public function doSetup()
|
||||||
{
|
{
|
||||||
if (Utils::isNinja() || Utils::isDatabaseSetup()) {
|
if (Utils::isNinja() || (Utils::isDatabaseSetup() && Account::count() > 0)) {
|
||||||
return Redirect::to('/');
|
return Redirect::to('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,7 +98,9 @@ class AppController extends BaseController
|
|||||||
// == DB Migrate & Seed == //
|
// == DB Migrate & Seed == //
|
||||||
// Artisan::call('migrate:rollback', array('--force' => true)); // Debug Purposes
|
// Artisan::call('migrate:rollback', array('--force' => true)); // Debug Purposes
|
||||||
Artisan::call('migrate', array('--force' => true));
|
Artisan::call('migrate', array('--force' => true));
|
||||||
Artisan::call('db:seed', array('--force' => true));
|
if (Industry::count() == 0) {
|
||||||
|
Artisan::call('db:seed', array('--force' => true));
|
||||||
|
}
|
||||||
Artisan::call('optimize', array('--force' => true));
|
Artisan::call('optimize', array('--force' => true));
|
||||||
|
|
||||||
$firstName = trim(Input::get('first_name'));
|
$firstName = trim(Input::get('first_name'));
|
||||||
@ -114,8 +110,6 @@ class AppController extends BaseController
|
|||||||
$account = $this->accountRepo->create($firstName, $lastName, $email, $password);
|
$account = $this->accountRepo->create($firstName, $lastName, $email, $password);
|
||||||
$user = $account->users()->first();
|
$user = $account->users()->first();
|
||||||
|
|
||||||
//Auth::login($user, true);
|
|
||||||
|
|
||||||
return Redirect::to('/login');
|
return Redirect::to('/login');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,7 +162,9 @@ class AppController extends BaseController
|
|||||||
if (!Utils::isNinja() && !Utils::isDatabaseSetup()) {
|
if (!Utils::isNinja() && !Utils::isDatabaseSetup()) {
|
||||||
try {
|
try {
|
||||||
Artisan::call('migrate', array('--force' => true));
|
Artisan::call('migrate', array('--force' => true));
|
||||||
Artisan::call('db:seed', array('--force' => true));
|
if (Industry::count() == 0) {
|
||||||
|
Artisan::call('db:seed', array('--force' => true));
|
||||||
|
}
|
||||||
Artisan::call('optimize', array('--force' => true));
|
Artisan::call('optimize', array('--force' => true));
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
Response::make($e->getMessage(), 500);
|
Response::make($e->getMessage(), 500);
|
||||||
|
@ -3,10 +3,12 @@
|
|||||||
use Auth;
|
use Auth;
|
||||||
use Event;
|
use Event;
|
||||||
use Utils;
|
use Utils;
|
||||||
|
use Session;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Events\UserLoggedIn;
|
use App\Events\UserLoggedIn;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Ninja\Repositories\AccountRepository;
|
||||||
use Illuminate\Contracts\Auth\Guard;
|
use Illuminate\Contracts\Auth\Guard;
|
||||||
use Illuminate\Contracts\Auth\Registrar;
|
use Illuminate\Contracts\Auth\Registrar;
|
||||||
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
|
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
|
||||||
@ -28,6 +30,7 @@ class AuthController extends Controller {
|
|||||||
|
|
||||||
protected $loginPath = '/login';
|
protected $loginPath = '/login';
|
||||||
protected $redirectTo = '/dashboard';
|
protected $redirectTo = '/dashboard';
|
||||||
|
protected $accountRepo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new authentication controller instance.
|
* Create a new authentication controller instance.
|
||||||
@ -36,12 +39,13 @@ class AuthController extends Controller {
|
|||||||
* @param \Illuminate\Contracts\Auth\Registrar $registrar
|
* @param \Illuminate\Contracts\Auth\Registrar $registrar
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function __construct(Guard $auth, Registrar $registrar)
|
public function __construct(Guard $auth, Registrar $registrar, AccountRepository $repo)
|
||||||
{
|
{
|
||||||
$this->auth = $auth;
|
$this->auth = $auth;
|
||||||
$this->registrar = $registrar;
|
$this->registrar = $registrar;
|
||||||
|
$this->accountRepo = $repo;
|
||||||
|
|
||||||
$this->middleware('guest', ['except' => 'getLogout']);
|
//$this->middleware('guest', ['except' => 'getLogout']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getLoginWrapper()
|
public function getLoginWrapper()
|
||||||
@ -55,13 +59,50 @@ class AuthController extends Controller {
|
|||||||
|
|
||||||
public function postLoginWrapper(Request $request)
|
public function postLoginWrapper(Request $request)
|
||||||
{
|
{
|
||||||
|
$userId = Auth::check() ? Auth::user()->id : null;
|
||||||
|
$user = User::where('email', '=', $request->input('email'))->first();
|
||||||
|
|
||||||
|
if ($user->failed_logins >= 3) {
|
||||||
|
Session::flash('error', 'These credentials do not match our records.');
|
||||||
|
return redirect()->to('login');
|
||||||
|
}
|
||||||
|
|
||||||
$response = self::postLogin($request);
|
$response = self::postLogin($request);
|
||||||
|
|
||||||
if (Auth::check()) {
|
if (Auth::check()) {
|
||||||
Event::fire(new UserLoggedIn());
|
Event::fire(new UserLoggedIn());
|
||||||
|
|
||||||
|
$users = false;
|
||||||
|
// we're linking a new account
|
||||||
|
if ($userId && Auth::user()->id != $userId) {
|
||||||
|
$users = $this->accountRepo->associateAccounts($userId, Auth::user()->id);
|
||||||
|
Session::flash('message', trans('texts.associated_accounts'));
|
||||||
|
// check if other accounts are linked
|
||||||
|
} else {
|
||||||
|
$users = $this->accountRepo->loadAccounts(Auth::user()->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
Session::put(SESSION_USER_ACCOUNTS, $users);
|
||||||
|
} elseif ($user) {
|
||||||
|
$user->failed_logins = $user->failed_logins + 1;
|
||||||
|
$user->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getLogoutWrapper()
|
||||||
|
{
|
||||||
|
if (Auth::check() && !Auth::user()->registered) {
|
||||||
|
$account = Auth::user()->account;
|
||||||
|
$this->accountRepo->unlinkAccount($account);
|
||||||
|
$account->forceDelete();
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = self::getLogout();
|
||||||
|
|
||||||
|
Session::flush();
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,8 +24,11 @@ class ClientApiController extends Controller
|
|||||||
|
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
$clients = Client::scope()->with('contacts')->orderBy('created_at', 'desc')->get();
|
$clients = Client::scope()
|
||||||
$clients = Utils::remapPublicIds($clients->toArray());
|
->with('country', 'contacts', 'industry', 'size', 'currency')
|
||||||
|
->orderBy('created_at', 'desc')
|
||||||
|
->get();
|
||||||
|
$clients = Utils::remapPublicIds($clients);
|
||||||
|
|
||||||
$response = json_encode($clients, JSON_PRETTY_PRINT);
|
$response = json_encode($clients, JSON_PRETTY_PRINT);
|
||||||
$headers = Utils::getApiHeaders(count($clients));
|
$headers = Utils::getApiHeaders(count($clients));
|
||||||
@ -43,9 +46,9 @@ class ClientApiController extends Controller
|
|||||||
|
|
||||||
return Response::make($error, 500, $headers);
|
return Response::make($error, 500, $headers);
|
||||||
} else {
|
} else {
|
||||||
$client = $this->clientRepo->save(false, $data, false);
|
$client = $this->clientRepo->save(isset($data['id']) ? $data['id'] : false, $data, false);
|
||||||
$client->load('contacts');
|
$client = Client::scope($client->public_id)->with('country', 'contacts', 'industry', 'size', 'currency')->first();
|
||||||
$client = Utils::remapPublicIds($client->toArray());
|
$client = Utils::remapPublicIds([$client]);
|
||||||
$response = json_encode($client, JSON_PRETTY_PRINT);
|
$response = json_encode($client, JSON_PRETTY_PRINT);
|
||||||
$headers = Utils::getApiHeaders();
|
$headers = Utils::getApiHeaders();
|
||||||
|
|
||||||
|
@ -44,6 +44,8 @@ class DashboardController extends BaseController
|
|||||||
->where('accounts.id', '=', Auth::user()->account_id)
|
->where('accounts.id', '=', Auth::user()->account_id)
|
||||||
->where('clients.is_deleted', '=', false)
|
->where('clients.is_deleted', '=', false)
|
||||||
->where('invoices.is_deleted', '=', false)
|
->where('invoices.is_deleted', '=', false)
|
||||||
|
->where('invoices.is_quote', '=', false)
|
||||||
|
->where('invoices.is_recurring', '=', false)
|
||||||
->groupBy('accounts.id')
|
->groupBy('accounts.id')
|
||||||
->groupBy(DB::raw('CASE WHEN clients.currency_id IS NULL THEN CASE WHEN accounts.currency_id IS NULL THEN 1 ELSE accounts.currency_id END ELSE clients.currency_id END'))
|
->groupBy(DB::raw('CASE WHEN clients.currency_id IS NULL THEN CASE WHEN accounts.currency_id IS NULL THEN 1 ELSE accounts.currency_id END ELSE clients.currency_id END'))
|
||||||
->get();
|
->get();
|
||||||
@ -83,6 +85,7 @@ class DashboardController extends BaseController
|
|||||||
'activities' => $activities,
|
'activities' => $activities,
|
||||||
'pastDue' => $pastDue,
|
'pastDue' => $pastDue,
|
||||||
'upcoming' => $upcoming,
|
'upcoming' => $upcoming,
|
||||||
|
'title' => trans('texts.dashboard'),
|
||||||
];
|
];
|
||||||
|
|
||||||
return View::make('dashboard', $data);
|
return View::make('dashboard', $data);
|
||||||
|
@ -27,10 +27,8 @@ class HomeController extends BaseController
|
|||||||
{
|
{
|
||||||
Session::reflash();
|
Session::reflash();
|
||||||
|
|
||||||
if (!Utils::isDatabaseSetup()) {
|
if (!Utils::isNinja() && (!Utils::isDatabaseSetup() || Account::count() == 0)) {
|
||||||
return Redirect::to('/setup');
|
return Redirect::to('/setup');
|
||||||
} elseif (Account::count() == 0) {
|
|
||||||
return Redirect::to('/invoice_now');
|
|
||||||
} elseif (Auth::check()) {
|
} elseif (Auth::check()) {
|
||||||
return Redirect::to('/dashboard');
|
return Redirect::to('/dashboard');
|
||||||
} else {
|
} else {
|
||||||
@ -45,6 +43,12 @@ class HomeController extends BaseController
|
|||||||
|
|
||||||
public function invoiceNow()
|
public function invoiceNow()
|
||||||
{
|
{
|
||||||
|
if (Auth::check() && Input::get('new_account')) {
|
||||||
|
Session::put(PREV_USER_ID, Auth::user()->id);
|
||||||
|
Auth::user()->clearSession();
|
||||||
|
Auth::logout();
|
||||||
|
}
|
||||||
|
|
||||||
if (Auth::check()) {
|
if (Auth::check()) {
|
||||||
return Redirect::to('invoices/create')->with('sign_up', Input::get('sign_up'));
|
return Redirect::to('invoices/create')->with('sign_up', Input::get('sign_up'));
|
||||||
} else {
|
} else {
|
||||||
|
@ -26,7 +26,7 @@ class InvoiceApiController extends Controller
|
|||||||
|
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
$invoices = Invoice::scope()->with('invitations')->where('invoices.is_quote', '=', false)->orderBy('created_at', 'desc')->get();
|
$invoices = Invoice::scope()->with('client', 'invitations.account')->where('invoices.is_quote', '=', false)->orderBy('created_at', 'desc')->get();
|
||||||
|
|
||||||
// Add the first invitation link to the data
|
// Add the first invitation link to the data
|
||||||
foreach ($invoices as $key => $invoice) {
|
foreach ($invoices as $key => $invoice) {
|
||||||
@ -36,7 +36,7 @@ class InvoiceApiController extends Controller
|
|||||||
unset($invoice['invitations']);
|
unset($invoice['invitations']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$invoices = Utils::remapPublicIds($invoices->toArray());
|
$invoices = Utils::remapPublicIds($invoices);
|
||||||
|
|
||||||
$response = json_encode($invoices, JSON_PRETTY_PRINT);
|
$response = json_encode($invoices, JSON_PRETTY_PRINT);
|
||||||
$headers = Utils::getApiHeaders(count($invoices));
|
$headers = Utils::getApiHeaders(count($invoices));
|
||||||
@ -99,7 +99,6 @@ class InvoiceApiController extends Controller
|
|||||||
$data = self::prepareData($data);
|
$data = self::prepareData($data);
|
||||||
$data['client_id'] = $client->id;
|
$data['client_id'] = $client->id;
|
||||||
$invoice = $this->invoiceRepo->save(false, $data, false);
|
$invoice = $this->invoiceRepo->save(false, $data, false);
|
||||||
$invoice->load('invoice_items');
|
|
||||||
|
|
||||||
$invitation = Invitation::createNew();
|
$invitation = Invitation::createNew();
|
||||||
$invitation->invoice_id = $invoice->id;
|
$invitation->invoice_id = $invoice->id;
|
||||||
@ -112,13 +111,9 @@ class InvoiceApiController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
// prepare the return data
|
// prepare the return data
|
||||||
$invoice = $invoice->toArray();
|
$invoice = Invoice::scope($invoice->public_id)->with('client', 'invoice_items', 'invitations')->first();
|
||||||
$invoice['link'] = $invitation->getLink();
|
$invoice = Utils::remapPublicIds([$invoice]);
|
||||||
unset($invoice['account']);
|
|
||||||
unset($invoice['client']);
|
|
||||||
$invoice = Utils::remapPublicIds($invoice);
|
|
||||||
$invoice['client_id'] = $client->public_id;
|
|
||||||
|
|
||||||
$response = json_encode($invoice, JSON_PRETTY_PRINT);
|
$response = json_encode($invoice, JSON_PRETTY_PRINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,6 +213,10 @@ class InvoiceController extends BaseController
|
|||||||
$invoice->due_date = Utils::fromSqlDate($invoice->due_date);
|
$invoice->due_date = Utils::fromSqlDate($invoice->due_date);
|
||||||
$invoice->is_pro = $account->isPro();
|
$invoice->is_pro = $account->isPro();
|
||||||
|
|
||||||
|
if ($invoice->invoice_design_id == CUSTOM_DESIGN) {
|
||||||
|
$invoice->invoice_design->javascript = $account->custom_design;
|
||||||
|
}
|
||||||
|
|
||||||
$contact = $invitation->contact;
|
$contact = $invitation->contact;
|
||||||
$contact->setVisible([
|
$contact->setVisible([
|
||||||
'first_name',
|
'first_name',
|
||||||
@ -224,17 +228,23 @@ class InvoiceController extends BaseController
|
|||||||
$paymentTypes = [];
|
$paymentTypes = [];
|
||||||
if ($client->getGatewayToken()) {
|
if ($client->getGatewayToken()) {
|
||||||
$paymentTypes[] = [
|
$paymentTypes[] = [
|
||||||
'url' => URL::to("payment/{$invitation->invitation_key}/".PAYMENT_TYPE_TOKEN), 'label' => trans('texts.use_card_on_file')
|
'url' => URL::to("payment/{$invitation->invitation_key}/token"), 'label' => trans('texts.use_card_on_file')
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
foreach(Gateway::$paymentTypes as $type) {
|
foreach(Gateway::$paymentTypes as $type) {
|
||||||
if ($account->getGatewayByType($type)) {
|
if ($account->getGatewayByType($type)) {
|
||||||
$paymentTypes[] = [
|
$typeLink = strtolower(str_replace('PAYMENT_TYPE_', '', $type));
|
||||||
'url' => URL::to("/payment/{$invitation->invitation_key}/{$type}"), 'label' => trans('texts.'.strtolower($type))
|
$paymentTypes[] = [
|
||||||
|
'url' => URL::to("/payment/{$invitation->invitation_key}/{$typeLink}"), 'label' => trans('texts.'.strtolower($type))
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$paymentURL = '';
|
||||||
|
if (count($paymentTypes)) {
|
||||||
|
$paymentURL = $paymentTypes[0]['url'];
|
||||||
|
}
|
||||||
|
|
||||||
$data = array(
|
$data = array(
|
||||||
'isConverted' => $invoice->quote_invoice_id ? true : false,
|
'isConverted' => $invoice->quote_invoice_id ? true : false,
|
||||||
'showBreadcrumbs' => false,
|
'showBreadcrumbs' => false,
|
||||||
@ -243,7 +253,8 @@ class InvoiceController extends BaseController
|
|||||||
'invitation' => $invitation,
|
'invitation' => $invitation,
|
||||||
'invoiceLabels' => $account->getInvoiceLabels(),
|
'invoiceLabels' => $account->getInvoiceLabels(),
|
||||||
'contact' => $contact,
|
'contact' => $contact,
|
||||||
'paymentTypes' => $paymentTypes
|
'paymentTypes' => $paymentTypes,
|
||||||
|
'paymentURL' => $paymentURL
|
||||||
);
|
);
|
||||||
|
|
||||||
return View::make('invoices.view', $data);
|
return View::make('invoices.view', $data);
|
||||||
@ -318,7 +329,6 @@ class InvoiceController extends BaseController
|
|||||||
$data = array(
|
$data = array(
|
||||||
'entityType' => $entityType,
|
'entityType' => $entityType,
|
||||||
'showBreadcrumbs' => $clone,
|
'showBreadcrumbs' => $clone,
|
||||||
'account' => $invoice->account,
|
|
||||||
'invoice' => $invoice,
|
'invoice' => $invoice,
|
||||||
'data' => false,
|
'data' => false,
|
||||||
'method' => $method,
|
'method' => $method,
|
||||||
@ -353,7 +363,6 @@ class InvoiceController extends BaseController
|
|||||||
{
|
{
|
||||||
$client = null;
|
$client = null;
|
||||||
$invoiceNumber = Auth::user()->account->getNextInvoiceNumber();
|
$invoiceNumber = Auth::user()->account->getNextInvoiceNumber();
|
||||||
$account = Account::with('country')->findOrFail(Auth::user()->account_id);
|
|
||||||
|
|
||||||
if ($clientPublicId) {
|
if ($clientPublicId) {
|
||||||
$client = Client::scope($clientPublicId)->firstOrFail();
|
$client = Client::scope($clientPublicId)->firstOrFail();
|
||||||
@ -361,17 +370,15 @@ class InvoiceController extends BaseController
|
|||||||
|
|
||||||
$data = array(
|
$data = array(
|
||||||
'entityType' => ENTITY_INVOICE,
|
'entityType' => ENTITY_INVOICE,
|
||||||
'account' => $account,
|
|
||||||
'invoice' => null,
|
'invoice' => null,
|
||||||
'data' => Input::old('data'),
|
'data' => Input::old('data'),
|
||||||
'invoiceNumber' => $invoiceNumber,
|
'invoiceNumber' => $invoiceNumber,
|
||||||
'method' => 'POST',
|
'method' => 'POST',
|
||||||
'url' => 'invoices',
|
'url' => 'invoices',
|
||||||
'title' => trans('texts.new_invoice'),
|
'title' => trans('texts.new_invoice'),
|
||||||
'client' => $client,
|
'client' => $client);
|
||||||
'tasks' => Session::get('tasks') ? json_encode(Session::get('tasks')) : null);
|
|
||||||
$data = array_merge($data, self::getViewModel());
|
$data = array_merge($data, self::getViewModel());
|
||||||
|
|
||||||
return View::make('invoices.edit', $data);
|
return View::make('invoices.edit', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -389,7 +396,7 @@ class InvoiceController extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'account' => Auth::user()->account,
|
'account' => Auth::user()->account->load('country'),
|
||||||
'products' => Product::scope()->orderBy('id')->get(array('product_key', 'notes', 'cost', 'qty')),
|
'products' => Product::scope()->orderBy('id')->get(array('product_key', 'notes', 'cost', 'qty')),
|
||||||
'countries' => Cache::get('countries'),
|
'countries' => Cache::get('countries'),
|
||||||
'clients' => Client::scope()->with('contacts', 'country')->orderBy('name')->get(),
|
'clients' => Client::scope()->with('contacts', 'country')->orderBy('name')->get(),
|
||||||
@ -398,7 +405,7 @@ class InvoiceController extends BaseController
|
|||||||
'sizes' => Cache::get('sizes'),
|
'sizes' => Cache::get('sizes'),
|
||||||
'paymentTerms' => Cache::get('paymentTerms'),
|
'paymentTerms' => Cache::get('paymentTerms'),
|
||||||
'industries' => Cache::get('industries'),
|
'industries' => Cache::get('industries'),
|
||||||
'invoiceDesigns' => InvoiceDesign::availableDesigns(),
|
'invoiceDesigns' => InvoiceDesign::getDesigns(),
|
||||||
'frequencies' => array(
|
'frequencies' => array(
|
||||||
1 => 'Weekly',
|
1 => 'Weekly',
|
||||||
2 => 'Two weeks',
|
2 => 'Two weeks',
|
||||||
@ -410,7 +417,7 @@ class InvoiceController extends BaseController
|
|||||||
),
|
),
|
||||||
'recurringHelp' => $recurringHelp,
|
'recurringHelp' => $recurringHelp,
|
||||||
'invoiceLabels' => Auth::user()->account->getInvoiceLabels(),
|
'invoiceLabels' => Auth::user()->account->getInvoiceLabels(),
|
||||||
|
'tasks' => Session::get('tasks') ? json_encode(Session::get('tasks')) : null,
|
||||||
];
|
];
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -504,9 +511,13 @@ class InvoiceController extends BaseController
|
|||||||
return $this->convertQuote($publicId);
|
return $this->convertQuote($publicId);
|
||||||
} elseif ($action == 'email') {
|
} elseif ($action == 'email') {
|
||||||
if (Auth::user()->confirmed && !Auth::user()->isDemo()) {
|
if (Auth::user()->confirmed && !Auth::user()->isDemo()) {
|
||||||
$message = trans("texts.emailed_{$entityType}");
|
$response = $this->mailer->sendInvoice($invoice);
|
||||||
$this->mailer->sendInvoice($invoice);
|
if ($response === true) {
|
||||||
Session::flash('message', $message);
|
$message = trans("texts.emailed_{$entityType}");
|
||||||
|
Session::flash('message', $message);
|
||||||
|
} else {
|
||||||
|
Session::flash('error', $response);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$errorMessage = trans(Auth::user()->registered ? 'texts.confirmation_required' : 'texts.registration_required');
|
$errorMessage = trans(Auth::user()->registered ? 'texts.confirmation_required' : 'texts.registration_required');
|
||||||
Session::flash('error', $errorMessage);
|
Session::flash('error', $errorMessage);
|
||||||
@ -635,7 +646,7 @@ class InvoiceController extends BaseController
|
|||||||
'invoice' => $invoice,
|
'invoice' => $invoice,
|
||||||
'versionsJson' => json_encode($versionsJson),
|
'versionsJson' => json_encode($versionsJson),
|
||||||
'versionsSelect' => $versionsSelect,
|
'versionsSelect' => $versionsSelect,
|
||||||
'invoiceDesigns' => InvoiceDesign::availableDesigns(),
|
'invoiceDesigns' => InvoiceDesign::getDesigns(),
|
||||||
];
|
];
|
||||||
|
|
||||||
return View::make('invoices.history', $data);
|
return View::make('invoices.history', $data);
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
<?php namespace App\Http\Controllers;
|
<?php namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Input;
|
||||||
use Utils;
|
use Utils;
|
||||||
use Response;
|
use Response;
|
||||||
use App\Models\Payment;
|
use App\Models\Payment;
|
||||||
|
use App\Models\Invoice;
|
||||||
use App\Ninja\Repositories\PaymentRepository;
|
use App\Ninja\Repositories\PaymentRepository;
|
||||||
|
|
||||||
class PaymentApiController extends Controller
|
class PaymentApiController extends Controller
|
||||||
@ -16,24 +18,50 @@ class PaymentApiController extends Controller
|
|||||||
|
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
$payments = Payment::scope()->orderBy('created_at', 'desc')->get();
|
$payments = Payment::scope()
|
||||||
$payments = Utils::remapPublicIds($payments->toArray());
|
->with('client', 'contact', 'invitation', 'user', 'invoice')
|
||||||
|
->orderBy('created_at', 'desc')
|
||||||
|
->get();
|
||||||
|
$payments = Utils::remapPublicIds($payments);
|
||||||
|
|
||||||
$response = json_encode($payments, JSON_PRETTY_PRINT);
|
$response = json_encode($payments, JSON_PRETTY_PRINT);
|
||||||
$headers = Utils::getApiHeaders(count($payments));
|
$headers = Utils::getApiHeaders(count($payments));
|
||||||
|
|
||||||
return Response::make($response, 200, $headers);
|
return Response::make($response, 200, $headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
public function store()
|
|
||||||
{
|
|
||||||
$data = Input::all();
|
|
||||||
$invoice = $this->invoiceRepo->save(false, $data, false);
|
|
||||||
|
|
||||||
$response = json_encode($invoice, JSON_PRETTY_PRINT);
|
public function store()
|
||||||
$headers = Utils::getApiHeaders();
|
{
|
||||||
return Response::make($response, 200, $headers);
|
$data = Input::all();
|
||||||
}
|
$error = false;
|
||||||
*/
|
|
||||||
|
if (isset($data['invoice_id'])) {
|
||||||
|
$invoice = Invoice::scope($data['invoice_id'])->with('client')->first();
|
||||||
|
|
||||||
|
if ($invoice) {
|
||||||
|
$data['invoice'] = $invoice->public_id;
|
||||||
|
$data['client'] = $invoice->client->public_id;
|
||||||
|
} else {
|
||||||
|
$error = trans('validation.not_in', ['attribute' => 'invoice_id']);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$error = trans('validation.not_in', ['attribute' => 'invoice_id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($data['transaction_reference'])) {
|
||||||
|
$data['transaction_reference'] = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$error) {
|
||||||
|
$payment = $this->paymentRepo->save(false, $data);
|
||||||
|
$payment = Payment::scope($payment->public_id)->with('client', 'contact', 'user', 'invoice')->first();
|
||||||
|
|
||||||
|
$payment = Utils::remapPublicIds([$payment]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = json_encode($error ?: $payment, JSON_PRETTY_PRINT);
|
||||||
|
$headers = Utils::getApiHeaders();
|
||||||
|
return Response::make($response, 200, $headers);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -233,33 +233,41 @@ class PaymentController extends BaseController
|
|||||||
|
|
||||||
private function convertInputForOmnipay($input)
|
private function convertInputForOmnipay($input)
|
||||||
{
|
{
|
||||||
$country = Country::find($input['country_id']);
|
$data = [
|
||||||
|
|
||||||
return [
|
|
||||||
'firstName' => $input['first_name'],
|
'firstName' => $input['first_name'],
|
||||||
'lastName' => $input['last_name'],
|
'lastName' => $input['last_name'],
|
||||||
'number' => $input['card_number'],
|
'number' => $input['card_number'],
|
||||||
'expiryMonth' => $input['expiration_month'],
|
'expiryMonth' => $input['expiration_month'],
|
||||||
'expiryYear' => $input['expiration_year'],
|
'expiryYear' => $input['expiration_year'],
|
||||||
'cvv' => $input['cvv'],
|
'cvv' => $input['cvv'],
|
||||||
'billingAddress1' => $input['address1'],
|
|
||||||
'billingAddress2' => $input['address2'],
|
|
||||||
'billingCity' => $input['city'],
|
|
||||||
'billingState' => $input['state'],
|
|
||||||
'billingPostcode' => $input['postal_code'],
|
|
||||||
'billingCountry' => $country->iso_3166_2,
|
|
||||||
'shippingAddress1' => $input['address1'],
|
|
||||||
'shippingAddress2' => $input['address2'],
|
|
||||||
'shippingCity' => $input['city'],
|
|
||||||
'shippingState' => $input['state'],
|
|
||||||
'shippingPostcode' => $input['postal_code'],
|
|
||||||
'shippingCountry' => $country->iso_3166_2
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if (isset($input['country_id'])) {
|
||||||
|
$country = Country::find($input['country_id']);
|
||||||
|
|
||||||
|
$data = array_merge($data, [
|
||||||
|
'billingAddress1' => $input['address1'],
|
||||||
|
'billingAddress2' => $input['address2'],
|
||||||
|
'billingCity' => $input['city'],
|
||||||
|
'billingState' => $input['state'],
|
||||||
|
'billingPostcode' => $input['postal_code'],
|
||||||
|
'billingCountry' => $country->iso_3166_2,
|
||||||
|
'shippingAddress1' => $input['address1'],
|
||||||
|
'shippingAddress2' => $input['address2'],
|
||||||
|
'shippingCity' => $input['city'],
|
||||||
|
'shippingState' => $input['state'],
|
||||||
|
'shippingPostcode' => $input['postal_code'],
|
||||||
|
'shippingCountry' => $country->iso_3166_2
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getPaymentDetails($invitation, $input = null)
|
private function getPaymentDetails($invitation, $input = null)
|
||||||
{
|
{
|
||||||
$invoice = $invitation->invoice;
|
$invoice = $invitation->invoice;
|
||||||
|
$account = $invoice->account;
|
||||||
$key = $invoice->account_id.'-'.$invoice->invoice_number;
|
$key = $invoice->account_id.'-'.$invoice->invoice_number;
|
||||||
$currencyCode = $invoice->client->currency ? $invoice->client->currency->code : ($invoice->account->currency ? $invoice->account->currency->code : 'USD');
|
$currencyCode = $invoice->client->currency ? $invoice->client->currency->code : ($invoice->account->currency ? $invoice->account->currency->code : 'USD');
|
||||||
|
|
||||||
@ -292,7 +300,9 @@ class PaymentController extends BaseController
|
|||||||
$account = $client->account;
|
$account = $client->account;
|
||||||
$useToken = false;
|
$useToken = false;
|
||||||
|
|
||||||
if (!$paymentType) {
|
if ($paymentType) {
|
||||||
|
$paymentType = 'PAYMENT_TYPE_' . strtoupper($paymentType);
|
||||||
|
} else {
|
||||||
$paymentType = Session::get('payment_type', $account->account_gateways[0]->getPaymentType());
|
$paymentType = Session::get('payment_type', $account->account_gateways[0]->getPaymentType());
|
||||||
}
|
}
|
||||||
if ($paymentType == PAYMENT_TYPE_TOKEN) {
|
if ($paymentType == PAYMENT_TYPE_TOKEN) {
|
||||||
@ -328,6 +338,7 @@ class PaymentController extends BaseController
|
|||||||
'currencyId' => $client->getCurrencyId(),
|
'currencyId' => $client->getCurrencyId(),
|
||||||
'account' => $client->account,
|
'account' => $client->account,
|
||||||
'hideLogo' => $account->isWhiteLabel(),
|
'hideLogo' => $account->isWhiteLabel(),
|
||||||
|
'showAddress' => $accountGateway->show_address,
|
||||||
];
|
];
|
||||||
|
|
||||||
return View::make('payments.payment', $data);
|
return View::make('payments.payment', $data);
|
||||||
@ -458,10 +469,11 @@ class PaymentController extends BaseController
|
|||||||
$this->contactMailer->sendLicensePaymentConfirmation($name, $license->email, $affiliate->price, $license->license_key, $license->product_id);
|
$this->contactMailer->sendLicensePaymentConfirmation($name, $license->email, $affiliate->price, $license->license_key, $license->product_id);
|
||||||
|
|
||||||
if (Session::has('return_url')) {
|
if (Session::has('return_url')) {
|
||||||
return Redirect::away(Session::get('return_url')."?license_key={$license->license_key}&product_id=".Session::get('product_id'));
|
$data['redirectTo'] = Session::get('return_url')."?license_key={$license->license_key}&product_id=".Session::get('product_id');
|
||||||
} else {
|
$data['message'] = "Redirecting to " . Session::get('return_url');
|
||||||
return View::make('public.license', $data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return View::make('public.license', $data);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$errorMessage = trans('texts.payment_error');
|
$errorMessage = trans('texts.payment_error');
|
||||||
Session::flash('error', $errorMessage);
|
Session::flash('error', $errorMessage);
|
||||||
@ -495,19 +507,30 @@ class PaymentController extends BaseController
|
|||||||
|
|
||||||
public function do_payment($invitationKey, $onSite = true, $useToken = false)
|
public function do_payment($invitationKey, $onSite = true, $useToken = false)
|
||||||
{
|
{
|
||||||
$rules = array(
|
$invitation = Invitation::with('invoice.invoice_items', 'invoice.client.currency', 'invoice.client.account.currency', 'invoice.client.account.account_gateways.gateway')->where('invitation_key', '=', $invitationKey)->firstOrFail();
|
||||||
|
$invoice = $invitation->invoice;
|
||||||
|
$client = $invoice->client;
|
||||||
|
$account = $client->account;
|
||||||
|
$accountGateway = $account->getGatewayByType(Session::get('payment_type'));
|
||||||
|
|
||||||
|
$rules = [
|
||||||
'first_name' => 'required',
|
'first_name' => 'required',
|
||||||
'last_name' => 'required',
|
'last_name' => 'required',
|
||||||
'card_number' => 'required',
|
'card_number' => 'required',
|
||||||
'expiration_month' => 'required',
|
'expiration_month' => 'required',
|
||||||
'expiration_year' => 'required',
|
'expiration_year' => 'required',
|
||||||
'cvv' => 'required',
|
'cvv' => 'required',
|
||||||
'address1' => 'required',
|
];
|
||||||
'city' => 'required',
|
|
||||||
'state' => 'required',
|
if ($accountGateway->show_address) {
|
||||||
'postal_code' => 'required',
|
$rules = array_merge($rules, [
|
||||||
'country_id' => 'required',
|
'address1' => 'required',
|
||||||
);
|
'city' => 'required',
|
||||||
|
'state' => 'required',
|
||||||
|
'postal_code' => 'required',
|
||||||
|
'country_id' => 'required',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
if ($onSite) {
|
if ($onSite) {
|
||||||
$validator = Validator::make(Input::all(), $rules);
|
$validator = Validator::make(Input::all(), $rules);
|
||||||
@ -519,23 +542,16 @@ class PaymentController extends BaseController
|
|||||||
->withInput();
|
->withInput();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$invitation = Invitation::with('invoice.invoice_items', 'invoice.client.currency', 'invoice.client.account.currency', 'invoice.client.account.account_gateways.gateway')->where('invitation_key', '=', $invitationKey)->firstOrFail();
|
if ($onSite && $accountGateway->update_address) {
|
||||||
$invoice = $invitation->invoice;
|
|
||||||
$client = $invoice->client;
|
|
||||||
$account = $client->account;
|
|
||||||
$accountGateway = $account->getGatewayByType(Session::get('payment_type'));
|
|
||||||
|
|
||||||
/*
|
|
||||||
if ($onSite) {
|
|
||||||
$client->address1 = trim(Input::get('address1'));
|
$client->address1 = trim(Input::get('address1'));
|
||||||
$client->address2 = trim(Input::get('address2'));
|
$client->address2 = trim(Input::get('address2'));
|
||||||
$client->city = trim(Input::get('city'));
|
$client->city = trim(Input::get('city'));
|
||||||
$client->state = trim(Input::get('state'));
|
$client->state = trim(Input::get('state'));
|
||||||
$client->postal_code = trim(Input::get('postal_code'));
|
$client->postal_code = trim(Input::get('postal_code'));
|
||||||
|
$client->country_id = Input::get('country_id');
|
||||||
$client->save();
|
$client->save();
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$gateway = self::createGateway($accountGateway);
|
$gateway = self::createGateway($accountGateway);
|
||||||
@ -628,8 +644,9 @@ class PaymentController extends BaseController
|
|||||||
$invoice = $invitation->invoice;
|
$invoice = $invitation->invoice;
|
||||||
$accountGateway = $invoice->client->account->getGatewayByType(Session::get('payment_type'));
|
$accountGateway = $invoice->client->account->getGatewayByType(Session::get('payment_type'));
|
||||||
|
|
||||||
if ($invoice->account->account_key == NINJA_ACCOUNT_KEY) {
|
if ($invoice->account->account_key == NINJA_ACCOUNT_KEY
|
||||||
$account = Account::find($invoice->client->public_id);
|
&& $invoice->amount == PRO_PLAN_PRICE) {
|
||||||
|
$account = Account::with('users')->find($invoice->client->public_id);
|
||||||
if ($account->pro_plan_paid && $account->pro_plan_paid != '0000-00-00') {
|
if ($account->pro_plan_paid && $account->pro_plan_paid != '0000-00-00') {
|
||||||
$date = DateTime::createFromFormat('Y-m-d', $account->pro_plan_paid);
|
$date = DateTime::createFromFormat('Y-m-d', $account->pro_plan_paid);
|
||||||
$account->pro_plan_paid = $date->modify('+1 year')->format('Y-m-d');
|
$account->pro_plan_paid = $date->modify('+1 year')->format('Y-m-d');
|
||||||
@ -637,6 +654,9 @@ class PaymentController extends BaseController
|
|||||||
$account->pro_plan_paid = date_create()->format('Y-m-d');
|
$account->pro_plan_paid = date_create()->format('Y-m-d');
|
||||||
}
|
}
|
||||||
$account->save();
|
$account->save();
|
||||||
|
|
||||||
|
$user = $account->users()->first();
|
||||||
|
$this->accountRepo->syncAccounts($user->id, $account->pro_plan_paid);
|
||||||
}
|
}
|
||||||
|
|
||||||
$payment = Payment::createNew($invitation);
|
$payment = Payment::createNew($invitation);
|
||||||
@ -679,6 +699,14 @@ class PaymentController extends BaseController
|
|||||||
$accountGateway = $invoice->client->account->getGatewayByType(Session::get('payment_type'));
|
$accountGateway = $invoice->client->account->getGatewayByType(Session::get('payment_type'));
|
||||||
$gateway = self::createGateway($accountGateway);
|
$gateway = self::createGateway($accountGateway);
|
||||||
|
|
||||||
|
// Check for Dwolla payment error
|
||||||
|
if ($accountGateway->isGateway(GATEWAY_DWOLLA) && Input::get('error')) {
|
||||||
|
$errorMessage = trans('texts.payment_error')."\n\n".Input::get('error_description');
|
||||||
|
Session::flash('error', $errorMessage);
|
||||||
|
Utils::logError($errorMessage);
|
||||||
|
return Redirect::to('view/'.$invitation->invitation_key);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (method_exists($gateway, 'completePurchase')) {
|
if (method_exists($gateway, 'completePurchase')) {
|
||||||
$details = self::getPaymentDetails($invitation);
|
$details = self::getPaymentDetails($invitation);
|
||||||
@ -731,14 +759,19 @@ class PaymentController extends BaseController
|
|||||||
->withErrors($errors)
|
->withErrors($errors)
|
||||||
->withInput();
|
->withInput();
|
||||||
} else {
|
} else {
|
||||||
$this->paymentRepo->save($publicId, Input::all());
|
$payment = $this->paymentRepo->save($publicId, Input::all());
|
||||||
|
|
||||||
if ($publicId) {
|
if ($publicId) {
|
||||||
Session::flash('message', trans('texts.updated_payment'));
|
Session::flash('message', trans('texts.updated_payment'));
|
||||||
|
|
||||||
return Redirect::to('payments/');
|
return Redirect::to('payments/');
|
||||||
} else {
|
} else {
|
||||||
Session::flash('message', trans('texts.created_payment'));
|
if (Input::get('email_receipt')) {
|
||||||
|
$this->contactMailer->sendPaymentConfirmation($payment);
|
||||||
|
Session::flash('message', trans('texts.created_payment_emailed_client'));
|
||||||
|
} else {
|
||||||
|
Session::flash('message', trans('texts.created_payment'));
|
||||||
|
}
|
||||||
|
|
||||||
return Redirect::to('clients/'.Input::get('client'));
|
return Redirect::to('clients/'.Input::get('client'));
|
||||||
}
|
}
|
||||||
|
@ -16,8 +16,8 @@ class QuoteApiController extends Controller
|
|||||||
|
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
$invoices = Invoice::scope()->where('invoices.is_quote', '=', true)->orderBy('created_at', 'desc')->get();
|
$invoices = Invoice::scope()->with('client', 'user')->where('invoices.is_quote', '=', true)->orderBy('created_at', 'desc')->get();
|
||||||
$invoices = Utils::remapPublicIds($invoices->toArray());
|
$invoices = Utils::remapPublicIds($invoices);
|
||||||
|
|
||||||
$response = json_encode($invoices, JSON_PRETTY_PRINT);
|
$response = json_encode($invoices, JSON_PRETTY_PRINT);
|
||||||
$headers = Utils::getApiHeaders(count($invoices));
|
$headers = Utils::getApiHeaders(count($invoices));
|
||||||
|
@ -156,7 +156,7 @@ class QuoteController extends BaseController
|
|||||||
'sizes' => Cache::get('sizes'),
|
'sizes' => Cache::get('sizes'),
|
||||||
'paymentTerms' => Cache::get('paymentTerms'),
|
'paymentTerms' => Cache::get('paymentTerms'),
|
||||||
'industries' => Cache::get('industries'),
|
'industries' => Cache::get('industries'),
|
||||||
'invoiceDesigns' => InvoiceDesign::availableDesigns(),
|
'invoiceDesigns' => InvoiceDesign::getDesigns(),
|
||||||
'invoiceLabels' => Auth::user()->account->getInvoiceLabels()
|
'invoiceLabels' => Auth::user()->account->getInvoiceLabels()
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<?php namespace App\Http\Controllers;
|
<?php namespace App\Http\Controllers;
|
||||||
|
|
||||||
use Auth;
|
use Auth;
|
||||||
|
use Config;
|
||||||
use Input;
|
use Input;
|
||||||
use Utils;
|
use Utils;
|
||||||
use DB;
|
use DB;
|
||||||
@ -149,53 +150,90 @@ class ReportController extends BaseController
|
|||||||
$reportTotals['balance'][$currencyId] += $record->balance;
|
$reportTotals['balance'][$currencyId] += $record->balance;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($action == 'export') {
|
if ($action == 'export')
|
||||||
|
{
|
||||||
self::export($exportData, $reportTotals);
|
self::export($exportData, $reportTotals);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($enableChart) {
|
if ($enableChart)
|
||||||
foreach ([ENTITY_INVOICE, ENTITY_PAYMENT, ENTITY_CREDIT] as $entityType) {
|
{
|
||||||
$records = DB::table($entityType.'s')
|
foreach ([ENTITY_INVOICE, ENTITY_PAYMENT, ENTITY_CREDIT] as $entityType)
|
||||||
->select(DB::raw('sum(amount) as total, concat(YEAR('.$entityType.'_date), '.$groupBy.'('.$entityType.'_date)) as '.$groupBy))
|
{
|
||||||
->where('account_id', '=', Auth::user()->account_id)
|
// SQLite does not support the YEAR(), MONTH(), WEEK() and similar functions.
|
||||||
->where($entityType.'s.is_deleted', '=', false)
|
// Let's see if SQLite is being used.
|
||||||
->where($entityType.'s.'.$entityType.'_date', '>=', $startDate->format('Y-m-d'))
|
if (Config::get('database.connections.'.Config::get('database.default').'.driver') == 'sqlite')
|
||||||
->where($entityType.'s.'.$entityType.'_date', '<=', $endDate->format('Y-m-d'))
|
{
|
||||||
->groupBy($groupBy);
|
// Replace the unsupported function with it's date format counterpart
|
||||||
|
switch ($groupBy)
|
||||||
|
{
|
||||||
|
case 'MONTH':
|
||||||
|
$dateFormat = '%m'; // returns 01-12
|
||||||
|
break;
|
||||||
|
case 'WEEK':
|
||||||
|
$dateFormat = '%W'; // returns 00-53
|
||||||
|
break;
|
||||||
|
case 'DAYOFYEAR':
|
||||||
|
$dateFormat = '%j'; // returns 001-366
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$dateFormat = '%m'; // MONTH by default
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if ($entityType == ENTITY_INVOICE) {
|
// Concatenate the year and the chosen timeframe (Month, Week or Day)
|
||||||
|
$timeframe = 'strftime("%Y", '.$entityType.'_date) || strftime("'.$dateFormat.'", '.$entityType.'_date)';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Supported by Laravel's other DBMS drivers (MySQL, MSSQL and PostgreSQL)
|
||||||
|
$timeframe = 'concat(YEAR('.$entityType.'_date), '.$groupBy.'('.$entityType.'_date))';
|
||||||
|
}
|
||||||
|
|
||||||
|
$records = DB::table($entityType.'s')
|
||||||
|
->select(DB::raw('sum(amount) as total, '.$timeframe.' as '.$groupBy))
|
||||||
|
->where('account_id', '=', Auth::user()->account_id)
|
||||||
|
->where($entityType.'s.is_deleted', '=', false)
|
||||||
|
->where($entityType.'s.'.$entityType.'_date', '>=', $startDate->format('Y-m-d'))
|
||||||
|
->where($entityType.'s.'.$entityType.'_date', '<=', $endDate->format('Y-m-d'))
|
||||||
|
->groupBy($groupBy);
|
||||||
|
|
||||||
|
if ($entityType == ENTITY_INVOICE)
|
||||||
|
{
|
||||||
$records->where('is_quote', '=', false)
|
$records->where('is_quote', '=', false)
|
||||||
->where('is_recurring', '=', false);
|
->where('is_recurring', '=', false);
|
||||||
}
|
}
|
||||||
|
|
||||||
$totals = $records->lists('total');
|
$totals = $records->lists('total');
|
||||||
$dates = $records->lists($groupBy);
|
$dates = $records->lists($groupBy);
|
||||||
$data = array_combine($dates, $totals);
|
$data = array_combine($dates, $totals);
|
||||||
|
|
||||||
$padding = $groupBy == 'DAYOFYEAR' ? 'day' : ($groupBy == 'WEEK' ? 'week' : 'month');
|
$padding = $groupBy == 'DAYOFYEAR' ? 'day' : ($groupBy == 'WEEK' ? 'week' : 'month');
|
||||||
$endDate->modify('+1 '.$padding);
|
$endDate->modify('+1 '.$padding);
|
||||||
$interval = new DateInterval('P1'.substr($groupBy, 0, 1));
|
$interval = new DateInterval('P1'.substr($groupBy, 0, 1));
|
||||||
$period = new DatePeriod($startDate, $interval, $endDate);
|
$period = new DatePeriod($startDate, $interval, $endDate);
|
||||||
$endDate->modify('-1 '.$padding);
|
$endDate->modify('-1 '.$padding);
|
||||||
|
|
||||||
$totals = [];
|
$totals = [];
|
||||||
|
|
||||||
foreach ($period as $d) {
|
foreach ($period as $d)
|
||||||
|
{
|
||||||
$dateFormat = $groupBy == 'DAYOFYEAR' ? 'z' : ($groupBy == 'WEEK' ? 'W' : 'n');
|
$dateFormat = $groupBy == 'DAYOFYEAR' ? 'z' : ($groupBy == 'WEEK' ? 'W' : 'n');
|
||||||
$date = $d->format('Y'.$dateFormat);
|
$date = $d->format('Y'.$dateFormat);
|
||||||
$totals[] = isset($data[$date]) ? $data[$date] : 0;
|
$totals[] = isset($data[$date]) ? $data[$date] : 0;
|
||||||
|
|
||||||
if ($entityType == ENTITY_INVOICE) {
|
if ($entityType == ENTITY_INVOICE)
|
||||||
|
{
|
||||||
$labelFormat = $groupBy == 'DAYOFYEAR' ? 'j' : ($groupBy == 'WEEK' ? 'W' : 'F');
|
$labelFormat = $groupBy == 'DAYOFYEAR' ? 'j' : ($groupBy == 'WEEK' ? 'W' : 'F');
|
||||||
$label = $d->format($labelFormat);
|
$label = $d->format($labelFormat);
|
||||||
$labels[] = $label;
|
$labels[] = $label;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$max = max($totals);
|
$max = max($totals);
|
||||||
|
|
||||||
if ($max > 0) {
|
if ($max > 0)
|
||||||
|
{
|
||||||
$datasets[] = [
|
$datasets[] = [
|
||||||
'totals' => $totals,
|
'totals' => $totals,
|
||||||
'colors' => $entityType == ENTITY_INVOICE ? '78,205,196' : ($entityType == ENTITY_CREDIT ? '199,244,100' : '255,107,107'),
|
'colors' => $entityType == ENTITY_INVOICE ? '78,205,196' : ($entityType == ENTITY_CREDIT ? '199,244,100' : '255,107,107'),
|
||||||
@ -243,6 +281,7 @@ class ReportController extends BaseController
|
|||||||
'reportType' => $reportType,
|
'reportType' => $reportType,
|
||||||
'enableChart' => $enableChart,
|
'enableChart' => $enableChart,
|
||||||
'enableReport' => $enableReport,
|
'enableReport' => $enableReport,
|
||||||
|
'title' => trans('texts.charts_and_reports'),
|
||||||
];
|
];
|
||||||
|
|
||||||
return View::make('reports.chart_builder', $params);
|
return View::make('reports.chart_builder', $params);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<?php namespace App\Http\Controllers;
|
<?php namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Auth;
|
||||||
use View;
|
use View;
|
||||||
use URL;
|
use URL;
|
||||||
use Utils;
|
use Utils;
|
||||||
@ -8,34 +9,24 @@ use Datatable;
|
|||||||
use Validator;
|
use Validator;
|
||||||
use Redirect;
|
use Redirect;
|
||||||
use Session;
|
use Session;
|
||||||
|
use DropdownButton;
|
||||||
|
use DateTime;
|
||||||
|
use DateTimeZone;
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
use App\Models\Task;
|
use App\Models\Task;
|
||||||
|
|
||||||
/*
|
|
||||||
use Auth;
|
|
||||||
use Cache;
|
|
||||||
|
|
||||||
use App\Models\Activity;
|
|
||||||
use App\Models\Contact;
|
|
||||||
use App\Models\Invoice;
|
|
||||||
use App\Models\Size;
|
|
||||||
use App\Models\PaymentTerm;
|
|
||||||
use App\Models\Industry;
|
|
||||||
use App\Models\Currency;
|
|
||||||
use App\Models\Country;
|
|
||||||
*/
|
|
||||||
|
|
||||||
use App\Ninja\Repositories\TaskRepository;
|
use App\Ninja\Repositories\TaskRepository;
|
||||||
|
use App\Ninja\Repositories\InvoiceRepository;
|
||||||
|
|
||||||
class TaskController extends BaseController
|
class TaskController extends BaseController
|
||||||
{
|
{
|
||||||
protected $taskRepo;
|
protected $taskRepo;
|
||||||
|
|
||||||
public function __construct(TaskRepository $taskRepo)
|
public function __construct(TaskRepository $taskRepo, InvoiceRepository $invoiceRepo)
|
||||||
{
|
{
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
|
|
||||||
$this->taskRepo = $taskRepo;
|
$this->taskRepo = $taskRepo;
|
||||||
|
$this->invoiceRepo = $invoiceRepo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -44,7 +35,9 @@ class TaskController extends BaseController
|
|||||||
* @return Response
|
* @return Response
|
||||||
*/
|
*/
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
|
self::checkTimezone();
|
||||||
|
|
||||||
return View::make('list', array(
|
return View::make('list', array(
|
||||||
'entityType' => ENTITY_TASK,
|
'entityType' => ENTITY_TASK,
|
||||||
'title' => trans('texts.tasks'),
|
'title' => trans('texts.tasks'),
|
||||||
@ -64,8 +57,8 @@ class TaskController extends BaseController
|
|||||||
->addColumn('client_name', function ($model) { return $model->client_public_id ? link_to('clients/'.$model->client_public_id, Utils::getClientDisplayName($model)) : ''; });
|
->addColumn('client_name', function ($model) { return $model->client_public_id ? link_to('clients/'.$model->client_public_id, Utils::getClientDisplayName($model)) : ''; });
|
||||||
}
|
}
|
||||||
|
|
||||||
return $table->addColumn('start_time', function($model) { return Utils::fromSqlDateTime($model->start_time); })
|
return $table->addColumn('created_at', function($model) { return Task::calcStartTime($model); })
|
||||||
->addColumn('duration', function($model) { return gmdate('H:i:s', $model->duration == -1 ? time() - strtotime($model->start_time) : $model->duration); })
|
->addColumn('time_log', function($model) { return gmdate('H:i:s', Task::calcDuration($model)); })
|
||||||
->addColumn('description', function($model) { return $model->description; })
|
->addColumn('description', function($model) { return $model->description; })
|
||||||
->addColumn('invoice_number', function($model) { return self::getStatusLabel($model); })
|
->addColumn('invoice_number', function($model) { return self::getStatusLabel($model); })
|
||||||
->addColumn('dropdown', function ($model) {
|
->addColumn('dropdown', function ($model) {
|
||||||
@ -81,7 +74,7 @@ class TaskController extends BaseController
|
|||||||
|
|
||||||
if ($model->invoice_number) {
|
if ($model->invoice_number) {
|
||||||
$str .= '<li>' . link_to("/invoices/{$model->invoice_public_id}/edit", trans('texts.view_invoice')) . '</li>';
|
$str .= '<li>' . link_to("/invoices/{$model->invoice_public_id}/edit", trans('texts.view_invoice')) . '</li>';
|
||||||
} elseif ($model->duration == -1) {
|
} elseif ($model->is_running) {
|
||||||
$str .= '<li><a href="javascript:stopTask('.$model->public_id.')">'.trans('texts.stop_task').'</a></li>';
|
$str .= '<li><a href="javascript:stopTask('.$model->public_id.')">'.trans('texts.stop_task').'</a></li>';
|
||||||
} elseif (!$model->deleted_at || $model->deleted_at == '0000-00-00') {
|
} elseif (!$model->deleted_at || $model->deleted_at == '0000-00-00') {
|
||||||
$str .= '<li><a href="javascript:invoiceTask('.$model->public_id.')">'.trans('texts.invoice_task').'</a></li>';
|
$str .= '<li><a href="javascript:invoiceTask('.$model->public_id.')">'.trans('texts.invoice_task').'</a></li>';
|
||||||
@ -107,7 +100,7 @@ class TaskController extends BaseController
|
|||||||
if ($model->invoice_number) {
|
if ($model->invoice_number) {
|
||||||
$class = 'success';
|
$class = 'success';
|
||||||
$label = trans('texts.invoiced');
|
$label = trans('texts.invoiced');
|
||||||
} elseif ($model->duration == -1) {
|
} elseif ($model->is_running) {
|
||||||
$class = 'primary';
|
$class = 'primary';
|
||||||
$label = trans('texts.running');
|
$label = trans('texts.running');
|
||||||
} else {
|
} else {
|
||||||
@ -135,12 +128,15 @@ class TaskController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function create($clientPublicId = 0)
|
public function create($clientPublicId = 0)
|
||||||
{
|
{
|
||||||
|
self::checkTimezone();
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'task' => null,
|
'task' => null,
|
||||||
'clientPublicId' => Input::old('client') ? Input::old('client') : $clientPublicId,
|
'clientPublicId' => Input::old('client') ? Input::old('client') : $clientPublicId,
|
||||||
'method' => 'POST',
|
'method' => 'POST',
|
||||||
'url' => 'tasks',
|
'url' => 'tasks',
|
||||||
'title' => trans('texts.new_task'),
|
'title' => trans('texts.new_task'),
|
||||||
|
'minuteOffset' => Utils::getTiemstampOffset(),
|
||||||
];
|
];
|
||||||
|
|
||||||
$data = array_merge($data, self::getViewModel());
|
$data = array_merge($data, self::getViewModel());
|
||||||
@ -156,15 +152,41 @@ class TaskController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function edit($publicId)
|
public function edit($publicId)
|
||||||
{
|
{
|
||||||
$task = Task::scope($publicId)->with('client')->firstOrFail();
|
self::checkTimezone();
|
||||||
|
|
||||||
|
$task = Task::scope($publicId)->with('client', 'invoice')->firstOrFail();
|
||||||
|
|
||||||
|
$actions = [];
|
||||||
|
if ($task->invoice) {
|
||||||
|
$actions[] = ['url' => URL::to("inovices/{$task->invoice->public_id}/edit"), 'label' => trans("texts.view_invoice")];
|
||||||
|
} else {
|
||||||
|
$actions[] = ['url' => 'javascript:submitAction("invoice")', 'label' => trans("texts.create_invoice")];
|
||||||
|
|
||||||
|
// check for any open invoices
|
||||||
|
$invoices = $task->client_id ? $this->invoiceRepo->findOpenInvoices($task->client_id) : [];
|
||||||
|
|
||||||
|
foreach ($invoices as $invoice) {
|
||||||
|
$actions[] = ['url' => 'javascript:submitAction("add_to_invoice", '.$invoice->public_id.')', 'label' => trans("texts.add_to_invoice", ["invoice" => $invoice->invoice_number])];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$actions[] = DropdownButton::DIVIDER;
|
||||||
|
if (!$task->trashed()) {
|
||||||
|
$actions[] = ['url' => 'javascript:submitAction("archive")', 'label' => trans('texts.archive_task')];
|
||||||
|
$actions[] = ['url' => 'javascript:onDeleteClick()', 'label' => trans('texts.delete_task')];
|
||||||
|
} else {
|
||||||
|
$actions[] = ['url' => 'javascript:submitAction("restore")', 'label' => trans('texts.restore_task')];
|
||||||
|
}
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'task' => $task,
|
'task' => $task,
|
||||||
'clientPublicId' => $task->client ? $task->client->public_id : 0,
|
'clientPublicId' => $task->client ? $task->client->public_id : 0,
|
||||||
'method' => 'PUT',
|
'method' => 'PUT',
|
||||||
'url' => 'tasks/'.$publicId,
|
'url' => 'tasks/'.$publicId,
|
||||||
'title' => trans('texts.edit_task'),
|
'title' => trans('texts.edit_task'),
|
||||||
'duration' => time() - strtotime($task->start_time),
|
'duration' => $task->is_running ? $task->getCurrentDuration() : $task->getDuration(),
|
||||||
|
'actions' => $actions,
|
||||||
|
'minuteOffset' => Utils::getTiemstampOffset(),
|
||||||
];
|
];
|
||||||
|
|
||||||
$data = array_merge($data, self::getViewModel());
|
$data = array_merge($data, self::getViewModel());
|
||||||
@ -192,15 +214,16 @@ class TaskController extends BaseController
|
|||||||
|
|
||||||
private function save($publicId = null)
|
private function save($publicId = null)
|
||||||
{
|
{
|
||||||
$task = $this->taskRepo->save($publicId, Input::all());
|
$action = Input::get('action');
|
||||||
|
|
||||||
|
if (in_array($action, ['archive', 'delete', 'invoice', 'restore', 'add_to_invoice'])) {
|
||||||
|
return self::bulk();
|
||||||
|
}
|
||||||
|
|
||||||
|
$task = $this->taskRepo->save($publicId, Input::all());
|
||||||
Session::flash('message', trans($publicId ? 'texts.updated_task' : 'texts.created_task'));
|
Session::flash('message', trans($publicId ? 'texts.updated_task' : 'texts.created_task'));
|
||||||
|
|
||||||
if (Input::get('action') == 'stop') {
|
return Redirect::to("tasks/{$task->public_id}/edit");
|
||||||
return Redirect::to("tasks");
|
|
||||||
} else {
|
|
||||||
return Redirect::to("tasks/{$task->public_id}/edit");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function bulk()
|
public function bulk()
|
||||||
@ -212,12 +235,11 @@ class TaskController extends BaseController
|
|||||||
$this->taskRepo->save($ids, ['action' => $action]);
|
$this->taskRepo->save($ids, ['action' => $action]);
|
||||||
Session::flash('message', trans('texts.stopped_task'));
|
Session::flash('message', trans('texts.stopped_task'));
|
||||||
return Redirect::to('tasks');
|
return Redirect::to('tasks');
|
||||||
} else if ($action == 'invoice') {
|
} else if ($action == 'invoice' || $action == 'add_to_invoice') {
|
||||||
|
|
||||||
$tasks = Task::scope($ids)->with('client')->get();
|
$tasks = Task::scope($ids)->with('client')->get();
|
||||||
$clientPublicId = false;
|
$clientPublicId = false;
|
||||||
$data = [];
|
$data = [];
|
||||||
|
|
||||||
foreach ($tasks as $task) {
|
foreach ($tasks as $task) {
|
||||||
if ($task->client) {
|
if ($task->client) {
|
||||||
if (!$clientPublicId) {
|
if (!$clientPublicId) {
|
||||||
@ -228,23 +250,28 @@ class TaskController extends BaseController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($task->duration == -1) {
|
if ($task->is_running) {
|
||||||
Session::flash('error', trans('texts.task_error_running'));
|
Session::flash('error', trans('texts.task_error_running'));
|
||||||
return Redirect::to('tasks');
|
return Redirect::to('tasks');
|
||||||
} else if ($task->invoice_id) {
|
} else if ($task->invoice_id) {
|
||||||
Session::flash('error', trans('texts.task_error_invoiced'));
|
Session::flash('error', trans('texts.task_error_invoiced'));
|
||||||
return Redirect::to('tasks');
|
return Redirect::to('tasks');
|
||||||
}
|
}
|
||||||
|
|
||||||
$data[] = [
|
$data[] = [
|
||||||
'publicId' => $task->public_id,
|
'publicId' => $task->public_id,
|
||||||
'description' => $task->description,
|
'description' => $task->description,
|
||||||
'startTime' => Utils::fromSqlDateTime($task->start_time),
|
'startTime' => $task->getStartTime(),
|
||||||
'duration' => round($task->duration / (60 * 60), 2)
|
'duration' => $task->getHours(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
return Redirect::to("invoices/create/{$clientPublicId}")->with('tasks', $data);
|
if ($action == 'invoice') {
|
||||||
|
return Redirect::to("invoices/create/{$clientPublicId}")->with('tasks', $data);
|
||||||
|
} else {
|
||||||
|
$invoiceId = Input::get('invoice_id');
|
||||||
|
return Redirect::to("invoices/{$invoiceId}/edit")->with('tasks', $data);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$count = $this->taskRepo->bulk($ids, $action);
|
$count = $this->taskRepo->bulk($ids, $action);
|
||||||
|
|
||||||
@ -258,4 +285,12 @@ class TaskController extends BaseController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function checkTimezone()
|
||||||
|
{
|
||||||
|
if (!Auth::user()->account->timezone) {
|
||||||
|
$link = link_to('/company/details', trans('texts.click_here'), ['target' => '_blank']);
|
||||||
|
Session::flash('warning', trans('texts.timezone_unset', ['link' => $link]));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ use DB;
|
|||||||
use Event;
|
use Event;
|
||||||
use Input;
|
use Input;
|
||||||
use View;
|
use View;
|
||||||
|
use Request;
|
||||||
use Redirect;
|
use Redirect;
|
||||||
use Session;
|
use Session;
|
||||||
use URL;
|
use URL;
|
||||||
@ -300,23 +301,24 @@ class UserController extends BaseController
|
|||||||
* Log the user out of the application.
|
* Log the user out of the application.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
/*
|
||||||
public function logout()
|
public function logout()
|
||||||
{
|
{
|
||||||
if (Auth::check()) {
|
if (Auth::check()) {
|
||||||
if (!Auth::user()->registered) {
|
if (!Auth::user()->registered) {
|
||||||
$account = Auth::user()->account;
|
$account = Auth::user()->account;
|
||||||
|
$this->accountRepo->unlinkAccount($account);
|
||||||
$account->forceDelete();
|
$account->forceDelete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Session::forget('news_feed_id');
|
|
||||||
Session::forget('news_feed_message');
|
|
||||||
|
|
||||||
Auth::logout();
|
Auth::logout();
|
||||||
|
Session::flush();
|
||||||
|
|
||||||
return Redirect::to('/')->with('clearGuestKey', true);
|
return Redirect::to('/')->with('clearGuestKey', true);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
public function changePassword()
|
public function changePassword()
|
||||||
{
|
{
|
||||||
// check the current password is correct
|
// check the current password is correct
|
||||||
@ -342,4 +344,36 @@ class UserController extends BaseController
|
|||||||
|
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function switchAccount($newUserId)
|
||||||
|
{
|
||||||
|
$oldUserId = Auth::user()->id;
|
||||||
|
$referer = Request::header('referer');
|
||||||
|
$account = $this->accountRepo->findUserAccounts($newUserId, $oldUserId);
|
||||||
|
|
||||||
|
if ($account) {
|
||||||
|
if ($account->hasUserId($newUserId) && $account->hasUserId($oldUserId)) {
|
||||||
|
Auth::loginUsingId($newUserId);
|
||||||
|
Auth::user()->account->loadLocalizationSettings();
|
||||||
|
|
||||||
|
// regenerate token to prevent open pages
|
||||||
|
// from saving under the wrong account
|
||||||
|
Session::put('_token', str_random(40));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Redirect::to($referer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function unlinkAccount($userAccountId, $userId)
|
||||||
|
{
|
||||||
|
$this->accountRepo->unlinkUser($userAccountId, $userId);
|
||||||
|
$referer = Request::header('referer');
|
||||||
|
|
||||||
|
$users = $this->accountRepo->loadAccounts(Auth::user()->id);
|
||||||
|
Session::put(SESSION_USER_ACCOUNTS, $users);
|
||||||
|
|
||||||
|
Session::flash('message', trans('texts.unlinked_account'));
|
||||||
|
return Redirect::to($referer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,7 @@ class StartupCheck
|
|||||||
'paymentTerms' => 'App\Models\PaymentTerm',
|
'paymentTerms' => 'App\Models\PaymentTerm',
|
||||||
'paymentTypes' => 'App\Models\PaymentType',
|
'paymentTypes' => 'App\Models\PaymentType',
|
||||||
'countries' => 'App\Models\Country',
|
'countries' => 'App\Models\Country',
|
||||||
|
'invoiceDesigns' => 'App\Models\InvoiceDesign',
|
||||||
];
|
];
|
||||||
foreach ($cachedTables as $name => $class) {
|
foreach ($cachedTables as $name => $class) {
|
||||||
if (Input::has('clear_cache')) {
|
if (Input::has('clear_cache')) {
|
||||||
@ -157,6 +158,14 @@ class StartupCheck
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $next($request);
|
if (preg_match('/(?i)msie [2-8]/', $_SERVER['HTTP_USER_AGENT'])) {
|
||||||
|
Session::flash('error', trans('texts.old_browser'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// for security prevent displaying within an iframe
|
||||||
|
$response = $next($request);
|
||||||
|
$response->headers->set('X-Frame-Options', 'DENY');
|
||||||
|
|
||||||
|
return $response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,7 @@ get('/signup', array('as' => 'signup', 'uses' => 'Auth\AuthController@getRegiste
|
|||||||
post('/signup', array('as' => 'signup', 'uses' => 'Auth\AuthController@postRegister'));
|
post('/signup', array('as' => 'signup', 'uses' => 'Auth\AuthController@postRegister'));
|
||||||
get('/login', array('as' => 'login', 'uses' => 'Auth\AuthController@getLoginWrapper'));
|
get('/login', array('as' => 'login', 'uses' => 'Auth\AuthController@getLoginWrapper'));
|
||||||
post('/login', array('as' => 'login', 'uses' => 'Auth\AuthController@postLoginWrapper'));
|
post('/login', array('as' => 'login', 'uses' => 'Auth\AuthController@postLoginWrapper'));
|
||||||
get('/logout', array('as' => 'logout', 'uses' => 'Auth\AuthController@getLogout'));
|
get('/logout', array('as' => 'logout', 'uses' => 'Auth\AuthController@getLogoutWrapper'));
|
||||||
get('/forgot', array('as' => 'forgot', 'uses' => 'Auth\PasswordController@getEmail'));
|
get('/forgot', array('as' => 'forgot', 'uses' => 'Auth\PasswordController@getEmail'));
|
||||||
post('/forgot', array('as' => 'forgot', 'uses' => 'Auth\PasswordController@postEmail'));
|
post('/forgot', array('as' => 'forgot', 'uses' => 'Auth\PasswordController@postEmail'));
|
||||||
get('/password/reset/{token}', array('as' => 'forgot', 'uses' => 'Auth\PasswordController@getReset'));
|
get('/password/reset/{token}', array('as' => 'forgot', 'uses' => 'Auth\PasswordController@getReset'));
|
||||||
@ -93,6 +93,8 @@ Route::group(['middleware' => 'auth'], function() {
|
|||||||
Route::get('send_confirmation/{user_id}', 'UserController@sendConfirmation');
|
Route::get('send_confirmation/{user_id}', 'UserController@sendConfirmation');
|
||||||
Route::get('restore_user/{user_id}', 'UserController@restoreUser');
|
Route::get('restore_user/{user_id}', 'UserController@restoreUser');
|
||||||
Route::post('users/change_password', 'UserController@changePassword');
|
Route::post('users/change_password', 'UserController@changePassword');
|
||||||
|
Route::get('/switch_account/{user_id}', 'UserController@switchAccount');
|
||||||
|
Route::get('/unlink_account/{user_account_id}/{user_id}', 'UserController@unlinkAccount');
|
||||||
|
|
||||||
Route::get('api/tokens', array('as'=>'api.tokens', 'uses'=>'TokenController@getDatatable'));
|
Route::get('api/tokens', array('as'=>'api.tokens', 'uses'=>'TokenController@getDatatable'));
|
||||||
Route::resource('tokens', 'TokenController');
|
Route::resource('tokens', 'TokenController');
|
||||||
@ -204,6 +206,9 @@ Route::get('/testimonials', function() {
|
|||||||
Route::get('/compare-online-invoicing{sites?}', function() {
|
Route::get('/compare-online-invoicing{sites?}', function() {
|
||||||
return Redirect::to(NINJA_WEB_URL, 301);
|
return Redirect::to(NINJA_WEB_URL, 301);
|
||||||
});
|
});
|
||||||
|
Route::get('/forgot_password', function() {
|
||||||
|
return Redirect::to(NINJA_APP_URL.'/forgot', 301);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
define('CONTACT_EMAIL', Config::get('mail.from.address'));
|
define('CONTACT_EMAIL', Config::get('mail.from.address'));
|
||||||
@ -241,6 +246,8 @@ define('ACCOUNT_USER_MANAGEMENT', 'user_management');
|
|||||||
define('ACCOUNT_DATA_VISUALIZATIONS', 'data_visualizations');
|
define('ACCOUNT_DATA_VISUALIZATIONS', 'data_visualizations');
|
||||||
define('ACCOUNT_EMAIL_TEMPLATES', 'email_templates');
|
define('ACCOUNT_EMAIL_TEMPLATES', 'email_templates');
|
||||||
define('ACCOUNT_TOKEN_MANAGEMENT', 'token_management');
|
define('ACCOUNT_TOKEN_MANAGEMENT', 'token_management');
|
||||||
|
define('ACCOUNT_CUSTOMIZE_DESIGN', 'customize_design');
|
||||||
|
|
||||||
|
|
||||||
define('ACTIVITY_TYPE_CREATE_CLIENT', 1);
|
define('ACTIVITY_TYPE_CREATE_CLIENT', 1);
|
||||||
define('ACTIVITY_TYPE_ARCHIVE_CLIENT', 2);
|
define('ACTIVITY_TYPE_ARCHIVE_CLIENT', 2);
|
||||||
@ -294,6 +301,7 @@ define('INVOICE_STATUS_PARTIAL', 4);
|
|||||||
define('INVOICE_STATUS_PAID', 5);
|
define('INVOICE_STATUS_PAID', 5);
|
||||||
|
|
||||||
define('PAYMENT_TYPE_CREDIT', 1);
|
define('PAYMENT_TYPE_CREDIT', 1);
|
||||||
|
define('CUSTOM_DESIGN', 11);
|
||||||
|
|
||||||
define('FREQUENCY_WEEKLY', 1);
|
define('FREQUENCY_WEEKLY', 1);
|
||||||
define('FREQUENCY_TWO_WEEKS', 2);
|
define('FREQUENCY_TWO_WEEKS', 2);
|
||||||
@ -310,6 +318,7 @@ define('SESSION_DATE_PICKER_FORMAT', 'datePickerFormat');
|
|||||||
define('SESSION_DATETIME_FORMAT', 'datetimeFormat');
|
define('SESSION_DATETIME_FORMAT', 'datetimeFormat');
|
||||||
define('SESSION_COUNTER', 'sessionCounter');
|
define('SESSION_COUNTER', 'sessionCounter');
|
||||||
define('SESSION_LOCALE', 'sessionLocale');
|
define('SESSION_LOCALE', 'sessionLocale');
|
||||||
|
define('SESSION_USER_ACCOUNTS', 'userAccounts');
|
||||||
|
|
||||||
define('SESSION_LAST_REQUEST_PAGE', 'SESSION_LAST_REQUEST_PAGE');
|
define('SESSION_LAST_REQUEST_PAGE', 'SESSION_LAST_REQUEST_PAGE');
|
||||||
define('SESSION_LAST_REQUEST_TIME', 'SESSION_LAST_REQUEST_TIME');
|
define('SESSION_LAST_REQUEST_TIME', 'SESSION_LAST_REQUEST_TIME');
|
||||||
@ -348,18 +357,23 @@ define('EVENT_CREATE_PAYMENT', 4);
|
|||||||
|
|
||||||
define('REQUESTED_PRO_PLAN', 'REQUESTED_PRO_PLAN');
|
define('REQUESTED_PRO_PLAN', 'REQUESTED_PRO_PLAN');
|
||||||
define('DEMO_ACCOUNT_ID', 'DEMO_ACCOUNT_ID');
|
define('DEMO_ACCOUNT_ID', 'DEMO_ACCOUNT_ID');
|
||||||
|
define('PREV_USER_ID', 'PREV_USER_ID');
|
||||||
define('NINJA_ACCOUNT_KEY', 'zg4ylmzDkdkPOT8yoKQw9LTWaoZJx79h');
|
define('NINJA_ACCOUNT_KEY', 'zg4ylmzDkdkPOT8yoKQw9LTWaoZJx79h');
|
||||||
define('NINJA_GATEWAY_ID', GATEWAY_STRIPE);
|
define('NINJA_GATEWAY_ID', GATEWAY_STRIPE);
|
||||||
define('NINJA_GATEWAY_CONFIG', '');
|
define('NINJA_GATEWAY_CONFIG', '');
|
||||||
define('NINJA_WEB_URL', 'https://www.invoiceninja.com');
|
define('NINJA_WEB_URL', 'https://www.invoiceninja.com');
|
||||||
define('NINJA_APP_URL', 'https://app.invoiceninja.com');
|
define('NINJA_APP_URL', 'https://app.invoiceninja.com');
|
||||||
define('NINJA_VERSION', '2.2.0');
|
define('NINJA_VERSION', '2.2.2');
|
||||||
define('NINJA_DATE', '2000-01-01');
|
define('NINJA_DATE', '2000-01-01');
|
||||||
|
|
||||||
define('NINJA_FROM_EMAIL', 'maildelivery@invoiceninja.com');
|
define('NINJA_FROM_EMAIL', 'maildelivery@invoiceninja.com');
|
||||||
define('RELEASES_URL', 'https://github.com/hillelcoren/invoice-ninja/releases/');
|
define('RELEASES_URL', 'https://github.com/hillelcoren/invoice-ninja/releases/');
|
||||||
define('ZAPIER_URL', 'https://zapier.com/developer/invite/11276/85cf0ee4beae8e802c6c579eb4e351f1/');
|
define('ZAPIER_URL', 'https://zapier.com/developer/invite/11276/85cf0ee4beae8e802c6c579eb4e351f1/');
|
||||||
|
define('OUTDATE_BROWSER_URL', 'http://browsehappy.com/');
|
||||||
|
define('PDFMAKE_DOCS', 'http://pdfmake.org/playground.html');
|
||||||
|
|
||||||
define('COUNT_FREE_DESIGNS', 4);
|
define('COUNT_FREE_DESIGNS', 4);
|
||||||
|
define('COUNT_FREE_DESIGNS_SELF_HOST', 5); // include the custom design
|
||||||
define('PRODUCT_ONE_CLICK_INSTALL', 1);
|
define('PRODUCT_ONE_CLICK_INSTALL', 1);
|
||||||
define('PRODUCT_INVOICE_DESIGNS', 2);
|
define('PRODUCT_INVOICE_DESIGNS', 2);
|
||||||
define('PRODUCT_WHITE_LABEL', 3);
|
define('PRODUCT_WHITE_LABEL', 3);
|
||||||
@ -452,6 +466,7 @@ Event::listen('illuminate.query', function($query, $bindings, $time, $name)
|
|||||||
});
|
});
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
if (Auth::check() && Auth::user()->id === 1)
|
if (Auth::check() && Auth::user()->id === 1)
|
||||||
{
|
{
|
||||||
|
@ -51,12 +51,17 @@ class Utils
|
|||||||
|
|
||||||
public static function isNinjaProd()
|
public static function isNinjaProd()
|
||||||
{
|
{
|
||||||
return isset($_ENV['NINJA_PROD']) && $_ENV['NINJA_PROD'];
|
return isset($_ENV['NINJA_PROD']) && $_ENV['NINJA_PROD'] == 'true';
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function isNinjaDev()
|
public static function isNinjaDev()
|
||||||
{
|
{
|
||||||
return isset($_ENV['NINJA_DEV']) && $_ENV['NINJA_DEV'];
|
return isset($_ENV['NINJA_DEV']) && $_ENV['NINJA_DEV'] == 'true';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function allowNewAccounts()
|
||||||
|
{
|
||||||
|
return Utils::isNinja() || (isset($_ENV['ALLOW_NEW_ACCOUNTS']) && $_ENV['ALLOW_NEW_ACCOUNTS'] == 'true');
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function isPro()
|
public static function isPro()
|
||||||
@ -246,6 +251,10 @@ class Utils
|
|||||||
$currency = Currency::find(1);
|
$currency = Currency::find(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$value) {
|
||||||
|
$value = 0;
|
||||||
|
}
|
||||||
|
|
||||||
Cache::add('currency', $currency, DEFAULT_QUERY_CACHE);
|
Cache::add('currency', $currency, DEFAULT_QUERY_CACHE);
|
||||||
|
|
||||||
return $currency->symbol.number_format($value, $currency->precision, $currency->decimal_separator, $currency->thousand_separator);
|
return $currency->symbol.number_format($value, $currency->precision, $currency->decimal_separator, $currency->thousand_separator);
|
||||||
@ -310,6 +319,16 @@ class Utils
|
|||||||
return $date->format($format);
|
return $date->format($format);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getTiemstampOffset()
|
||||||
|
{
|
||||||
|
$timezone = new DateTimeZone(Session::get(SESSION_TIMEZONE, DEFAULT_TIMEZONE));
|
||||||
|
$datetime = new DateTime('now', $timezone);
|
||||||
|
$offset = $timezone->getOffset($datetime);
|
||||||
|
$minutes = $offset / 60;
|
||||||
|
|
||||||
|
return $minutes;
|
||||||
|
}
|
||||||
|
|
||||||
public static function toSqlDate($date, $formatResult = true)
|
public static function toSqlDate($date, $formatResult = true)
|
||||||
{
|
{
|
||||||
if (!$date) {
|
if (!$date) {
|
||||||
@ -347,7 +366,7 @@ class Utils
|
|||||||
|
|
||||||
$timezone = Session::get(SESSION_TIMEZONE, DEFAULT_TIMEZONE);
|
$timezone = Session::get(SESSION_TIMEZONE, DEFAULT_TIMEZONE);
|
||||||
$format = Session::get(SESSION_DATETIME_FORMAT, DEFAULT_DATETIME_FORMAT);
|
$format = Session::get(SESSION_DATETIME_FORMAT, DEFAULT_DATETIME_FORMAT);
|
||||||
|
|
||||||
$dateTime = DateTime::createFromFormat('Y-m-d H:i:s', $date);
|
$dateTime = DateTime::createFromFormat('Y-m-d H:i:s', $date);
|
||||||
$dateTime->setTimeZone(new DateTimeZone($timezone));
|
$dateTime->setTimeZone(new DateTimeZone($timezone));
|
||||||
|
|
||||||
@ -563,14 +582,15 @@ class Utils
|
|||||||
{
|
{
|
||||||
$curl = curl_init();
|
$curl = curl_init();
|
||||||
|
|
||||||
$jsonEncodedData = json_encode($data->toJson());
|
$jsonEncodedData = json_encode($data->toPublicArray());
|
||||||
|
|
||||||
$opts = [
|
$opts = [
|
||||||
CURLOPT_URL => $subscription->target_url,
|
CURLOPT_URL => $subscription->target_url,
|
||||||
CURLOPT_RETURNTRANSFER => true,
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
CURLOPT_CUSTOMREQUEST => 'POST',
|
CURLOPT_CUSTOMREQUEST => 'POST',
|
||||||
CURLOPT_POST => 1,
|
CURLOPT_POST => 1,
|
||||||
CURLOPT_POSTFIELDS => $jsonEncodedData,
|
CURLOPT_POSTFIELDS => $jsonEncodedData,
|
||||||
CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Content-Length: '.strlen($jsonEncodedData)],
|
CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Content-Length: '.strlen($jsonEncodedData)],
|
||||||
];
|
];
|
||||||
|
|
||||||
curl_setopt_array($curl, $opts);
|
curl_setopt_array($curl, $opts);
|
||||||
@ -586,27 +606,39 @@ class Utils
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static function remapPublicIds(array $data)
|
public static function remapPublicIds($items)
|
||||||
{
|
{
|
||||||
$return = [];
|
$return = [];
|
||||||
|
|
||||||
foreach ($data as $key => $val) {
|
foreach ($items as $item) {
|
||||||
if ($key === 'public_id') {
|
$return[] = $item->toPublicArray();
|
||||||
$key = 'id';
|
|
||||||
} elseif (strpos($key, '_id')) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_array($val)) {
|
|
||||||
$val = Utils::remapPublicIds($val);
|
|
||||||
}
|
|
||||||
|
|
||||||
$return[$key] = $val;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $return;
|
return $return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function hideIds($data)
|
||||||
|
{
|
||||||
|
$publicId = null;
|
||||||
|
|
||||||
|
foreach ($data as $key => $val) {
|
||||||
|
if (is_array($val)) {
|
||||||
|
$data[$key] = Utils::hideIds($val);
|
||||||
|
} else if ($key == 'id' || strpos($key, '_id')) {
|
||||||
|
if ($key == 'public_id') {
|
||||||
|
$publicId = $val;
|
||||||
|
}
|
||||||
|
unset($data[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($publicId) {
|
||||||
|
$data['id'] = $publicId;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
public static function getApiHeaders($count = 0)
|
public static function getApiHeaders($count = 0)
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
@ -659,4 +691,29 @@ class Utils
|
|||||||
|
|
||||||
fwrite($output, "\n");
|
fwrite($output, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function stringToObjectResolution($baseObject, $rawPath)
|
||||||
|
{
|
||||||
|
$val = '';
|
||||||
|
|
||||||
|
if (!is_object($baseObject)) {
|
||||||
|
return $val;
|
||||||
|
}
|
||||||
|
|
||||||
|
$path = preg_split('/->/', $rawPath);
|
||||||
|
$node = $baseObject;
|
||||||
|
|
||||||
|
while (($prop = array_shift($path)) !== null) {
|
||||||
|
if (property_exists($node, $prop)) {
|
||||||
|
$val = $node->$prop;
|
||||||
|
$node = $node->$prop;
|
||||||
|
} else if (is_object($node) && isset($node->$prop)) {
|
||||||
|
$node = $node->{$prop};
|
||||||
|
} else if ( method_exists($node, $prop)) {
|
||||||
|
$val = call_user_func(array($node, $prop));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $val;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
use Utils;
|
use Utils;
|
||||||
use Auth;
|
use Auth;
|
||||||
use Carbon;
|
use Carbon;
|
||||||
|
use Session;
|
||||||
use App\Events\UserLoggedIn;
|
use App\Events\UserLoggedIn;
|
||||||
use App\Ninja\Repositories\AccountRepository;
|
use App\Ninja\Repositories\AccountRepository;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
@ -32,13 +33,16 @@ class HandleUserLoggedIn {
|
|||||||
{
|
{
|
||||||
$account = Auth::user()->account;
|
$account = Auth::user()->account;
|
||||||
|
|
||||||
if (!Utils::isNinja() && empty($account->last_login)) {
|
if (!Utils::isNinja() && Auth::user()->id == 1 && empty($account->last_login)) {
|
||||||
$this->accountRepo->registerUser(Auth::user());
|
$this->accountRepo->registerUser(Auth::user());
|
||||||
}
|
}
|
||||||
|
|
||||||
$account->last_login = Carbon::now()->toDateTimeString();
|
$account->last_login = Carbon::now()->toDateTimeString();
|
||||||
$account->save();
|
$account->save();
|
||||||
|
|
||||||
|
$users = $this->accountRepo->loadAccounts(Auth::user()->id);
|
||||||
|
Session::put(SESSION_USER_ACCOUNTS, $users);
|
||||||
|
|
||||||
$account->loadLocalizationSettings();
|
$account->loadLocalizationSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
<?php namespace App\Listeners;
|
<?php namespace App\Listeners;
|
||||||
|
|
||||||
use Auth;
|
use Auth;
|
||||||
|
use Session;
|
||||||
use App\Events\UserSettingsChanged;
|
use App\Events\UserSettingsChanged;
|
||||||
|
use App\Ninja\Repositories\AccountRepository;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Contracts\Queue\ShouldBeQueued;
|
use Illuminate\Contracts\Queue\ShouldBeQueued;
|
||||||
|
|
||||||
@ -14,9 +14,9 @@ class HandleUserSettingsChanged {
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function __construct()
|
public function __construct(AccountRepository $accountRepo)
|
||||||
{
|
{
|
||||||
//
|
$this->accountRepo = $accountRepo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -29,6 +29,9 @@ class HandleUserSettingsChanged {
|
|||||||
{
|
{
|
||||||
$account = Auth::user()->account;
|
$account = Auth::user()->account;
|
||||||
$account->loadLocalizationSettings();
|
$account->loadLocalizationSettings();
|
||||||
|
|
||||||
|
$users = $this->accountRepo->loadAccounts(Auth::user()->id);
|
||||||
|
Session::put(SESSION_USER_ACCOUNTS, $users);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,10 @@ class Account extends Eloquent
|
|||||||
use SoftDeletes;
|
use SoftDeletes;
|
||||||
protected $dates = ['deleted_at'];
|
protected $dates = ['deleted_at'];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'utf8_invoice' => 'boolean',
|
||||||
|
];
|
||||||
|
|
||||||
public function users()
|
public function users()
|
||||||
{
|
{
|
||||||
return $this->hasMany('App\Models\User');
|
return $this->hasMany('App\Models\User');
|
||||||
@ -133,9 +137,17 @@ class Account extends Eloquent
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
public function hasLogo()
|
||||||
|
{
|
||||||
|
file_exists($this->getLogoPath());
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
public function getLogoPath()
|
public function getLogoPath()
|
||||||
{
|
{
|
||||||
return 'logo/'.$this->account_key.'.jpg';
|
$fileName = 'logo/' . $this->account_key;
|
||||||
|
return file_exists($fileName.'.png') ? $fileName.'.png' : $fileName.'.jpg';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getLogoWidth()
|
public function getLogoWidth()
|
||||||
@ -164,7 +176,7 @@ class Account extends Eloquent
|
|||||||
{
|
{
|
||||||
$counter = $isQuote && !$this->share_counter ? $this->quote_number_counter : $this->invoice_number_counter;
|
$counter = $isQuote && !$this->share_counter ? $this->quote_number_counter : $this->invoice_number_counter;
|
||||||
$prefix .= $isQuote ? $this->quote_number_prefix : $this->invoice_number_prefix;
|
$prefix .= $isQuote ? $this->quote_number_prefix : $this->invoice_number_prefix;
|
||||||
|
|
||||||
// confirm the invoice number isn't already taken
|
// confirm the invoice number isn't already taken
|
||||||
do {
|
do {
|
||||||
$number = $prefix.str_pad($counter, 4, "0", STR_PAD_LEFT);
|
$number = $prefix.str_pad($counter, 4, "0", STR_PAD_LEFT);
|
||||||
@ -179,11 +191,14 @@ class Account extends Eloquent
|
|||||||
{
|
{
|
||||||
// check if the user modified the invoice number
|
// check if the user modified the invoice number
|
||||||
if (!$isRecurring && $invoiceNumber != $this->getNextInvoiceNumber($isQuote)) {
|
if (!$isRecurring && $invoiceNumber != $this->getNextInvoiceNumber($isQuote)) {
|
||||||
$number = intval(preg_replace('/[^0-9]/', '', $invoiceNumber));
|
// remove the prefix
|
||||||
|
$prefix = $isQuote ? $this->quote_number_prefix : $this->invoice_number_prefix;
|
||||||
|
$invoiceNumber = preg_replace('/^'.$prefix.'/', '', $invoiceNumber);
|
||||||
|
$invoiceNumber = intval(preg_replace('/[^0-9]/', '', $invoiceNumber));
|
||||||
if ($isQuote && !$this->share_counter) {
|
if ($isQuote && !$this->share_counter) {
|
||||||
$this->quote_number_counter = $number + 1;
|
$this->quote_number_counter = $invoiceNumber + 1;
|
||||||
} else {
|
} else {
|
||||||
$this->invoice_number_counter = $number + 1;
|
$this->invoice_number_counter = $invoiceNumber + 1;
|
||||||
}
|
}
|
||||||
// otherwise, just increment the counter
|
// otherwise, just increment the counter
|
||||||
} else {
|
} else {
|
||||||
@ -250,6 +265,12 @@ class Account extends Eloquent
|
|||||||
'date',
|
'date',
|
||||||
'rate',
|
'rate',
|
||||||
'hours',
|
'hours',
|
||||||
|
'balance',
|
||||||
|
'from',
|
||||||
|
'to',
|
||||||
|
'invoice_to',
|
||||||
|
'details',
|
||||||
|
'invoice_no',
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($fields as $field) {
|
foreach ($fields as $field) {
|
||||||
@ -401,7 +422,7 @@ class Account extends Eloquent
|
|||||||
|
|
||||||
Account::updating(function ($account) {
|
Account::updating(function ($account) {
|
||||||
// Lithuanian requires UTF8 support
|
// Lithuanian requires UTF8 support
|
||||||
if (!Utils::isPro()) {
|
if (!Utils::isPro() && $account->language_id == 13) {
|
||||||
$account->utf8_invoices = ($account->language_id == 13) ? 1 : 0;
|
$account->utf8_invoices = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -34,5 +34,9 @@ class AccountGateway extends EntityModel
|
|||||||
public function isPaymentType($type) {
|
public function isPaymentType($type) {
|
||||||
return $this->getPaymentType() == $type;
|
return $this->getPaymentType() == $type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isGateway($gatewayId) {
|
||||||
|
return $this->gateway_id == $gatewayId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ class Client extends EntityModel
|
|||||||
|
|
||||||
public function getName()
|
public function getName()
|
||||||
{
|
{
|
||||||
return $this->getDisplayName();
|
return $this->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDisplayName()
|
public function getDisplayName()
|
||||||
@ -82,8 +82,9 @@ class Client extends EntityModel
|
|||||||
if ($this->name) {
|
if ($this->name) {
|
||||||
return $this->name;
|
return $this->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->load('contacts');
|
$this->load('contacts');
|
||||||
|
|
||||||
$contact = $this->contacts()->first();
|
$contact = $this->contacts()->first();
|
||||||
|
|
||||||
return $contact->getDisplayName();
|
return $contact->getDisplayName();
|
||||||
|
@ -38,6 +38,11 @@ class Contact extends EntityModel
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return $this->getDisplayName();
|
||||||
|
}
|
||||||
|
|
||||||
public function getDisplayName()
|
public function getDisplayName()
|
||||||
{
|
{
|
||||||
if ($this->getFullName()) {
|
if ($this->getFullName()) {
|
||||||
|
@ -4,7 +4,12 @@ use Eloquent;
|
|||||||
|
|
||||||
class Country extends Eloquent
|
class Country extends Eloquent
|
||||||
{
|
{
|
||||||
public $timestamps = false;
|
public $timestamps = false;
|
||||||
|
|
||||||
protected $visible = ['id', 'name'];
|
protected $visible = ['id', 'name'];
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,4 +5,9 @@ use Eloquent;
|
|||||||
class Currency extends Eloquent
|
class Currency extends Eloquent
|
||||||
{
|
{
|
||||||
public $timestamps = false;
|
public $timestamps = false;
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,4 +77,34 @@ class EntityModel extends Eloquent
|
|||||||
|
|
||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return $this->public_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remap ids to public_ids and show name
|
||||||
|
public function toPublicArray()
|
||||||
|
{
|
||||||
|
$data = $this->toArray();
|
||||||
|
|
||||||
|
foreach ($this->attributes as $key => $val) {
|
||||||
|
if (strpos($key, '_id')) {
|
||||||
|
list($field, $id) = explode('_', $key);
|
||||||
|
if ($field == 'account') {
|
||||||
|
// do nothing
|
||||||
|
} else {
|
||||||
|
$entity = @$this->$field;
|
||||||
|
if ($entity) {
|
||||||
|
$data["{$field}_name"] = $entity->getName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = Utils::hideIds($data);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,14 @@ class Gateway extends Eloquent
|
|||||||
return '/images/gateways/logo_'.$this->provider.'.png';
|
return '/images/gateways/logo_'.$this->provider.'.png';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getPaymentTypeLinks() {
|
||||||
|
$data = [];
|
||||||
|
foreach (self::$paymentTypes as $type) {
|
||||||
|
$data[] = strtolower(str_replace('PAYMENT_TYPE_', '', $type));
|
||||||
|
}
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
public function getHelp()
|
public function getHelp()
|
||||||
{
|
{
|
||||||
$link = '';
|
$link = '';
|
||||||
|
@ -5,4 +5,9 @@ use Eloquent;
|
|||||||
class Industry extends Eloquent
|
class Industry extends Eloquent
|
||||||
{
|
{
|
||||||
public $timestamps = false;
|
public $timestamps = false;
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,10 @@ class Invitation extends EntityModel
|
|||||||
|
|
||||||
public function getLink()
|
public function getLink()
|
||||||
{
|
{
|
||||||
$this->load('account');
|
if (!$this->account) {
|
||||||
|
$this->load('account');
|
||||||
|
}
|
||||||
|
|
||||||
$url = SITE_URL;
|
$url = SITE_URL;
|
||||||
|
|
||||||
if ($this->account->subdomain) {
|
if ($this->account->subdomain) {
|
||||||
@ -41,4 +44,9 @@ class Invitation extends EntityModel
|
|||||||
|
|
||||||
return "{$url}/view/{$this->invitation_key}";
|
return "{$url}/view/{$this->invitation_key}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return $this->invitation_key;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,11 @@ class Invoice extends EntityModel
|
|||||||
return $this->belongsTo('App\Models\InvoiceDesign');
|
return $this->belongsTo('App\Models\InvoiceDesign');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function recurring_invoice()
|
||||||
|
{
|
||||||
|
return $this->belongsTo('App\Models\Invoice');
|
||||||
|
}
|
||||||
|
|
||||||
public function invitations()
|
public function invitations()
|
||||||
{
|
{
|
||||||
return $this->hasMany('App\Models\Invitation')->orderBy('invitations.contact_id');
|
return $this->hasMany('App\Models\Invitation')->orderBy('invitations.contact_id');
|
||||||
@ -247,8 +252,11 @@ class Invoice extends EntityModel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Invoice::created(function ($invoice) {
|
Invoice::creating(function ($invoice) {
|
||||||
$invoice->account->incrementCounter($invoice->invoice_number, $invoice->is_quote, $invoice->recurring_invoice_id);
|
$invoice->account->incrementCounter($invoice->invoice_number, $invoice->is_quote, $invoice->recurring_invoice_id);
|
||||||
|
});
|
||||||
|
|
||||||
|
Invoice::created(function ($invoice) {
|
||||||
Activity::createInvoice($invoice);
|
Activity::createInvoice($invoice);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -262,4 +270,4 @@ Invoice::deleting(function ($invoice) {
|
|||||||
|
|
||||||
Invoice::restoring(function ($invoice) {
|
Invoice::restoring(function ($invoice) {
|
||||||
Activity::restoreInvoice($invoice);
|
Activity::restoreInvoice($invoice);
|
||||||
});
|
});
|
@ -2,22 +2,38 @@
|
|||||||
|
|
||||||
use Eloquent;
|
use Eloquent;
|
||||||
use Auth;
|
use Auth;
|
||||||
|
use Cache;
|
||||||
|
use App\Models\InvoiceDesign;
|
||||||
|
|
||||||
class InvoiceDesign extends Eloquent
|
class InvoiceDesign extends Eloquent
|
||||||
{
|
{
|
||||||
public $timestamps = false;
|
public $timestamps = false;
|
||||||
|
|
||||||
public function scopeAvailableDesigns($query)
|
public static function getDesigns($forceUtf8 = false)
|
||||||
{
|
{
|
||||||
$designs = $query->where('id', '<=', \Auth::user()->maxInvoiceDesignId())->orderBy('id')->get();
|
$account = Auth::user()->account;
|
||||||
|
$designs = Cache::get('invoiceDesigns');
|
||||||
|
$utf8 = $forceUtf8 || $account->utf8_invoices;
|
||||||
|
|
||||||
foreach ($designs as $design) {
|
foreach ($designs as $design) {
|
||||||
$fileName = public_path(strtolower("js/templates/{$design->name}.js"));
|
if ($design->id > Auth::user()->maxInvoiceDesignId()) {
|
||||||
if (Auth::user()->account->utf8_invoices && file_exists($fileName)) {
|
$designs->pull($design->id);
|
||||||
$design->javascript = file_get_contents($fileName);
|
}
|
||||||
|
|
||||||
|
if ($utf8) {
|
||||||
|
$design->javascript = $design->pdfmake;
|
||||||
|
}
|
||||||
|
$design->pdfmake = null;
|
||||||
|
|
||||||
|
if ($design->id == CUSTOM_DESIGN) {
|
||||||
|
if ($utf8 && $account->custom_design) {
|
||||||
|
$design->javascript = $account->custom_design;
|
||||||
|
} else {
|
||||||
|
$designs->pop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $designs;
|
return $designs;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -22,6 +22,11 @@ class Payment extends EntityModel
|
|||||||
return $this->belongsTo('App\Models\Client')->withTrashed();
|
return $this->belongsTo('App\Models\Client')->withTrashed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo('App\Models\User')->withTrashed();
|
||||||
|
}
|
||||||
|
|
||||||
public function account()
|
public function account()
|
||||||
{
|
{
|
||||||
return $this->belongsTo('App\Models\Account');
|
return $this->belongsTo('App\Models\Account');
|
||||||
|
@ -5,4 +5,9 @@ use Eloquent;
|
|||||||
class Size extends Eloquent
|
class Size extends Eloquent
|
||||||
{
|
{
|
||||||
public $timestamps = false;
|
public $timestamps = false;
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<?php namespace App\Models;
|
<?php namespace App\Models;
|
||||||
|
|
||||||
use DB;
|
use DB;
|
||||||
|
use Utils;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
class Task extends EntityModel
|
class Task extends EntityModel
|
||||||
@ -13,10 +13,75 @@ class Task extends EntityModel
|
|||||||
return $this->belongsTo('App\Models\Account');
|
return $this->belongsTo('App\Models\Account');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function invoice()
|
||||||
|
{
|
||||||
|
return $this->belongsTo('App\Models\Invoice');
|
||||||
|
}
|
||||||
|
|
||||||
public function client()
|
public function client()
|
||||||
{
|
{
|
||||||
return $this->belongsTo('App\Models\Client')->withTrashed();
|
return $this->belongsTo('App\Models\Client')->withTrashed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function calcStartTime($task)
|
||||||
|
{
|
||||||
|
$parts = json_decode($task->time_log) ?: [];
|
||||||
|
|
||||||
|
if (count($parts)) {
|
||||||
|
return Utils::timestampToDateTimeString($parts[0][0]);
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStartTime()
|
||||||
|
{
|
||||||
|
return self::calcStartTime($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function calcDuration($task)
|
||||||
|
{
|
||||||
|
$duration = 0;
|
||||||
|
$parts = json_decode($task->time_log) ?: [];
|
||||||
|
|
||||||
|
foreach ($parts as $part) {
|
||||||
|
if (count($part) == 1 || !$part[1]) {
|
||||||
|
$duration += time() - $part[0];
|
||||||
|
} else {
|
||||||
|
$duration += $part[1] - $part[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDuration()
|
||||||
|
{
|
||||||
|
return self::calcDuration($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCurrentDuration()
|
||||||
|
{
|
||||||
|
$parts = json_decode($this->time_log) ?: [];
|
||||||
|
$part = $parts[count($parts)-1];
|
||||||
|
|
||||||
|
if (count($part) == 1 || !$part[1]) {
|
||||||
|
return time() - $part[0];
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasPreviousDuration()
|
||||||
|
{
|
||||||
|
$parts = json_decode($this->time_log) ?: [];
|
||||||
|
return count($parts) && (count($parts[0]) && $parts[0][1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHours()
|
||||||
|
{
|
||||||
|
return round($this->getDuration() / (60 * 60), 2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Task::created(function ($task) {
|
Task::created(function ($task) {
|
||||||
|
@ -48,6 +48,11 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
|
|||||||
return $this->belongsTo('App\Models\Theme');
|
return $this->belongsTo('App\Models\Theme');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return $this->getDisplayName();
|
||||||
|
}
|
||||||
|
|
||||||
public function getPersonType()
|
public function getPersonType()
|
||||||
{
|
{
|
||||||
return PERSON_USER;
|
return PERSON_USER;
|
||||||
@ -95,7 +100,7 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
|
|||||||
|
|
||||||
public function maxInvoiceDesignId()
|
public function maxInvoiceDesignId()
|
||||||
{
|
{
|
||||||
return $this->isPro() ? 10 : COUNT_FREE_DESIGNS;
|
return $this->isPro() ? 11 : (Utils::isNinja() ? COUNT_FREE_DESIGNS : COUNT_FREE_DESIGNS_SELF_HOST);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDisplayName()
|
public function getDisplayName()
|
||||||
@ -128,6 +133,7 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
|
|||||||
return Session::get(SESSION_COUNTER, 0);
|
return Session::get(SESSION_COUNTER, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
public function getPopOverText()
|
public function getPopOverText()
|
||||||
{
|
{
|
||||||
if (!Utils::isNinja() || !Auth::check() || Session::has('error')) {
|
if (!Utils::isNinja() || !Auth::check() || Session::has('error')) {
|
||||||
@ -146,7 +152,8 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
public function afterSave($success = true, $forced = false)
|
public function afterSave($success = true, $forced = false)
|
||||||
{
|
{
|
||||||
if ($this->email) {
|
if ($this->email) {
|
||||||
@ -176,4 +183,33 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
|
|||||||
return 'remember_token';
|
return 'remember_token';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function clearSession()
|
||||||
|
{
|
||||||
|
$keys = [
|
||||||
|
RECENTLY_VIEWED,
|
||||||
|
SESSION_USER_ACCOUNTS,
|
||||||
|
SESSION_TIMEZONE,
|
||||||
|
SESSION_DATE_FORMAT,
|
||||||
|
SESSION_DATE_PICKER_FORMAT,
|
||||||
|
SESSION_DATETIME_FORMAT,
|
||||||
|
SESSION_CURRENCY,
|
||||||
|
SESSION_LOCALE,
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($keys as $key) {
|
||||||
|
Session::forget($key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function updateUser($user)
|
||||||
|
{
|
||||||
|
if ($user->password != !$user->getOriginal('password')) {
|
||||||
|
$user->failed_logins = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
User::updating(function ($user) {
|
||||||
|
User::updateUser($user);
|
||||||
|
});
|
||||||
|
52
app/Models/UserAccount.php
Normal file
52
app/Models/UserAccount.php
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<?php namespace App\Models;
|
||||||
|
|
||||||
|
use Eloquent;
|
||||||
|
|
||||||
|
class UserAccount extends Eloquent
|
||||||
|
{
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
public function hasUserId($userId)
|
||||||
|
{
|
||||||
|
if (!$userId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ($i=1; $i<=5; $i++) {
|
||||||
|
$field = "user_id{$i}";
|
||||||
|
if ($this->$field && $this->$field == $userId) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setUserId($userId)
|
||||||
|
{
|
||||||
|
if (self::hasUserId($userId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ($i=1; $i<=5; $i++) {
|
||||||
|
$field = "user_id{$i}";
|
||||||
|
if (!$this->$field) {
|
||||||
|
$this->$field = $userId;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeUserId($userId)
|
||||||
|
{
|
||||||
|
if (!$userId || !self::hasUserId($userId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ($i=1; $i<=5; $i++) {
|
||||||
|
$field = "user_id{$i}";
|
||||||
|
if ($this->$field && $this->$field == $userId) {
|
||||||
|
$this->$field = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -7,6 +7,7 @@ use URL;
|
|||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
use App\Models\Payment;
|
use App\Models\Payment;
|
||||||
use App\Models\Activity;
|
use App\Models\Activity;
|
||||||
|
use App\Models\Gateway;
|
||||||
use App\Events\InvoiceSent;
|
use App\Events\InvoiceSent;
|
||||||
|
|
||||||
class ContactMailer extends Mailer
|
class ContactMailer extends Mailer
|
||||||
@ -22,6 +23,8 @@ class ContactMailer extends Mailer
|
|||||||
$emailTemplate = $invoice->account->getEmailTemplate($entityType);
|
$emailTemplate = $invoice->account->getEmailTemplate($entityType);
|
||||||
$invoiceAmount = Utils::formatMoney($invoice->getRequestedAmount(), $invoice->client->getCurrencyId());
|
$invoiceAmount = Utils::formatMoney($invoice->getRequestedAmount(), $invoice->client->getCurrencyId());
|
||||||
|
|
||||||
|
$this->initClosure($invoice);
|
||||||
|
|
||||||
foreach ($invoice->invitations as $invitation) {
|
foreach ($invoice->invitations as $invitation) {
|
||||||
if (!$invitation->user || !$invitation->user->email || $invitation->user->trashed()) {
|
if (!$invitation->user || !$invitation->user->email || $invitation->user->trashed()) {
|
||||||
return false;
|
return false;
|
||||||
@ -39,28 +42,27 @@ class ContactMailer extends Mailer
|
|||||||
'$client' => $invoice->client->getDisplayName(),
|
'$client' => $invoice->client->getDisplayName(),
|
||||||
'$account' => $accountName,
|
'$account' => $accountName,
|
||||||
'$contact' => $invitation->contact->getDisplayName(),
|
'$contact' => $invitation->contact->getDisplayName(),
|
||||||
'$amount' => $invoiceAmount
|
'$amount' => $invoiceAmount,
|
||||||
|
'$advancedRawInvoice->' => '$'
|
||||||
];
|
];
|
||||||
|
|
||||||
// Add variables for available payment types
|
// Add variables for available payment types
|
||||||
foreach([PAYMENT_TYPE_CREDIT_CARD, PAYMENT_TYPE_PAYPAL, PAYMENT_TYPE_BITCOIN] as $type) {
|
foreach (Gateway::getPaymentTypeLinks() as $type) {
|
||||||
if ($invoice->account->getGatewayByType($type)) {
|
$variables["\${$type}_link"] = URL::to("/payment/{$invitation->invitation_key}/{$type}");
|
||||||
|
|
||||||
// Changes "PAYMENT_TYPE_CREDIT_CARD" to "$credit_card_link"
|
|
||||||
$gateway_slug = '$'.strtolower(str_replace('PAYMENT_TYPE_', '', $type)).'_link';
|
|
||||||
|
|
||||||
$variables[$gateway_slug] = URL::to("/payment/{$invitation->invitation_key}/{$type}");
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$data['body'] = str_replace(array_keys($variables), array_values($variables), $emailTemplate);
|
$data['body'] = str_replace(array_keys($variables), array_values($variables), $emailTemplate);
|
||||||
|
$data['body'] = preg_replace_callback('/\{\{\$?(.*)\}\}/', $this->advancedTemplateHandler, $data['body']);
|
||||||
$data['link'] = $invitation->getLink();
|
$data['link'] = $invitation->getLink();
|
||||||
$data['entityType'] = $entityType;
|
$data['entityType'] = $entityType;
|
||||||
$data['invoice_id'] = $invoice->id;
|
$data['invoice_id'] = $invoice->id;
|
||||||
|
|
||||||
$fromEmail = $invitation->user->email;
|
$fromEmail = $invitation->user->email;
|
||||||
$this->sendTo($invitation->contact->email, $fromEmail, $accountName, $subject, $view, $data);
|
$response = $this->sendTo($invitation->contact->email, $fromEmail, $accountName, $subject, $view, $data);
|
||||||
|
|
||||||
|
if ($response !== true) {
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
Activity::emailInvoice($invitation);
|
Activity::emailInvoice($invitation);
|
||||||
}
|
}
|
||||||
@ -71,6 +73,8 @@ class ContactMailer extends Mailer
|
|||||||
}
|
}
|
||||||
|
|
||||||
Event::fire(new InvoiceSent($invoice));
|
Event::fire(new InvoiceSent($invoice));
|
||||||
|
|
||||||
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function sendPaymentConfirmation(Payment $payment)
|
public function sendPaymentConfirmation(Payment $payment)
|
||||||
@ -90,8 +94,17 @@ class ContactMailer extends Mailer
|
|||||||
|
|
||||||
$data = ['body' => str_replace(array_keys($variables), array_values($variables), $emailTemplate)];
|
$data = ['body' => str_replace(array_keys($variables), array_values($variables), $emailTemplate)];
|
||||||
|
|
||||||
$user = $payment->invitation->user;
|
if ($payment->invitation) {
|
||||||
$this->sendTo($payment->contact->email, $user->email, $accountName, $subject, $view, $data);
|
$user = $payment->invitation->user;
|
||||||
|
$contact = $payment->contact;
|
||||||
|
} else {
|
||||||
|
$user = $payment->user;
|
||||||
|
$contact = $payment->client->contacts[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($user->email && $contact->email) {
|
||||||
|
$this->sendTo($contact->email, $user->email, $accountName, $subject, $view, $data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function sendLicensePaymentConfirmation($name, $email, $amount, $license, $productId)
|
public function sendLicensePaymentConfirmation($name, $email, $amount, $license, $productId)
|
||||||
@ -116,4 +129,22 @@ class ContactMailer extends Mailer
|
|||||||
|
|
||||||
$this->sendTo($email, CONTACT_EMAIL, CONTACT_NAME, $subject, $view, $data);
|
$this->sendTo($email, CONTACT_EMAIL, CONTACT_NAME, $subject, $view, $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function initClosure($object)
|
||||||
|
{
|
||||||
|
$this->advancedTemplateHandler = function($match) use ($object) {
|
||||||
|
for ($i = 1; $i < count($match); $i++) {
|
||||||
|
$blobConversion = $match[$i];
|
||||||
|
|
||||||
|
if (isset($$blobConversion)) {
|
||||||
|
return $$blobConversion;
|
||||||
|
} else if (preg_match('/trans\(([\w\.]+)\)/', $blobConversion, $regexTranslation)) {
|
||||||
|
return trans($regexTranslation[1]);
|
||||||
|
} else if (strpos($blobConversion, '->') !== false) {
|
||||||
|
return Utils::stringToObjectResolution($object, $blobConversion);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<?php namespace App\Ninja\Mailers;
|
<?php namespace App\Ninja\Mailers;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
use Mail;
|
use Mail;
|
||||||
use Utils;
|
use Utils;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
@ -13,26 +14,38 @@ class Mailer
|
|||||||
'emails.'.$view.'_text',
|
'emails.'.$view.'_text',
|
||||||
];
|
];
|
||||||
|
|
||||||
Mail::send($views, $data, function ($message) use ($toEmail, $fromEmail, $fromName, $subject, $data) {
|
try {
|
||||||
$replyEmail = $fromEmail;
|
Mail::send($views, $data, function ($message) use ($toEmail, $fromEmail, $fromName, $subject, $data) {
|
||||||
|
|
||||||
// http://stackoverflow.com/questions/2421234/gmail-appearing-to-ignore-reply-to
|
$replyEmail = $fromEmail;
|
||||||
if (Utils::isNinja() && $toEmail != CONTACT_EMAIL) {
|
$fromEmail = CONTACT_EMAIL;
|
||||||
$fromEmail = NINJA_FROM_EMAIL;
|
|
||||||
}
|
if(isset($data['invoice_id'])) {
|
||||||
|
$invoice = Invoice::with('account')->where('id', '=', $data['invoice_id'])->get()->first();
|
||||||
if(isset($data['invoice_id'])) {
|
if($invoice->account->pdf_email_attachment && file_exists($invoice->getPDFPath())) {
|
||||||
$invoice = Invoice::with('account')->where('id', '=', $data['invoice_id'])->get()->first();
|
$message->attach(
|
||||||
if($invoice->account->pdf_email_attachment && file_exists($invoice->getPDFPath())) {
|
$invoice->getPDFPath(),
|
||||||
$message->attach(
|
array('as' => $invoice->getFileName(), 'mime' => 'application/pdf')
|
||||||
$invoice->getPDFPath(),
|
);
|
||||||
array('as' => $invoice->getFileName(), 'mime' => 'application/pdf')
|
}
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
$message->to($toEmail)
|
||||||
|
->from($fromEmail, $fromName)
|
||||||
|
->replyTo($replyEmail, $fromName)
|
||||||
|
->subject($subject);
|
||||||
|
|
||||||
//$message->setEncoder(\Swift_Encoding::get8BitEncoding());
|
});
|
||||||
$message->to($toEmail)->from($fromEmail, $fromName)->replyTo($replyEmail, $fromName)->subject($subject);
|
|
||||||
});
|
return true;
|
||||||
|
} catch (Exception $exception) {
|
||||||
|
if (method_exists($exception, 'getResponse')) {
|
||||||
|
$response = $exception->getResponse()->getBody()->getContents();
|
||||||
|
$response = json_decode($response);
|
||||||
|
return nl2br($response->Message);
|
||||||
|
} else {
|
||||||
|
return $exception->getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,8 @@ use Auth;
|
|||||||
use Request;
|
use Request;
|
||||||
use Session;
|
use Session;
|
||||||
use Utils;
|
use Utils;
|
||||||
|
use DB;
|
||||||
|
use stdClass;
|
||||||
|
|
||||||
use App\Models\AccountGateway;
|
use App\Models\AccountGateway;
|
||||||
use App\Models\Invitation;
|
use App\Models\Invitation;
|
||||||
@ -14,6 +16,7 @@ use App\Models\Language;
|
|||||||
use App\Models\Contact;
|
use App\Models\Contact;
|
||||||
use App\Models\Account;
|
use App\Models\Account;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use App\Models\UserAccount;
|
||||||
|
|
||||||
class AccountRepository
|
class AccountRepository
|
||||||
{
|
{
|
||||||
@ -244,4 +247,138 @@ class AccountRepository
|
|||||||
curl_exec($ch);
|
curl_exec($ch);
|
||||||
curl_close($ch);
|
curl_close($ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function findUserAccounts($userId1, $userId2 = false)
|
||||||
|
{
|
||||||
|
$query = UserAccount::where('user_id1', '=', $userId1)
|
||||||
|
->orWhere('user_id2', '=', $userId1)
|
||||||
|
->orWhere('user_id3', '=', $userId1)
|
||||||
|
->orWhere('user_id4', '=', $userId1)
|
||||||
|
->orWhere('user_id5', '=', $userId1);
|
||||||
|
|
||||||
|
if ($userId2) {
|
||||||
|
$query->orWhere('user_id1', '=', $userId2)
|
||||||
|
->orWhere('user_id2', '=', $userId2)
|
||||||
|
->orWhere('user_id3', '=', $userId2)
|
||||||
|
->orWhere('user_id4', '=', $userId2)
|
||||||
|
->orWhere('user_id5', '=', $userId2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query->first(['id', 'user_id1', 'user_id2', 'user_id3', 'user_id4', 'user_id5']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function prepareUsersData($record) {
|
||||||
|
|
||||||
|
if (!$record) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$userIds = [];
|
||||||
|
for ($i=1; $i<=5; $i++) {
|
||||||
|
$field = "user_id$i";
|
||||||
|
if ($record->$field) {
|
||||||
|
$userIds[] = $record->$field;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$users = User::with('account')
|
||||||
|
->whereIn('id', $userIds)
|
||||||
|
->get();
|
||||||
|
|
||||||
|
$data = [];
|
||||||
|
foreach ($users as $user) {
|
||||||
|
$item = new stdClass();
|
||||||
|
$item->id = $record->id;
|
||||||
|
$item->user_id = $user->id;
|
||||||
|
$item->user_name = $user->getDisplayName();
|
||||||
|
$item->account_id = $user->account->id;
|
||||||
|
$item->account_name = $user->account->getDisplayName();
|
||||||
|
$item->pro_plan_paid = $user->account->pro_plan_paid;
|
||||||
|
$item->account_key = file_exists($user->account->getLogoPath()) ? $user->account->account_key : null;
|
||||||
|
$data[] = $item;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function loadAccounts($userId) {
|
||||||
|
$record = self::findUserAccounts($userId);
|
||||||
|
return self::prepareUsersData($record);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function syncAccounts($userId, $proPlanPaid) {
|
||||||
|
$users = self::loadAccounts($userId);
|
||||||
|
self::syncUserAccounts($users, $proPlanPaid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function syncUserAccounts($users, $proPlanPaid = false) {
|
||||||
|
|
||||||
|
if (!$proPlanPaid) {
|
||||||
|
foreach ($users as $user) {
|
||||||
|
if ($user->pro_plan_paid && $user->pro_plan_paid != '0000-00-00') {
|
||||||
|
$proPlanPaid = $user->pro_plan_paid;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$proPlanPaid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$accountIds = [];
|
||||||
|
foreach ($users as $user) {
|
||||||
|
if ($user->pro_plan_paid != $proPlanPaid) {
|
||||||
|
$accountIds[] = $user->account_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($accountIds)) {
|
||||||
|
DB::table('accounts')
|
||||||
|
->whereIn('id', $accountIds)
|
||||||
|
->update(['pro_plan_paid' => $proPlanPaid]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function associateAccounts($userId1, $userId2) {
|
||||||
|
|
||||||
|
$record = self::findUserAccounts($userId1, $userId2);
|
||||||
|
|
||||||
|
if ($record) {
|
||||||
|
foreach ([$userId1, $userId2] as $userId) {
|
||||||
|
if (!$record->hasUserId($userId)) {
|
||||||
|
$record->setUserId($userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$record = new UserAccount();
|
||||||
|
$record->user_id1 = $userId1;
|
||||||
|
$record->user_id2 = $userId2;
|
||||||
|
}
|
||||||
|
|
||||||
|
$record->save();
|
||||||
|
|
||||||
|
$users = self::prepareUsersData($record);
|
||||||
|
self::syncUserAccounts($users);
|
||||||
|
|
||||||
|
return $users;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function unlinkAccount($account) {
|
||||||
|
foreach ($account->users as $user) {
|
||||||
|
if ($userAccount = self::findUserAccounts($user->id)) {
|
||||||
|
$userAccount->removeUserId($user->id);
|
||||||
|
$userAccount->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function unlinkUser($userAccountId, $userId) {
|
||||||
|
|
||||||
|
$userAccount = UserAccount::whereId($userAccountId)->first();
|
||||||
|
if ($userAccount->hasUserId($userId)) {
|
||||||
|
$userAccount->removeUserId($userId);
|
||||||
|
$userAccount->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -536,4 +536,16 @@ class InvoiceRepository
|
|||||||
|
|
||||||
return count($invoices);
|
return count($invoices);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function findOpenInvoices($clientId)
|
||||||
|
{
|
||||||
|
return Invoice::scope()
|
||||||
|
->whereClientId($clientId)
|
||||||
|
->whereIsQuote(false)
|
||||||
|
->whereIsRecurring(false)
|
||||||
|
->whereHasTasks(true)
|
||||||
|
->where('balance', '>', 0)
|
||||||
|
->select(['public_id', 'invoice_number'])
|
||||||
|
->get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,14 @@ class PaymentRepository
|
|||||||
$payment->payment_type_id = $paymentTypeId;
|
$payment->payment_type_id = $paymentTypeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
$payment->payment_date = Utils::toSqlDate($input['payment_date']);
|
if (isset($input['payment_date_sql'])) {
|
||||||
|
$payment->payment_date = $input['payment_date_sql'];
|
||||||
|
} elseif (isset($input['payment_date'])) {
|
||||||
|
$payment->payment_date = Utils::toSqlDate($input['payment_date']);
|
||||||
|
} else {
|
||||||
|
$payment->payment_date = date('Y-m-d');
|
||||||
|
}
|
||||||
|
|
||||||
$payment->transaction_reference = trim($input['transaction_reference']);
|
$payment->transaction_reference = trim($input['transaction_reference']);
|
||||||
|
|
||||||
if (!$publicId) {
|
if (!$publicId) {
|
||||||
|
@ -23,7 +23,7 @@ class TaskRepository
|
|||||||
})
|
})
|
||||||
->where('contacts.deleted_at', '=', null)
|
->where('contacts.deleted_at', '=', null)
|
||||||
->where('clients.deleted_at', '=', null)
|
->where('clients.deleted_at', '=', null)
|
||||||
->select('tasks.public_id', 'clients.name as client_name', 'clients.public_id as client_public_id', 'contacts.first_name', 'contacts.email', 'contacts.last_name', 'invoices.invoice_status_id', 'tasks.start_time', 'tasks.description', 'tasks.duration', 'tasks.is_deleted', 'tasks.deleted_at', 'invoices.invoice_number', 'invoices.public_id as invoice_public_id');
|
->select('tasks.public_id', 'clients.name as client_name', 'clients.public_id as client_public_id', 'contacts.first_name', 'contacts.email', 'contacts.last_name', 'invoices.invoice_status_id', 'tasks.description', 'tasks.is_deleted', 'tasks.deleted_at', 'invoices.invoice_number', 'invoices.public_id as invoice_public_id', 'tasks.is_running', 'tasks.time_log', 'tasks.created_at');
|
||||||
|
|
||||||
if ($clientPublicId) {
|
if ($clientPublicId) {
|
||||||
$query->where('clients.public_id', '=', $clientPublicId);
|
$query->where('clients.public_id', '=', $clientPublicId);
|
||||||
@ -58,20 +58,22 @@ class TaskRepository
|
|||||||
}
|
}
|
||||||
if (isset($data['description'])) {
|
if (isset($data['description'])) {
|
||||||
$task->description = trim($data['description']);
|
$task->description = trim($data['description']);
|
||||||
}
|
|
||||||
|
|
||||||
if ($data['action'] == 'start') {
|
|
||||||
$task->start_time = Carbon::now()->toDateTimeString();
|
|
||||||
$task->duration = -1;
|
|
||||||
} else if ($data['action'] == 'stop' && $task->duration == -1) {
|
|
||||||
$task->duration = strtotime('now') - strtotime($task->start_time);
|
|
||||||
} else if ($data['action'] == 'save' && $task->duration != -1) {
|
|
||||||
$task->start_time = $data['start_time'];
|
|
||||||
$task->duration = $data['duration'];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$task->duration = max($task->duration, -1);
|
//$timeLog = $task->time_log ? json_decode($task->time_log, true) : [];
|
||||||
|
$timeLog = isset($data['time_log']) ? json_decode($data['time_log']) : [];
|
||||||
|
if ($data['action'] == 'start') {
|
||||||
|
$task->is_running = true;
|
||||||
|
$timeLog[] = [strtotime('now'), false];
|
||||||
|
} else if ($data['action'] == 'resume') {
|
||||||
|
$task->is_running = true;
|
||||||
|
$timeLog[] = [strtotime('now'), false];
|
||||||
|
} else if ($data['action'] == 'stop' && $task->is_running) {
|
||||||
|
$timeLog[count($timeLog)-1][1] = time();
|
||||||
|
$task->is_running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$task->time_log = json_encode($timeLog);
|
||||||
$task->save();
|
$task->save();
|
||||||
|
|
||||||
return $task;
|
return $task;
|
||||||
|
@ -44,6 +44,10 @@ class AppServiceProvider extends ServiceProvider {
|
|||||||
$str .= '<li class="divider"></li>
|
$str .= '<li class="divider"></li>
|
||||||
<li><a href="'.URL::to('quotes').'">'.trans("texts.quotes").'</a></li>
|
<li><a href="'.URL::to('quotes').'">'.trans("texts.quotes").'</a></li>
|
||||||
<li><a href="'.URL::to('quotes/create').'">'.trans("texts.new_quote").'</a></li>';
|
<li><a href="'.URL::to('quotes/create').'">'.trans("texts.new_quote").'</a></li>';
|
||||||
|
} else if ($type == ENTITY_CLIENT) {
|
||||||
|
$str .= '<li class="divider"></li>
|
||||||
|
<li><a href="'.URL::to('credits').'">'.trans("texts.credits").'</a></li>
|
||||||
|
<li><a href="'.URL::to('credits/create').'">'.trans("texts.new_credit").'</a></li>';
|
||||||
}
|
}
|
||||||
|
|
||||||
$str .= '</ul>
|
$str .= '</ul>
|
||||||
|
29
bower.json
29
bower.json
@ -2,25 +2,26 @@
|
|||||||
"name": "hillelcoren/invoice-ninja",
|
"name": "hillelcoren/invoice-ninja",
|
||||||
"version": "0.9.0",
|
"version": "0.9.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"jquery": "~1.11",
|
"jquery": "1.11.3",
|
||||||
"bootstrap": "~3.*",
|
"bootstrap": "3.3.1",
|
||||||
"jquery-ui": "~1.*",
|
"jquery-ui": "1.11.2",
|
||||||
"datatables": "1.10.4",
|
"datatables": "1.10.4",
|
||||||
"datatables-bootstrap3": "*",
|
"datatables-bootstrap3": "*",
|
||||||
"knockout.js": "~3.*",
|
"knockout.js": "3.1.0",
|
||||||
"knockout-mapping": "*",
|
"knockout-mapping": "2.4.1",
|
||||||
"knockout-sortable": "*",
|
"knockout-sortable": "0.9.3",
|
||||||
"font-awesome": "~4.*",
|
"font-awesome": "~4.*",
|
||||||
"underscore": "~1.*",
|
"underscore": "1.7.0",
|
||||||
"jspdf": "*",
|
"jspdf": "1.0.272",
|
||||||
"bootstrap-datepicker": "~1.*",
|
"bootstrap-datepicker": "1.4.0",
|
||||||
"typeahead.js": "~0.9.3",
|
"typeahead.js": "0.9.3",
|
||||||
"accounting": "~0.*",
|
"accounting": "0.3.2",
|
||||||
"spectrum": "~1.3.4",
|
"spectrum": "1.3.4",
|
||||||
"d3": "~3.4.11",
|
"d3": "3.4.11",
|
||||||
"handsontable": "*",
|
"handsontable": "*",
|
||||||
"pdfmake": "*",
|
"pdfmake": "*",
|
||||||
"moment": "*"
|
"moment": "*",
|
||||||
|
"jsoneditor": "*"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"jquery": "~1.11"
|
"jquery": "~1.11"
|
||||||
|
@ -21,7 +21,7 @@ class AddTasks extends Migration {
|
|||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
$table->softDeletes();
|
$table->softDeletes();
|
||||||
|
|
||||||
$table->timestamp('start_time');
|
$table->timestamp('start_time')->nullable();
|
||||||
$table->integer('duration')->nullable();
|
$table->integer('duration')->nullable();
|
||||||
$table->string('description')->nullable();
|
$table->string('description')->nullable();
|
||||||
$table->boolean('is_deleted')->default(false);
|
$table->boolean('is_deleted')->default(false);
|
||||||
|
@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
class EnableResumingTasks extends Migration {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('tasks', function($table)
|
||||||
|
{
|
||||||
|
$table->boolean('is_running')->default(false);
|
||||||
|
$table->integer('break_duration')->nullable();
|
||||||
|
$table->timestamp('resume_time')->nullable();
|
||||||
|
$table->text('time_log')->nullable();
|
||||||
|
});
|
||||||
|
|
||||||
|
$tasks = DB::table('tasks')
|
||||||
|
->where('duration', '=', -1)
|
||||||
|
->select('id', 'duration', 'start_time')
|
||||||
|
->get();
|
||||||
|
|
||||||
|
foreach ($tasks as $task) {
|
||||||
|
$data = [
|
||||||
|
'is_running' => true,
|
||||||
|
'duration' => 0,
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
|
DB::table('tasks')
|
||||||
|
->where('id', $task->id)
|
||||||
|
->update($data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
|
||||||
|
Schema::table('tasks', function($table)
|
||||||
|
{
|
||||||
|
$table->dropColumn('is_running');
|
||||||
|
$table->dropColumn('resume_time');
|
||||||
|
$table->dropColumn('break_duration');
|
||||||
|
$table->dropColumn('time_log');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
class MultiCompanySupport extends Migration {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('user_accounts', function($table)
|
||||||
|
{
|
||||||
|
$table->increments('id');
|
||||||
|
|
||||||
|
$table->unsignedInteger('user_id1')->nullable();
|
||||||
|
$table->unsignedInteger('user_id2')->nullable();
|
||||||
|
$table->unsignedInteger('user_id3')->nullable();
|
||||||
|
$table->unsignedInteger('user_id4')->nullable();
|
||||||
|
$table->unsignedInteger('user_id5')->nullable();
|
||||||
|
|
||||||
|
$table->foreign('user_id1')->references('id')->on('users');
|
||||||
|
$table->foreign('user_id2')->references('id')->on('users');
|
||||||
|
$table->foreign('user_id3')->references('id')->on('users');
|
||||||
|
$table->foreign('user_id4')->references('id')->on('users');
|
||||||
|
$table->foreign('user_id5')->references('id')->on('users');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('user_accounts');
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
class SupportLockingAccount extends Migration {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('users', function($table)
|
||||||
|
{
|
||||||
|
$table->smallInteger('failed_logins')->nullable();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('account_gateways', function($table)
|
||||||
|
{
|
||||||
|
$table->boolean('show_address')->default(true)->nullable();
|
||||||
|
$table->boolean('update_address')->default(true)->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('users', function($table)
|
||||||
|
{
|
||||||
|
$table->dropColumn('failed_logins');
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('account_gateways', function($table)
|
||||||
|
{
|
||||||
|
$table->dropColumn('show_address');
|
||||||
|
$table->dropColumn('update_address');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
73
database/migrations/2015_07_08_114333_simplify_tasks.php
Normal file
73
database/migrations/2015_07_08_114333_simplify_tasks.php
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
class SimplifyTasks extends Migration {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
$tasks = \App\Models\Task::all();
|
||||||
|
|
||||||
|
foreach ($tasks as $task) {
|
||||||
|
$startTime = strtotime($task->start_time);
|
||||||
|
if (!$task->time_log || !count(json_decode($task->time_log))) {
|
||||||
|
$task->time_log = json_encode([[$startTime, $startTime + $task->duration]]);
|
||||||
|
$task->save();
|
||||||
|
} elseif ($task->getDuration() != intval($task->duration)) {
|
||||||
|
$task->time_log = json_encode([[$startTime, $startTime + $task->duration]]);
|
||||||
|
$task->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Schema::table('tasks', function($table)
|
||||||
|
{
|
||||||
|
$table->dropColumn('start_time');
|
||||||
|
$table->dropColumn('duration');
|
||||||
|
$table->dropColumn('break_duration');
|
||||||
|
$table->dropColumn('resume_time');
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('users', function($table)
|
||||||
|
{
|
||||||
|
$table->boolean('dark_mode')->default(false)->nullable();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('users', function($table)
|
||||||
|
{
|
||||||
|
$table->dropColumn('theme_id');
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('tasks', function($table)
|
||||||
|
{
|
||||||
|
$table->timestamp('start_time')->nullable();
|
||||||
|
$table->integer('duration')->nullable();
|
||||||
|
$table->timestamp('resume_time')->nullable();
|
||||||
|
$table->integer('break_duration')->nullable();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('users', function($table)
|
||||||
|
{
|
||||||
|
$table->dropColumn('dark_mode');
|
||||||
|
});
|
||||||
|
Schema::table('users', function($table)
|
||||||
|
{
|
||||||
|
$table->integer('theme_id')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
36
database/migrations/2015_07_19_081332_add_custom_design.php
Normal file
36
database/migrations/2015_07_19_081332_add_custom_design.php
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
class AddCustomDesign extends Migration {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('accounts', function($table)
|
||||||
|
{
|
||||||
|
$table->text('custom_design')->nullable();
|
||||||
|
});
|
||||||
|
|
||||||
|
DB::table('invoice_designs')->insert(['id' => CUSTOM_DESIGN, 'name' => 'Custom']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('accounts', function($table)
|
||||||
|
{
|
||||||
|
$table->dropColumn('custom_design');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
class AddPdfmakeSupport extends Migration {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('invoice_designs', function($table)
|
||||||
|
{
|
||||||
|
$table->text('pdfmake')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('invoice_designs', function($table)
|
||||||
|
{
|
||||||
|
$table->dropColumn('pdfmake');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -5,6 +5,7 @@ use App\Models\PaymentTerm;
|
|||||||
use App\Models\Currency;
|
use App\Models\Currency;
|
||||||
use App\Models\DateFormat;
|
use App\Models\DateFormat;
|
||||||
use App\Models\DatetimeFormat;
|
use App\Models\DatetimeFormat;
|
||||||
|
use App\Models\InvoiceDesign;
|
||||||
|
|
||||||
class PaymentLibrariesSeeder extends Seeder
|
class PaymentLibrariesSeeder extends Seeder
|
||||||
{
|
{
|
||||||
@ -16,6 +17,7 @@ class PaymentLibrariesSeeder extends Seeder
|
|||||||
$this->createPaymentTerms();
|
$this->createPaymentTerms();
|
||||||
$this->createDateFormats();
|
$this->createDateFormats();
|
||||||
$this->createDatetimeFormats();
|
$this->createDatetimeFormats();
|
||||||
|
$this->createInvoiceDesigns();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function createGateways() {
|
private function createGateways() {
|
||||||
@ -131,4 +133,33 @@ class PaymentLibrariesSeeder extends Seeder
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function createInvoiceDesigns() {
|
||||||
|
$designs = [
|
||||||
|
'Clean',
|
||||||
|
'Bold',
|
||||||
|
'Modern',
|
||||||
|
'Plain',
|
||||||
|
'Business',
|
||||||
|
'Creative',
|
||||||
|
'Elegant',
|
||||||
|
'Hipster',
|
||||||
|
'Playful',
|
||||||
|
'Photo',
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($designs as $design) {
|
||||||
|
$fileName = storage_path() . '/templates/' . strtolower($design) . '.js';
|
||||||
|
$pdfmake = file_get_contents($fileName);
|
||||||
|
if ($pdfmake) {
|
||||||
|
$record = InvoiceDesign::whereName($design)->first();
|
||||||
|
if (!$record) {
|
||||||
|
$record = new InvoiceDesign;
|
||||||
|
$record->name = $design;
|
||||||
|
}
|
||||||
|
$record->pdfmake = $pdfmake;
|
||||||
|
$record->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
156
public/css/built.css
vendored
156
public/css/built.css
vendored
File diff suppressed because one or more lines are too long
4
public/css/built.public.css
vendored
4
public/css/built.public.css
vendored
File diff suppressed because one or more lines are too long
BIN
public/css/img/jsoneditor-icons.png
Normal file
BIN
public/css/img/jsoneditor-icons.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
1
public/css/jsoneditor.min.css
vendored
Normal file
1
public/css/jsoneditor.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
96
public/css/style.css
vendored
96
public/css/style.css
vendored
@ -83,6 +83,8 @@ th {border-left: 1px solid #d26b26; }
|
|||||||
.table>thead>tr>th, .table>tbody>tr>th, .table>tfoot>tr>th, .table>thead>tr>td, .table>tbody>tr>td, .table>tfoot>tr>td {
|
.table>thead>tr>th, .table>tbody>tr>th, .table>tfoot>tr>th, .table>thead>tr>td, .table>tbody>tr>td, .table>tfoot>tr>td {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
border-top: none;
|
border-top: none;
|
||||||
|
}
|
||||||
|
table.invoice-table>thead>tr>th, table.invoice-table>tbody>tr>th, table.invoice-table>tfoot>tr>th, table.invoice-table>thead>tr>td, table.invoice-table>tbody>tr>td, table.invoice-table>tfoot>tr>td {
|
||||||
border-bottom: 1px solid #dfe0e1;
|
border-bottom: 1px solid #dfe0e1;
|
||||||
}
|
}
|
||||||
table.dataTable.no-footer {
|
table.dataTable.no-footer {
|
||||||
@ -883,4 +885,96 @@ div.dataTables_length label {
|
|||||||
a .glyphicon,
|
a .glyphicon,
|
||||||
button .glyphicon {
|
button .glyphicon {
|
||||||
padding-left: 8px;
|
padding-left: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pro-plan-modal {
|
||||||
|
background-color: #4b4b4b;
|
||||||
|
padding-bottom: 40px;
|
||||||
|
padding-right: 25px;
|
||||||
|
opacity:0.95 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pro-plan-modal .left-side {
|
||||||
|
margin-top: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pro-plan-modal h2 {
|
||||||
|
color: #36c157;
|
||||||
|
font-size: 71px;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pro-plan-modal img.price {
|
||||||
|
height: 90px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pro-plan-modal a.button {
|
||||||
|
font-family: 'roboto_slabregular', Georgia, Times, serif;
|
||||||
|
background: #f38c4f;
|
||||||
|
background: -moz-linear-gradient(top, #f38c4f 0%, #db7134 100%);
|
||||||
|
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f38c4f), color-stop(100%,#db7134));
|
||||||
|
background: -webkit-linear-gradient(top, #f38c4f 0%,#db7134 100%);
|
||||||
|
background: -o-linear-gradient(top, #f38c4f 0%,#db7134 100%);
|
||||||
|
background: -ms-linear-gradient(top, #f38c4f 0%,#db7134 100%);
|
||||||
|
background: linear-gradient(to bottom, #f38c4f 0%,#db7134 100%);
|
||||||
|
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f38c4f', endColorstr='#db7134',GradientType=0 );
|
||||||
|
text-shadow: 1px 1px 1px rgba(0, 0, 0, .25);
|
||||||
|
width: 68%;
|
||||||
|
margin-top: 20px;
|
||||||
|
font-size: 28px;
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 20px 0;
|
||||||
|
display: inline-block;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pro-plan-modal a.button:hover {
|
||||||
|
background: #db7134; /* Old browsers */
|
||||||
|
background: -moz-linear-gradient(top, #db7134 0%, #f38c4f 100%); /* FF3.6+ */
|
||||||
|
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#db7134), color-stop(100%,#f38c4f)); /* Chrome,Safari4+ */
|
||||||
|
background: -webkit-linear-gradient(top, #db7134 0%,#f38c4f 100%); /* Chrome10+,Safari5.1+ */
|
||||||
|
background: -o-linear-gradient(top, #db7134 0%,#f38c4f 100%); /* Opera 11.10+ */
|
||||||
|
background: -ms-linear-gradient(top, #db7134 0%,#f38c4f 100%); /* IE10+ */
|
||||||
|
background: linear-gradient(to bottom, #db7134 0%,#f38c4f 100%); /* W3C */
|
||||||
|
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#db7134', endColorstr='#f38c4f',GradientType=0 ); /* IE6-9 */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.pro-plan-modal ul {
|
||||||
|
color: #fff;
|
||||||
|
list-style: none;
|
||||||
|
padding: 0 0 30px 0;
|
||||||
|
text-align: left;
|
||||||
|
white-space: pre-line;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pro-plan-modal ul li {
|
||||||
|
font-family: 'roboto_slabregular', Georgia, Times, serif;
|
||||||
|
background: url('../images/pro_plan/check.png') no-repeat 0px 12px;
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 17px;
|
||||||
|
line-height: 36px;
|
||||||
|
padding: 0 0 0 19px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pro-plan-modal img.close {
|
||||||
|
width: 35px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.user-accounts div.account {
|
||||||
|
font-size: large;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.user-accounts div.remove {
|
||||||
|
padding-top: 14px;
|
||||||
|
color: #BBB;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.user-accounts a:hover div.remove {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
BIN
public/fonts/fontawesome-webfont.woff2
Normal file
BIN
public/fonts/fontawesome-webfont.woff2
Normal file
Binary file not shown.
BIN
public/images/pro_plan/check.png
Normal file
BIN
public/images/pro_plan/check.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
BIN
public/images/pro_plan/close.png
Normal file
BIN
public/images/pro_plan/close.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
BIN
public/images/pro_plan/price.png
Normal file
BIN
public/images/pro_plan/price.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
2259
public/js/built.js
2259
public/js/built.js
File diff suppressed because one or more lines are too long
44
public/js/jsoneditor.min.js
vendored
Normal file
44
public/js/jsoneditor.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -1,72 +1,65 @@
|
|||||||
var NINJA = NINJA || {};
|
var NINJA = NINJA || {};
|
||||||
|
|
||||||
function GetPdfMake(invoice, javascript, callback) {
|
NINJA.TEMPLATES = {
|
||||||
var account = invoice.account;
|
CLEAN: "1",
|
||||||
var baseDD = {
|
BOLD:"2",
|
||||||
pageMargins: [40, 40, 40, 40],
|
MODERN: "3",
|
||||||
styles: {
|
NORMAL:"4",
|
||||||
bold: {
|
BUSINESS:"5",
|
||||||
bold: true
|
CREATIVE:"6",
|
||||||
},
|
ELEGANT:"7",
|
||||||
cost: {
|
HIPSTER:"8",
|
||||||
alignment: 'right'
|
PLAYFUL:"9",
|
||||||
},
|
PHOTO:"10"
|
||||||
quantity: {
|
};
|
||||||
alignment: 'right'
|
|
||||||
},
|
|
||||||
tax: {
|
|
||||||
alignment: 'right'
|
|
||||||
},
|
|
||||||
lineTotal: {
|
|
||||||
alignment: 'right'
|
|
||||||
},
|
|
||||||
right: {
|
|
||||||
alignment: 'right'
|
|
||||||
},
|
|
||||||
subtotals: {
|
|
||||||
alignment: 'right'
|
|
||||||
},
|
|
||||||
termsLabel: {
|
|
||||||
bold: true,
|
|
||||||
margin: [0, 10, 0, 4]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
footer: function(){
|
|
||||||
f = [{ text:invoice.invoice_footer?processVariables(invoice.invoice_footer):"", margin: [40, 0]}]
|
|
||||||
if (!invoice.is_pro && logoImages.imageLogo1) {
|
|
||||||
f.push({
|
|
||||||
image: logoImages.imageLogo1,
|
|
||||||
width: 150,
|
|
||||||
margin: [40,0]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return f;
|
|
||||||
},
|
|
||||||
|
|
||||||
};
|
function GetPdfMake(invoice, javascript, callback) {
|
||||||
|
|
||||||
eval(javascript);
|
javascript = NINJA.decodeJavascript(invoice, javascript);
|
||||||
dd = $.extend(true, baseDD, dd);
|
|
||||||
|
|
||||||
/*
|
function jsonCallBack(key, val) {
|
||||||
pdfMake.fonts = {
|
if ((val+'').indexOf('$firstAndLast') === 0) {
|
||||||
wqy: {
|
var parts = val.split(':');
|
||||||
normal: 'wqy.ttf',
|
return function (i, node) {
|
||||||
bold: 'wqy.ttf',
|
return (i === 0 || i === node.table.body.length) ? parseFloat(parts[1]) : 0;
|
||||||
italics: 'wqy.ttf',
|
};
|
||||||
bolditalics: 'wqy.ttf'
|
} else if ((val+'').indexOf('$none') === 0) {
|
||||||
|
return function (i, node) {
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
} else if ((val+'').indexOf('$notFirst') === 0) {
|
||||||
|
var parts = val.split(':');
|
||||||
|
return function (i, node) {
|
||||||
|
return i === 0 ? 0 : parseFloat(parts[1]);
|
||||||
|
};
|
||||||
|
} else if ((val+'').indexOf('$amount') === 0) {
|
||||||
|
var parts = val.split(':');
|
||||||
|
return function (i, node) {
|
||||||
|
return parseFloat(parts[1]);
|
||||||
|
};
|
||||||
|
} else if ((val+'').indexOf('$primaryColor') === 0) {
|
||||||
|
var parts = val.split(':');
|
||||||
|
return NINJA.primaryColor || parts[1];
|
||||||
|
} else if ((val+'').indexOf('$secondaryColor') === 0) {
|
||||||
|
var parts = val.split(':');
|
||||||
|
return NINJA.secondaryColor || parts[1];
|
||||||
}
|
}
|
||||||
};
|
|
||||||
*/
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//console.log(javascript);
|
||||||
|
var dd = JSON.parse(javascript, jsonCallBack);
|
||||||
|
|
||||||
|
if (!invoice.is_pro && dd.hasOwnProperty('footer') && dd.footer.hasOwnProperty('columns')) {
|
||||||
|
dd.footer.columns.push({image: logoImages.imageLogo1, alignment: 'right', width: 130})
|
||||||
|
}
|
||||||
|
|
||||||
|
//console.log(JSON.stringify(dd));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
pdfMake.fonts = {
|
var fonts = {
|
||||||
NotoSansCJKsc: {
|
|
||||||
normal: 'NotoSansCJKsc-Regular.ttf',
|
|
||||||
bold: 'NotoSansCJKsc-Medium.ttf',
|
|
||||||
italics: 'NotoSansCJKsc-Italic.ttf',
|
|
||||||
bolditalics: 'NotoSansCJKsc-Italic.ttf'
|
|
||||||
},
|
|
||||||
Roboto: {
|
Roboto: {
|
||||||
normal: 'Roboto-Regular.ttf',
|
normal: 'Roboto-Regular.ttf',
|
||||||
bold: 'Roboto-Medium.ttf',
|
bold: 'Roboto-Medium.ttf',
|
||||||
@ -83,30 +76,123 @@ function GetPdfMake(invoice, javascript, callback) {
|
|||||||
return doc;
|
return doc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NINJA.decodeJavascript = function(invoice, javascript)
|
||||||
|
{
|
||||||
|
var account = invoice.account;
|
||||||
|
var blankImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVQYV2NgYAAAAAMAAWgmWQ0AAAAASUVORK5CYII=';
|
||||||
|
|
||||||
|
// search/replace variables
|
||||||
|
var json = {
|
||||||
|
'accountName': account.name || ' ',
|
||||||
|
'accountLogo': window.accountLogo || blankImage,
|
||||||
|
'accountDetails': NINJA.accountDetails(invoice),
|
||||||
|
'accountAddress': NINJA.accountAddress(invoice),
|
||||||
|
'invoiceDetails': NINJA.invoiceDetails(invoice),
|
||||||
|
'invoiceDetailsHeight': NINJA.invoiceDetails(invoice).length * 22,
|
||||||
|
'invoiceLineItems': NINJA.invoiceLines(invoice),
|
||||||
|
'invoiceLineItemColumns': NINJA.invoiceColumns(invoice),
|
||||||
|
'clientDetails': NINJA.clientDetails(invoice),
|
||||||
|
'notesAndTerms': NINJA.notesAndTerms(invoice),
|
||||||
|
'subtotals': NINJA.subtotals(invoice),
|
||||||
|
'subtotalsHeight': NINJA.subtotals(invoice).length * 22,
|
||||||
|
'subtotalsWithoutBalance': NINJA.subtotals(invoice, true),
|
||||||
|
'balanceDue': formatMoney(invoice.balance_amount, invoice.client.currency_id),
|
||||||
|
'invoiceFooter': account.invoice_footer || ' ',
|
||||||
|
'invoiceNumber': invoice.invoice_number || ' ',
|
||||||
|
'entityType': invoice.is_quote ? invoiceLabels.quote : invoiceLabels.invoice,
|
||||||
|
'entityTypeUC': (invoice.is_quote ? invoiceLabels.quote : invoiceLabels.invoice).toUpperCase(),
|
||||||
|
'fontSize': NINJA.fontSize,
|
||||||
|
'fontSizeLarger': NINJA.fontSize + 1,
|
||||||
|
'fontSizeLargest': NINJA.fontSize + 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var key in json) {
|
||||||
|
var regExp = new RegExp('"\\$'+key+'"', 'g');
|
||||||
|
var val = JSON.stringify(json[key]);
|
||||||
|
javascript = javascript.replace(regExp, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
// search/replace labels
|
||||||
|
var regExp = new RegExp('"\\$\\\w*?Label(UC)?(:)?(\\\?)?"', 'g');
|
||||||
|
var matches = javascript.match(regExp);
|
||||||
|
|
||||||
|
if (matches) {
|
||||||
|
for (var i=0; i<matches.length; i++) {
|
||||||
|
var match = matches[i];
|
||||||
|
field = match.substring(2, match.indexOf('Label'));
|
||||||
|
field = toSnakeCase(field);
|
||||||
|
var value = getDescendantProp(invoice, field);
|
||||||
|
if (match.indexOf('?') < 0) {
|
||||||
|
var label = invoiceLabels[field];
|
||||||
|
if (match.indexOf('UC') >= 0) {
|
||||||
|
if (!label) console.log('match: ' + field);
|
||||||
|
label = label.toUpperCase();
|
||||||
|
}
|
||||||
|
if (match.indexOf(':') >= 0) {
|
||||||
|
label = label + ':';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
label = ' ';
|
||||||
|
}
|
||||||
|
javascript = javascript.replace(match, '"'+label+'"');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// search/replace values
|
||||||
|
var regExp = new RegExp('"\\$\\\w*?Value"', 'g');
|
||||||
|
var matches = javascript.match(regExp);
|
||||||
|
|
||||||
|
if (matches) {
|
||||||
|
for (var i=0; i<matches.length; i++) {
|
||||||
|
var match = matches[i];
|
||||||
|
field = match.substring(2, match.indexOf('Value'));
|
||||||
|
field = toSnakeCase(field);
|
||||||
|
var value = getDescendantProp(invoice, field) || ' ';
|
||||||
|
if (field.toLowerCase().indexOf('date') >= 0 && value != ' ') {
|
||||||
|
value = moment(value, 'YYYY-MM-DD').format('MMM D YYYY');
|
||||||
|
}
|
||||||
|
javascript = javascript.replace(match, '"'+value+'"');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return javascript;
|
||||||
|
}
|
||||||
|
|
||||||
NINJA.notesAndTerms = function(invoice)
|
NINJA.notesAndTerms = function(invoice)
|
||||||
{
|
{
|
||||||
var text = [];
|
var data = [];
|
||||||
|
|
||||||
if (invoice.public_notes) {
|
if (invoice.public_notes) {
|
||||||
text.push({text:processVariables(invoice.public_notes), style:'notes'});
|
data.push({text:invoice.public_notes, style: ['notes']});
|
||||||
|
data.push({text:' '});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (invoice.terms) {
|
if (invoice.terms) {
|
||||||
text.push({text:invoiceLabels.terms, style:'termsLabel'});
|
data.push({text:invoiceLabels.terms, style: ['termsLabel']});
|
||||||
text.push({text:processVariables(invoice.terms), style:'terms'});
|
data.push({text:invoice.terms, style: ['terms']});
|
||||||
}
|
}
|
||||||
|
|
||||||
return text;
|
return NINJA.prepareDataList(data, 'notesAndTerms');
|
||||||
|
}
|
||||||
|
|
||||||
|
NINJA.invoiceColumns = function(invoice)
|
||||||
|
{
|
||||||
|
if (invoice.has_taxes) {
|
||||||
|
return ["15%", "*", "auto", "auto", "auto", "15%"];
|
||||||
|
} else {
|
||||||
|
return ["15%", "*", "auto", "auto", "15%"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NINJA.invoiceLines = function(invoice) {
|
NINJA.invoiceLines = function(invoice) {
|
||||||
var grid = [
|
var grid = [
|
||||||
[
|
[
|
||||||
{text: invoiceLabels.item, style: 'tableHeader'},
|
{text: invoiceLabels.item, style: ['tableHeader', 'itemTableHeader']},
|
||||||
{text: invoiceLabels.description, style: 'tableHeader'},
|
{text: invoiceLabels.description, style: ['tableHeader', 'descriptionTableHeader']},
|
||||||
{text: invoiceLabels.unit_cost, style: 'tableHeader'},
|
{text: invoiceLabels.unit_cost, style: ['tableHeader', 'costTableHeader']},
|
||||||
{text: invoiceLabels.quantity, style: 'tableHeader'},
|
{text: invoiceLabels.quantity, style: ['tableHeader', 'qtyTableHeader']},
|
||||||
{text: invoice.has_taxes?invoiceLabels.tax:'', style: 'tableHeader'},
|
{text: invoice.has_taxes ? invoiceLabels.tax : '', style: ['tableHeader', 'taxTableHeader']},
|
||||||
{text: invoiceLabels.line_total, style: 'tableHeader'}
|
{text: invoiceLabels.line_total, style: ['tableHeader', 'lineTotalTableHeader']}
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -116,23 +202,26 @@ NINJA.invoiceLines = function(invoice) {
|
|||||||
var hideQuantity = invoice.account.hide_quantity == '1';
|
var hideQuantity = invoice.account.hide_quantity == '1';
|
||||||
|
|
||||||
for (var i = 0; i < invoice.invoice_items.length; i++) {
|
for (var i = 0; i < invoice.invoice_items.length; i++) {
|
||||||
|
|
||||||
var row = [];
|
var row = [];
|
||||||
var item = invoice.invoice_items[i];
|
var item = invoice.invoice_items[i];
|
||||||
var cost = formatMoney(item.cost, currencyId, true);
|
var cost = formatMoney(item.cost, currencyId, true);
|
||||||
var qty = NINJA.parseFloat(item.qty) ? roundToTwo(NINJA.parseFloat(item.qty)) + '' : '';
|
var qty = NINJA.parseFloat(item.qty) ? roundToTwo(NINJA.parseFloat(item.qty)) + '' : '';
|
||||||
var notes = item.notes;
|
var notes = item.notes;
|
||||||
var productKey = item.product_key;
|
var productKey = item.product_key;
|
||||||
var tax = "";
|
var tax = '';
|
||||||
|
|
||||||
if (item.tax && parseFloat(item.tax.rate)) {
|
if (item.tax && parseFloat(item.tax.rate)) {
|
||||||
tax = parseFloat(item.tax.rate);
|
tax = parseFloat(item.tax.rate);
|
||||||
} else if (item.tax_rate && parseFloat(item.tax_rate)) {
|
} else if (item.tax_rate && parseFloat(item.tax_rate)) {
|
||||||
tax = parseFloat(item.tax_rate);
|
tax = parseFloat(item.tax_rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
// show at most one blank line
|
// show at most one blank line
|
||||||
if (shownItem && (!cost || cost == '0.00') && !notes && !productKey) {
|
if (shownItem && (!cost || cost == '0.00') && !notes && !productKey) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
shownItem = true;
|
shownItem = true;
|
||||||
|
|
||||||
// process date variables
|
// process date variables
|
||||||
@ -150,140 +239,165 @@ NINJA.invoiceLines = function(invoice) {
|
|||||||
}
|
}
|
||||||
lineTotal = formatMoney(lineTotal, currencyId);
|
lineTotal = formatMoney(lineTotal, currencyId);
|
||||||
|
|
||||||
rowStyle = i%2===0?'odd':'even';
|
rowStyle = (i % 2 == 0) ? 'odd' : 'even';
|
||||||
|
|
||||||
|
row.push({style:["productKey", rowStyle], text:productKey || ' '}); // product key can be blank when selecting from a datalist
|
||||||
|
row.push({style:["notes", rowStyle], text:notes || ' '});
|
||||||
|
row.push({style:["cost", rowStyle], text:cost});
|
||||||
|
row.push({style:["quantity", rowStyle], text:qty || ' '});
|
||||||
|
|
||||||
row[0] = {style:["productKey", rowStyle], text:productKey};
|
if (invoice.has_taxes) {
|
||||||
row[1] = {style:["notes", rowStyle], text:notes};
|
row.push({style:["tax", rowStyle], text: tax+'' || ''});
|
||||||
row[2] = {style:["cost", rowStyle], text:cost};
|
}
|
||||||
row[3] = {style:["quantity", rowStyle], text:qty};
|
|
||||||
row[4] = {style:["tax", rowStyle], text:""+tax};
|
row.push({style:["lineTotal", rowStyle], text:lineTotal || ' '});
|
||||||
row[5] = {style:["lineTotal", rowStyle], text:lineTotal};
|
|
||||||
|
|
||||||
grid.push(row);
|
grid.push(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
return grid;
|
return NINJA.prepareDataTable(grid, 'invoiceItems');
|
||||||
}
|
}
|
||||||
|
|
||||||
NINJA.subtotals = function(invoice)
|
NINJA.subtotals = function(invoice, removeBalance)
|
||||||
{
|
{
|
||||||
if (!invoice) {
|
if (!invoice) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var data = [
|
var account = invoice.account;
|
||||||
[invoiceLabels.subtotal, formatMoney(invoice.subtotal_amount, invoice.client.currency_id)],
|
var data = [];
|
||||||
];
|
data.push([{text: invoiceLabels.subtotal}, {text: formatMoney(invoice.subtotal_amount, invoice.client.currency_id)}]);
|
||||||
|
|
||||||
if(invoice.discount_amount != 0) {
|
if (invoice.discount_amount != 0) {
|
||||||
data.push([invoiceLabels.discount, formatMoney(invoice.discount_amount, invoice.client.currency_id)]);
|
data.push([{text: invoiceLabels.discount}, {text: formatMoney(invoice.discount_amount, invoice.client.currency_id)}]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NINJA.parseFloat(invoice.custom_value1) && invoice.custom_taxes1 == '1') {
|
if (NINJA.parseFloat(invoice.custom_value1) && invoice.custom_taxes1 == '1') {
|
||||||
data.push([invoiceLabels.custom_invoice_label1, formatMoney(invoice.custom_value1, invoice.client.currency_id)]);
|
data.push([{text: account.custom_invoice_label1}, {text: formatMoney(invoice.custom_value1, invoice.client.currency_id)}]);
|
||||||
}
|
}
|
||||||
if (NINJA.parseFloat(invoice.custom_value2) && invoice.custom_taxes2 == '1') {
|
if (NINJA.parseFloat(invoice.custom_value2) && invoice.custom_taxes2 == '1') {
|
||||||
data.push([invoiceLabels.custom_invoice_label2, formatMoney(invoice.custom_value2, invoice.client.currency_id)]);
|
data.push([{text: account.custom_invoice_label2}, {text: formatMoney(invoice.custom_value2, invoice.client.currency_id)}]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(invoice.tax && invoice.tax.name || invoice.tax_name) {
|
if (invoice.tax && invoice.tax.name || invoice.tax_name) {
|
||||||
data.push([invoiceLabels.tax, formatMoney(invoice.tax_amount, invoice.client.currency_id)]);
|
data.push([{text: invoiceLabels.tax}, {text: formatMoney(invoice.tax_amount, invoice.client.currency_id)}]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NINJA.parseFloat(invoice.custom_value1) && invoice.custom_taxes1 != '1') {
|
if (NINJA.parseFloat(invoice.custom_value1) && invoice.custom_taxes1 != '1') {
|
||||||
data.push([invoiceLabels.custom_invoice_label1, formatMoney(invoice.custom_value1, invoice.client.currency_id)]);
|
data.push([{text: account.custom_invoice_label1}, {text: formatMoney(invoice.custom_value1, invoice.client.currency_id)}]);
|
||||||
}
|
}
|
||||||
if (NINJA.parseFloat(invoice.custom_value2) && invoice.custom_taxes2 != '1') {
|
if (NINJA.parseFloat(invoice.custom_value2) && invoice.custom_taxes2 != '1') {
|
||||||
data.push([invoiceLabels.custom_invoice_label2, formatMoney(invoice.custom_value2, invoice.client.currency_id)]);
|
data.push([{text: account.custom_invoice_label2}, {text: formatMoney(invoice.custom_value2, invoice.client.currency_id)}]);
|
||||||
}
|
|
||||||
|
|
||||||
var paid = invoice.amount - invoice.balance;
|
|
||||||
if (invoice.account.hide_paid_to_date != '1' || paid) {
|
|
||||||
data.push([invoiceLabels.paid_to_date, formatMoney(paid, invoice.client.currency_id)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
data.push([{text:invoice.is_quote ? invoiceLabels.total : invoiceLabels.balance_due, style:'balanceDueLabel'},
|
|
||||||
{text:formatMoney(invoice.balance_amount, invoice.client.currency_id), style:'balanceDueValue'}]);
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
NINJA.accountDetails = function(account) {
|
|
||||||
var data = [];
|
|
||||||
if(account.name) data.push({text:account.name, style:'accountName'});
|
|
||||||
if(account.id_number) data.push({text:account.id_number, style:'accountDetails'});
|
|
||||||
if(account.vat_number) data.push({text:account.vat_number, style:'accountDetails'});
|
|
||||||
if(account.work_email) data.push({text:account.work_email, style:'accountDetails'});
|
|
||||||
if(account.work_phone) data.push({text:account.work_phone, style:'accountDetails'});
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
NINJA.accountAddress = function(account) {
|
|
||||||
var address = '';
|
|
||||||
if (account.city || account.state || account.postal_code) {
|
|
||||||
address = ((account.city ? account.city + ', ' : '') + account.state + ' ' + account.postal_code).trim();
|
|
||||||
}
|
}
|
||||||
var data = [];
|
|
||||||
if(account.address1) data.push({text:account.address1, style:'accountDetails'});
|
var paid = invoice.amount - invoice.balance;
|
||||||
if(account.address2) data.push({text:account.address2, style:'accountDetails'});
|
if (invoice.account.hide_paid_to_date != '1' || paid) {
|
||||||
if(address) data.push({text:address, style:'accountDetails'});
|
data.push([{text:invoiceLabels.paid_to_date}, {text:formatMoney(paid, invoice.client.currency_id)}]);
|
||||||
if(account.country) data.push({text:account.country.name, style: 'accountDetails'});
|
}
|
||||||
if(account.custom_label1 && account.custom_value1) data.push({text:account.custom_label1 +' '+ account.custom_value1, style: 'accountDetails'});
|
|
||||||
if(account.custom_label2 && account.custom_value2) data.push({text:account.custom_label2 +' '+ account.custom_value2, style: 'accountDetails'});
|
if (!removeBalance) {
|
||||||
return data;
|
data.push([
|
||||||
|
{text:invoice.is_quote ? invoiceLabels.balance_due : invoiceLabels.balance_due, style:['balanceDueLabel']},
|
||||||
|
{text:formatMoney(invoice.balance_amount, invoice.client.currency_id), style:['balanceDue']}
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NINJA.prepareDataPairs(data, 'subtotals');
|
||||||
|
}
|
||||||
|
|
||||||
|
NINJA.accountDetails = function(invoice) {
|
||||||
|
var account = invoice.account;
|
||||||
|
var data = [
|
||||||
|
{text:account.name, style: ['accountName']},
|
||||||
|
{text:account.id_number},
|
||||||
|
{text:account.vat_number},
|
||||||
|
{text:account.work_email},
|
||||||
|
{text:account.work_phone}
|
||||||
|
];
|
||||||
|
return NINJA.prepareDataList(data, 'accountDetails');
|
||||||
|
}
|
||||||
|
|
||||||
|
NINJA.accountAddress = function(invoice) {
|
||||||
|
var account = invoice.account;
|
||||||
|
var cityStatePostal = '';
|
||||||
|
if (account.city || account.state || account.postal_code) {
|
||||||
|
cityStatePostal = ((account.city ? account.city + ', ' : '') + account.state + ' ' + account.postal_code).trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
var data = [
|
||||||
|
{text: account.address1},
|
||||||
|
{text: account.address2},
|
||||||
|
{text: cityStatePostal},
|
||||||
|
{text: account.country ? account.country.name : ''}
|
||||||
|
];
|
||||||
|
|
||||||
|
return NINJA.prepareDataList(data, 'accountAddress');
|
||||||
}
|
}
|
||||||
|
|
||||||
NINJA.invoiceDetails = function(invoice) {
|
NINJA.invoiceDetails = function(invoice) {
|
||||||
|
|
||||||
var data = [
|
var data = [
|
||||||
[
|
[
|
||||||
invoice.is_quote ? invoiceLabels.quote_number : invoiceLabels.invoice_number,
|
{text: (invoice.is_quote ? invoiceLabels.quote_number : invoiceLabels.invoice_number), style: ['invoiceNumberLabel']},
|
||||||
{style: 'bold', text: invoice.invoice_number},
|
{text: invoice.invoice_number, style: ['invoiceNumber']}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
invoice.is_quote ? invoiceLabels.quote_date : invoiceLabels.invoice_date,
|
{text: invoiceLabels.po_number},
|
||||||
invoice.invoice_date,
|
{text: invoice.po_number}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
invoice.is_quote ? invoiceLabels.total : invoiceLabels.balance_due,
|
{text: invoiceLabels.invoice_date},
|
||||||
formatMoney(invoice.balance_amount, invoice.client.currency_id),
|
{text: invoice.invoice_date}
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
{text: invoiceLabels.due_date},
|
||||||
|
{text: invoice.due_date}
|
||||||
|
]
|
||||||
];
|
];
|
||||||
|
|
||||||
return data;
|
if (NINJA.parseFloat(invoice.balance) < NINJA.parseFloat(invoice.amount)) {
|
||||||
|
data.push([
|
||||||
|
{text: invoiceLabels.total},
|
||||||
|
{text: formatMoney(invoice.amount, invoice.client.currency_id)}
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NINJA.parseFloat(invoice.partial)) {
|
||||||
|
data.push([
|
||||||
|
{text: invoiceLabels.balance},
|
||||||
|
{text: formatMoney(invoice.total_amount, invoice.client.currency_id)}
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
data.push([
|
||||||
|
{text: invoiceLabels.balance_due, style: ['invoiceDetailBalanceDueLabel']},
|
||||||
|
{text: formatMoney(invoice.balance_amount, invoice.client.currency_id), style: ['invoiceDetailBalanceDue']}
|
||||||
|
])
|
||||||
|
|
||||||
|
return NINJA.prepareDataPairs(data, 'invoiceDetails');
|
||||||
}
|
}
|
||||||
|
|
||||||
NINJA.clientDetails = function(invoice) {
|
NINJA.clientDetails = function(invoice) {
|
||||||
var client = invoice.client;
|
var client = invoice.client;
|
||||||
|
var data;
|
||||||
if (!client) {
|
if (!client) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
var contact = client.contacts[0];
|
||||||
|
var clientName = client.name || (contact.first_name || contact.last_name ? (contact.first_name + ' ' + contact.last_name) : contact.email);
|
||||||
|
var clientEmail = client.contacts[0].email == clientName ? '' : client.contacts[0].email;
|
||||||
|
|
||||||
var fields = [
|
data = [
|
||||||
getClientDisplayName(client),
|
{text:clientName || ' ', style: ['clientName']},
|
||||||
client.id_number,
|
{text:client.address1},
|
||||||
client.vat_number,
|
{text:concatStrings(client.city, client.state, client.postal_code)},
|
||||||
concatStrings(client.address1, client.address2),
|
{text:client.country ? client.country.name : ''},
|
||||||
concatStrings(client.city, client.state, client.postal_code),
|
{text:clientEmail}
|
||||||
client.country ? client.country.name : false,
|
|
||||||
invoice.contact && getClientDisplayName(client) != invoice.contact.email ? invoice.contact.email : false,
|
|
||||||
invoice.client.custom_value1 ? invoice.account['custom_client_label1'] + ' ' + invoice.client.custom_value1 : false,
|
|
||||||
invoice.client.custom_value2 ? invoice.account['custom_client_label2'] + ' ' + invoice.client.custom_value2 : false,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
var data = [];
|
return NINJA.prepareDataList(data, 'clientDetails');
|
||||||
for (var i=0; i<fields.length; i++) {
|
|
||||||
var field = fields[i];
|
|
||||||
if (!field) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
data.push([field]);
|
|
||||||
}
|
|
||||||
if (!data.length) {
|
|
||||||
data.push(['']);
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
NINJA.getPrimaryColor = function(defaultColor) {
|
NINJA.getPrimaryColor = function(defaultColor) {
|
||||||
return NINJA.primaryColor ? NINJA.primaryColor : defaultColor;
|
return NINJA.primaryColor ? NINJA.primaryColor : defaultColor;
|
||||||
}
|
}
|
||||||
@ -292,6 +406,62 @@ NINJA.getSecondaryColor = function(defaultColor) {
|
|||||||
return NINJA.primaryColor ? NINJA.secondaryColor : defaultColor;
|
return NINJA.primaryColor ? NINJA.secondaryColor : defaultColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
NINJA.getEntityLabel = function(invoice) {
|
// remove blanks and add section style to all elements
|
||||||
return invoice.is_quote ? invoiceLabels.quote : invoiceLabels.invoice;
|
NINJA.prepareDataList = function(oldData, section) {
|
||||||
|
var newData = [];
|
||||||
|
for (var i=0; i<oldData.length; i++) {
|
||||||
|
var item = NINJA.processItem(oldData[i], section);
|
||||||
|
if (item.text) {
|
||||||
|
newData.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newData;
|
||||||
|
}
|
||||||
|
|
||||||
|
NINJA.prepareDataTable = function(oldData, section) {
|
||||||
|
var newData = [];
|
||||||
|
for (var i=0; i<oldData.length; i++) {
|
||||||
|
var row = oldData[i];
|
||||||
|
var newRow = [];
|
||||||
|
for (var j=0; j<row.length; j++) {
|
||||||
|
var item = NINJA.processItem(row[j], section);
|
||||||
|
if (item.text) {
|
||||||
|
newRow.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (newRow.length) {
|
||||||
|
newData.push(newRow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newData;
|
||||||
|
}
|
||||||
|
|
||||||
|
NINJA.prepareDataPairs = function(oldData, section) {
|
||||||
|
var newData = [];
|
||||||
|
for (var i=0; i<oldData.length; i++) {
|
||||||
|
var row = oldData[i];
|
||||||
|
var isBlank = false;
|
||||||
|
for (var j=0; j<row.length; j++) {
|
||||||
|
var item = NINJA.processItem(row[j], section);
|
||||||
|
if (!item.text) {
|
||||||
|
isBlank = true;
|
||||||
|
}
|
||||||
|
if (j == 1) {
|
||||||
|
NINJA.processItem(row[j], section + "Value");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!isBlank) {
|
||||||
|
newData.push(oldData[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newData;
|
||||||
|
}
|
||||||
|
|
||||||
|
NINJA.processItem = function(item, section) {
|
||||||
|
if (item.style && item.style instanceof Array) {
|
||||||
|
item.style.push(section);
|
||||||
|
} else {
|
||||||
|
item.style = [section];
|
||||||
|
}
|
||||||
|
return item;
|
||||||
}
|
}
|
32
public/js/pdfmake.min.js
vendored
32
public/js/pdfmake.min.js
vendored
File diff suppressed because one or more lines are too long
@ -8,33 +8,51 @@ var isIE = /*@cc_on!@*/false || !!document.documentMode; // At least IE6
|
|||||||
|
|
||||||
|
|
||||||
var invoiceOld;
|
var invoiceOld;
|
||||||
|
var refreshTimer;
|
||||||
function generatePDF(invoice, javascript, force, cb) {
|
function generatePDF(invoice, javascript, force, cb) {
|
||||||
|
if (!invoice || !javascript) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log('== generatePDF - force: %s', force);
|
||||||
|
if (force || !invoiceOld) {
|
||||||
|
refreshTimer = null;
|
||||||
|
} else {
|
||||||
|
if (refreshTimer) {
|
||||||
|
clearTimeout(refreshTimer);
|
||||||
|
}
|
||||||
|
refreshTimer = setTimeout(function() {
|
||||||
|
generatePDF(invoice, javascript, true, cb);
|
||||||
|
}, 500);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
invoice = calculateAmounts(invoice);
|
invoice = calculateAmounts(invoice);
|
||||||
var a = copyInvoice(invoice);
|
var a = copyObject(invoice);
|
||||||
var b = copyInvoice(invoiceOld);
|
var b = copyObject(invoiceOld);
|
||||||
if (!force && _.isEqual(a, b)) {
|
if (!force && _.isEqual(a, b)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pdfmakeMarker = "//pdfmake";
|
|
||||||
invoiceOld = invoice;
|
invoiceOld = invoice;
|
||||||
report_id = invoice.invoice_design_id;
|
pdfmakeMarker = "{";
|
||||||
if(javascript.slice(0, pdfmakeMarker.length) === pdfmakeMarker) {
|
if(javascript.slice(0, pdfmakeMarker.length) === pdfmakeMarker) {
|
||||||
doc = GetPdfMake(invoice, javascript, cb);
|
doc = GetPdfMake(invoice, javascript, cb);
|
||||||
//doc.getDataUrl(cb);
|
|
||||||
} else {
|
} else {
|
||||||
doc = GetPdf(invoice, javascript);
|
doc = GetPdf(invoice, javascript);
|
||||||
doc.getDataUrl = function(cb) {
|
doc.getDataUrl = function(cb) {
|
||||||
cb( this.output("datauristring"));
|
cb( this.output("datauristring"));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cb) {
|
||||||
|
doc.getDataUrl(cb);
|
||||||
|
}
|
||||||
|
|
||||||
return doc;
|
return doc;
|
||||||
}
|
}
|
||||||
|
|
||||||
function copyInvoice(orig) {
|
function copyObject(orig) {
|
||||||
if (!orig) return false;
|
if (!orig) return false;
|
||||||
var copy = JSON.stringify(orig);
|
return JSON.parse(JSON.stringify(orig));
|
||||||
var copy = JSON.parse(copy);
|
|
||||||
return copy;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -705,8 +723,12 @@ function getInvoiceDetails(invoice) {
|
|||||||
{'due_date': invoice.due_date},
|
{'due_date': invoice.due_date},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if (NINJA.parseFloat(invoice.balance) < NINJA.parseFloat(invoice.amount)) {
|
||||||
|
fields.push({'total': formatMoney(invoice.amount, invoice.client.currency_id)});
|
||||||
|
}
|
||||||
|
|
||||||
if (NINJA.parseFloat(invoice.partial)) {
|
if (NINJA.parseFloat(invoice.partial)) {
|
||||||
fields.push({'total': formatMoney(invoice.total_amount, invoice.client.currency_id)});
|
fields.push({'balance': formatMoney(invoice.total_amount, invoice.client.currency_id)});
|
||||||
}
|
}
|
||||||
|
|
||||||
fields.push({'balance_due': formatMoney(invoice.balance_amount, invoice.client.currency_id)})
|
fields.push({'balance_due': formatMoney(invoice.balance_amount, invoice.client.currency_id)})
|
||||||
@ -762,12 +784,16 @@ function displaySubtotals(doc, layout, invoice, y, rightAlignTitleX)
|
|||||||
}
|
}
|
||||||
|
|
||||||
var paid = invoice.amount - invoice.balance;
|
var paid = invoice.amount - invoice.balance;
|
||||||
|
if (paid) {
|
||||||
|
data.push({'total': formatMoney(invoice.amount, invoice.client.currency_id)});
|
||||||
|
}
|
||||||
|
|
||||||
if (invoice.account.hide_paid_to_date != '1' || paid) {
|
if (invoice.account.hide_paid_to_date != '1' || paid) {
|
||||||
data.push({'paid_to_date': formatMoney(paid, invoice.client.currency_id)});
|
data.push({'paid_to_date': formatMoney(paid, invoice.client.currency_id)});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NINJA.parseFloat(invoice.partial) && invoice.total_amount != invoice.subtotal_amount) {
|
if (NINJA.parseFloat(invoice.partial) && invoice.total_amount != invoice.subtotal_amount) {
|
||||||
data.push({'total': formatMoney(invoice.total_amount, invoice.client.currency_id)});
|
data.push({'balance': formatMoney(invoice.total_amount, invoice.client.currency_id)});
|
||||||
}
|
}
|
||||||
|
|
||||||
var options = {
|
var options = {
|
||||||
@ -1053,7 +1079,7 @@ function displayInvoiceItems(doc, invoice, layout) {
|
|||||||
}
|
}
|
||||||
shownItem = true;
|
shownItem = true;
|
||||||
|
|
||||||
var numLines = doc.splitTextToSize(item.notes, 200).length + 2;
|
var numLines = Math.max(doc.splitTextToSize(item.notes, 200).length, doc.splitTextToSize(item.product_key, 60).length) + 2;
|
||||||
//console.log('num lines %s', numLines);
|
//console.log('num lines %s', numLines);
|
||||||
|
|
||||||
var y = tableTop + (line * layout.tableRowHeight) + (2 * layout.tablePadding);
|
var y = tableTop + (line * layout.tableRowHeight) + (2 * layout.tablePadding);
|
||||||
@ -1566,4 +1592,15 @@ function twoDigits(value) {
|
|||||||
return '0' + value;
|
return '0' + value;
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toSnakeCase(str) {
|
||||||
|
if (!str) return '';
|
||||||
|
return str.replace(/([A-Z])/g, function($1){return "_"+$1.toLowerCase();});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDescendantProp(obj, desc) {
|
||||||
|
var arr = desc.split(".");
|
||||||
|
while(arr.length && (obj = obj[arr.shift()]));
|
||||||
|
return obj;
|
||||||
}
|
}
|
@ -1,162 +0,0 @@
|
|||||||
//pdfmake
|
|
||||||
|
|
||||||
/*
|
|
||||||
var dd = {
|
|
||||||
content: 'wqy中文wqy',
|
|
||||||
defaultStyle: {
|
|
||||||
font: 'wqy'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
*/
|
|
||||||
|
|
||||||
var dd = {
|
|
||||||
content: [
|
|
||||||
{
|
|
||||||
columns: [
|
|
||||||
[
|
|
||||||
invoice.image?
|
|
||||||
{
|
|
||||||
image: invoice.image,
|
|
||||||
fit: [150, 80]
|
|
||||||
}:""
|
|
||||||
],
|
|
||||||
{
|
|
||||||
stack: NINJA.accountDetails(account)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
stack: NINJA.accountAddress(account)
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text:(NINJA.getEntityLabel(invoice)).toUpperCase(),
|
|
||||||
margin: [8, 70, 8, 16],
|
|
||||||
style: 'primaryColor',
|
|
||||||
fontSize: NINJA.fontSize + 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
table: {
|
|
||||||
headerRows: 1,
|
|
||||||
widths: ['auto', 'auto', '*'],
|
|
||||||
body: [
|
|
||||||
[
|
|
||||||
{
|
|
||||||
table: {
|
|
||||||
body: NINJA.invoiceDetails(invoice),
|
|
||||||
},
|
|
||||||
layout: 'noBorders',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
table: {
|
|
||||||
body: NINJA.clientDetails(invoice),
|
|
||||||
},
|
|
||||||
layout: 'noBorders',
|
|
||||||
},
|
|
||||||
''
|
|
||||||
]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
layout: {
|
|
||||||
hLineWidth: function (i, node) {
|
|
||||||
return (i === 0 || i === node.table.body.length) ? .5 : 0;
|
|
||||||
},
|
|
||||||
vLineWidth: function (i, node) {
|
|
||||||
return 0;
|
|
||||||
},
|
|
||||||
hLineColor: function (i, node) {
|
|
||||||
return '#D8D8D8';
|
|
||||||
},
|
|
||||||
paddingLeft: function(i, node) { return 8; },
|
|
||||||
paddingRight: function(i, node) { return 8; },
|
|
||||||
paddingTop: function(i, node) { return 4; },
|
|
||||||
paddingBottom: function(i, node) { return 4; }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'\n',
|
|
||||||
{
|
|
||||||
table: {
|
|
||||||
headerRows: 1,
|
|
||||||
widths: ['15%', '*', 'auto', 'auto', 'auto', 'auto'],
|
|
||||||
body: NINJA.invoiceLines(invoice),
|
|
||||||
},
|
|
||||||
layout: {
|
|
||||||
hLineWidth: function (i, node) {
|
|
||||||
return i === 0 ? 0 : .5;
|
|
||||||
},
|
|
||||||
vLineWidth: function (i, node) {
|
|
||||||
return 0;
|
|
||||||
},
|
|
||||||
hLineColor: function (i, node) {
|
|
||||||
return '#D8D8D8';
|
|
||||||
},
|
|
||||||
paddingLeft: function(i, node) { return 8; },
|
|
||||||
paddingRight: function(i, node) { return 8; },
|
|
||||||
paddingTop: function(i, node) { return 8; },
|
|
||||||
paddingBottom: function(i, node) { return 8; }
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'\n',
|
|
||||||
{
|
|
||||||
columns: [
|
|
||||||
NINJA.notesAndTerms(invoice),
|
|
||||||
{
|
|
||||||
style: 'subtotals',
|
|
||||||
table: {
|
|
||||||
widths: ['*', '*'],
|
|
||||||
body: NINJA.subtotals(invoice),
|
|
||||||
},
|
|
||||||
layout: {
|
|
||||||
hLineWidth: function (i, node) {
|
|
||||||
return 0;
|
|
||||||
},
|
|
||||||
vLineWidth: function (i, node) {
|
|
||||||
return 0;
|
|
||||||
},
|
|
||||||
paddingLeft: function(i, node) { return 8; },
|
|
||||||
paddingRight: function(i, node) { return 8; },
|
|
||||||
paddingTop: function(i, node) { return 4; },
|
|
||||||
paddingBottom: function(i, node) { return 4; }
|
|
||||||
},
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
defaultStyle: {
|
|
||||||
//font: 'arialuni',
|
|
||||||
fontSize: NINJA.fontSize,
|
|
||||||
margin: [8, 4, 8, 4]
|
|
||||||
},
|
|
||||||
styles: {
|
|
||||||
primaryColor:{
|
|
||||||
color: NINJA.getPrimaryColor('#299CC2')
|
|
||||||
},
|
|
||||||
accountName: {
|
|
||||||
margin: [4, 2, 4, 2],
|
|
||||||
color: NINJA.getPrimaryColor('#299CC2')
|
|
||||||
},
|
|
||||||
accountDetails: {
|
|
||||||
margin: [4, 2, 4, 2],
|
|
||||||
color: '#AAA9A9'
|
|
||||||
},
|
|
||||||
even: {
|
|
||||||
},
|
|
||||||
odd: {
|
|
||||||
fillColor:'#F4F4F4'
|
|
||||||
},
|
|
||||||
productKey: {
|
|
||||||
color: NINJA.getPrimaryColor('#299CC2')
|
|
||||||
},
|
|
||||||
tableHeader: {
|
|
||||||
bold: true
|
|
||||||
},
|
|
||||||
balanceDueLabel: {
|
|
||||||
fontSize: NINJA.fontSize + 2
|
|
||||||
},
|
|
||||||
balanceDueValue: {
|
|
||||||
fontSize: NINJA.fontSize + 2,
|
|
||||||
color: NINJA.getPrimaryColor('#299CC2')
|
|
||||||
},
|
|
||||||
},
|
|
||||||
pageMargins: [40, 40, 40, 40],
|
|
||||||
};
|
|
22
readme.md
22
readme.md
@ -1,18 +1,20 @@
|
|||||||
# Invoice Ninja
|
# Invoice Ninja
|
||||||
### [https://www.invoiceninja.com](https://www.invoiceninja.com)
|
### [https://www.invoiceninja.com](https://www.invoiceninja.com)
|
||||||
|
|
||||||
If you'd like to use our code to sell your own invoicing app we have an affiliate program. Get in touch for more details.
|
If you'd like to use our code to sell your own invoicing app email us for details about our affiliate program.
|
||||||
|
|
||||||
### Introduction
|
### Installation Options
|
||||||
|
|
||||||
To setup the site you can either use the [zip file](https://www.invoiceninja.com/knowledgebase/self-host/) (easier to run) or checkout the code from GitHub (easier to make changes).
|
* [Zip - Free](https://www.invoiceninja.com/knowledgebase/self-host/)
|
||||||
|
* [Bitnami - Free](https://bitnami.com/stack/invoice-ninja)
|
||||||
|
* [Softaculous - $30](https://www.softaculous.com/apps/ecommerce/Invoice_Ninja)
|
||||||
|
|
||||||
For updates follow [@invoiceninja](https://twitter.com/invoiceninja) or join the [Facebook Group](https://www.facebook.com/invoiceninja). For discussion of the app please use our [new forum](http://www.invoiceninja.com/forums).
|
### Getting Started
|
||||||
|
|
||||||
|
If you have any questions or comments please use our [support forum](https://www.invoiceninja.com/forums/forum/support/). For updates follow [@invoiceninja](https://twitter.com/invoiceninja) or join the [Facebook Group](https://www.facebook.com/invoiceninja).
|
||||||
|
|
||||||
If you'd like to translate the site please use [caouecs/Laravel4-long](https://github.com/caouecs/Laravel4-lang) for the starter files.
|
If you'd like to translate the site please use [caouecs/Laravel4-long](https://github.com/caouecs/Laravel4-lang) for the starter files.
|
||||||
|
|
||||||
Developed by [@hillelcoren](https://twitter.com/hillelcoren) | Designed by [kantorp-wegl.in](http://kantorp-wegl.in/).
|
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
* Built using Laravel 5
|
* Built using Laravel 5
|
||||||
@ -33,12 +35,11 @@ Developed by [@hillelcoren](https://twitter.com/hillelcoren) | Designed by [kant
|
|||||||
* [Jeramy Simpson](https://github.com/JeramyMywork) - [MyWork](https://www.mywork.com.au)
|
* [Jeramy Simpson](https://github.com/JeramyMywork) - [MyWork](https://www.mywork.com.au)
|
||||||
* [Sigitas Limontas](https://lt.linkedin.com/in/sigitaslimontas)
|
* [Sigitas Limontas](https://lt.linkedin.com/in/sigitaslimontas)
|
||||||
|
|
||||||
### Documentation
|
### Documentation
|
||||||
|
|
||||||
* [Self Host](https://www.invoiceninja.com/knowledgebase/self-host/)
|
|
||||||
* [Ubuntu and Apache](http://blog.technerdservices.com/index.php/2015/04/techpop-how-to-install-invoice-ninja-on-ubuntu-14-04/)
|
* [Ubuntu and Apache](http://blog.technerdservices.com/index.php/2015/04/techpop-how-to-install-invoice-ninja-on-ubuntu-14-04/)
|
||||||
* [Debian and Nginx](https://www.rosehosting.com/blog/install-invoice-ninja-on-a-debian-7-vps/)
|
* [Debian and Nginx](https://www.rosehosting.com/blog/install-invoice-ninja-on-a-debian-7-vps/)
|
||||||
* [API Documentation](https://www.invoiceninja.com/knowledgebase/api-documentation/)
|
* [API Documentation](https://www.invoiceninja.com/knowledgebase/api-documentation/)
|
||||||
|
* [User Guide](https://www.invoiceninja.com/user-guide/)
|
||||||
* [Developer Guide](https://www.invoiceninja.com/knowledgebase/developer-guide/)
|
* [Developer Guide](https://www.invoiceninja.com/knowledgebase/developer-guide/)
|
||||||
|
|
||||||
### Frameworks/Libraries
|
### Frameworks/Libraries
|
||||||
@ -69,4 +70,5 @@ Developed by [@hillelcoren](https://twitter.com/hillelcoren) | Designed by [kant
|
|||||||
* [jashkenas/underscore](https://github.com/jashkenas/underscore) - JavaScript's utility _ belt
|
* [jashkenas/underscore](https://github.com/jashkenas/underscore) - JavaScript's utility _ belt
|
||||||
* [caouecs/Laravel4-long](https://github.com/caouecs/Laravel4-lang) - List of languages for Laravel4
|
* [caouecs/Laravel4-long](https://github.com/caouecs/Laravel4-lang) - List of languages for Laravel4
|
||||||
* [bgrins/spectrum](https://github.com/bgrins/spectrum) - The No Hassle JavaScript Colorpicker
|
* [bgrins/spectrum](https://github.com/bgrins/spectrum) - The No Hassle JavaScript Colorpicker
|
||||||
* [lokesh/lightbox2](https://github.com/lokesh/lightbox2/) - The original lightbox script
|
* [lokesh/lightbox2](https://github.com/lokesh/lightbox2/) - The original lightbox script
|
||||||
|
* [josdejong/jsoneditor](https://github.com/josdejong/jsoneditor/) - A web-based tool to view, edit and format JSON
|
@ -599,7 +599,7 @@ return array(
|
|||||||
'less_fields' => 'Less Fields',
|
'less_fields' => 'Less Fields',
|
||||||
'client_name' => 'Client Name',
|
'client_name' => 'Client Name',
|
||||||
'pdf_settings' => 'PDF Settings',
|
'pdf_settings' => 'PDF Settings',
|
||||||
'utf8_invoices' => 'Cyrillic Support <sup>Beta</sup>',
|
'utf8_invoices' => 'New PDF Engine <sup>Beta</sup>',
|
||||||
'product_settings' => 'Product Settings',
|
'product_settings' => 'Product Settings',
|
||||||
'auto_wrap' => 'Auto Line Wrap',
|
'auto_wrap' => 'Auto Line Wrap',
|
||||||
'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.',
|
'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.',
|
||||||
@ -677,5 +677,68 @@ return array(
|
|||||||
'gateway_help_43' => ':link to sign up for Dwolla.',
|
'gateway_help_43' => ':link to sign up for Dwolla.',
|
||||||
'partial_value' => 'Must be greater than zero and less than the total',
|
'partial_value' => 'Must be greater than zero and less than the total',
|
||||||
'more_actions' => 'More Actions',
|
'more_actions' => 'More Actions',
|
||||||
|
|
||||||
|
'pro_plan_title' => 'NINJA PRO',
|
||||||
|
'pro_plan_call_to_action' => 'Upgrade Now!',
|
||||||
|
'pro_plan_feature1' => 'Create Unlimited Clients',
|
||||||
|
'pro_plan_feature2' => 'Access to 10 Beautiful Invoice Designs',
|
||||||
|
'pro_plan_feature3' => 'Custom URLs - "YourBrand.InvoiceNinja.com"',
|
||||||
|
'pro_plan_feature4' => 'Remove "Created by Invoice Ninja"',
|
||||||
|
'pro_plan_feature5' => 'Multi-user Access & Activity Tracking',
|
||||||
|
'pro_plan_feature6' => 'Create Quotes & Pro-forma Invoices',
|
||||||
|
'pro_plan_feature7' => 'Customize Invoice Field Titles & Numbering',
|
||||||
|
'pro_plan_feature8' => 'Option to Attach PDFs to Client Emails',
|
||||||
|
|
||||||
|
'resume' => 'Resume',
|
||||||
|
'break_duration' => 'Break',
|
||||||
|
'edit_details' => 'Edit Details',
|
||||||
|
'work' => 'Work',
|
||||||
|
'timezone_unset' => 'Please :link to set your timezone',
|
||||||
|
'click_here' => 'click here',
|
||||||
|
|
||||||
|
'email_receipt' => 'Email payment receipt to the client',
|
||||||
|
'created_payment_emailed_client' => 'Successfully created payment and emailed client',
|
||||||
|
'add_account' => 'Add Account',
|
||||||
|
'untitled' => 'Untitled',
|
||||||
|
'new_account' => 'New Account',
|
||||||
|
'associated_accounts' => 'Successfully linked accounts',
|
||||||
|
'unlinked_account' => 'Successfully unlinked accounts',
|
||||||
|
'login' => 'Login',
|
||||||
|
'or' => 'or',
|
||||||
|
|
||||||
|
'email_error' => 'There was a problem sending the email',
|
||||||
|
'created_by_recurring' => 'Created by recurring invoice :invoice',
|
||||||
|
'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.',
|
||||||
|
'old_browser' => 'Please use a <a href="'.OUTDATE_BROWSER_URL.'" target="_blank">newer browser</a>',
|
||||||
|
'payment_terms_help' => 'Sets the default invoice due date',
|
||||||
|
'unlink_account' => 'Unlink Account',
|
||||||
|
'unlink' => 'Unlink',
|
||||||
|
'show_address' => 'Show Address',
|
||||||
|
'show_address_help' => 'Require client to provide their billing address',
|
||||||
|
'update_address' => 'Update Address',
|
||||||
|
'update_address_help' => 'Update client\'s address with provided details',
|
||||||
|
'times' => 'Times',
|
||||||
|
'set_now' => 'Set now',
|
||||||
|
'dark_mode' => 'Dark Mode',
|
||||||
|
'dark_mode_help' => 'Show white text on black background',
|
||||||
|
'add_to_invoice' => 'Add to invoice :invoice',
|
||||||
|
'create_new_invoice' => 'Create new invoice',
|
||||||
|
'task_errors' => 'Please correct any overlapping times',
|
||||||
|
'from' => 'From',
|
||||||
|
'to' => 'To',
|
||||||
|
'font_size' => 'Font Size',
|
||||||
|
'primary_color' => 'Primary Color',
|
||||||
|
'secondary_color' => 'Secondary Color',
|
||||||
|
'customize_design' => 'Customize Design',
|
||||||
|
|
||||||
|
'content' => 'Content',
|
||||||
|
'styles' => 'Styles',
|
||||||
|
'defaults' => 'Defaults',
|
||||||
|
'margins' => 'Margins',
|
||||||
|
'header' => 'Header',
|
||||||
|
'footer' => 'Footer',
|
||||||
|
'custom' => 'Custom',
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
);
|
);
|
||||||
|
@ -419,7 +419,7 @@ return array(
|
|||||||
'confirm_email_quote' => 'Bist du sicher, dass du dieses Angebot per E-Mail versenden möchtest',
|
'confirm_email_quote' => 'Bist du sicher, dass du dieses Angebot per E-Mail versenden möchtest',
|
||||||
'confirm_recurring_email_invoice' => 'Wiederkehrende Rechnung ist aktiv. Bis du sicher, dass du diese Rechnung weiterhin als E-Mail verschicken möchtest?',
|
'confirm_recurring_email_invoice' => 'Wiederkehrende Rechnung ist aktiv. Bis du sicher, dass du diese Rechnung weiterhin als E-Mail verschicken möchtest?',
|
||||||
|
|
||||||
'cancel_account' => 'Account Kündigen',
|
'cancel_account' => 'Konto Kündigen',
|
||||||
'cancel_account_message' => 'Warnung: Alle Daten werden unwiderruflich und vollständig gelöscht, es gibt kein zurück.',
|
'cancel_account_message' => 'Warnung: Alle Daten werden unwiderruflich und vollständig gelöscht, es gibt kein zurück.',
|
||||||
'go_back' => 'Zurück',
|
'go_back' => 'Zurück',
|
||||||
|
|
||||||
@ -481,7 +481,7 @@ return array(
|
|||||||
'restored_client' => 'Kunde erfolgreich wiederhergestellt',
|
'restored_client' => 'Kunde erfolgreich wiederhergestellt',
|
||||||
'restored_payment' => 'Zahlung erfolgreich wiederhergestellt',
|
'restored_payment' => 'Zahlung erfolgreich wiederhergestellt',
|
||||||
'restored_credit' => 'Guthaben erfolgreich wiederhergestellt',
|
'restored_credit' => 'Guthaben erfolgreich wiederhergestellt',
|
||||||
|
|
||||||
'reason_for_canceling' => 'Hilf uns, unser Angebot zu verbessern, indem du uns mitteilst, weswegen du dich dazu entschieden hast, unseren Service nicht länger zu nutzen.',
|
'reason_for_canceling' => 'Hilf uns, unser Angebot zu verbessern, indem du uns mitteilst, weswegen du dich dazu entschieden hast, unseren Service nicht länger zu nutzen.',
|
||||||
'discount_percent' => 'Prozent',
|
'discount_percent' => 'Prozent',
|
||||||
'discount_amount' => 'Wert',
|
'discount_amount' => 'Wert',
|
||||||
@ -562,7 +562,7 @@ return array(
|
|||||||
|
|
||||||
'api_tokens' => 'API Token',
|
'api_tokens' => 'API Token',
|
||||||
'users_and_tokens' => 'Benutzer & Token',
|
'users_and_tokens' => 'Benutzer & Token',
|
||||||
'account_login' => 'Account Login',
|
'account_login' => 'Konto Login',
|
||||||
'recover_password' => 'Passwort wiederherstellen',
|
'recover_password' => 'Passwort wiederherstellen',
|
||||||
'forgot_password' => 'Passwort vergessen?',
|
'forgot_password' => 'Passwort vergessen?',
|
||||||
'email_address' => 'E-Mail-Adresse',
|
'email_address' => 'E-Mail-Adresse',
|
||||||
@ -590,14 +590,13 @@ return array(
|
|||||||
'less_fields' => 'Weniger Felder',
|
'less_fields' => 'Weniger Felder',
|
||||||
'client_name' => 'Kundenname',
|
'client_name' => 'Kundenname',
|
||||||
'pdf_settings' => 'PDF Einstellungen',
|
'pdf_settings' => 'PDF Einstellungen',
|
||||||
'utf8_invoices' => 'Cyrillic Unterstützung <sup>Beta</sup>',
|
|
||||||
'product_settings' => 'Produkt Einstellungen',
|
'product_settings' => 'Produkt Einstellungen',
|
||||||
'auto_wrap' => 'Automatischer Zeilenumbruch',
|
'auto_wrap' => 'Automatischer Zeilenumbruch',
|
||||||
'duplicate_post' => 'Achtung: Die vorherige Seite wurde zweimal abgeschickt. Das zweite Abschicken wurde ignoriert.',
|
'duplicate_post' => 'Achtung: Die vorherige Seite wurde zweimal abgeschickt. Das zweite Abschicken wurde ignoriert.',
|
||||||
'view_documentation' => 'Dokumentation anzeigen',
|
'view_documentation' => 'Dokumentation anzeigen',
|
||||||
'app_title' => 'Kostenlose Online Open-Source Rechnungsausstellung',
|
'app_title' => 'Kostenlose Online Open-Source Rechnungsausstellung',
|
||||||
'app_description' => 'Invoice Ninja is a free, open-source solution for invoicing and billing customers. With Invoice Ninja, you can easily build and send beautiful invoices from any device that has access to the web. Your clients can print your invoices, download them as pdf files, and even pay you online from within the system.',
|
'app_description' => 'Invoice Ninja is a free, open-source solution for invoicing and billing customers. With Invoice Ninja, you can easily build and send beautiful invoices from any device that has access to the web. Your clients can print your invoices, download them as pdf files, and even pay you online from within the system.',
|
||||||
|
|
||||||
'rows' => 'Zeilen',
|
'rows' => 'Zeilen',
|
||||||
'www' => 'www',
|
'www' => 'www',
|
||||||
'logo' => 'Logo',
|
'logo' => 'Logo',
|
||||||
@ -660,7 +659,7 @@ return array(
|
|||||||
'create_task' => 'Aufgabe erstellen',
|
'create_task' => 'Aufgabe erstellen',
|
||||||
'stopped_task' => 'Aufgabe erfolgreich angehalten',
|
'stopped_task' => 'Aufgabe erfolgreich angehalten',
|
||||||
'invoice_task' => 'Aufgabe in Rechnung stellen',
|
'invoice_task' => 'Aufgabe in Rechnung stellen',
|
||||||
'invoice_labels' => 'Rechnung Etiketten',
|
'invoice_labels' => 'Rechnung Spaltenüberschriften',
|
||||||
'prefix' => 'Präfix',
|
'prefix' => 'Präfix',
|
||||||
'counter' => 'Zähler',
|
'counter' => 'Zähler',
|
||||||
|
|
||||||
@ -669,4 +668,68 @@ return array(
|
|||||||
'partial_value' => 'Must be greater than zero and less than the total',
|
'partial_value' => 'Must be greater than zero and less than the total',
|
||||||
'more_actions' => 'More Actions',
|
'more_actions' => 'More Actions',
|
||||||
|
|
||||||
|
'pro_plan_title' => 'NINJA PRO',
|
||||||
|
'pro_plan_call_to_action' => 'Jetzt Upgraden!',
|
||||||
|
'pro_plan_feature1' => 'Unlimitierte Anzahl Kunden erstellen',
|
||||||
|
'pro_plan_feature2' => 'Zugriff ui 10 schönen Rechnungsdesigns',
|
||||||
|
'pro_plan_feature3' => 'Benutzerdefinierte URLs - "DeineFirma.InvoiceNinja.com"',
|
||||||
|
'pro_plan_feature4' => '"Created by Invoice Ninja" entfernen',
|
||||||
|
'pro_plan_feature5' => 'Multi-Benutzer Zugriff & Aktivitätstracking',
|
||||||
|
'pro_plan_feature6' => 'Angebote & pro-forma Rechnungen erstellen',
|
||||||
|
'pro_plan_feature7' => 'Rechungstitelfelder und Nummerierung anpassen',
|
||||||
|
'pro_plan_feature8' => 'PDFs an E-Mails zu Kunden anhängen',
|
||||||
|
|
||||||
|
'resume' => 'Fortfahren',
|
||||||
|
'break_duration' => 'Pause',
|
||||||
|
'edit_details' => 'Details bearbeiten',
|
||||||
|
'work' => 'Arbeiten',
|
||||||
|
'timezone_unset' => 'Bitte :link um deine Zeitzone zu setzen',
|
||||||
|
'click_here' => 'hier klicken',
|
||||||
|
|
||||||
|
'email_receipt' => 'Zahlungsbestätigung an Kunden per E-Mail senden',
|
||||||
|
'created_payment_emailed_client' => 'Zahlung erfolgreich erstellt und Kunde per E-Mail benachrichtigt',
|
||||||
|
'add_account' => 'Konto hinzufügen',
|
||||||
|
'untitled' => 'Unbenannt',
|
||||||
|
'new_account' => 'Neues Konto',
|
||||||
|
'associated_accounts' => 'Konten erfolgreich verlinkt',
|
||||||
|
'unlinked_account' => 'Konten erfolgreich getrennt',
|
||||||
|
'login' => 'Login',
|
||||||
|
'or' => 'oder',
|
||||||
|
|
||||||
|
'email_error' => 'There was a problem sending the email',
|
||||||
|
'created_by_recurring' => 'Created by recurring invoice :invoice',
|
||||||
|
'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.',
|
||||||
|
'old_browser' => 'Please use a <a href="'.OUTDATE_BROWSER_URL.'" target="_blank">newer browser</a>',
|
||||||
|
'payment_terms_help' => 'Sets the default invoice due date',
|
||||||
|
'unlink_account' => 'Unlink Account',
|
||||||
|
'unlink' => 'Unlink',
|
||||||
|
'show_address' => 'Show Address',
|
||||||
|
'show_address_help' => 'Require client to provide their billing address',
|
||||||
|
'update_address' => 'Update Address',
|
||||||
|
'update_address_help' => 'Update client\'s address with provided details',
|
||||||
|
'times' => 'Times',
|
||||||
|
'set_now' => 'Set now',
|
||||||
|
'dark_mode' => 'Dark Mode',
|
||||||
|
'dark_mode_help' => 'Show white text on black background',
|
||||||
|
'add_to_invoice' => 'Add to invoice :invoice',
|
||||||
|
'create_new_invoice' => 'Create new invoice',
|
||||||
|
'task_errors' => 'Please correct any overlapping times',
|
||||||
|
'utf8_invoices' => 'New PDF Engine <sup>Beta</sup>',
|
||||||
|
'from' => 'From',
|
||||||
|
'to' => 'To',
|
||||||
|
'font_size' => 'Font Size',
|
||||||
|
'primary_color' => 'Primary Color',
|
||||||
|
'secondary_color' => 'Secondary Color',
|
||||||
|
'customize_design' => 'Customize Design',
|
||||||
|
|
||||||
|
'content' => 'Content',
|
||||||
|
'styles' => 'Styles',
|
||||||
|
'defaults' => 'Defaults',
|
||||||
|
'margins' => 'Margins',
|
||||||
|
'header' => 'Header',
|
||||||
|
'footer' => 'Footer',
|
||||||
|
'custom' => 'Custom',
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
);
|
);
|
@ -40,8 +40,8 @@ return array(
|
|||||||
'taxes' => 'Taxes',
|
'taxes' => 'Taxes',
|
||||||
'tax' => 'Tax',
|
'tax' => 'Tax',
|
||||||
'item' => 'Item',
|
'item' => 'Item',
|
||||||
'description' => 'Description',
|
'description' => 'Description',
|
||||||
'unit_cost' => 'Unit Cost',
|
'unit_cost' => 'Cost',
|
||||||
'quantity' => 'Quantity',
|
'quantity' => 'Quantity',
|
||||||
'line_total' => 'Line Total',
|
'line_total' => 'Line Total',
|
||||||
'subtotal' => 'Subtotal',
|
'subtotal' => 'Subtotal',
|
||||||
@ -276,9 +276,9 @@ return array(
|
|||||||
|
|
||||||
// Payment page
|
// Payment page
|
||||||
'secure_payment' => 'Secure Payment',
|
'secure_payment' => 'Secure Payment',
|
||||||
'card_number' => 'Card number',
|
'card_number' => 'Card Number',
|
||||||
'expiration_month' => 'Expiration month',
|
'expiration_month' => 'Expiration Month',
|
||||||
'expiration_year' => 'Expiration year',
|
'expiration_year' => 'Expiration Year',
|
||||||
'cvv' => 'CVV',
|
'cvv' => 'CVV',
|
||||||
|
|
||||||
// Security alerts
|
// Security alerts
|
||||||
@ -401,9 +401,9 @@ return array(
|
|||||||
|
|
||||||
'invoice_fields' => 'Invoice Fields',
|
'invoice_fields' => 'Invoice Fields',
|
||||||
'invoice_options' => 'Invoice Options',
|
'invoice_options' => 'Invoice Options',
|
||||||
'hide_quantity' => 'Hide quantity',
|
'hide_quantity' => 'Hide Quantity',
|
||||||
'hide_quantity_help' => 'If your line items quantities are always 1, then you can declutter invoices by no longer displaying this field.',
|
'hide_quantity_help' => 'If your line items quantities are always 1, then you can declutter invoices by no longer displaying this field.',
|
||||||
'hide_paid_to_date' => 'Hide paid to date',
|
'hide_paid_to_date' => 'Hide Paid to Date',
|
||||||
'hide_paid_to_date_help' => 'Only display the "Paid to Date" area on your invoices once a payment has been received.',
|
'hide_paid_to_date_help' => 'Only display the "Paid to Date" area on your invoices once a payment has been received.',
|
||||||
|
|
||||||
'charge_taxes' => 'Charge taxes',
|
'charge_taxes' => 'Charge taxes',
|
||||||
@ -526,11 +526,11 @@ return array(
|
|||||||
'token_billing_secure' => 'The data is stored securely by :stripe_link',
|
'token_billing_secure' => 'The data is stored securely by :stripe_link',
|
||||||
|
|
||||||
'support' => 'Support',
|
'support' => 'Support',
|
||||||
'contact_information' => 'Contact information',
|
'contact_information' => 'Contact Information',
|
||||||
'256_encryption' => '256-Bit Encryption',
|
'256_encryption' => '256-Bit Encryption',
|
||||||
'amount_due' => 'Amount due',
|
'amount_due' => 'Amount due',
|
||||||
'billing_address' => 'Billing address',
|
'billing_address' => 'Billing Address',
|
||||||
'billing_method' => 'Billing method',
|
'billing_method' => 'Billing Method',
|
||||||
'order_overview' => 'Order overview',
|
'order_overview' => 'Order overview',
|
||||||
'match_address' => '*Address must match address associated with credit card.',
|
'match_address' => '*Address must match address associated with credit card.',
|
||||||
'click_once' => '*Please click "PAY NOW" only once - transaction may take up to 1 minute to process.',
|
'click_once' => '*Please click "PAY NOW" only once - transaction may take up to 1 minute to process.',
|
||||||
@ -597,7 +597,7 @@ return array(
|
|||||||
'less_fields' => 'Less Fields',
|
'less_fields' => 'Less Fields',
|
||||||
'client_name' => 'Client Name',
|
'client_name' => 'Client Name',
|
||||||
'pdf_settings' => 'PDF Settings',
|
'pdf_settings' => 'PDF Settings',
|
||||||
'utf8_invoices' => 'Cyrillic Support <sup>Beta</sup>',
|
'utf8_invoices' => 'New PDF Engine <sup>Beta</sup>',
|
||||||
'product_settings' => 'Product Settings',
|
'product_settings' => 'Product Settings',
|
||||||
'auto_wrap' => 'Auto Line Wrap',
|
'auto_wrap' => 'Auto Line Wrap',
|
||||||
'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.',
|
'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.',
|
||||||
@ -676,4 +676,68 @@ return array(
|
|||||||
'partial_value' => 'Must be greater than zero and less than the total',
|
'partial_value' => 'Must be greater than zero and less than the total',
|
||||||
'more_actions' => 'More Actions',
|
'more_actions' => 'More Actions',
|
||||||
|
|
||||||
|
'pro_plan_title' => 'NINJA PRO',
|
||||||
|
'pro_plan_call_to_action' => 'Upgrade Now!',
|
||||||
|
'pro_plan_feature1' => 'Create Unlimited Clients',
|
||||||
|
'pro_plan_feature2' => 'Access to 10 Beautiful Invoice Designs',
|
||||||
|
'pro_plan_feature3' => 'Custom URLs - "YourBrand.InvoiceNinja.com"',
|
||||||
|
'pro_plan_feature4' => 'Remove "Created by Invoice Ninja"',
|
||||||
|
'pro_plan_feature5' => 'Multi-user Access & Activity Tracking',
|
||||||
|
'pro_plan_feature6' => 'Create Quotes & Pro-forma Invoices',
|
||||||
|
'pro_plan_feature7' => 'Customize Invoice Field Titles & Numbering',
|
||||||
|
'pro_plan_feature8' => 'Option to Attach PDFs to Client Emails',
|
||||||
|
|
||||||
|
'resume' => 'Resume',
|
||||||
|
'break_duration' => 'Break',
|
||||||
|
'edit_details' => 'Edit Details',
|
||||||
|
'work' => 'Work',
|
||||||
|
'timezone_unset' => 'Please :link to set your timezone',
|
||||||
|
'click_here' => 'click here',
|
||||||
|
|
||||||
|
'email_receipt' => 'Email payment receipt to the client',
|
||||||
|
'created_payment_emailed_client' => 'Successfully created payment and emailed client',
|
||||||
|
'add_account' => 'Add Account',
|
||||||
|
'untitled' => 'Untitled',
|
||||||
|
'new_account' => 'New Account',
|
||||||
|
'associated_accounts' => 'Successfully linked accounts',
|
||||||
|
'unlinked_account' => 'Successfully unlinked accounts',
|
||||||
|
'login' => 'Login',
|
||||||
|
'or' => 'or',
|
||||||
|
|
||||||
|
'email_error' => 'There was a problem sending the email',
|
||||||
|
'created_by_recurring' => 'Created by recurring invoice :invoice',
|
||||||
|
'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.',
|
||||||
|
'old_browser' => 'Please use a <a href="'.OUTDATE_BROWSER_URL.'" target="_blank">newer browser</a>',
|
||||||
|
'payment_terms_help' => 'Sets the default invoice due date',
|
||||||
|
'unlink_account' => 'Unlink Account',
|
||||||
|
'unlink' => 'Unlink',
|
||||||
|
'show_address' => 'Show Address',
|
||||||
|
'show_address_help' => 'Require client to provide their billing address',
|
||||||
|
'update_address' => 'Update Address',
|
||||||
|
'update_address_help' => 'Update client\'s address with provided details',
|
||||||
|
'times' => 'Times',
|
||||||
|
'set_now' => 'Set now',
|
||||||
|
'dark_mode' => 'Dark Mode',
|
||||||
|
'dark_mode_help' => 'Show white text on black background',
|
||||||
|
'add_to_invoice' => 'Add to invoice :invoice',
|
||||||
|
'create_new_invoice' => 'Create new invoice',
|
||||||
|
'task_errors' => 'Please correct any overlapping times',
|
||||||
|
'from' => 'From',
|
||||||
|
'to' => 'To',
|
||||||
|
'font_size' => 'Font Size',
|
||||||
|
'primary_color' => 'Primary Color',
|
||||||
|
'secondary_color' => 'Secondary Color',
|
||||||
|
'customize_design' => 'Customize Design',
|
||||||
|
|
||||||
|
'content' => 'Content',
|
||||||
|
'styles' => 'Styles',
|
||||||
|
'defaults' => 'Defaults',
|
||||||
|
'margins' => 'Margins',
|
||||||
|
'header' => 'Header',
|
||||||
|
'footer' => 'Footer',
|
||||||
|
'custom' => 'Custom',
|
||||||
|
'invoice_to' => 'Invoice to',
|
||||||
|
'invoice_no' => 'Invoice No.',
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -569,7 +569,7 @@ return array(
|
|||||||
'less_fields' => 'Less Fields',
|
'less_fields' => 'Less Fields',
|
||||||
'client_name' => 'Client Name',
|
'client_name' => 'Client Name',
|
||||||
'pdf_settings' => 'PDF Settings',
|
'pdf_settings' => 'PDF Settings',
|
||||||
'utf8_invoices' => 'Cyrillic Support <sup>Beta</sup>',
|
'utf8_invoices' => 'New PDF Engine <sup>Beta</sup>',
|
||||||
'product_settings' => 'Product Settings',
|
'product_settings' => 'Product Settings',
|
||||||
'auto_wrap' => 'Auto Line Wrap',
|
'auto_wrap' => 'Auto Line Wrap',
|
||||||
'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.',
|
'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.',
|
||||||
@ -648,4 +648,66 @@ return array(
|
|||||||
'partial_value' => 'Must be greater than zero and less than the total',
|
'partial_value' => 'Must be greater than zero and less than the total',
|
||||||
'more_actions' => 'More Actions',
|
'more_actions' => 'More Actions',
|
||||||
|
|
||||||
|
'pro_plan_title' => 'NINJA PRO',
|
||||||
|
'pro_plan_call_to_action' => 'Upgrade Now!',
|
||||||
|
'pro_plan_feature1' => 'Create Unlimited Clients',
|
||||||
|
'pro_plan_feature2' => 'Access to 10 Beautiful Invoice Designs',
|
||||||
|
'pro_plan_feature3' => 'Custom URLs - "YourBrand.InvoiceNinja.com"',
|
||||||
|
'pro_plan_feature4' => 'Remove "Created by Invoice Ninja"',
|
||||||
|
'pro_plan_feature5' => 'Multi-user Access & Activity Tracking',
|
||||||
|
'pro_plan_feature6' => 'Create Quotes & Pro-forma Invoices',
|
||||||
|
'pro_plan_feature7' => 'Customize Invoice Field Titles & Numbering',
|
||||||
|
'pro_plan_feature8' => 'Option to Attach PDFs to Client Emails',
|
||||||
|
|
||||||
|
'resume' => 'Resume',
|
||||||
|
'break_duration' => 'Break',
|
||||||
|
'edit_details' => 'Edit Details',
|
||||||
|
'work' => 'Work',
|
||||||
|
'timezone_unset' => 'Please :link to set your timezone',
|
||||||
|
'click_here' => 'click here',
|
||||||
|
|
||||||
|
'email_receipt' => 'Email payment receipt to the client',
|
||||||
|
'created_payment_emailed_client' => 'Successfully created payment and emailed client',
|
||||||
|
'add_account' => 'Add Account',
|
||||||
|
'untitled' => 'Untitled',
|
||||||
|
'new_account' => 'New Account',
|
||||||
|
'associated_accounts' => 'Successfully linked accounts',
|
||||||
|
'unlinked_account' => 'Successfully unlinked accounts',
|
||||||
|
'login' => 'Login',
|
||||||
|
'or' => 'or',
|
||||||
|
|
||||||
|
'email_error' => 'There was a problem sending the email',
|
||||||
|
'created_by_recurring' => 'Created by recurring invoice :invoice',
|
||||||
|
'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.',
|
||||||
|
'old_browser' => 'Please use a <a href="'.OUTDATE_BROWSER_URL.'" target="_blank">newer browser</a>',
|
||||||
|
'payment_terms_help' => 'Sets the default invoice due date',
|
||||||
|
'unlink_account' => 'Unlink Account',
|
||||||
|
'unlink' => 'Unlink',
|
||||||
|
'show_address' => 'Show Address',
|
||||||
|
'show_address_help' => 'Require client to provide their billing address',
|
||||||
|
'update_address' => 'Update Address',
|
||||||
|
'update_address_help' => 'Update client\'s address with provided details',
|
||||||
|
'times' => 'Times',
|
||||||
|
'set_now' => 'Set now',
|
||||||
|
'dark_mode' => 'Dark Mode',
|
||||||
|
'dark_mode_help' => 'Show white text on black background',
|
||||||
|
'add_to_invoice' => 'Add to invoice :invoice',
|
||||||
|
'create_new_invoice' => 'Create new invoice',
|
||||||
|
'task_errors' => 'Please correct any overlapping times',
|
||||||
|
'from' => 'From',
|
||||||
|
'to' => 'To',
|
||||||
|
'font_size' => 'Font Size',
|
||||||
|
'primary_color' => 'Primary Color',
|
||||||
|
'secondary_color' => 'Secondary Color',
|
||||||
|
'customize_design' => 'Customize Design',
|
||||||
|
|
||||||
|
'content' => 'Content',
|
||||||
|
'styles' => 'Styles',
|
||||||
|
'defaults' => 'Defaults',
|
||||||
|
'margins' => 'Margins',
|
||||||
|
'header' => 'Header',
|
||||||
|
'footer' => 'Footer',
|
||||||
|
'custom' => 'Custom',
|
||||||
|
|
||||||
|
|
||||||
);
|
);
|
@ -598,7 +598,7 @@ return array(
|
|||||||
'less_fields' => 'Less Fields',
|
'less_fields' => 'Less Fields',
|
||||||
'client_name' => 'Client Name',
|
'client_name' => 'Client Name',
|
||||||
'pdf_settings' => 'PDF Settings',
|
'pdf_settings' => 'PDF Settings',
|
||||||
'utf8_invoices' => 'Cyrillic Support <sup>Beta</sup>',
|
'utf8_invoices' => 'New PDF Engine <sup>Beta</sup>',
|
||||||
'product_settings' => 'Product Settings',
|
'product_settings' => 'Product Settings',
|
||||||
'auto_wrap' => 'Auto Line Wrap',
|
'auto_wrap' => 'Auto Line Wrap',
|
||||||
'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.',
|
'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.',
|
||||||
@ -677,4 +677,67 @@ return array(
|
|||||||
'partial_value' => 'Must be greater than zero and less than the total',
|
'partial_value' => 'Must be greater than zero and less than the total',
|
||||||
'more_actions' => 'More Actions',
|
'more_actions' => 'More Actions',
|
||||||
|
|
||||||
|
'pro_plan_title' => 'NINJA PRO',
|
||||||
|
'pro_plan_call_to_action' => 'Upgrade Now!',
|
||||||
|
'pro_plan_feature1' => 'Create Unlimited Clients',
|
||||||
|
'pro_plan_feature2' => 'Access to 10 Beautiful Invoice Designs',
|
||||||
|
'pro_plan_feature3' => 'Custom URLs - "YourBrand.InvoiceNinja.com"',
|
||||||
|
'pro_plan_feature4' => 'Remove "Created by Invoice Ninja"',
|
||||||
|
'pro_plan_feature5' => 'Multi-user Access & Activity Tracking',
|
||||||
|
'pro_plan_feature6' => 'Create Quotes & Pro-forma Invoices',
|
||||||
|
'pro_plan_feature7' => 'Customize Invoice Field Titles & Numbering',
|
||||||
|
'pro_plan_feature8' => 'Option to Attach PDFs to Client Emails',
|
||||||
|
|
||||||
|
'resume' => 'Resume',
|
||||||
|
'break_duration' => 'Break',
|
||||||
|
'edit_details' => 'Edit Details',
|
||||||
|
'work' => 'Work',
|
||||||
|
'timezone_unset' => 'Please :link to set your timezone',
|
||||||
|
'click_here' => 'click here',
|
||||||
|
|
||||||
|
'email_receipt' => 'Email payment receipt to the client',
|
||||||
|
'created_payment_emailed_client' => 'Successfully created payment and emailed client',
|
||||||
|
'add_account' => 'Add Account',
|
||||||
|
'untitled' => 'Untitled',
|
||||||
|
'new_account' => 'New Account',
|
||||||
|
'associated_accounts' => 'Successfully linked accounts',
|
||||||
|
'unlinked_account' => 'Successfully unlinked accounts',
|
||||||
|
'login' => 'Login',
|
||||||
|
'or' => 'or',
|
||||||
|
|
||||||
|
'email_error' => 'There was a problem sending the email',
|
||||||
|
'created_by_recurring' => 'Created by recurring invoice :invoice',
|
||||||
|
'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.',
|
||||||
|
'old_browser' => 'Please use a <a href="'.OUTDATE_BROWSER_URL.'" target="_blank">newer browser</a>',
|
||||||
|
'payment_terms_help' => 'Sets the default invoice due date',
|
||||||
|
'unlink_account' => 'Unlink Account',
|
||||||
|
'unlink' => 'Unlink',
|
||||||
|
'show_address' => 'Show Address',
|
||||||
|
'show_address_help' => 'Require client to provide their billing address',
|
||||||
|
'update_address' => 'Update Address',
|
||||||
|
'update_address_help' => 'Update client\'s address with provided details',
|
||||||
|
'times' => 'Times',
|
||||||
|
'set_now' => 'Set now',
|
||||||
|
'dark_mode' => 'Dark Mode',
|
||||||
|
'dark_mode_help' => 'Show white text on black background',
|
||||||
|
'add_to_invoice' => 'Add to invoice :invoice',
|
||||||
|
'create_new_invoice' => 'Create new invoice',
|
||||||
|
'task_errors' => 'Please correct any overlapping times',
|
||||||
|
'from' => 'From',
|
||||||
|
'to' => 'To',
|
||||||
|
'font_size' => 'Font Size',
|
||||||
|
'primary_color' => 'Primary Color',
|
||||||
|
'secondary_color' => 'Secondary Color',
|
||||||
|
'customize_design' => 'Customize Design',
|
||||||
|
|
||||||
|
'content' => 'Content',
|
||||||
|
'styles' => 'Styles',
|
||||||
|
'defaults' => 'Defaults',
|
||||||
|
'margins' => 'Margins',
|
||||||
|
'header' => 'Header',
|
||||||
|
'footer' => 'Footer',
|
||||||
|
'custom' => 'Custom',
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
);
|
);
|
@ -1,4 +1,4 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
|
|
||||||
@ -12,9 +12,9 @@ return array(
|
|||||||
'address2' => 'Appt/Bâtiment',
|
'address2' => 'Appt/Bâtiment',
|
||||||
'city' => 'Ville',
|
'city' => 'Ville',
|
||||||
'state' => 'Région/Département',
|
'state' => 'Région/Département',
|
||||||
'postal_code' => 'Code Postal',
|
'postal_code' => 'Code postal',
|
||||||
'country_id' => 'Pays',
|
'country_id' => 'Pays',
|
||||||
'contacts' => 'Informations de contact', //if you speak about contact details
|
'contacts' => 'Informations de contact',
|
||||||
'first_name' => 'Prénom',
|
'first_name' => 'Prénom',
|
||||||
'last_name' => 'Nom',
|
'last_name' => 'Nom',
|
||||||
'phone' => 'Téléphone',
|
'phone' => 'Téléphone',
|
||||||
@ -23,7 +23,7 @@ return array(
|
|||||||
'payment_terms' => 'Conditions de paiement',
|
'payment_terms' => 'Conditions de paiement',
|
||||||
'currency_id' => 'Devise',
|
'currency_id' => 'Devise',
|
||||||
'size_id' => 'Taille',
|
'size_id' => 'Taille',
|
||||||
'industry_id' => 'Secteur', // literal translation : Industrie
|
'industry_id' => 'Secteur',
|
||||||
'private_notes' => 'Note personnelle',
|
'private_notes' => 'Note personnelle',
|
||||||
|
|
||||||
// invoice
|
// invoice
|
||||||
@ -35,21 +35,21 @@ return array(
|
|||||||
'invoice_number_short' => 'Facture #',
|
'invoice_number_short' => 'Facture #',
|
||||||
'po_number' => 'Numéro du bon de commande',
|
'po_number' => 'Numéro du bon de commande',
|
||||||
'po_number_short' => 'Bon de commande #',
|
'po_number_short' => 'Bon de commande #',
|
||||||
'frequency_id' => 'Fréquence',
|
'frequency_id' => 'Fréquence',
|
||||||
'discount' => 'Remise',
|
'discount' => 'Remise',
|
||||||
'taxes' => 'Taxes',
|
'taxes' => 'Taxes',
|
||||||
'tax' => 'Taxe',
|
'tax' => 'Taxe',
|
||||||
'item' => 'Article',
|
'item' => 'Article',
|
||||||
'description' => 'Description',
|
'description' => 'Description',
|
||||||
'unit_cost' => 'Coût unitaire',
|
'unit_cost' => 'Coût unitaire',
|
||||||
'quantity' => 'Quantité',
|
'quantity' => 'Quantité',
|
||||||
'line_total' => 'Total',
|
'line_total' => 'Total',
|
||||||
'subtotal' => 'Total',
|
'subtotal' => 'Total',
|
||||||
'paid_to_date' => 'Versé à ce jour',//this one is not very used in France
|
'paid_to_date' => 'Versé à ce jour',
|
||||||
'balance_due' => 'Montant total',//can be "Montant à verser" or "Somme totale"
|
'balance_due' => 'Montant total',
|
||||||
'invoice_design_id' => 'Design', //if you speak about invoice's design -> "Modèle"
|
'invoice_design_id' => 'Design',
|
||||||
'terms' => 'Conditions',
|
'terms' => 'Conditions',
|
||||||
'your_invoice' => 'Votre Facture',
|
'your_invoice' => 'Votre facture',
|
||||||
|
|
||||||
'remove_contact' => 'Supprimer un contact',
|
'remove_contact' => 'Supprimer un contact',
|
||||||
'add_contact' => 'Ajouter un contact',
|
'add_contact' => 'Ajouter un contact',
|
||||||
@ -117,11 +117,11 @@ return array(
|
|||||||
'billed_client' => 'client facturé',
|
'billed_client' => 'client facturé',
|
||||||
'billed_clients' => 'clients facturés',
|
'billed_clients' => 'clients facturés',
|
||||||
'active_client' => 'client actif',
|
'active_client' => 'client actif',
|
||||||
'active_clients' => 'clients actifs',
|
'active_clients' => 'clients actifs',
|
||||||
'invoices_past_due' => 'Date limite de paiement dépassée',
|
'invoices_past_due' => 'Date limite de paiement dépassée',
|
||||||
'upcoming_invoices' => 'Factures à venir',
|
'upcoming_invoices' => 'Factures à venir',
|
||||||
'average_invoice' => 'Moyenne de facturation',
|
'average_invoice' => 'Moyenne de facturation',
|
||||||
|
|
||||||
// list pages
|
// list pages
|
||||||
'archive' => 'Archiver',
|
'archive' => 'Archiver',
|
||||||
'delete' => 'Supprimer',
|
'delete' => 'Supprimer',
|
||||||
@ -133,17 +133,17 @@ return array(
|
|||||||
'delete_credit' => 'Supprimer ce crédit',
|
'delete_credit' => 'Supprimer ce crédit',
|
||||||
'show_archived_deleted' => 'Afficher archivés/supprimés',
|
'show_archived_deleted' => 'Afficher archivés/supprimés',
|
||||||
'filter' => 'Filtrer',
|
'filter' => 'Filtrer',
|
||||||
'new_client' => 'Nouveau Client',
|
'new_client' => 'Nouveau client',
|
||||||
'new_invoice' => 'Nouvelle Facture',
|
'new_invoice' => 'Nouvelle facture',
|
||||||
'new_payment' => 'Nouveau Paiement',
|
'new_payment' => 'Nouveau paiement',
|
||||||
'new_credit' => 'Nouveau Crédit',
|
'new_credit' => 'Nouveau crédit',
|
||||||
'contact' => 'Contact',
|
'contact' => 'Contact',
|
||||||
'date_created' => 'Date de création',
|
'date_created' => 'Date de création',
|
||||||
'last_login' => 'Dernière connexion',
|
'last_login' => 'Dernière connexion',
|
||||||
'balance' => 'Solde',
|
'balance' => 'Solde',
|
||||||
'action' => 'Action',
|
'action' => 'Action',
|
||||||
'status' => 'Statut',
|
'status' => 'Statut',
|
||||||
'invoice_total' => 'Montant Total',
|
'invoice_total' => 'Montant total',
|
||||||
'frequency' => 'Fréquence',
|
'frequency' => 'Fréquence',
|
||||||
'start_date' => 'Date de début',
|
'start_date' => 'Date de début',
|
||||||
'end_date' => 'Date de fin',
|
'end_date' => 'Date de fin',
|
||||||
@ -156,8 +156,8 @@ return array(
|
|||||||
'credit_date' => 'Date de crédit',
|
'credit_date' => 'Date de crédit',
|
||||||
'empty_table' => 'Aucune donnée disponible dans la table',
|
'empty_table' => 'Aucune donnée disponible dans la table',
|
||||||
'select' => 'Sélectionner',
|
'select' => 'Sélectionner',
|
||||||
'edit_client' => 'Éditer le Client',
|
'edit_client' => 'Éditer le client',
|
||||||
'edit_invoice' => 'Éditer la Facture',
|
'edit_invoice' => 'Éditer la facture',
|
||||||
|
|
||||||
// client view page
|
// client view page
|
||||||
'create_invoice' => 'Créer une facture',
|
'create_invoice' => 'Créer une facture',
|
||||||
@ -206,13 +206,13 @@ return array(
|
|||||||
'import_to' => 'Importer en tant que',
|
'import_to' => 'Importer en tant que',
|
||||||
'client_will_create' => 'client sera créé',
|
'client_will_create' => 'client sera créé',
|
||||||
'clients_will_create' => 'clients seront créés',
|
'clients_will_create' => 'clients seront créés',
|
||||||
'email_settings' => 'Email Settings',
|
'email_settings' => 'Paramètres mail',
|
||||||
'pdf_email_attachment' => 'Attach PDF to Emails',
|
'pdf_email_attachment' => 'Joindre PDF aux emails',
|
||||||
|
|
||||||
// application messages
|
// application messages
|
||||||
'created_client' => 'Client créé avec succès',
|
'created_client' => 'Client créé avec succès',
|
||||||
'created_clients' => ':count clients créés ave csuccès',
|
'created_clients' => ':count clients créés avec succès',
|
||||||
'updated_settings' => 'paramètres mis à jour avec succès',
|
'updated_settings' => 'Paramètres mis à jour avec succès',
|
||||||
'removed_logo' => 'Logo supprimé avec succès',
|
'removed_logo' => 'Logo supprimé avec succès',
|
||||||
'sent_message' => 'Message envoyé avec succès',
|
'sent_message' => 'Message envoyé avec succès',
|
||||||
'invoice_error' => 'Veuillez vous assurer de sélectionner un client et de corriger les erreurs',
|
'invoice_error' => 'Veuillez vous assurer de sélectionner un client et de corriger les erreurs',
|
||||||
@ -252,7 +252,7 @@ return array(
|
|||||||
'deleted_credits' => ':count crédits supprimés avec succès',
|
'deleted_credits' => ':count crédits supprimés avec succès',
|
||||||
|
|
||||||
// Emails
|
// Emails
|
||||||
'confirmation_subject' => 'Validation du compte invoice ninja',
|
'confirmation_subject' => 'Validation du compte Invoice Ninja',
|
||||||
'confirmation_header' => 'Validation du compte',
|
'confirmation_header' => 'Validation du compte',
|
||||||
'confirmation_message' => 'Veuillez cliquer sur le lien ci-après pour valider votre compte.',
|
'confirmation_message' => 'Veuillez cliquer sur le lien ci-après pour valider votre compte.',
|
||||||
'invoice_subject' => 'Nouvelle facture :invoice en provenance de :account',
|
'invoice_subject' => 'Nouvelle facture :invoice en provenance de :account',
|
||||||
@ -261,7 +261,7 @@ return array(
|
|||||||
'payment_message' => 'Merci pour votre paiement d\'un montant de :amount',
|
'payment_message' => 'Merci pour votre paiement d\'un montant de :amount',
|
||||||
'email_salutation' => 'Cher :name,',
|
'email_salutation' => 'Cher :name,',
|
||||||
'email_signature' => 'Cordialement,',
|
'email_signature' => 'Cordialement,',
|
||||||
'email_from' => 'L\'équipe InvoiceNinja',
|
'email_from' => 'L\'équipe Invoice Ninja',
|
||||||
'user_email_footer' => 'Pour modifier vos paramètres de notification par courriel, veuillez visiter '.SITE_URL.'/company/notifications',
|
'user_email_footer' => 'Pour modifier vos paramètres de notification par courriel, veuillez visiter '.SITE_URL.'/company/notifications',
|
||||||
'invoice_link_message' => 'Pour voir la facture de votre client cliquez sur le lien ci-après :',
|
'invoice_link_message' => 'Pour voir la facture de votre client cliquez sur le lien ci-après :',
|
||||||
'notification_invoice_paid_subject' => 'La facture :invoice a été payée par le client :client',
|
'notification_invoice_paid_subject' => 'La facture :invoice a été payée par le client :client',
|
||||||
@ -276,7 +276,7 @@ return array(
|
|||||||
// Payment page
|
// Payment page
|
||||||
'secure_payment' => 'Paiement sécurisé',
|
'secure_payment' => 'Paiement sécurisé',
|
||||||
'card_number' => 'Numéro de carte',
|
'card_number' => 'Numéro de carte',
|
||||||
'expiration_month' => 'Mois d\'expiration',
|
'expiration_month' => 'Mois d\'expiration',
|
||||||
'expiration_year' => 'Année d\'expiration',
|
'expiration_year' => 'Année d\'expiration',
|
||||||
'cvv' => 'CVV',
|
'cvv' => 'CVV',
|
||||||
|
|
||||||
@ -293,12 +293,12 @@ return array(
|
|||||||
|
|
||||||
// Pro Plan
|
// Pro Plan
|
||||||
'pro_plan' => [
|
'pro_plan' => [
|
||||||
'remove_logo' => ':link pour supprimer le logo Invoice Ninja en souscrivant au plan pro',
|
'remove_logo' => ':link pour supprimer le logo Invoice Ninja en souscrivant au Plan Pro',
|
||||||
'remove_logo_link' => 'Cliquez ici',
|
'remove_logo_link' => 'Cliquez ici',
|
||||||
],
|
],
|
||||||
|
|
||||||
'logout' => 'Se déconnecter',
|
'logout' => 'Se déconnecter',
|
||||||
'sign_up_to_save' => 'Connectez vous pour sauvegarder votre travail',
|
'sign_up_to_save' => 'Connectez vous pour sauvegarder votre travail',
|
||||||
'agree_to_terms' =>'J\'accepte les conditions d\'utilisation d\'Invoice ninja :terms',
|
'agree_to_terms' =>'J\'accepte les conditions d\'utilisation d\'Invoice ninja :terms',
|
||||||
'terms_of_service' => 'Conditions d\'utilisation',
|
'terms_of_service' => 'Conditions d\'utilisation',
|
||||||
'email_taken' => 'L\'adresse courriel existe déjà',
|
'email_taken' => 'L\'adresse courriel existe déjà',
|
||||||
@ -319,7 +319,7 @@ return array(
|
|||||||
'field_label' => 'Nom du champ',
|
'field_label' => 'Nom du champ',
|
||||||
'field_value' => 'Valeur du champ',
|
'field_value' => 'Valeur du champ',
|
||||||
'edit' => 'Éditer',
|
'edit' => 'Éditer',
|
||||||
'view_as_recipient' => 'Voir en tant que destinataire',
|
'view_as_recipient' => 'Voir en tant que destinataire',
|
||||||
|
|
||||||
// product management
|
// product management
|
||||||
'product_library' => 'Inventaire',
|
'product_library' => 'Inventaire',
|
||||||
@ -330,7 +330,7 @@ return array(
|
|||||||
'update_products' => 'Mise à jour auto des produits',
|
'update_products' => 'Mise à jour auto des produits',
|
||||||
'update_products_help' => 'La mise à jour d\'une facture entraîne la <b>mise à jour des produits</b>',
|
'update_products_help' => 'La mise à jour d\'une facture entraîne la <b>mise à jour des produits</b>',
|
||||||
'create_product' => 'Nouveau produit',
|
'create_product' => 'Nouveau produit',
|
||||||
'edit_product' => 'Éditer Produit',
|
'edit_product' => 'Éditer produit',
|
||||||
'archive_product' => 'Archiver Produit',
|
'archive_product' => 'Archiver Produit',
|
||||||
'updated_product' => 'Produit mis à jour',
|
'updated_product' => 'Produit mis à jour',
|
||||||
'created_product' => 'Produit créé',
|
'created_product' => 'Produit créé',
|
||||||
@ -387,7 +387,7 @@ return array(
|
|||||||
'notification_quote_sent_subject' => 'Le devis :invoice a été envoyé à :client',
|
'notification_quote_sent_subject' => 'Le devis :invoice a été envoyé à :client',
|
||||||
'notification_quote_viewed_subject' => 'Le devis :invoice a été visionné par :client',
|
'notification_quote_viewed_subject' => 'Le devis :invoice a été visionné par :client',
|
||||||
'notification_quote_sent' => 'Le devis :invoice de :amount a été envoyé au client :client.',
|
'notification_quote_sent' => 'Le devis :invoice de :amount a été envoyé au client :client.',
|
||||||
'notification_quote_viewed' => 'Le devis :invoice de :amount a été visioné par le client :client.',
|
'notification_quote_viewed' => 'Le devis :invoice de :amount a été visioné par le client :client.',
|
||||||
|
|
||||||
'session_expired' => 'Votre session a expiré.',
|
'session_expired' => 'Votre session a expiré.',
|
||||||
|
|
||||||
@ -426,7 +426,7 @@ return array(
|
|||||||
'sample_data' => 'Données fictives présentées',
|
'sample_data' => 'Données fictives présentées',
|
||||||
'hide' => 'Cacher',
|
'hide' => 'Cacher',
|
||||||
'new_version_available' => 'Une nouvelle version de :releases_link est disponible. Vous utilisez v:user_version, la plus récente est v:latest_version',
|
'new_version_available' => 'Une nouvelle version de :releases_link est disponible. Vous utilisez v:user_version, la plus récente est v:latest_version',
|
||||||
|
|
||||||
|
|
||||||
'invoice_settings' => 'Paramètres des factures',
|
'invoice_settings' => 'Paramètres des factures',
|
||||||
'invoice_number_prefix' => 'Préfixe du numéro de facture',
|
'invoice_number_prefix' => 'Préfixe du numéro de facture',
|
||||||
@ -436,7 +436,7 @@ return array(
|
|||||||
'share_invoice_counter' => 'Partager le compteur de facture',
|
'share_invoice_counter' => 'Partager le compteur de facture',
|
||||||
'invoice_issued_to' => 'Facture destinée à',
|
'invoice_issued_to' => 'Facture destinée à',
|
||||||
'invalid_counter' => 'Pour éviter un éventuel conflit, merci de définir un préfixe pour le numéro de facture ou pour le numéro de devis',
|
'invalid_counter' => 'Pour éviter un éventuel conflit, merci de définir un préfixe pour le numéro de facture ou pour le numéro de devis',
|
||||||
'mark_sent' => 'Marquer comme envoyé',
|
'mark_sent' => 'Marquer comme envoyé',
|
||||||
|
|
||||||
'gateway_help_1' => ':link to sign up for Authorize.net.',
|
'gateway_help_1' => ':link to sign up for Authorize.net.',
|
||||||
'gateway_help_2' => ':link to sign up for Authorize.net.',
|
'gateway_help_2' => ':link to sign up for Authorize.net.',
|
||||||
@ -452,15 +452,15 @@ return array(
|
|||||||
'more_designs_self_host_text' => '',
|
'more_designs_self_host_text' => '',
|
||||||
'buy' => 'Acheter',
|
'buy' => 'Acheter',
|
||||||
'bought_designs' => 'Les nouveaux modèles ont été ajoutés avec succès',
|
'bought_designs' => 'Les nouveaux modèles ont été ajoutés avec succès',
|
||||||
|
|
||||||
'sent' => 'envoyé',
|
'sent' => 'envoyé',
|
||||||
'timesheets' => 'Feuilles de temps',
|
'timesheets' => 'Feuilles de temps',
|
||||||
|
|
||||||
'payment_title' => 'Enter Your Billing Address and Credit Card information',
|
'payment_title' => 'Entrez votre adresse de facturation et vos informations bancaires',
|
||||||
'payment_cvv' => '*This is the 3-4 digit number onthe back of your card',
|
'payment_cvv' => '*Numéro à 3 ou 4 chiffres au dos de votre carte',
|
||||||
'payment_footer1' => '*Billing address must match address associated with credit card.',
|
'payment_footer1' => '*L\'adresse de facturation doit correspondre à celle enregistrée avec votre carte bancaire',
|
||||||
'payment_footer2' => '*Please click "PAY NOW" only once - transaction may take up to 1 minute to process.',
|
'payment_footer2' => '*Merci de cliquer sur "Payer maintenant" une seule fois. Le processus peut prendre jusqu\'à 1 minute.',
|
||||||
'vat_number' => 'Numéro de TVA',
|
'vat_number' => 'Numéro de TVA',
|
||||||
|
|
||||||
'id_number' => 'Numéro ID',
|
'id_number' => 'Numéro ID',
|
||||||
'white_label_link' => 'Marque blanche',
|
'white_label_link' => 'Marque blanche',
|
||||||
@ -485,25 +485,25 @@ return array(
|
|||||||
'reason_for_canceling' => 'Aidez nous à améliorer notre site en nous disant pourquoi vous partez.',
|
'reason_for_canceling' => 'Aidez nous à améliorer notre site en nous disant pourquoi vous partez.',
|
||||||
'discount_percent' => 'Pourcent',
|
'discount_percent' => 'Pourcent',
|
||||||
'discount_amount' => 'Montant',
|
'discount_amount' => 'Montant',
|
||||||
|
|
||||||
'invoice_history' => 'Historique des factures',
|
'invoice_history' => 'Historique des factures',
|
||||||
'quote_history' => 'Historique des devis',
|
'quote_history' => 'Historique des devis',
|
||||||
'current_version' => 'Version courante',
|
'current_version' => 'Version courante',
|
||||||
'select_versiony' => 'Choix de la verison',
|
'select_versiony' => 'Choix de la verison',
|
||||||
'view_history' => 'Consulter l\'historique',
|
'view_history' => 'Consulter l\'historique',
|
||||||
|
|
||||||
'edit_payment' => 'Edit Payment',
|
'edit_payment' => 'Editer le paiement',
|
||||||
'updated_payment' => 'Successfully updated payment',
|
'updated_payment' => 'Paiement édité avec succès',
|
||||||
'deleted' => 'Deleted',
|
'deleted' => 'Supprimé',
|
||||||
'restore_user' => 'Restore User',
|
'restore_user' => 'Restaurer l\'utilisateur',
|
||||||
'restored_user' => 'Successfully restored user',
|
'restored_user' => 'Restaurer la commande',
|
||||||
'show_deleted_users' => 'Show deleted users',
|
'show_deleted_users' => 'Voir les utilisateurs supprimés',
|
||||||
'email_templates' => 'Email Templates',
|
'email_templates' => 'Templates de mail',
|
||||||
'invoice_email' => 'Invoice Email',
|
'invoice_email' => 'Templates de facture',
|
||||||
'payment_email' => 'Payment Email',
|
'payment_email' => 'Email de paiement',
|
||||||
'quote_email' => 'Quote Email',
|
'quote_email' => 'Email de déclaration',
|
||||||
'reset_all' => 'Reset All',
|
'reset_all' => 'Réinitialiser',
|
||||||
'approve' => 'Approve',
|
'approve' => 'Accepter',
|
||||||
|
|
||||||
'token_billing_type_id' => 'Token Billing',
|
'token_billing_type_id' => 'Token Billing',
|
||||||
'token_billing_help' => 'Enables you to store credit cards with your gateway, and charge them at a later date.',
|
'token_billing_help' => 'Enables you to store credit cards with your gateway, and charge them at a later date.',
|
||||||
@ -519,18 +519,18 @@ return array(
|
|||||||
'token_billing_secure' => 'The data is stored securely by :stripe_link',
|
'token_billing_secure' => 'The data is stored securely by :stripe_link',
|
||||||
|
|
||||||
'support' => 'Support',
|
'support' => 'Support',
|
||||||
'contact_information' => 'Contact information',
|
'contact_information' => 'Information de contact',
|
||||||
'256_encryption' => '256-Bit Encryption',
|
'256_encryption' => '256-Bit Encryption',
|
||||||
'amount_due' => 'Amount due',
|
'amount_due' => 'Montant dû',
|
||||||
'billing_address' => 'Billing address',
|
'billing_address' => 'Billing address',
|
||||||
'billing_method' => 'Billing method',
|
'billing_method' => 'Billing method',
|
||||||
'order_overview' => 'Order overview',
|
'order_overview' => 'Order overview',
|
||||||
'match_address' => '*Address must match address associated with credit card.',
|
'match_address' => '*Address must match address associated with credit card.',
|
||||||
'click_once' => '*Please click "PAY NOW" only once - transaction may take up to 1 minute to process.',
|
'click_once' => '*Please click "PAY NOW" only once - transaction may take up to 1 minute to process.',
|
||||||
|
|
||||||
'default_invoice_footer' => 'Set default invoice footer',
|
'default_invoice_footer' => 'Définir par défaut',
|
||||||
'invoice_footer' => 'Invoice footer',
|
'invoice_footer' => 'Pied de facture',
|
||||||
'save_as_default_footer' => 'Save as default footer',
|
'save_as_default_footer' => 'Définir comme pied de facture par défatu',
|
||||||
|
|
||||||
'token_management' => 'Token Management',
|
'token_management' => 'Token Management',
|
||||||
'tokens' => 'Tokens',
|
'tokens' => 'Tokens',
|
||||||
@ -543,30 +543,30 @@ return array(
|
|||||||
'delete_token' => 'Delete Token',
|
'delete_token' => 'Delete Token',
|
||||||
'token' => 'Token',
|
'token' => 'Token',
|
||||||
|
|
||||||
'add_gateway' => 'Add Gateway',
|
'add_gateway' => 'Ajouter passerelle',
|
||||||
'delete_gateway' => 'Delete Gateway',
|
'delete_gateway' => 'Supprimer passerelle',
|
||||||
'edit_gateway' => 'Edit Gateway',
|
'edit_gateway' => 'Editer passerelle',
|
||||||
'updated_gateway' => 'Successfully updated gateway',
|
'updated_gateway' => 'Passerelle mise à jour avec succès',
|
||||||
'created_gateway' => 'Successfully created gateway',
|
'created_gateway' => 'Passerelle crée avec succès',
|
||||||
'deleted_gateway' => 'Successfully deleted gateway',
|
'deleted_gateway' => 'Passerelle supprimée avec succès',
|
||||||
'pay_with_paypal' => 'PayPal',
|
'pay_with_paypal' => 'PayPal',
|
||||||
'pay_with_card' => 'Credit card',
|
'pay_with_card' => 'Carte bancaire',
|
||||||
|
|
||||||
'change_password' => 'Change password',
|
'change_password' => 'Changer de pot de passe',
|
||||||
'current_password' => 'Current password',
|
'current_password' => 'Mot de passe actuel',
|
||||||
'new_password' => 'New password',
|
'new_password' => 'Nouveau mot de passe',
|
||||||
'confirm_password' => 'Confirm password',
|
'confirm_password' => 'Confirmer le mot de passe',
|
||||||
'password_error_incorrect' => 'The current password is incorrect.',
|
'password_error_incorrect' => 'Le mot de passe actuel est incorrect.',
|
||||||
'password_error_invalid' => 'The new password is invalid.',
|
'password_error_invalid' => 'Le nouveau mot de passe est invalide',
|
||||||
'updated_password' => 'Successfully updated password',
|
'updated_password' => 'Mot de passe mis à jour avec succès',
|
||||||
|
|
||||||
'api_tokens' => 'API Tokens',
|
'api_tokens' => 'API Tokens',
|
||||||
'users_and_tokens' => 'Users & Tokens',
|
'users_and_tokens' => 'Users & Tokens',
|
||||||
'account_login' => 'Account Login',
|
'account_login' => 'Account Login',
|
||||||
'recover_password' => 'Recover your password',
|
'recover_password' => 'Recover your password',
|
||||||
'forgot_password' => 'Forgot your password?',
|
'forgot_password' => 'Mot de passe oublié ?',
|
||||||
'email_address' => 'Email address',
|
'email_address' => 'Adresse email',
|
||||||
'lets_go' => 'Let’s go',
|
'lets_go' => 'Allons-y !',
|
||||||
'password_recovery' => 'Password Recovery',
|
'password_recovery' => 'Password Recovery',
|
||||||
'send_email' => 'Send email',
|
'send_email' => 'Send email',
|
||||||
'set_password' => 'Set Password',
|
'set_password' => 'Set Password',
|
||||||
@ -577,96 +577,159 @@ return array(
|
|||||||
'notification_quote_approved' => 'The following client :client approved Quote :invoice for :amount.',
|
'notification_quote_approved' => 'The following client :client approved Quote :invoice for :amount.',
|
||||||
'resend_confirmation' => 'Resend confirmation email',
|
'resend_confirmation' => 'Resend confirmation email',
|
||||||
'confirmation_resent' => 'The confirmation email was resent',
|
'confirmation_resent' => 'The confirmation email was resent',
|
||||||
|
|
||||||
'gateway_help_42' => ':link to sign up for BitPay.<br/>Note: use a Legacy API Key, not an API token.',
|
'gateway_help_42' => ':link to sign up for BitPay.<br/>Note: use a Legacy API Key, not an API token.',
|
||||||
'payment_type_credit_card' => 'Credit card',
|
'payment_type_credit_card' => 'Carte de crédit',
|
||||||
'payment_type_paypal' => 'PayPal',
|
'payment_type_paypal' => 'PayPal',
|
||||||
'payment_type_bitcoin' => 'Bitcoin',
|
'payment_type_bitcoin' => 'Bitcoin',
|
||||||
'knowledge_base' => 'Knowledge Base',
|
'knowledge_base' => 'Base de connaissances',
|
||||||
'partial' => 'Partial',
|
'partial' => 'Partiel',
|
||||||
'partial_remaining' => ':partial of :balance',
|
'partial_remaining' => ':partial de :balance',
|
||||||
|
|
||||||
'more_fields' => 'More Fields',
|
'more_fields' => 'Plus de champs',
|
||||||
'less_fields' => 'Less Fields',
|
'less_fields' => 'Moins de champs',
|
||||||
'client_name' => 'Client Name',
|
'client_name' => 'Nom du client',
|
||||||
'pdf_settings' => 'PDF Settings',
|
'pdf_settings' => 'Réglages PDF',
|
||||||
'utf8_invoices' => 'Cyrillic Support <sup>Beta</sup>',
|
'utf8_invoices' => 'New PDF Engine <sup>Beta</sup>',
|
||||||
'product_settings' => 'Product Settings',
|
'product_settings' => 'Réglages du produit',
|
||||||
'auto_wrap' => 'Auto Line Wrap',
|
'auto_wrap' => 'Auto Line Wrap',
|
||||||
'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.',
|
'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.',
|
||||||
'view_documentation' => 'View Documentation',
|
'view_documentation' => 'Voir documentation',
|
||||||
'app_title' => 'Free Open-Source Online Invoicing',
|
'app_title' => 'Free Open-Source Online Invoicing',
|
||||||
'app_description' => 'Invoice Ninja is a free, open-source solution for invoicing and billing customers. With Invoice Ninja, you can easily build and send beautiful invoices from any device that has access to the web. Your clients can print your invoices, download them as pdf files, and even pay you online from within the system.',
|
'app_description' => 'Invoice Ninja is a free, open-source solution for invoicing and billing customers. With Invoice Ninja, you can easily build and send beautiful invoices from any device that has access to the web. Your clients can print your invoices, download them as pdf files, and even pay you online from within the system.',
|
||||||
|
|
||||||
'rows' => 'rows',
|
'rows' => 'lignes',
|
||||||
'www' => 'www',
|
'www' => 'www',
|
||||||
'logo' => 'Logo',
|
'logo' => 'Logo',
|
||||||
'subdomain' => 'Subdomain',
|
'subdomain' => 'Sous domaine',
|
||||||
'provide_name_or_email' => 'Please provide a contact name or email',
|
'provide_name_or_email' => 'Merci d\'indiquer un nom ou une adresse email',
|
||||||
'charts_and_reports' => 'Charts & Reports',
|
'charts_and_reports' => 'Charts & Reports',
|
||||||
'chart' => 'Chart',
|
'chart' => 'Chart',
|
||||||
'report' => 'Report',
|
'report' => 'Report',
|
||||||
'group_by' => 'Group by',
|
'group_by' => 'Grouper par',
|
||||||
'paid' => 'Paid',
|
'paid' => 'Payé',
|
||||||
'enable_report' => 'Report',
|
'enable_report' => 'Report',
|
||||||
'enable_chart' => 'Chart',
|
'enable_chart' => 'Chart',
|
||||||
'totals' => 'Totals',
|
'totals' => 'Totals',
|
||||||
'run' => 'Run',
|
'run' => 'Run',
|
||||||
'export' => 'Export',
|
'export' => 'Exporter',
|
||||||
'documentation' => 'Documentation',
|
'documentation' => 'Documentation',
|
||||||
'zapier' => 'Zapier <sup>Beta</sup>',
|
'zapier' => 'Zapier <sup>Beta</sup>',
|
||||||
'recurring' => 'Recurring',
|
'recurring' => 'Récurrent',
|
||||||
'last_invoice_sent' => 'Last invoice sent :date',
|
'last_invoice_sent' => 'Dernière facture envoyée le :date',
|
||||||
|
|
||||||
'processed_updates' => 'Successfully completed update',
|
'processed_updates' => 'Mise à jour effectuée avec succès',
|
||||||
'tasks' => 'Tasks',
|
'tasks' => 'Tâches',
|
||||||
'new_task' => 'New Task',
|
'new_task' => 'Nouvelle tâche',
|
||||||
'start_time' => 'Start Time',
|
'start_time' => 'Début',
|
||||||
'created_task' => 'Successfully created task',
|
'created_task' => 'Tâche crée avec succès',
|
||||||
'updated_task' => 'Successfully updated task',
|
'updated_task' => 'Tâche mise à jour avec succès',
|
||||||
'edit_task' => 'Edit Task',
|
'edit_task' => 'Editer la tâche',
|
||||||
'archive_task' => 'Archive Task',
|
'archive_task' => 'Archiver tâche',
|
||||||
'restore_task' => 'Restore Task',
|
'restore_task' => 'Restaurer tâche',
|
||||||
'delete_task' => 'Delete Task',
|
'delete_task' => 'Supprimer tâche',
|
||||||
'stop_task' => 'Stop Task',
|
'stop_task' => 'Arrêter tâche',
|
||||||
'time' => 'Time',
|
'time' => 'Temps',
|
||||||
'start' => 'Start',
|
'start' => 'Début',
|
||||||
'stop' => 'Stop',
|
'stop' => 'Fin',
|
||||||
'now' => 'Now',
|
'now' => 'Maintenant',
|
||||||
'timer' => 'Timer',
|
'timer' => 'Compteur',
|
||||||
'manual' => 'Manual',
|
'manual' => 'Manuel',
|
||||||
'date_and_time' => 'Date & Time',
|
'date_and_time' => 'Date & heure',
|
||||||
'second' => 'second',
|
'second' => 'seconde',
|
||||||
'seconds' => 'seconds',
|
'seconds' => 'secondes',
|
||||||
'minute' => 'minute',
|
'minute' => 'minute',
|
||||||
'minutes' => 'minutes',
|
'minutes' => 'minutes',
|
||||||
'hour' => 'hour',
|
'hour' => 'heure',
|
||||||
'hours' => 'hours',
|
'hours' => 'heures',
|
||||||
'task_details' => 'Task Details',
|
'task_details' => 'Détails tâche',
|
||||||
'duration' => 'Duration',
|
'duration' => 'Durée',
|
||||||
'end_time' => 'End Time',
|
'end_time' => 'Heure de fin',
|
||||||
'end' => 'End',
|
'end' => 'Fin',
|
||||||
'invoiced' => 'Invoiced',
|
'invoiced' => 'Facturé',
|
||||||
'logged' => 'Logged',
|
'logged' => 'Connecté',
|
||||||
'running' => 'Running',
|
'running' => 'En cours',
|
||||||
'task_error_multiple_clients' => 'The tasks can\'t belong to different clients',
|
'task_error_multiple_clients' => 'Cette tâche ne peut appartenir à plusieurs clients',
|
||||||
'task_error_running' => 'Please stop running tasks first',
|
'task_error_running' => 'Merci d\'arrêter les tâches en cours',
|
||||||
'task_error_invoiced' => 'Tasks have already been invoiced',
|
'task_error_invoiced' => 'Tâches déjà facturées',
|
||||||
'restored_task' => 'Successfully restored task',
|
'restored_task' => 'Tâche restaurée avec succès',
|
||||||
'archived_task' => 'Successfully archived task',
|
'archived_task' => 'Tâche archivée avec succès',
|
||||||
'archived_tasks' => 'Successfully archived :count tasks',
|
'archived_tasks' => ':count tâches archivées avec succès',
|
||||||
'deleted_task' => 'Successfully deleted task',
|
'deleted_task' => 'Tâche supprimée avec succès',
|
||||||
'deleted_tasks' => 'Successfully deleted :count tasks',
|
'deleted_tasks' => ':count tâches supprimées avec succès',
|
||||||
'create_task' => 'Create Task',
|
'create_task' => 'Créer tâche',
|
||||||
'stopped_task' => 'Successfully stopped task',
|
'stopped_task' => 'Tâche stoppée avec succès',
|
||||||
'invoice_task' => 'Invoice Task',
|
'invoice_task' => 'Tâche facturation',
|
||||||
'invoice_labels' => 'Invoice Labels',
|
'invoice_labels' => 'Champs facture',
|
||||||
'prefix' => 'Prefix',
|
'prefix' => 'Préfixe',
|
||||||
'counter' => 'Counter',
|
'counter' => 'Compteur',
|
||||||
|
|
||||||
'payment_type_dwolla' => 'Dwolla',
|
'payment_type_dwolla' => 'Dwolla',
|
||||||
'gateway_help_43' => ':link to sign up for Dwolla.',
|
'gateway_help_43' => ':link to sign up for Dwolla.',
|
||||||
'partial_value' => 'Must be greater than zero and less than the total',
|
'partial_value' => 'Must be greater than zero and less than the total',
|
||||||
'more_actions' => 'More Actions',
|
'more_actions' => 'More Actions',
|
||||||
|
|
||||||
);
|
'pro_plan_title' => 'NINJA PRO',
|
||||||
|
'pro_plan_call_to_action' => 'Upgrade Now!',
|
||||||
|
'pro_plan_feature1' => 'Create Unlimited Clients',
|
||||||
|
'pro_plan_feature2' => 'Access to 10 Beautiful Invoice Designs',
|
||||||
|
'pro_plan_feature3' => 'Custom URLs - "YourBrand.InvoiceNinja.com"',
|
||||||
|
'pro_plan_feature4' => 'Remove "Created by Invoice Ninja"',
|
||||||
|
'pro_plan_feature5' => 'Multi-user Access & Activity Tracking',
|
||||||
|
'pro_plan_feature6' => 'Create Quotes & Pro-forma Invoices',
|
||||||
|
'pro_plan_feature7' => 'Customize Invoice Field Titles & Numbering',
|
||||||
|
'pro_plan_feature8' => 'Option to Attach PDFs to Client Emails',
|
||||||
|
|
||||||
|
'resume' => 'Resume',
|
||||||
|
'break_duration' => 'Break',
|
||||||
|
'edit_details' => 'Modifier',
|
||||||
|
'work' => 'Travail',
|
||||||
|
'timezone_unset' => 'Please :link to set your timezone',
|
||||||
|
'click_here' => 'cliquer ici',
|
||||||
|
|
||||||
|
'email_receipt' => 'Email payment receipt to the client',
|
||||||
|
'created_payment_emailed_client' => 'Paiement crée avec succès et envoyé au client',
|
||||||
|
'add_account' => 'Ajouter compte',
|
||||||
|
'untitled' => 'Sans titre',
|
||||||
|
'new_account' => 'Nouveau compte',
|
||||||
|
'associated_accounts' => 'Successfully linked accounts',
|
||||||
|
'unlinked_account' => 'Successfully unlinked accounts',
|
||||||
|
'login' => 'Connexion',
|
||||||
|
'or' => 'ou',
|
||||||
|
|
||||||
|
'email_error' => 'There was a problem sending the email',
|
||||||
|
'created_by_recurring' => 'Created by recurring invoice :invoice',
|
||||||
|
'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.',
|
||||||
|
'old_browser' => 'Please use a <a href="'.OUTDATE_BROWSER_URL.'" target="_blank">newer browser</a>',
|
||||||
|
'payment_terms_help' => 'Sets the default invoice due date',
|
||||||
|
'unlink_account' => 'Unlink Account',
|
||||||
|
'unlink' => 'Unlink',
|
||||||
|
'show_address' => 'Show Address',
|
||||||
|
'show_address_help' => 'Require client to provide their billing address',
|
||||||
|
'update_address' => 'Update Address',
|
||||||
|
'update_address_help' => 'Update client\'s address with provided details',
|
||||||
|
'times' => 'Times',
|
||||||
|
'set_now' => 'Set now',
|
||||||
|
'dark_mode' => 'Dark Mode',
|
||||||
|
'dark_mode_help' => 'Show white text on black background',
|
||||||
|
'add_to_invoice' => 'Add to invoice :invoice',
|
||||||
|
'create_new_invoice' => 'Create new invoice',
|
||||||
|
'task_errors' => 'Please correct any overlapping times',
|
||||||
|
'from' => 'From',
|
||||||
|
'to' => 'To',
|
||||||
|
'font_size' => 'Font Size',
|
||||||
|
'primary_color' => 'Primary Color',
|
||||||
|
'secondary_color' => 'Secondary Color',
|
||||||
|
'customize_design' => 'Customize Design',
|
||||||
|
|
||||||
|
'content' => 'Content',
|
||||||
|
'styles' => 'Styles',
|
||||||
|
'defaults' => 'Defaults',
|
||||||
|
'margins' => 'Margins',
|
||||||
|
'header' => 'Header',
|
||||||
|
'footer' => 'Footer',
|
||||||
|
'custom' => 'Custom',
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
|
|
||||||
@ -35,11 +35,11 @@ return array(
|
|||||||
'invoice_number_short' => 'Facture #',
|
'invoice_number_short' => 'Facture #',
|
||||||
'po_number' => 'Numéro du bon de commande',
|
'po_number' => 'Numéro du bon de commande',
|
||||||
'po_number_short' => 'Bon de commande #',
|
'po_number_short' => 'Bon de commande #',
|
||||||
'frequency_id' => 'Fréquence',
|
'frequency_id' => 'Fréquence',
|
||||||
'discount' => 'Remise',
|
'discount' => 'Remise',
|
||||||
'taxes' => 'Taxes',
|
'taxes' => 'Taxes',
|
||||||
'tax' => 'Taxe',
|
'tax' => 'Taxe',
|
||||||
'item' => 'Article',
|
'item' => 'Article',
|
||||||
'description' => 'Description',
|
'description' => 'Description',
|
||||||
'unit_cost' => 'Coût unitaire',
|
'unit_cost' => 'Coût unitaire',
|
||||||
'quantity' => 'Quantité',
|
'quantity' => 'Quantité',
|
||||||
@ -117,11 +117,11 @@ return array(
|
|||||||
'billed_client' => 'client facturé',
|
'billed_client' => 'client facturé',
|
||||||
'billed_clients' => 'clients facturés',
|
'billed_clients' => 'clients facturés',
|
||||||
'active_client' => 'client actif',
|
'active_client' => 'client actif',
|
||||||
'active_clients' => 'clients actifs',
|
'active_clients' => 'clients actifs',
|
||||||
'invoices_past_due' => 'Date limite de paiement dépassée',
|
'invoices_past_due' => 'Date limite de paiement dépassée',
|
||||||
'upcoming_invoices' => 'Factures à venir',
|
'upcoming_invoices' => 'Factures à venir',
|
||||||
'average_invoice' => 'Moyenne de facturation',
|
'average_invoice' => 'Moyenne de facturation',
|
||||||
|
|
||||||
// list pages
|
// list pages
|
||||||
'archive' => 'Archiver',
|
'archive' => 'Archiver',
|
||||||
'delete' => 'Supprimer',
|
'delete' => 'Supprimer',
|
||||||
@ -276,7 +276,7 @@ return array(
|
|||||||
// Payment page
|
// Payment page
|
||||||
'secure_payment' => 'Paiement sécurisé',
|
'secure_payment' => 'Paiement sécurisé',
|
||||||
'card_number' => 'Numéro de carte',
|
'card_number' => 'Numéro de carte',
|
||||||
'expiration_month' => 'Mois d\'expiration',
|
'expiration_month' => 'Mois d\'expiration',
|
||||||
'expiration_year' => 'Année d\'expiration',
|
'expiration_year' => 'Année d\'expiration',
|
||||||
'cvv' => 'CVV',
|
'cvv' => 'CVV',
|
||||||
|
|
||||||
@ -297,8 +297,8 @@ return array(
|
|||||||
'remove_logo_link' => 'Cliquez ici',
|
'remove_logo_link' => 'Cliquez ici',
|
||||||
],
|
],
|
||||||
|
|
||||||
'logout' => 'Se déconnecter',
|
'logout' => 'Se déconnecter',
|
||||||
'sign_up_to_save' => 'Connectez vous pour sauvegarder votre travail',
|
'sign_up_to_save' => 'Connectez vous pour sauvegarder votre travail',
|
||||||
'agree_to_terms' =>'J\'accepte les conditions d\'utilisation d\'Invoice ninja :terms',
|
'agree_to_terms' =>'J\'accepte les conditions d\'utilisation d\'Invoice ninja :terms',
|
||||||
'terms_of_service' => 'Conditions d\'utilisation',
|
'terms_of_service' => 'Conditions d\'utilisation',
|
||||||
'email_taken' => 'L\'adresse courriel existe déjà',
|
'email_taken' => 'L\'adresse courriel existe déjà',
|
||||||
@ -319,7 +319,7 @@ return array(
|
|||||||
'field_label' => 'Nom du champ',
|
'field_label' => 'Nom du champ',
|
||||||
'field_value' => 'Valeur du champ',
|
'field_value' => 'Valeur du champ',
|
||||||
'edit' => 'Éditer',
|
'edit' => 'Éditer',
|
||||||
'view_as_recipient' => 'Voir en tant que destinataire',
|
'view_as_recipient' => 'Voir en tant que destinataire',
|
||||||
|
|
||||||
// product management
|
// product management
|
||||||
'product_library' => 'Inventaire',
|
'product_library' => 'Inventaire',
|
||||||
@ -387,7 +387,7 @@ return array(
|
|||||||
'notification_quote_sent_subject' => 'Le devis :invoice a été envoyé à :client',
|
'notification_quote_sent_subject' => 'Le devis :invoice a été envoyé à :client',
|
||||||
'notification_quote_viewed_subject' => 'Le devis :invoice a été visionné par :client',
|
'notification_quote_viewed_subject' => 'Le devis :invoice a été visionné par :client',
|
||||||
'notification_quote_sent' => 'Le devis :invoice de :amount a été envoyé au client :client.',
|
'notification_quote_sent' => 'Le devis :invoice de :amount a été envoyé au client :client.',
|
||||||
'notification_quote_viewed' => 'Le devis :invoice de :amount a été visioné par le client :client.',
|
'notification_quote_viewed' => 'Le devis :invoice de :amount a été visioné par le client :client.',
|
||||||
|
|
||||||
'session_expired' => 'Votre session a expiré.',
|
'session_expired' => 'Votre session a expiré.',
|
||||||
|
|
||||||
@ -426,7 +426,7 @@ return array(
|
|||||||
'sample_data' => 'Données fictives présentées',
|
'sample_data' => 'Données fictives présentées',
|
||||||
'hide' => 'Cacher',
|
'hide' => 'Cacher',
|
||||||
'new_version_available' => 'Une nouvelle version de :releases_link est disponible. Vous utilisez v:user_version, la plus récente est v:latest_version',
|
'new_version_available' => 'Une nouvelle version de :releases_link est disponible. Vous utilisez v:user_version, la plus récente est v:latest_version',
|
||||||
|
|
||||||
|
|
||||||
'invoice_settings' => 'Paramètres des factures',
|
'invoice_settings' => 'Paramètres des factures',
|
||||||
'invoice_number_prefix' => 'Préfixe du numéro de facture',
|
'invoice_number_prefix' => 'Préfixe du numéro de facture',
|
||||||
@ -436,7 +436,7 @@ return array(
|
|||||||
'share_invoice_counter' => 'Partager le compteur de facture',
|
'share_invoice_counter' => 'Partager le compteur de facture',
|
||||||
'invoice_issued_to' => 'Facture destinée à',
|
'invoice_issued_to' => 'Facture destinée à',
|
||||||
'invalid_counter' => 'Pour éviter un éventuel conflit, merci de définir un préfixe pour le numéro de facture ou pour le numéro de devis',
|
'invalid_counter' => 'Pour éviter un éventuel conflit, merci de définir un préfixe pour le numéro de facture ou pour le numéro de devis',
|
||||||
'mark_sent' => 'Marquer comme envoyé',
|
'mark_sent' => 'Marquer comme envoyé',
|
||||||
|
|
||||||
'gateway_help_1' => ':link to sign up for Authorize.net.',
|
'gateway_help_1' => ':link to sign up for Authorize.net.',
|
||||||
'gateway_help_2' => ':link to sign up for Authorize.net.',
|
'gateway_help_2' => ':link to sign up for Authorize.net.',
|
||||||
@ -452,7 +452,7 @@ return array(
|
|||||||
'more_designs_self_host_text' => '',
|
'more_designs_self_host_text' => '',
|
||||||
'buy' => 'Acheter',
|
'buy' => 'Acheter',
|
||||||
'bought_designs' => 'Les nouveaux modèles ont été ajoutés avec succès',
|
'bought_designs' => 'Les nouveaux modèles ont été ajoutés avec succès',
|
||||||
|
|
||||||
'sent' => 'envoyé',
|
'sent' => 'envoyé',
|
||||||
'timesheets' => 'Feuilles de temps',
|
'timesheets' => 'Feuilles de temps',
|
||||||
|
|
||||||
@ -460,7 +460,7 @@ return array(
|
|||||||
'payment_cvv' => '*This is the 3-4 digit number onthe back of your card',
|
'payment_cvv' => '*This is the 3-4 digit number onthe back of your card',
|
||||||
'payment_footer1' => '*Billing address must match address associated with credit card.',
|
'payment_footer1' => '*Billing address must match address associated with credit card.',
|
||||||
'payment_footer2' => '*Please click "PAY NOW" only once - transaction may take up to 1 minute to process.',
|
'payment_footer2' => '*Please click "PAY NOW" only once - transaction may take up to 1 minute to process.',
|
||||||
'vat_number' => 'Numéro de TVA',
|
'vat_number' => 'Numéro de TVA',
|
||||||
|
|
||||||
'id_number' => 'Numéro ID',
|
'id_number' => 'Numéro ID',
|
||||||
'white_label_link' => 'Marque blanche',
|
'white_label_link' => 'Marque blanche',
|
||||||
@ -485,7 +485,7 @@ return array(
|
|||||||
'reason_for_canceling' => 'Aidez nous à améliorer notre site en nous disant pourquoi vous partez.',
|
'reason_for_canceling' => 'Aidez nous à améliorer notre site en nous disant pourquoi vous partez.',
|
||||||
'discount_percent' => 'Pourcent',
|
'discount_percent' => 'Pourcent',
|
||||||
'discount_amount' => 'Montant',
|
'discount_amount' => 'Montant',
|
||||||
|
|
||||||
'invoice_history' => 'Historique des factures',
|
'invoice_history' => 'Historique des factures',
|
||||||
'quote_history' => 'Historique des devis',
|
'quote_history' => 'Historique des devis',
|
||||||
'current_version' => 'Version courante',
|
'current_version' => 'Version courante',
|
||||||
@ -503,7 +503,7 @@ return array(
|
|||||||
'payment_email' => 'Courriel de paiement',
|
'payment_email' => 'Courriel de paiement',
|
||||||
'quote_email' => 'Courriel de devis',
|
'quote_email' => 'Courriel de devis',
|
||||||
'reset_all' => 'Tout remettre à zéro',
|
'reset_all' => 'Tout remettre à zéro',
|
||||||
'approve' => 'Approuver',
|
'approve' => 'Approuver',
|
||||||
|
|
||||||
'token_billing_type_id' => 'Token Billing',
|
'token_billing_type_id' => 'Token Billing',
|
||||||
'token_billing_help' => 'Enables you to store credit cards with your gateway, and charge them at a later date.',
|
'token_billing_help' => 'Enables you to store credit cards with your gateway, and charge them at a later date.',
|
||||||
@ -527,7 +527,7 @@ return array(
|
|||||||
'order_overview' => 'Order overview',
|
'order_overview' => 'Order overview',
|
||||||
'match_address' => '*Address must match address associated with credit card.',
|
'match_address' => '*Address must match address associated with credit card.',
|
||||||
'click_once' => '*Please click "PAY NOW" only once - transaction may take up to 1 minute to process.',
|
'click_once' => '*Please click "PAY NOW" only once - transaction may take up to 1 minute to process.',
|
||||||
|
|
||||||
'default_invoice_footer' => 'Set default invoice footer',
|
'default_invoice_footer' => 'Set default invoice footer',
|
||||||
'invoice_footer' => 'Invoice footer',
|
'invoice_footer' => 'Invoice footer',
|
||||||
'save_as_default_footer' => 'Save as default footer',
|
'save_as_default_footer' => 'Save as default footer',
|
||||||
@ -571,13 +571,13 @@ return array(
|
|||||||
'send_email' => 'Send email',
|
'send_email' => 'Send email',
|
||||||
'set_password' => 'Set Password',
|
'set_password' => 'Set Password',
|
||||||
'converted' => 'Converted',
|
'converted' => 'Converted',
|
||||||
|
|
||||||
'email_approved' => 'Email me when a quote is <b>approved</b>',
|
'email_approved' => 'Email me when a quote is <b>approved</b>',
|
||||||
'notification_quote_approved_subject' => 'Quote :invoice was approved by :client',
|
'notification_quote_approved_subject' => 'Quote :invoice was approved by :client',
|
||||||
'notification_quote_approved' => 'The following client :client approved Quote :invoice for :amount.',
|
'notification_quote_approved' => 'The following client :client approved Quote :invoice for :amount.',
|
||||||
'resend_confirmation' => 'Resend confirmation email',
|
'resend_confirmation' => 'Resend confirmation email',
|
||||||
'confirmation_resent' => 'The confirmation email was resent',
|
'confirmation_resent' => 'The confirmation email was resent',
|
||||||
|
|
||||||
'gateway_help_42' => ':link to sign up for BitPay.<br/>Note: use a Legacy API Key, not an API token.',
|
'gateway_help_42' => ':link to sign up for BitPay.<br/>Note: use a Legacy API Key, not an API token.',
|
||||||
'payment_type_credit_card' => 'Credit card',
|
'payment_type_credit_card' => 'Credit card',
|
||||||
'payment_type_paypal' => 'PayPal',
|
'payment_type_paypal' => 'PayPal',
|
||||||
@ -590,14 +590,14 @@ return array(
|
|||||||
'less_fields' => 'Less Fields',
|
'less_fields' => 'Less Fields',
|
||||||
'client_name' => 'Client Name',
|
'client_name' => 'Client Name',
|
||||||
'pdf_settings' => 'PDF Settings',
|
'pdf_settings' => 'PDF Settings',
|
||||||
'utf8_invoices' => 'Cyrillic Support <sup>Beta</sup>',
|
'utf8_invoices' => 'New PDF Engine <sup>Beta</sup>',
|
||||||
'product_settings' => 'Product Settings',
|
'product_settings' => 'Product Settings',
|
||||||
'auto_wrap' => 'Auto Line Wrap',
|
'auto_wrap' => 'Auto Line Wrap',
|
||||||
'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.',
|
'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.',
|
||||||
'view_documentation' => 'View Documentation',
|
'view_documentation' => 'View Documentation',
|
||||||
'app_title' => 'Free Open-Source Online Invoicing',
|
'app_title' => 'Free Open-Source Online Invoicing',
|
||||||
'app_description' => 'Invoice Ninja is a free, open-source solution for invoicing and billing customers. With Invoice Ninja, you can easily build and send beautiful invoices from any device that has access to the web. Your clients can print your invoices, download them as pdf files, and even pay you online from within the system.',
|
'app_description' => 'Invoice Ninja is a free, open-source solution for invoicing and billing customers. With Invoice Ninja, you can easily build and send beautiful invoices from any device that has access to the web. Your clients can print your invoices, download them as pdf files, and even pay you online from within the system.',
|
||||||
|
|
||||||
'rows' => 'rows',
|
'rows' => 'rows',
|
||||||
'www' => 'www',
|
'www' => 'www',
|
||||||
'logo' => 'Logo',
|
'logo' => 'Logo',
|
||||||
@ -619,54 +619,117 @@ return array(
|
|||||||
'last_invoice_sent' => 'Last invoice sent :date',
|
'last_invoice_sent' => 'Last invoice sent :date',
|
||||||
|
|
||||||
'processed_updates' => 'Successfully completed update',
|
'processed_updates' => 'Successfully completed update',
|
||||||
'tasks' => 'Tasks',
|
'tasks' => 'Tâches',
|
||||||
'new_task' => 'New Task',
|
'new_task' => 'Nouvelle Tâche',
|
||||||
'start_time' => 'Start Time',
|
'start_time' => 'Démarrée à',
|
||||||
'created_task' => 'Successfully created task',
|
'created_task' => 'Tâche créée avec succès',
|
||||||
'updated_task' => 'Successfully updated task',
|
'updated_task' => 'Tâche modifiée avec succès',
|
||||||
'edit_task' => 'Edit Task',
|
'edit_task' => 'Edit Task',
|
||||||
'archive_task' => 'Archive Task',
|
'archive_task' => 'Archiver la Tâche',
|
||||||
'restore_task' => 'Restore Task',
|
'restore_task' => 'Restaurer la Tâche',
|
||||||
'delete_task' => 'Delete Task',
|
'delete_task' => 'Supprimer la Tâche',
|
||||||
'stop_task' => 'Stop Task',
|
'stop_task' => 'Arrêter la Tâche',
|
||||||
'time' => 'Time',
|
'time' => 'Time',
|
||||||
'start' => 'Start',
|
'start' => 'Démarrer',
|
||||||
'stop' => 'Stop',
|
'stop' => 'Arrêter',
|
||||||
'now' => 'Now',
|
'now' => 'Now',
|
||||||
'timer' => 'Timer',
|
'timer' => 'Timer',
|
||||||
'manual' => 'Manual',
|
'manual' => 'Manual',
|
||||||
'date_and_time' => 'Date & Time',
|
'date_and_time' => 'Date & Time',
|
||||||
'second' => 'second',
|
'second' => 'seconde',
|
||||||
'seconds' => 'seconds',
|
'seconds' => 'secondes',
|
||||||
'minute' => 'minute',
|
'minute' => 'minute',
|
||||||
'minutes' => 'minutes',
|
'minutes' => 'minutes',
|
||||||
'hour' => 'hour',
|
'hour' => 'heure',
|
||||||
'hours' => 'hours',
|
'hours' => 'heures',
|
||||||
'task_details' => 'Task Details',
|
'task_details' => 'Détails de la Tâche',
|
||||||
'duration' => 'Duration',
|
'duration' => 'Durée',
|
||||||
'end_time' => 'End Time',
|
'end_time' => 'Arrêtée à',
|
||||||
'end' => 'End',
|
'end' => 'End',
|
||||||
'invoiced' => 'Invoiced',
|
'invoiced' => 'Invoiced',
|
||||||
'logged' => 'Logged',
|
'logged' => 'Logged',
|
||||||
'running' => 'Running',
|
'running' => 'Running',
|
||||||
'task_error_multiple_clients' => 'The tasks can\'t belong to different clients',
|
'task_error_multiple_clients' => 'Une tâche ne peut appartenir à plusieurs clients',
|
||||||
'task_error_running' => 'Please stop running tasks first',
|
'task_error_running' => 'Merci d\'arrêter les tâches en cours',
|
||||||
'task_error_invoiced' => 'Tasks have already been invoiced',
|
'task_error_invoiced' => 'Ces tâches ont déjà été facturées',
|
||||||
'restored_task' => 'Successfully restored task',
|
'restored_task' => 'Tâche restaurée avec succès',
|
||||||
'archived_task' => 'Successfully archived task',
|
'archived_task' => 'Tâche archivée avec succès',
|
||||||
'archived_tasks' => 'Successfully archived :count tasks',
|
'archived_tasks' => ':count tâches archivées avec succès',
|
||||||
'deleted_task' => 'Successfully deleted task',
|
'deleted_task' => 'Tâche supprimée avec succès',
|
||||||
'deleted_tasks' => 'Successfully deleted :count tasks',
|
'deleted_tasks' => ':count tâches supprimées avec succès',
|
||||||
'create_task' => 'Create Task',
|
'create_task' => 'Créer une Tâche',
|
||||||
'stopped_task' => 'Successfully stopped task',
|
'stopped_task' => 'Tâche arrêtée avec succès',
|
||||||
'invoice_task' => 'Invoice Task',
|
'invoice_task' => 'Facturer Tâche',
|
||||||
'invoice_labels' => 'Invoice Labels',
|
'invoice_labels' => 'Invoice Labels',
|
||||||
'prefix' => 'Prefix',
|
'prefix' => 'Préfixe',
|
||||||
'counter' => 'Counter',
|
'counter' => 'Compteur',
|
||||||
|
|
||||||
'payment_type_dwolla' => 'Dwolla',
|
'payment_type_dwolla' => 'Dwolla',
|
||||||
'gateway_help_43' => ':link to sign up for Dwolla.',
|
'gateway_help_43' => ':link to sign up for Dwolla.',
|
||||||
'partial_value' => 'Must be greater than zero and less than the total',
|
'partial_value' => 'Must be greater than zero and less than the total',
|
||||||
'more_actions' => 'More Actions',
|
'more_actions' => 'More Actions',
|
||||||
|
|
||||||
|
|
||||||
|
'pro_plan_title' => 'NINJA PRO',
|
||||||
|
'pro_plan_call_to_action' => 'Upgrade Now!',
|
||||||
|
'pro_plan_feature1' => 'Create Unlimited Clients',
|
||||||
|
'pro_plan_feature2' => 'Access to 10 Beautiful Invoice Designs',
|
||||||
|
'pro_plan_feature3' => 'Custom URLs - "YourBrand.InvoiceNinja.com"',
|
||||||
|
'pro_plan_feature4' => 'Remove "Created by Invoice Ninja"',
|
||||||
|
'pro_plan_feature5' => 'Multi-user Access & Activity Tracking',
|
||||||
|
'pro_plan_feature6' => 'Create Quotes & Pro-forma Invoices',
|
||||||
|
'pro_plan_feature7' => 'Customize Invoice Field Titles & Numbering',
|
||||||
|
'pro_plan_feature8' => 'Option to Attach PDFs to Client Emails',
|
||||||
|
|
||||||
|
'resume' => 'Continuer',
|
||||||
|
'break_duration' => 'Pause',
|
||||||
|
'edit_details' => 'Modifier',
|
||||||
|
'work' => 'Travail',
|
||||||
|
'timezone_unset' => 'Please :link to set your timezone',
|
||||||
|
'click_here' => 'cliquer içi',
|
||||||
|
|
||||||
|
'email_receipt' => 'Email payment receipt to the client',
|
||||||
|
'created_payment_emailed_client' => 'Successfully created payment and emailed client',
|
||||||
|
'add_account' => 'Add Account',
|
||||||
|
'untitled' => 'Untitled',
|
||||||
|
'new_account' => 'New Account',
|
||||||
|
'associated_accounts' => 'Successfully linked accounts',
|
||||||
|
'unlinked_account' => 'Successfully unlinked accounts',
|
||||||
|
'login' => 'Login',
|
||||||
|
'or' => 'or',
|
||||||
|
|
||||||
|
'email_error' => 'There was a problem sending the email',
|
||||||
|
'created_by_recurring' => 'Created by recurring invoice :invoice',
|
||||||
|
'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.',
|
||||||
|
'old_browser' => 'Please use a <a href="'.OUTDATE_BROWSER_URL.'" target="_blank">newer browser</a>',
|
||||||
|
'payment_terms_help' => 'Sets the default invoice due date',
|
||||||
|
'unlink_account' => 'Unlink Account',
|
||||||
|
'unlink' => 'Unlink',
|
||||||
|
'show_address' => 'Show Address',
|
||||||
|
'show_address_help' => 'Require client to provide their billing address',
|
||||||
|
'update_address' => 'Update Address',
|
||||||
|
'update_address_help' => 'Update client\'s address with provided details',
|
||||||
|
'times' => 'Times',
|
||||||
|
'set_now' => 'Set now',
|
||||||
|
'dark_mode' => 'Dark Mode',
|
||||||
|
'dark_mode_help' => 'Show white text on black background',
|
||||||
|
'add_to_invoice' => 'Add to invoice :invoice',
|
||||||
|
'create_new_invoice' => 'Create new invoice',
|
||||||
|
'task_errors' => 'Please correct any overlapping times',
|
||||||
|
'from' => 'From',
|
||||||
|
'to' => 'To',
|
||||||
|
'font_size' => 'Font Size',
|
||||||
|
'primary_color' => 'Primary Color',
|
||||||
|
'secondary_color' => 'Secondary Color',
|
||||||
|
'customize_design' => 'Customize Design',
|
||||||
|
|
||||||
|
'content' => 'Content',
|
||||||
|
'styles' => 'Styles',
|
||||||
|
'defaults' => 'Defaults',
|
||||||
|
'margins' => 'Margins',
|
||||||
|
'header' => 'Header',
|
||||||
|
'footer' => 'Footer',
|
||||||
|
'custom' => 'Custom',
|
||||||
|
|
||||||
|
|
||||||
);
|
);
|
||||||
|
@ -592,7 +592,7 @@ return array(
|
|||||||
'less_fields' => 'Less Fields',
|
'less_fields' => 'Less Fields',
|
||||||
'client_name' => 'Client Name',
|
'client_name' => 'Client Name',
|
||||||
'pdf_settings' => 'PDF Settings',
|
'pdf_settings' => 'PDF Settings',
|
||||||
'utf8_invoices' => 'Cyrillic Support <sup>Beta</sup>',
|
'utf8_invoices' => 'New PDF Engine <sup>Beta</sup>',
|
||||||
'product_settings' => 'Product Settings',
|
'product_settings' => 'Product Settings',
|
||||||
'auto_wrap' => 'Auto Line Wrap',
|
'auto_wrap' => 'Auto Line Wrap',
|
||||||
'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.',
|
'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.',
|
||||||
@ -670,5 +670,69 @@ return array(
|
|||||||
'gateway_help_43' => ':link to sign up for Dwolla.',
|
'gateway_help_43' => ':link to sign up for Dwolla.',
|
||||||
'partial_value' => 'Must be greater than zero and less than the total',
|
'partial_value' => 'Must be greater than zero and less than the total',
|
||||||
'more_actions' => 'More Actions',
|
'more_actions' => 'More Actions',
|
||||||
|
|
||||||
|
|
||||||
|
'pro_plan_title' => 'NINJA PRO',
|
||||||
|
'pro_plan_call_to_action' => 'Upgrade Now!',
|
||||||
|
'pro_plan_feature1' => 'Create Unlimited Clients',
|
||||||
|
'pro_plan_feature2' => 'Access to 10 Beautiful Invoice Designs',
|
||||||
|
'pro_plan_feature3' => 'Custom URLs - "YourBrand.InvoiceNinja.com"',
|
||||||
|
'pro_plan_feature4' => 'Remove "Created by Invoice Ninja"',
|
||||||
|
'pro_plan_feature5' => 'Multi-user Access & Activity Tracking',
|
||||||
|
'pro_plan_feature6' => 'Create Quotes & Pro-forma Invoices',
|
||||||
|
'pro_plan_feature7' => 'Customize Invoice Field Titles & Numbering',
|
||||||
|
'pro_plan_feature8' => 'Option to Attach PDFs to Client Emails',
|
||||||
|
|
||||||
|
'resume' => 'Resume',
|
||||||
|
'break_duration' => 'Break',
|
||||||
|
'edit_details' => 'Edit Details',
|
||||||
|
'work' => 'Work',
|
||||||
|
'timezone_unset' => 'Please :link to set your timezone',
|
||||||
|
'click_here' => 'click here',
|
||||||
|
|
||||||
|
'email_receipt' => 'Email payment receipt to the client',
|
||||||
|
'created_payment_emailed_client' => 'Successfully created payment and emailed client',
|
||||||
|
'add_account' => 'Add Account',
|
||||||
|
'untitled' => 'Untitled',
|
||||||
|
'new_account' => 'New Account',
|
||||||
|
'associated_accounts' => 'Successfully linked accounts',
|
||||||
|
'unlinked_account' => 'Successfully unlinked accounts',
|
||||||
|
'login' => 'Login',
|
||||||
|
'or' => 'or',
|
||||||
|
|
||||||
|
'email_error' => 'There was a problem sending the email',
|
||||||
|
'created_by_recurring' => 'Created by recurring invoice :invoice',
|
||||||
|
'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.',
|
||||||
|
'old_browser' => 'Please use a <a href="'.OUTDATE_BROWSER_URL.'" target="_blank">newer browser</a>',
|
||||||
|
'payment_terms_help' => 'Sets the default invoice due date',
|
||||||
|
'unlink_account' => 'Unlink Account',
|
||||||
|
'unlink' => 'Unlink',
|
||||||
|
'show_address' => 'Show Address',
|
||||||
|
'show_address_help' => 'Require client to provide their billing address',
|
||||||
|
'update_address' => 'Update Address',
|
||||||
|
'update_address_help' => 'Update client\'s address with provided details',
|
||||||
|
'times' => 'Times',
|
||||||
|
'set_now' => 'Set now',
|
||||||
|
'dark_mode' => 'Dark Mode',
|
||||||
|
'dark_mode_help' => 'Show white text on black background',
|
||||||
|
'add_to_invoice' => 'Add to invoice :invoice',
|
||||||
|
'create_new_invoice' => 'Create new invoice',
|
||||||
|
'task_errors' => 'Please correct any overlapping times',
|
||||||
|
'from' => 'From',
|
||||||
|
'to' => 'To',
|
||||||
|
'font_size' => 'Font Size',
|
||||||
|
'primary_color' => 'Primary Color',
|
||||||
|
'secondary_color' => 'Secondary Color',
|
||||||
|
'customize_design' => 'Customize Design',
|
||||||
|
|
||||||
|
'content' => 'Content',
|
||||||
|
'styles' => 'Styles',
|
||||||
|
'defaults' => 'Defaults',
|
||||||
|
'margins' => 'Margins',
|
||||||
|
'header' => 'Header',
|
||||||
|
'footer' => 'Footer',
|
||||||
|
'custom' => 'Custom',
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
);
|
);
|
||||||
|
@ -1,20 +1,19 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
return array(
|
return [
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| Pagination Language Lines
|
| Puslapiavimo kalbos eilutės
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
|
||||||
| The following language lines are used by the paginator library to build
|
| Šios kalbos eilutės yra naudojamas puslapiavimo bibliotekos kurti
|
||||||
| the simple pagination links. You are free to change them to anything
|
| paprastas puslapiavimo nuorodas. Jūs galite laisvai keisti jas
|
||||||
| you want to customize your views to better match your application.
|
| į bet kokias kitas labiau tinkančias Jūsų programai.
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'previous' => '« Previous',
|
'previous' => '« Ankstesnis',
|
||||||
|
'next' => 'Sekantis »',
|
||||||
|
|
||||||
'next' => 'Next »',
|
];
|
||||||
|
|
||||||
);
|
|
||||||
|
@ -1,24 +1,21 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
return array(
|
return [
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| Password Reminder Language Lines
|
| Slaptažodžio priminimo kalbos eilutės
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
|
||||||
| The following language lines are the default lines which match reasons
|
| Sekančios kalbos eilutės yra numatytos elutės, atitinkančios priežastims,
|
||||||
| that are given by the password broker for a password update attempt
|
| pateikiamoms slatažodžių tarpininko, kai nepavyksta slaptažodžio atnaujinimo
|
||||||
| has failed, such as for an invalid token or invalid new password.
|
| bandymas, tokioms kaip negaliojanti žymė ar neteisingas naujas slaptažodis..
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
"password" => "Passwords must be at least six characters and match the confirmation.",
|
"password" => "Slaptažodis turi būti bent šešių simbolių ir sutapti su patvirtinimu.",
|
||||||
|
"user" => "Vartotojas su tokiu el. pašu nerastas.",
|
||||||
"user" => "We can't find a user with that e-mail address.",
|
"token" => "Šis slaptažodžio raktas yra neteisingas.",
|
||||||
|
"sent" => "Naujo slaptažodžio nustatymo nuoroda išsiųsta",
|
||||||
"token" => "This password reset token is invalid.",
|
"reset" => "Nustatytas naujas slaptažodis!",
|
||||||
|
];
|
||||||
"sent" => "Password reminder sent!",
|
|
||||||
|
|
||||||
);
|
|
||||||
|
@ -600,7 +600,7 @@ return array(
|
|||||||
'less_fields' => 'Less Fields',
|
'less_fields' => 'Less Fields',
|
||||||
'client_name' => 'Client Name',
|
'client_name' => 'Client Name',
|
||||||
'pdf_settings' => 'PDF Settings',
|
'pdf_settings' => 'PDF Settings',
|
||||||
'utf8_invoices' => 'Cyrillic Support <sup>Beta</sup>',
|
'utf8_invoices' => 'New PDF Engine <sup>Beta</sup>',
|
||||||
'product_settings' => 'Product Settings',
|
'product_settings' => 'Product Settings',
|
||||||
'auto_wrap' => 'Auto Line Wrap',
|
'auto_wrap' => 'Auto Line Wrap',
|
||||||
'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.',
|
'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.',
|
||||||
@ -678,6 +678,69 @@ return array(
|
|||||||
'gateway_help_43' => ':link to sign up for Dwolla.',
|
'gateway_help_43' => ':link to sign up for Dwolla.',
|
||||||
'partial_value' => 'Must be greater than zero and less than the total',
|
'partial_value' => 'Must be greater than zero and less than the total',
|
||||||
'more_actions' => 'More Actions',
|
'more_actions' => 'More Actions',
|
||||||
|
|
||||||
|
'pro_plan_title' => 'NINJA PRO',
|
||||||
|
'pro_plan_call_to_action' => 'Upgrade Now!',
|
||||||
|
'pro_plan_feature1' => 'Create Unlimited Clients',
|
||||||
|
'pro_plan_feature2' => 'Access to 10 Beautiful Invoice Designs',
|
||||||
|
'pro_plan_feature3' => 'Custom URLs - "YourBrand.InvoiceNinja.com"',
|
||||||
|
'pro_plan_feature4' => 'Remove "Created by Invoice Ninja"',
|
||||||
|
'pro_plan_feature5' => 'Multi-user Access & Activity Tracking',
|
||||||
|
'pro_plan_feature6' => 'Create Quotes & Pro-forma Invoices',
|
||||||
|
'pro_plan_feature7' => 'Customize Invoice Field Titles & Numbering',
|
||||||
|
'pro_plan_feature8' => 'Option to Attach PDFs to Client Emails',
|
||||||
|
|
||||||
|
'resume' => 'Resume',
|
||||||
|
'break_duration' => 'Break',
|
||||||
|
'edit_details' => 'Edit Details',
|
||||||
|
'work' => 'Work',
|
||||||
|
'timezone_unset' => 'Please :link to set your timezone',
|
||||||
|
'click_here' => 'click here',
|
||||||
|
|
||||||
|
'email_receipt' => 'Email payment receipt to the client',
|
||||||
|
'created_payment_emailed_client' => 'Successfully created payment and emailed client',
|
||||||
|
'add_account' => 'Add Account',
|
||||||
|
'untitled' => 'Untitled',
|
||||||
|
'new_account' => 'New Account',
|
||||||
|
'associated_accounts' => 'Successfully linked accounts',
|
||||||
|
'unlinked_account' => 'Successfully unlinked accounts',
|
||||||
|
'login' => 'Login',
|
||||||
|
'or' => 'or',
|
||||||
|
|
||||||
|
'email_error' => 'There was a problem sending the email',
|
||||||
|
'created_by_recurring' => 'Created by recurring invoice :invoice',
|
||||||
|
'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.',
|
||||||
|
'old_browser' => 'Please use a <a href="'.OUTDATE_BROWSER_URL.'" target="_blank">newer browser</a>',
|
||||||
|
'payment_terms_help' => 'Sets the default invoice due date',
|
||||||
|
'unlink_account' => 'Unlink Account',
|
||||||
|
'unlink' => 'Unlink',
|
||||||
|
'show_address' => 'Show Address',
|
||||||
|
'show_address_help' => 'Require client to provide their billing address',
|
||||||
|
'update_address' => 'Update Address',
|
||||||
|
'update_address_help' => 'Update client\'s address with provided details',
|
||||||
|
'times' => 'Times',
|
||||||
|
'set_now' => 'Set now',
|
||||||
|
'dark_mode' => 'Dark Mode',
|
||||||
|
'dark_mode_help' => 'Show white text on black background',
|
||||||
|
'add_to_invoice' => 'Add to invoice :invoice',
|
||||||
|
'create_new_invoice' => 'Create new invoice',
|
||||||
|
'task_errors' => 'Please correct any overlapping times',
|
||||||
|
'from' => 'From',
|
||||||
|
'to' => 'To',
|
||||||
|
'font_size' => 'Font Size',
|
||||||
|
'primary_color' => 'Primary Color',
|
||||||
|
'secondary_color' => 'Secondary Color',
|
||||||
|
'customize_design' => 'Customize Design',
|
||||||
|
|
||||||
|
'content' => 'Content',
|
||||||
|
'styles' => 'Styles',
|
||||||
|
'defaults' => 'Defaults',
|
||||||
|
'margins' => 'Margins',
|
||||||
|
'header' => 'Header',
|
||||||
|
'footer' => 'Footer',
|
||||||
|
'custom' => 'Custom',
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,103 +1,108 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
return array(
|
return [
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| Validation Language Lines
|
| Patvirtinimo kalbos eilutės
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
|
||||||
| The following language lines contain the default error messages used by
|
| Sekančios kalbos eilutėse yra numatyti klaidos pranešimai naudojami
|
||||||
| the validator class. Some of these rules have multiple versions such
|
| patvirtinimo klasėje. Kai kurios iš šių eilučių turi keletą versijų
|
||||||
| such as the size rules. Feel free to tweak each of these messages.
|
| tokių kaip dydžio taisyklės. Galite laisvai pataisyti bet kuriuos pranešimus.
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
"accepted" => "The :attribute must be accepted.",
|
"accepted" => "Laukas :attribute turi būti priimtas.",
|
||||||
"active_url" => "The :attribute is not a valid URL.",
|
"active_url" => "Laukas :attribute nėra galiojantis internetinis adresas.",
|
||||||
"after" => "The :attribute must be a date after :date.",
|
"after" => "Laukelyje :attribute turi būti data po :date.",
|
||||||
"alpha" => "The :attribute may only contain letters.",
|
"alpha" => "Laukas :attribute gali turėti tik raides.",
|
||||||
"alpha_dash" => "The :attribute may only contain letters, numbers, and dashes.",
|
"alpha_dash" => "Laukas :attribute gali turėti tik raides, skaičius ir brūkšnelius.",
|
||||||
"alpha_num" => "The :attribute may only contain letters and numbers.",
|
"alpha_num" => "Laukas :attribute gali turėti tik raides ir skaičius.",
|
||||||
"array" => "The :attribute must be an array.",
|
"array" => "Laukas :attribute turi būti masyvas.",
|
||||||
"before" => "The :attribute must be a date before :date.",
|
"before" => "Laukas :attribute turi būti data prieš :date.",
|
||||||
"between" => array(
|
"between" => [
|
||||||
"numeric" => "The :attribute must be between :min - :max.",
|
"numeric" => "Lauko :attribute reikšmė turi būti tarp :min ir :max.",
|
||||||
"file" => "The :attribute must be between :min - :max kilobytes.",
|
"file" => "Failo dydis lauke :attribute turi būti tarp :min ir :max kilobaitų.",
|
||||||
"string" => "The :attribute must be between :min - :max characters.",
|
"string" => "Simbolių skaičius lauke :attribute turi būti tarp :min ir :max.",
|
||||||
"array" => "The :attribute must have between :min - :max items.",
|
"array" => "Elementų skaičius lauke :attribute turi turėti nuo :min iki :max.",
|
||||||
),
|
],
|
||||||
"confirmed" => "The :attribute confirmation does not match.",
|
"boolean" => "Lauko reikšmė :attribute turi būti 'taip' arba 'ne'.",
|
||||||
"date" => "The :attribute is not a valid date.",
|
"confirmed" => "Lauko :attribute patvirtinimas nesutampa.",
|
||||||
"date_format" => "The :attribute does not match the format :format.",
|
"date" => "Lauko :attribute reikšmė nėra galiojanti data.",
|
||||||
"different" => "The :attribute and :other must be different.",
|
"date_format" => "Lauko :attribute reikšmė neatitinka formato :format.",
|
||||||
"digits" => "The :attribute must be :digits digits.",
|
"different" => "Laukų :attribute ir :other reikšmės turi skirtis.",
|
||||||
"digits_between" => "The :attribute must be between :min and :max digits.",
|
"digits" => "Laukas :attribute turi būti sudarytas iš :digits skaitmenų.",
|
||||||
"email" => "The :attribute format is invalid.",
|
"digits_between" => "Laukas :attribute tuti turėti nuo :min iki :max skaitmenų.",
|
||||||
"exists" => "The selected :attribute is invalid.",
|
"email" => "Lauko :attribute reikšmė turi būti galiojantis el. pašto adresas.",
|
||||||
"image" => "The :attribute must be an image.",
|
"filled" => "Laukas :attribute turi būti užpildytas.",
|
||||||
"in" => "The selected :attribute is invalid.",
|
"exists" => "Pasirinkta negaliojanti :attribute reikšmė.",
|
||||||
"integer" => "The :attribute must be an integer.",
|
"image" => "Lauko :attribute reikšmė turi būti paveikslėlis.",
|
||||||
"ip" => "The :attribute must be a valid IP address.",
|
"in" => "Pasirinkta negaliojanti :attribute reikšmė.",
|
||||||
"max" => array(
|
"integer" => "Lauko :attribute reikšmė turi būti veikasis skaičius.",
|
||||||
"numeric" => "The :attribute may not be greater than :max.",
|
"ip" => "Lauko :attribute reikšmė turi būti galiojantis IP adresas.",
|
||||||
"file" => "The :attribute may not be greater than :max kilobytes.",
|
"max" => [
|
||||||
"string" => "The :attribute may not be greater than :max characters.",
|
"numeric" => "Lauko :attribute reikšmė negali būti didesnė nei :max.",
|
||||||
"array" => "The :attribute may not have more than :max items.",
|
"file" => "Failo dydis lauke :attribute reikšmė negali būti didesnė nei :max kilobaitų.",
|
||||||
),
|
"string" => "Simbolių kiekis lauke :attribute reikšmė negali būti didesnė nei :max simbolių.",
|
||||||
"mimes" => "The :attribute must be a file of type: :values.",
|
"array" => "Elementų kiekis lauke :attribute negali turėti daugiau nei :max elementų.",
|
||||||
"min" => array(
|
],
|
||||||
"numeric" => "The :attribute must be at least :min.",
|
"mimes" => "Lauko reikšmė :attribute turi būti failas vieno iš sekančių tipų: :values.",
|
||||||
"file" => "The :attribute must be at least :min kilobytes.",
|
"min" => [
|
||||||
"string" => "The :attribute must be at least :min characters.",
|
"numeric" => "Lauko :attribute reikšmė turi būti ne mažesnė nei :min.",
|
||||||
"array" => "The :attribute must have at least :min items.",
|
"file" => "Failo dydis lauke :attribute turi būti ne mažesnis nei :min kilobaitų.",
|
||||||
),
|
"string" => "Simbolių kiekis lauke :attribute turi būti ne mažiau nei :min.",
|
||||||
"not_in" => "The selected :attribute is invalid.",
|
"array" => "Elementų kiekis lauke :attribute turi būti ne mažiau nei :min.",
|
||||||
"numeric" => "The :attribute must be a number.",
|
],
|
||||||
"regex" => "The :attribute format is invalid.",
|
"not_in" => "Pasirinkta negaliojanti reikšmė :attribute.",
|
||||||
"required" => "The :attribute field is required.",
|
"numeric" => "Lauko :attribute reikšmė turi būti skaičius.",
|
||||||
"required_if" => "The :attribute field is required when :other is :value.",
|
"regex" => "Negaliojantis lauko :attribute formatas.",
|
||||||
"required_with" => "The :attribute field is required when :values is present.",
|
"required" => "Privaloma užpildyti lauką :attribute.",
|
||||||
"required_without" => "The :attribute field is required when :values is not present.",
|
"required_if" => "Privaloma užpildyti lauką :attribute kai :other yra :value.",
|
||||||
"same" => "The :attribute and :other must match.",
|
"required_with" => "Privaloma užpildyti lauką :attribute kai pateikta :values.",
|
||||||
"size" => array(
|
"required_with_all" => "Privaloma užpildyti lauką :attribute kai pateikta :values.",
|
||||||
"numeric" => "The :attribute must be :size.",
|
"required_without" => "Privaloma užpildyti lauką :attribute kai nepateikta :values.",
|
||||||
"file" => "The :attribute must be :size kilobytes.",
|
"required_without_all" => "Privaloma užpildyti lauką :attribute kai nepateikta nei viena iš reikšmių :values.",
|
||||||
"string" => "The :attribute must be :size characters.",
|
"same" => "Laukai :attribute ir :other turi sutapti.",
|
||||||
"array" => "The :attribute must contain :size items.",
|
"size" => [
|
||||||
),
|
"numeric" => "Lauko :attribute reikšmė turi būti :size.",
|
||||||
"unique" => "The :attribute has already been taken.",
|
"file" => "Failo dydis lauke :attribute turi būti :size kilobaitai.",
|
||||||
"url" => "The :attribute format is invalid.",
|
"string" => "Simbolių skaičius lauke :attribute turi būti :size.",
|
||||||
|
"array" => "Elementų kiekis lauke :attribute turi būti :size.",
|
||||||
"positive" => "The :attribute must be greater than zero.",
|
],
|
||||||
"has_credit" => "The client does not have enough credit.",
|
"string" => "The :attribute must be a string.",
|
||||||
"notmasked" => "The values are masked",
|
"timezone" => "Lauko :attribute reikšmė turi būti galiojanti laiko zona.",
|
||||||
"less_than" => 'The :attribute must be less than :value',
|
"unique" => "Tokia :attribute reikšmė jau pasirinkta.",
|
||||||
|
"url" => "Negaliojantis lauko :attribute formatas.",
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Custom Validation Language Lines
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Here you may specify custom validation messages for attributes using the
|
|
||||||
| convention "attribute.rule" to name the lines. This makes it quick to
|
|
||||||
| specify a specific custom language line for a given attribute rule.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
'custom' => array(),
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Pasirinktiniai patvirtinimo kalbos eilutės
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Čia galite nurodyti pasirinktinius patvirtinimo pranešimus, naudodami
|
||||||
|
| konvenciją "attribute.rule" eilučių pavadinimams. Tai leidžia greitai
|
||||||
|
| nurodyti konkrečią pasirinktinę kalbos eilutę tam tikrai atributo taisyklei.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
'custom' => [
|
||||||
|--------------------------------------------------------------------------
|
'attribute-name' => [
|
||||||
| Custom Validation Attributes
|
'rule-name' => 'custom-message',
|
||||||
|--------------------------------------------------------------------------
|
],
|
||||||
|
|
],
|
||||||
| The following language lines are used to swap attribute place-holders
|
|
||||||
| with something more reader friendly such as E-Mail Address instead
|
|
||||||
| of "email". This simply helps us make messages a little cleaner.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
'attributes' => array(),
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Pasirinktiniai patvirtinimo atributai
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Sekančios kalbos eilutės naudojamos pakeisti vietos žymes
|
||||||
|
| kuo nors labiau priimtinu skaitytojui (pvz. "El.Pašto Adresas" vietoj
|
||||||
|
| "email". TTai tiesiog padeda mums padaryti žinutes truputi aiškesnėmis.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
);
|
'attributes' => [],
|
||||||
|
|
||||||
|
];
|
||||||
|
@ -598,7 +598,7 @@ return array(
|
|||||||
'less_fields' => 'Less Fields',
|
'less_fields' => 'Less Fields',
|
||||||
'client_name' => 'Client Name',
|
'client_name' => 'Client Name',
|
||||||
'pdf_settings' => 'PDF Settings',
|
'pdf_settings' => 'PDF Settings',
|
||||||
'utf8_invoices' => 'Cyrillic Support <sup>Beta</sup>',
|
'utf8_invoices' => 'New PDF Engine <sup>Beta</sup>',
|
||||||
'product_settings' => 'Product Settings',
|
'product_settings' => 'Product Settings',
|
||||||
'auto_wrap' => 'Auto Line Wrap',
|
'auto_wrap' => 'Auto Line Wrap',
|
||||||
'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.',
|
'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.',
|
||||||
@ -676,5 +676,68 @@ return array(
|
|||||||
'gateway_help_43' => ':link to sign up for Dwolla.',
|
'gateway_help_43' => ':link to sign up for Dwolla.',
|
||||||
'partial_value' => 'Must be greater than zero and less than the total',
|
'partial_value' => 'Must be greater than zero and less than the total',
|
||||||
'more_actions' => 'More Actions',
|
'more_actions' => 'More Actions',
|
||||||
|
|
||||||
|
'pro_plan_title' => 'NINJA PRO',
|
||||||
|
'pro_plan_call_to_action' => 'Upgrade Now!',
|
||||||
|
'pro_plan_feature1' => 'Create Unlimited Clients',
|
||||||
|
'pro_plan_feature2' => 'Access to 10 Beautiful Invoice Designs',
|
||||||
|
'pro_plan_feature3' => 'Custom URLs - "YourBrand.InvoiceNinja.com"',
|
||||||
|
'pro_plan_feature4' => 'Remove "Created by Invoice Ninja"',
|
||||||
|
'pro_plan_feature5' => 'Multi-user Access & Activity Tracking',
|
||||||
|
'pro_plan_feature6' => 'Create Quotes & Pro-forma Invoices',
|
||||||
|
'pro_plan_feature7' => 'Customize Invoice Field Titles & Numbering',
|
||||||
|
'pro_plan_feature8' => 'Option to Attach PDFs to Client Emails',
|
||||||
|
|
||||||
|
'resume' => 'Resume',
|
||||||
|
'break_duration' => 'Break',
|
||||||
|
'edit_details' => 'Edit Details',
|
||||||
|
'work' => 'Work',
|
||||||
|
'timezone_unset' => 'Please :link to set your timezone',
|
||||||
|
'click_here' => 'click here',
|
||||||
|
|
||||||
|
'email_receipt' => 'Email payment receipt to the client',
|
||||||
|
'created_payment_emailed_client' => 'Successfully created payment and emailed client',
|
||||||
|
'add_account' => 'Add Account',
|
||||||
|
'untitled' => 'Untitled',
|
||||||
|
'new_account' => 'New Account',
|
||||||
|
'associated_accounts' => 'Successfully linked accounts',
|
||||||
|
'unlinked_account' => 'Successfully unlinked accounts',
|
||||||
|
'login' => 'Login',
|
||||||
|
'or' => 'or',
|
||||||
|
|
||||||
|
'email_error' => 'There was a problem sending the email',
|
||||||
|
'created_by_recurring' => 'Created by recurring invoice :invoice',
|
||||||
|
'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.',
|
||||||
|
'old_browser' => 'Please use a <a href="'.OUTDATE_BROWSER_URL.'" target="_blank">newer browser</a>',
|
||||||
|
'payment_terms_help' => 'Sets the default invoice due date',
|
||||||
|
'unlink_account' => 'Unlink Account',
|
||||||
|
'unlink' => 'Unlink',
|
||||||
|
'show_address' => 'Show Address',
|
||||||
|
'show_address_help' => 'Require client to provide their billing address',
|
||||||
|
'update_address' => 'Update Address',
|
||||||
|
'update_address_help' => 'Update client\'s address with provided details',
|
||||||
|
'times' => 'Times',
|
||||||
|
'set_now' => 'Set now',
|
||||||
|
'dark_mode' => 'Dark Mode',
|
||||||
|
'dark_mode_help' => 'Show white text on black background',
|
||||||
|
'add_to_invoice' => 'Add to invoice :invoice',
|
||||||
|
'create_new_invoice' => 'Create new invoice',
|
||||||
|
'task_errors' => 'Please correct any overlapping times',
|
||||||
|
'from' => 'From',
|
||||||
|
'to' => 'To',
|
||||||
|
'font_size' => 'Font Size',
|
||||||
|
'primary_color' => 'Primary Color',
|
||||||
|
'secondary_color' => 'Secondary Color',
|
||||||
|
'customize_design' => 'Customize Design',
|
||||||
|
|
||||||
|
'content' => 'Content',
|
||||||
|
'styles' => 'Styles',
|
||||||
|
'defaults' => 'Defaults',
|
||||||
|
'margins' => 'Margins',
|
||||||
|
'header' => 'Header',
|
||||||
|
'footer' => 'Footer',
|
||||||
|
'custom' => 'Custom',
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
);
|
);
|
@ -593,7 +593,7 @@ return array(
|
|||||||
'less_fields' => 'Less Fields',
|
'less_fields' => 'Less Fields',
|
||||||
'client_name' => 'Client Name',
|
'client_name' => 'Client Name',
|
||||||
'pdf_settings' => 'PDF Settings',
|
'pdf_settings' => 'PDF Settings',
|
||||||
'utf8_invoices' => 'Cyrillic Support <sup>Beta</sup>',
|
'utf8_invoices' => 'New PDF Engine <sup>Beta</sup>',
|
||||||
'product_settings' => 'Product Settings',
|
'product_settings' => 'Product Settings',
|
||||||
'auto_wrap' => 'Auto Line Wrap',
|
'auto_wrap' => 'Auto Line Wrap',
|
||||||
'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.',
|
'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.',
|
||||||
@ -671,5 +671,68 @@ return array(
|
|||||||
'gateway_help_43' => ':link to sign up for Dwolla.',
|
'gateway_help_43' => ':link to sign up for Dwolla.',
|
||||||
'partial_value' => 'Must be greater than zero and less than the total',
|
'partial_value' => 'Must be greater than zero and less than the total',
|
||||||
'more_actions' => 'More Actions',
|
'more_actions' => 'More Actions',
|
||||||
|
|
||||||
|
'pro_plan_title' => 'NINJA PRO',
|
||||||
|
'pro_plan_call_to_action' => 'Upgrade Now!',
|
||||||
|
'pro_plan_feature1' => 'Create Unlimited Clients',
|
||||||
|
'pro_plan_feature2' => 'Access to 10 Beautiful Invoice Designs',
|
||||||
|
'pro_plan_feature3' => 'Custom URLs - "YourBrand.InvoiceNinja.com"',
|
||||||
|
'pro_plan_feature4' => 'Remove "Created by Invoice Ninja"',
|
||||||
|
'pro_plan_feature5' => 'Multi-user Access & Activity Tracking',
|
||||||
|
'pro_plan_feature6' => 'Create Quotes & Pro-forma Invoices',
|
||||||
|
'pro_plan_feature7' => 'Customize Invoice Field Titles & Numbering',
|
||||||
|
'pro_plan_feature8' => 'Option to Attach PDFs to Client Emails',
|
||||||
|
|
||||||
|
'resume' => 'Resume',
|
||||||
|
'break_duration' => 'Break',
|
||||||
|
'edit_details' => 'Edit Details',
|
||||||
|
'work' => 'Work',
|
||||||
|
'timezone_unset' => 'Please :link to set your timezone',
|
||||||
|
'click_here' => 'click here',
|
||||||
|
|
||||||
|
'email_receipt' => 'Email payment receipt to the client',
|
||||||
|
'created_payment_emailed_client' => 'Successfully created payment and emailed client',
|
||||||
|
'add_account' => 'Add Account',
|
||||||
|
'untitled' => 'Untitled',
|
||||||
|
'new_account' => 'New Account',
|
||||||
|
'associated_accounts' => 'Successfully linked accounts',
|
||||||
|
'unlinked_account' => 'Successfully unlinked accounts',
|
||||||
|
'login' => 'Login',
|
||||||
|
'or' => 'or',
|
||||||
|
|
||||||
|
'email_error' => 'There was a problem sending the email',
|
||||||
|
'created_by_recurring' => 'Created by recurring invoice :invoice',
|
||||||
|
'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.',
|
||||||
|
'old_browser' => 'Please use a <a href="'.OUTDATE_BROWSER_URL.'" target="_blank">newer browser</a>',
|
||||||
|
'payment_terms_help' => 'Sets the default invoice due date',
|
||||||
|
'unlink_account' => 'Unlink Account',
|
||||||
|
'unlink' => 'Unlink',
|
||||||
|
'show_address' => 'Show Address',
|
||||||
|
'show_address_help' => 'Require client to provide their billing address',
|
||||||
|
'update_address' => 'Update Address',
|
||||||
|
'update_address_help' => 'Update client\'s address with provided details',
|
||||||
|
'times' => 'Times',
|
||||||
|
'set_now' => 'Set now',
|
||||||
|
'dark_mode' => 'Dark Mode',
|
||||||
|
'dark_mode_help' => 'Show white text on black background',
|
||||||
|
'add_to_invoice' => 'Add to invoice :invoice',
|
||||||
|
'create_new_invoice' => 'Create new invoice',
|
||||||
|
'task_errors' => 'Please correct any overlapping times',
|
||||||
|
'from' => 'From',
|
||||||
|
'to' => 'To',
|
||||||
|
'font_size' => 'Font Size',
|
||||||
|
'primary_color' => 'Primary Color',
|
||||||
|
'secondary_color' => 'Secondary Color',
|
||||||
|
'customize_design' => 'Customize Design',
|
||||||
|
|
||||||
|
'content' => 'Content',
|
||||||
|
'styles' => 'Styles',
|
||||||
|
'defaults' => 'Defaults',
|
||||||
|
'margins' => 'Margins',
|
||||||
|
'header' => 'Header',
|
||||||
|
'footer' => 'Footer',
|
||||||
|
'custom' => 'Custom',
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
);
|
);
|
||||||
|
@ -593,7 +593,7 @@ return array(
|
|||||||
'less_fields' => 'Less Fields',
|
'less_fields' => 'Less Fields',
|
||||||
'client_name' => 'Client Name',
|
'client_name' => 'Client Name',
|
||||||
'pdf_settings' => 'PDF Settings',
|
'pdf_settings' => 'PDF Settings',
|
||||||
'utf8_invoices' => 'Cyrillic Support <sup>Beta</sup>',
|
'utf8_invoices' => 'New PDF Engine <sup>Beta</sup>',
|
||||||
'product_settings' => 'Product Settings',
|
'product_settings' => 'Product Settings',
|
||||||
'auto_wrap' => 'Auto Line Wrap',
|
'auto_wrap' => 'Auto Line Wrap',
|
||||||
'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.',
|
'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.',
|
||||||
@ -671,5 +671,67 @@ return array(
|
|||||||
'gateway_help_43' => ':link to sign up for Dwolla.',
|
'gateway_help_43' => ':link to sign up for Dwolla.',
|
||||||
'partial_value' => 'Must be greater than zero and less than the total',
|
'partial_value' => 'Must be greater than zero and less than the total',
|
||||||
'more_actions' => 'More Actions',
|
'more_actions' => 'More Actions',
|
||||||
|
|
||||||
|
'pro_plan_title' => 'NINJA PRO',
|
||||||
|
'pro_plan_call_to_action' => 'Upgrade Now!',
|
||||||
|
'pro_plan_feature1' => 'Create Unlimited Clients',
|
||||||
|
'pro_plan_feature2' => 'Access to 10 Beautiful Invoice Designs',
|
||||||
|
'pro_plan_feature3' => 'Custom URLs - "YourBrand.InvoiceNinja.com"',
|
||||||
|
'pro_plan_feature4' => 'Remove "Created by Invoice Ninja"',
|
||||||
|
'pro_plan_feature5' => 'Multi-user Access & Activity Tracking',
|
||||||
|
'pro_plan_feature6' => 'Create Quotes & Pro-forma Invoices',
|
||||||
|
'pro_plan_feature7' => 'Customize Invoice Field Titles & Numbering',
|
||||||
|
'pro_plan_feature8' => 'Option to Attach PDFs to Client Emails',
|
||||||
|
|
||||||
|
'resume' => 'Resume',
|
||||||
|
'break_duration' => 'Break',
|
||||||
|
'edit_details' => 'Edit Details',
|
||||||
|
'work' => 'Work',
|
||||||
|
'timezone_unset' => 'Please :link to set your timezone',
|
||||||
|
'click_here' => 'click here',
|
||||||
|
|
||||||
|
'email_receipt' => 'Email payment receipt to the client',
|
||||||
|
'created_payment_emailed_client' => 'Successfully created payment and emailed client',
|
||||||
|
'add_account' => 'Add Account',
|
||||||
|
'untitled' => 'Untitled',
|
||||||
|
'new_account' => 'New Account',
|
||||||
|
'associated_accounts' => 'Successfully linked accounts',
|
||||||
|
'unlinked_account' => 'Successfully unlinked accounts',
|
||||||
|
'login' => 'Login',
|
||||||
|
'or' => 'or',
|
||||||
|
|
||||||
|
'email_error' => 'There was a problem sending the email',
|
||||||
|
'created_by_recurring' => 'Created by recurring invoice :invoice',
|
||||||
|
'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.',
|
||||||
|
'old_browser' => 'Please use a <a href="'.OUTDATE_BROWSER_URL.'" target="_blank">newer browser</a>',
|
||||||
|
'payment_terms_help' => 'Sets the default invoice due date',
|
||||||
|
'unlink_account' => 'Unlink Account',
|
||||||
|
'unlink' => 'Unlink',
|
||||||
|
'show_address' => 'Show Address',
|
||||||
|
'show_address_help' => 'Require client to provide their billing address',
|
||||||
|
'update_address' => 'Update Address',
|
||||||
|
'update_address_help' => 'Update client\'s address with provided details',
|
||||||
|
'times' => 'Times',
|
||||||
|
'set_now' => 'Set now',
|
||||||
|
'dark_mode' => 'Dark Mode',
|
||||||
|
'dark_mode_help' => 'Show white text on black background',
|
||||||
|
'add_to_invoice' => 'Add to invoice :invoice',
|
||||||
|
'create_new_invoice' => 'Create new invoice',
|
||||||
|
'task_errors' => 'Please correct any overlapping times',
|
||||||
|
'from' => 'From',
|
||||||
|
'to' => 'To',
|
||||||
|
'font_size' => 'Font Size',
|
||||||
|
'primary_color' => 'Primary Color',
|
||||||
|
'secondary_color' => 'Secondary Color',
|
||||||
|
'customize_design' => 'Customize Design',
|
||||||
|
|
||||||
|
'content' => 'Content',
|
||||||
|
'styles' => 'Styles',
|
||||||
|
'defaults' => 'Defaults',
|
||||||
|
'margins' => 'Margins',
|
||||||
|
'header' => 'Header',
|
||||||
|
'footer' => 'Footer',
|
||||||
|
'custom' => 'Custom',
|
||||||
|
|
||||||
|
|
||||||
);
|
);
|
||||||
|
@ -596,7 +596,7 @@ return array(
|
|||||||
'less_fields' => 'Less Fields',
|
'less_fields' => 'Less Fields',
|
||||||
'client_name' => 'Client Name',
|
'client_name' => 'Client Name',
|
||||||
'pdf_settings' => 'PDF Settings',
|
'pdf_settings' => 'PDF Settings',
|
||||||
'utf8_invoices' => 'Cyrillic Support <sup>Beta</sup>',
|
'utf8_invoices' => 'New PDF Engine <sup>Beta</sup>',
|
||||||
'product_settings' => 'Product Settings',
|
'product_settings' => 'Product Settings',
|
||||||
'auto_wrap' => 'Auto Line Wrap',
|
'auto_wrap' => 'Auto Line Wrap',
|
||||||
'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.',
|
'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.',
|
||||||
@ -674,5 +674,68 @@ return array(
|
|||||||
'gateway_help_43' => ':link to sign up for Dwolla.',
|
'gateway_help_43' => ':link to sign up for Dwolla.',
|
||||||
'partial_value' => 'Must be greater than zero and less than the total',
|
'partial_value' => 'Must be greater than zero and less than the total',
|
||||||
'more_actions' => 'More Actions',
|
'more_actions' => 'More Actions',
|
||||||
|
|
||||||
|
'pro_plan_title' => 'NINJA PRO',
|
||||||
|
'pro_plan_call_to_action' => 'Upgrade Now!',
|
||||||
|
'pro_plan_feature1' => 'Create Unlimited Clients',
|
||||||
|
'pro_plan_feature2' => 'Access to 10 Beautiful Invoice Designs',
|
||||||
|
'pro_plan_feature3' => 'Custom URLs - "YourBrand.InvoiceNinja.com"',
|
||||||
|
'pro_plan_feature4' => 'Remove "Created by Invoice Ninja"',
|
||||||
|
'pro_plan_feature5' => 'Multi-user Access & Activity Tracking',
|
||||||
|
'pro_plan_feature6' => 'Create Quotes & Pro-forma Invoices',
|
||||||
|
'pro_plan_feature7' => 'Customize Invoice Field Titles & Numbering',
|
||||||
|
'pro_plan_feature8' => 'Option to Attach PDFs to Client Emails',
|
||||||
|
|
||||||
|
'resume' => 'Resume',
|
||||||
|
'break_duration' => 'Break',
|
||||||
|
'edit_details' => 'Edit Details',
|
||||||
|
'work' => 'Work',
|
||||||
|
'timezone_unset' => 'Please :link to set your timezone',
|
||||||
|
'click_here' => 'click here',
|
||||||
|
|
||||||
|
'email_receipt' => 'Email payment receipt to the client',
|
||||||
|
'created_payment_emailed_client' => 'Successfully created payment and emailed client',
|
||||||
|
'add_account' => 'Add Account',
|
||||||
|
'untitled' => 'Untitled',
|
||||||
|
'new_account' => 'New Account',
|
||||||
|
'associated_accounts' => 'Successfully linked accounts',
|
||||||
|
'unlinked_account' => 'Successfully unlinked accounts',
|
||||||
|
'login' => 'Login',
|
||||||
|
'or' => 'or',
|
||||||
|
|
||||||
|
'email_error' => 'There was a problem sending the email',
|
||||||
|
'created_by_recurring' => 'Created by recurring invoice :invoice',
|
||||||
|
'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.',
|
||||||
|
'old_browser' => 'Please use a <a href="'.OUTDATE_BROWSER_URL.'" target="_blank">newer browser</a>',
|
||||||
|
'payment_terms_help' => 'Sets the default invoice due date',
|
||||||
|
'unlink_account' => 'Unlink Account',
|
||||||
|
'unlink' => 'Unlink',
|
||||||
|
'show_address' => 'Show Address',
|
||||||
|
'show_address_help' => 'Require client to provide their billing address',
|
||||||
|
'update_address' => 'Update Address',
|
||||||
|
'update_address_help' => 'Update client\'s address with provided details',
|
||||||
|
'times' => 'Times',
|
||||||
|
'set_now' => 'Set now',
|
||||||
|
'dark_mode' => 'Dark Mode',
|
||||||
|
'dark_mode_help' => 'Show white text on black background',
|
||||||
|
'add_to_invoice' => 'Add to invoice :invoice',
|
||||||
|
'create_new_invoice' => 'Create new invoice',
|
||||||
|
'task_errors' => 'Please correct any overlapping times',
|
||||||
|
'from' => 'From',
|
||||||
|
'to' => 'To',
|
||||||
|
'font_size' => 'Font Size',
|
||||||
|
'primary_color' => 'Primary Color',
|
||||||
|
'secondary_color' => 'Secondary Color',
|
||||||
|
'customize_design' => 'Customize Design',
|
||||||
|
|
||||||
|
'content' => 'Content',
|
||||||
|
'styles' => 'Styles',
|
||||||
|
'defaults' => 'Defaults',
|
||||||
|
'margins' => 'Margins',
|
||||||
|
'header' => 'Header',
|
||||||
|
'footer' => 'Footer',
|
||||||
|
'custom' => 'Custom',
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
);
|
);
|
||||||
|
@ -14,9 +14,12 @@
|
|||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
|
|
||||||
@if ($accountGateway)
|
@if ($accountGateway)
|
||||||
{!! Former::populateField('payment_type_id', $paymentTypeId) !!}
|
|
||||||
{!! Former::populateField('gateway_id', $accountGateway->gateway_id) !!}
|
{!! Former::populateField('gateway_id', $accountGateway->gateway_id) !!}
|
||||||
{!! Former::populateField('recommendedGateway_id', $accountGateway->gateway_id) !!}
|
{!! Former::populateField('payment_type_id', $paymentTypeId) !!}
|
||||||
|
{!! Former::populateField('recommendedGateway_id', $accountGateway->gateway_id) !!}
|
||||||
|
{!! Former::populateField('show_address', intval($accountGateway->show_address)) !!}
|
||||||
|
{!! Former::populateField('update_address', intval($accountGateway->update_address)) !!}
|
||||||
|
|
||||||
@if ($config)
|
@if ($config)
|
||||||
@foreach ($accountGateway->fields as $field => $junk)
|
@foreach ($accountGateway->fields as $field => $junk)
|
||||||
@if (in_array($field, $hiddenFields))
|
@if (in_array($field, $hiddenFields))
|
||||||
@ -28,6 +31,8 @@
|
|||||||
@endif
|
@endif
|
||||||
@else
|
@else
|
||||||
{!! Former::populateField('gateway_id', GATEWAY_STRIPE) !!}
|
{!! Former::populateField('gateway_id', GATEWAY_STRIPE) !!}
|
||||||
|
{!! Former::populateField('show_address', 1) !!}
|
||||||
|
{!! Former::populateField('update_address', 1) !!}
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
{!! Former::select('payment_type_id')
|
{!! Former::select('payment_type_id')
|
||||||
@ -77,6 +82,15 @@
|
|||||||
|
|
||||||
@endforeach
|
@endforeach
|
||||||
|
|
||||||
|
{!! Former::checkbox('show_address')
|
||||||
|
->label(trans('texts.billing_address'))
|
||||||
|
->text(trans('texts.show_address_help'))
|
||||||
|
->addGroupClass('gateway-option') !!}
|
||||||
|
{!! Former::checkbox('update_address')
|
||||||
|
->label(' ')
|
||||||
|
->text(trans('texts.update_address_help'))
|
||||||
|
->addGroupClass('gateway-option') !!}
|
||||||
|
|
||||||
{!! Former::checkboxes('creditCardTypes[]')
|
{!! Former::checkboxes('creditCardTypes[]')
|
||||||
->label('Accepted Credit Cards')
|
->label('Accepted Credit Cards')
|
||||||
->checkboxes($creditCardTypes)
|
->checkboxes($creditCardTypes)
|
||||||
@ -131,11 +145,25 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function enableUpdateAddress(event) {
|
||||||
|
var disabled = !$('#show_address').is(':checked');
|
||||||
|
$('#update_address').prop('disabled', disabled);
|
||||||
|
$('label[for=update_address]').css('color', disabled ? '#888' : '#000');
|
||||||
|
if (disabled) {
|
||||||
|
$('#update_address').prop('checked', false);
|
||||||
|
} else if (event) {
|
||||||
|
$('#update_address').prop('checked', true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$(function() {
|
$(function() {
|
||||||
setPaymentType();
|
setPaymentType();
|
||||||
@if ($accountGateway)
|
@if ($accountGateway)
|
||||||
$('.payment-type-option').hide();
|
$('.payment-type-option').hide();
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
|
$('#show_address').change(enableUpdateAddress);
|
||||||
|
enableUpdateAddress();
|
||||||
})
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
183
resources/views/accounts/customize_design.blade.php
Normal file
183
resources/views/accounts/customize_design.blade.php
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
@extends('accounts.nav')
|
||||||
|
|
||||||
|
@section('head')
|
||||||
|
@parent
|
||||||
|
|
||||||
|
<script src="{{ asset('js/pdf_viewer.js') }}" type="text/javascript"></script>
|
||||||
|
<script src="{{ asset('js/compatibility.js') }}" type="text/javascript"></script>
|
||||||
|
|
||||||
|
<link href="{{ asset('css/jsoneditor.min.css') }}" rel="stylesheet" type="text/css">
|
||||||
|
<script src="{{ asset('js/jsoneditor.min.js') }}" type="text/javascript"></script>
|
||||||
|
|
||||||
|
<script src="{{ asset('js/pdfmake.min.js') }}" type="text/javascript"></script>
|
||||||
|
<script src="{{ asset('js/vfs_fonts.js') }}" type="text/javascript"></script>
|
||||||
|
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
select.form-control {
|
||||||
|
background: #FFFFFF !important;
|
||||||
|
margin-right: 12px;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
background: #FFFFFF !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
@stop
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
@parent
|
||||||
|
@include('accounts.nav_advanced')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var invoiceDesigns = {!! $invoiceDesigns !!};
|
||||||
|
var invoice = {!! json_encode($invoice) !!};
|
||||||
|
var sections = ['content', 'styles', 'defaultStyle', 'pageMargins', 'header', 'footer'];
|
||||||
|
var customDesign = origCustomDesign = {!! $customDesign ?: 'JSON.parse(invoiceDesigns[0].javascript);' !!};
|
||||||
|
|
||||||
|
function getPDFString(cb, force) {
|
||||||
|
invoice.is_pro = {!! Auth::user()->isPro() ? 'true' : 'false' !!};
|
||||||
|
invoice.account.hide_quantity = {!! Auth::user()->account->hide_quantity ? 'true' : 'false' !!};
|
||||||
|
invoice.account.hide_paid_to_date = {!! Auth::user()->account->hide_paid_to_date ? 'true' : 'false' !!};
|
||||||
|
invoice.invoice_design_id = {!! Auth::user()->account->invoice_design_id !!};
|
||||||
|
|
||||||
|
NINJA.primaryColor = '{!! Auth::user()->account->primary_color !!}';
|
||||||
|
NINJA.secondaryColor = '{!! Auth::user()->account->secondary_color !!}';
|
||||||
|
NINJA.fontSize = {!! Auth::user()->account->font_size !!};
|
||||||
|
|
||||||
|
generatePDF(invoice, getDesignJavascript(), force, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDesignJavascript() {
|
||||||
|
var id = $('#invoice_design_id').val();
|
||||||
|
if (id == '-1') {
|
||||||
|
showMoreDesigns();
|
||||||
|
$('#invoice_design_id').val(1);
|
||||||
|
return invoiceDesigns[0].javascript;
|
||||||
|
} else if (customDesign) {
|
||||||
|
return JSON.stringify(customDesign);
|
||||||
|
} else {
|
||||||
|
return invoiceDesigns[0].javascript;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadEditor(section)
|
||||||
|
{
|
||||||
|
editorSection = section;
|
||||||
|
editor.set(customDesign[section]);
|
||||||
|
|
||||||
|
// the function throws an error if the editor is in code view
|
||||||
|
try {
|
||||||
|
editor.expandAll();
|
||||||
|
} catch(err) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveEditor(data)
|
||||||
|
{
|
||||||
|
setTimeout(function() {
|
||||||
|
customDesign[editorSection] = editor.get();
|
||||||
|
refreshPDF();
|
||||||
|
}, 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSelectChange()
|
||||||
|
{
|
||||||
|
var id = $('#invoice_design_id').val();
|
||||||
|
if (parseInt(id)) {
|
||||||
|
var design = _.find(invoiceDesigns, function(design){ return design.id == id});
|
||||||
|
customDesign = JSON.parse(design.javascript);
|
||||||
|
} else {
|
||||||
|
customDesign = origCustomDesign;
|
||||||
|
}
|
||||||
|
|
||||||
|
loadEditor(editorSection);
|
||||||
|
refreshPDF(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function submitForm()
|
||||||
|
{
|
||||||
|
$('#custom_design').val(JSON.stringify(customDesign));
|
||||||
|
$('form.warn-on-exit').submit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
refreshPDF(true);
|
||||||
|
|
||||||
|
var container = document.getElementById("jsoneditor");
|
||||||
|
var options = {
|
||||||
|
mode: 'form',
|
||||||
|
modes: ['form', 'code'],
|
||||||
|
change: function() {
|
||||||
|
saveEditor();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
window.editor = new JSONEditor(container, options);
|
||||||
|
loadEditor('content');
|
||||||
|
|
||||||
|
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
|
||||||
|
var target = $(e.target).attr("href") // activated tab
|
||||||
|
target = target.substring(1); // strip leading #
|
||||||
|
loadEditor(target);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
|
||||||
|
{!! Former::open()->addClass('warn-on-exit') !!}
|
||||||
|
{!! Former::populateField('invoice_design_id', $account->invoice_design_id) !!}
|
||||||
|
|
||||||
|
<div style="display:none">
|
||||||
|
{!! Former::text('custom_design') !!}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div role="tabpanel">
|
||||||
|
<ul class="nav nav-tabs" role="tablist" style="border: none">
|
||||||
|
<li role="presentation" class="active"><a href="#content" aria-controls="content" role="tab" data-toggle="tab">{{ trans('texts.content') }}</a></li>
|
||||||
|
<li role="presentation"><a href="#styles" aria-controls="styles" role="tab" data-toggle="tab">{{ trans('texts.styles') }}</a></li>
|
||||||
|
<li role="presentation"><a href="#defaultStyle" aria-controls="defaultStyle" role="tab" data-toggle="tab">{{ trans('texts.defaults') }}</a></li>
|
||||||
|
<li role="presentation"><a href="#pageMargins" aria-controls="margins" role="tab" data-toggle="tab">{{ trans('texts.margins') }}</a></li>
|
||||||
|
<li role="presentation"><a href="#header" aria-controls="header" role="tab" data-toggle="tab">{{ trans('texts.header') }}</a></li>
|
||||||
|
<li role="presentation"><a href="#footer" aria-controls="footer" role="tab" data-toggle="tab">{{ trans('texts.footer') }}</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div id="jsoneditor" style="width: 550px; height: 743px;"></div>
|
||||||
|
<p> </p>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
{!! Former::select('invoice_design_id')->style('display:inline;width:120px')->fromQuery($invoiceDesigns, 'name', 'id')->onchange('onSelectChange()')->raw() !!}
|
||||||
|
<div class="pull-right">
|
||||||
|
{!! Button::normal(trans('texts.documentation'))->asLinkTo(PDFMAKE_DOCS)->withAttributes(['target' => '_blank'])->appendIcon(Icon::create('info-sign')) !!}
|
||||||
|
{!! Button::normal(trans('texts.cancel'))->asLinkTo(URL::to('/company/advanced_settings/invoice_design'))->appendIcon(Icon::create('remove-circle')) !!}
|
||||||
|
@if (Auth::user()->isPro())
|
||||||
|
{!! Button::success(trans('texts.save'))->withAttributes(['onclick' => 'submitForm()'])->appendIcon(Icon::create('floppy-disk')) !!}
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if (!Auth::user()->isPro())
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
$('form.warn-on-exit input').prop('disabled', true);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
{!! Former::close() !!}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
|
||||||
|
@include('invoices.pdf', ['account' => Auth::user()->account, 'pdfHeight' => 800])
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@stop
|
@ -22,6 +22,9 @@
|
|||||||
{{ Former::populateField('last_name', $account->users()->first()->last_name) }}
|
{{ Former::populateField('last_name', $account->users()->first()->last_name) }}
|
||||||
{{ Former::populateField('email', $account->users()->first()->email) }}
|
{{ Former::populateField('email', $account->users()->first()->email) }}
|
||||||
{{ Former::populateField('phone', $account->users()->first()->phone) }}
|
{{ Former::populateField('phone', $account->users()->first()->phone) }}
|
||||||
|
@if (Utils::isNinja())
|
||||||
|
{{ Former::populateField('dark_mode', intval($account->users()->first()->dark_mode)) }}
|
||||||
|
@endif
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@ -88,6 +91,10 @@
|
|||||||
{!! Former::text('last_name') !!}
|
{!! Former::text('last_name') !!}
|
||||||
{!! Former::text('email') !!}
|
{!! Former::text('email') !!}
|
||||||
{!! Former::text('phone') !!}
|
{!! Former::text('phone') !!}
|
||||||
|
@if (Utils::isNinja())
|
||||||
|
{!! Former::checkbox('dark_mode')->text(trans('texts.dark_mode_help')) !!}
|
||||||
|
@endif
|
||||||
|
|
||||||
@if (Auth::user()->confirmed)
|
@if (Auth::user()->confirmed)
|
||||||
{!! Former::actions( Button::primary(trans('texts.change_password'))->small()->withAttributes(['onclick'=>'showChangePassword()'])) !!}
|
{!! Former::actions( Button::primary(trans('texts.change_password'))->small()->withAttributes(['onclick'=>'showChangePassword()'])) !!}
|
||||||
@elseif (Auth::user()->registered)
|
@elseif (Auth::user()->registered)
|
||||||
|
@ -111,20 +111,10 @@
|
|||||||
vals = [{!! json_encode($emailFooter) !!}, '{!! Auth::user()->account->getDisplayName() !!}', 'Client Name', formatMoney(100), '{!! NINJA_WEB_URL !!}', 'Contact Name'];
|
vals = [{!! json_encode($emailFooter) !!}, '{!! Auth::user()->account->getDisplayName() !!}', 'Client Name', formatMoney(100), '{!! NINJA_WEB_URL !!}', 'Contact Name'];
|
||||||
|
|
||||||
// Add any available payment method links
|
// Add any available payment method links
|
||||||
<?php
|
@foreach (\App\Models\Gateway::getPaymentTypeLinks() as $type)
|
||||||
foreach([PAYMENT_TYPE_CREDIT_CARD, PAYMENT_TYPE_PAYPAL, PAYMENT_TYPE_BITCOIN] as $type) {
|
{!! "keys.push('" . $type.'_link' . "');" !!}
|
||||||
if (Auth::user()->account->getGatewayByType($type)) {
|
{!! "vals.push('" . URL::to("/payment/xxxxxx/{$type}") . "');" !!}
|
||||||
|
@endforeach
|
||||||
// Changes "PAYMENT_TYPE_CREDIT_CARD" to "credit_card"
|
|
||||||
$gateway_slug = strtolower(str_replace('PAYMENT_TYPE_', '', $type)).'_link';
|
|
||||||
|
|
||||||
echo "keys.push('$gateway_slug'); ";
|
|
||||||
echo "vals.push('".URL::to("/payment/xxxxxx/{$type}")."'); ";
|
|
||||||
echo "\n";
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
|
|
||||||
for (var i=0; i<keys.length; i++) {
|
for (var i=0; i<keys.length; i++) {
|
||||||
var regExp = new RegExp('\\$'+keys[i], 'g');
|
var regExp = new RegExp('\\$'+keys[i], 'g');
|
||||||
|
@ -27,8 +27,9 @@
|
|||||||
showMoreDesigns();
|
showMoreDesigns();
|
||||||
$('#invoice_design_id').val(1);
|
$('#invoice_design_id').val(1);
|
||||||
return invoiceDesigns[0].javascript;
|
return invoiceDesigns[0].javascript;
|
||||||
} else {
|
} else {
|
||||||
return invoiceDesigns[id-1].javascript;
|
var design = _.find(invoiceDesigns, function(design){ return design.id == id});
|
||||||
|
return design ? design.javascript : '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,8 +56,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
doc = generatePDF(invoice, getDesignJavascript(), true);
|
generatePDF(invoice, getDesignJavascript(), true, cb);
|
||||||
doc.getDataUrl(cb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$(function() {
|
$(function() {
|
||||||
@ -96,7 +96,7 @@
|
|||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
|
|
||||||
|
|
||||||
@if (!Utils::isPro() || \App\Models\InvoiceDesign::count() == COUNT_FREE_DESIGNS)
|
@if (!Utils::isPro() || \App\Models\InvoiceDesign::count() == COUNT_FREE_DESIGNS_SELF_HOST)
|
||||||
{!! Former::select('invoice_design_id')->style('display:inline;width:120px')->fromQuery($invoiceDesigns, 'name', 'id')->addOption(trans('texts.more_designs') . '...', '-1') !!}
|
{!! Former::select('invoice_design_id')->style('display:inline;width:120px')->fromQuery($invoiceDesigns, 'name', 'id')->addOption(trans('texts.more_designs') . '...', '-1') !!}
|
||||||
@else
|
@else
|
||||||
{!! Former::select('invoice_design_id')->style('display:inline;width:120px')->fromQuery($invoiceDesigns, 'name', 'id') !!}
|
{!! Former::select('invoice_design_id')->style('display:inline;width:120px')->fromQuery($invoiceDesigns, 'name', 'id') !!}
|
||||||
@ -109,6 +109,10 @@
|
|||||||
{!! Former::text('primary_color') !!}
|
{!! Former::text('primary_color') !!}
|
||||||
{!! Former::text('secondary_color') !!}
|
{!! Former::text('secondary_color') !!}
|
||||||
|
|
||||||
|
{!! Former::actions(
|
||||||
|
Button::primary(trans('texts.customize_design'))->small()->asLinkTo(URL::to('/company/advanced_settings/customize_design'))
|
||||||
|
) !!}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -23,8 +23,7 @@
|
|||||||
{{ Former::populateField('custom_invoice_taxes2', intval($account->custom_invoice_taxes2)) }}
|
{{ Former::populateField('custom_invoice_taxes2', intval($account->custom_invoice_taxes2)) }}
|
||||||
{{ Former::populateField('share_counter', intval($account->share_counter)) }}
|
{{ Former::populateField('share_counter', intval($account->share_counter)) }}
|
||||||
{{ Former::populateField('pdf_email_attachment', intval($account->pdf_email_attachment)) }}
|
{{ Former::populateField('pdf_email_attachment', intval($account->pdf_email_attachment)) }}
|
||||||
{{ Former::populateField('utf8_invoices', intval($account->utf8_invoices)) }}
|
{{ Former::populateField('utf8_invoices', intval($account->utf8_invoices)) }}
|
||||||
{{ Former::populateField('auto_wrap', intval($account->auto_wrap)) }}
|
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
@ -99,9 +98,6 @@
|
|||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
{!! Former::checkbox('pdf_email_attachment')->text(trans('texts.enable')) !!}
|
{!! Former::checkbox('pdf_email_attachment')->text(trans('texts.enable')) !!}
|
||||||
{!! Former::checkbox('utf8_invoices')->text(trans('texts.enable')) !!}
|
{!! Former::checkbox('utf8_invoices')->text(trans('texts.enable')) !!}
|
||||||
<div style="display:none">
|
|
||||||
{!! Former::checkbox('auto_wrap')->text(trans('texts.enable')) !!}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
{!! HTML::nav_link('company/products', 'product_library') !!}
|
{!! HTML::nav_link('company/products', 'product_library') !!}
|
||||||
{!! HTML::nav_link('company/notifications', 'notifications') !!}
|
{!! HTML::nav_link('company/notifications', 'notifications') !!}
|
||||||
{!! HTML::nav_link('company/import_export', 'import_export', 'company/import_map') !!}
|
{!! HTML::nav_link('company/import_export', 'import_export', 'company/import_map') !!}
|
||||||
{!! HTML::nav_link('company/advanced_settings/invoice_settings', 'advanced_settings', '*/advanced_settings/*') !!}
|
{!! HTML::nav_link('company/advanced_settings/invoice_design', 'advanced_settings', '*/advanced_settings/*') !!}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<ul class="nav nav-tabs nav nav-justified">
|
<ul class="nav nav-tabs nav nav-justified">
|
||||||
{!! HTML::nav_link('company/advanced_settings/invoice_settings', 'invoice_settings') !!}
|
|
||||||
{!! HTML::nav_link('company/advanced_settings/invoice_design', 'invoice_design') !!}
|
{!! HTML::nav_link('company/advanced_settings/invoice_design', 'invoice_design') !!}
|
||||||
|
{!! HTML::nav_link('company/advanced_settings/invoice_settings', 'invoice_settings') !!}
|
||||||
{!! HTML::nav_link('company/advanced_settings/email_templates', 'email_templates') !!}
|
{!! HTML::nav_link('company/advanced_settings/email_templates', 'email_templates') !!}
|
||||||
{!! HTML::nav_link('company/advanced_settings/charts_and_reports', 'charts_and_reports') !!}
|
{!! HTML::nav_link('company/advanced_settings/charts_and_reports', 'charts_and_reports') !!}
|
||||||
{!! HTML::nav_link('company/advanced_settings/user_management', 'users_and_tokens') !!}
|
{!! HTML::nav_link('company/advanced_settings/user_management', 'users_and_tokens') !!}
|
||||||
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
@if (!Auth::user()->account->isPro())
|
@if (!Auth::user()->account->isPro())
|
||||||
<center>
|
<center>
|
||||||
<div style="font-size:larger;" class="col-md-8 col-md-offset-2">{!! trans('texts.pro_plan_advanced_settings', ['link'=>'<a href="#" onclick="submitProPlan(\''.$feature.'\')">'.trans('texts.pro_plan.remove_logo_link').'</a>']) !!}</div>
|
<div style="font-size:larger;" class="col-md-8 col-md-offset-2">{!! trans('texts.pro_plan_advanced_settings', ['link'=>'<a href="#" onclick="showProPlan(\''.$feature.'\')">'.trans('texts.pro_plan.remove_logo_link').'</a>']) !!}</div>
|
||||||
<p/>
|
<p/>
|
||||||
</center>
|
</center>
|
||||||
@endif
|
@endif
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
@parent
|
@parent
|
||||||
|
|
||||||
{!! Former::open($url)->method($method)
|
{!! Former::open($url)->method($method)
|
||||||
->rules(['product_key' => 'required|max:20'])
|
->rules(['product_key' => 'required|max:255'])
|
||||||
->addClass('col-md-8 col-md-offset-2 warn-on-exit') !!}
|
->addClass('col-md-8 col-md-offset-2 warn-on-exit') !!}
|
||||||
|
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user