mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-08 20:22:42 +01:00
merging
This commit is contained in:
commit
7cdbb56284
@ -20,6 +20,6 @@ MAIL_FROM_ADDRESS
|
||||
MAIL_FROM_NAME
|
||||
MAIL_PASSWORD
|
||||
|
||||
#PHANTOMJS_CLOUD_KEY='a-demo-key-with-low-quota-per-ip-address'
|
||||
PHANTOMJS_CLOUD_KEY='a-demo-key-with-low-quota-per-ip-address'
|
||||
|
||||
LOG=single
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -14,7 +14,7 @@
|
||||
/vendor
|
||||
/node_modules
|
||||
/.DS_Store
|
||||
/Thumbs.db
|
||||
Thumbs.db
|
||||
/.env
|
||||
/.env.development.php
|
||||
/.env.php
|
||||
|
10
Gruntfile.js
10
Gruntfile.js
@ -130,6 +130,16 @@ module.exports = function(grunt) {
|
||||
options: {
|
||||
process: false
|
||||
}
|
||||
},
|
||||
js_pdf: {
|
||||
src: [
|
||||
'public/js/pdf_viewer.js',
|
||||
'public/js/compatibility.js',
|
||||
'public/js/pdfmake.min.js',
|
||||
'public/js/vfs_fonts.js',
|
||||
],
|
||||
dest: 'public/js/pdf.built.js',
|
||||
nonull: true
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -235,7 +235,7 @@ class CheckData extends Command {
|
||||
'updated_at' => new Carbon,
|
||||
'account_id' => $client->account_id,
|
||||
'client_id' => $client->id,
|
||||
'message' => 'Recovered update to invoice [<a href="https://github.com/hillelcoren/invoice-ninja/releases/tag/v1.7.1" target="_blank">details</a>]',
|
||||
'message' => 'Corrected client balance',
|
||||
'adjustment' => $client->actual_balance - $activity->balance,
|
||||
'balance' => $client->actual_balance,
|
||||
]);
|
||||
|
@ -59,7 +59,7 @@ class CreateRandomData extends Command {
|
||||
}
|
||||
|
||||
$invoice = Invoice::createNew($user);
|
||||
$invoice->invoice_number = $user->account->getNextInvoiceNumber();
|
||||
$invoice->invoice_number = $user->account->getNextInvoiceNumber($invoice);
|
||||
$invoice->amount = $invoice->balance = $price;
|
||||
$invoice->created_at = date('Y-m-d', strtotime(date("Y-m-d") . ' - ' . rand(1, 100) . ' days'));
|
||||
$client->invoices()->save($invoice);
|
||||
|
@ -33,15 +33,22 @@ class SendRecurringInvoices extends Command
|
||||
$today = new DateTime();
|
||||
|
||||
$invoices = Invoice::with('account.timezone', 'invoice_items', 'client', 'user')
|
||||
->whereRaw('is_deleted IS FALSE AND deleted_at IS NULL AND is_recurring IS TRUE AND start_date <= ? AND (end_date IS NULL OR end_date >= ?)', array($today, $today))->get();
|
||||
->whereRaw('is_deleted IS FALSE AND deleted_at IS NULL AND is_recurring IS TRUE AND frequency_id > 0 AND start_date <= ? AND (end_date IS NULL OR end_date >= ?)', array($today, $today))
|
||||
->orderBy('id', 'asc')
|
||||
->get();
|
||||
$this->info(count($invoices).' recurring invoice(s) found');
|
||||
|
||||
foreach ($invoices as $recurInvoice) {
|
||||
if (!$recurInvoice->user->confirmed) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$recurInvoice->account->loadLocalizationSettings($recurInvoice->client);
|
||||
$this->info('Processing Invoice '.$recurInvoice->id.' - Should send '.($recurInvoice->shouldSendToday() ? 'YES' : 'NO'));
|
||||
$invoice = $this->invoiceRepo->createRecurringInvoice($recurInvoice);
|
||||
|
||||
if ($invoice && !$invoice->isPaid()) {
|
||||
$recurInvoice->account->loadLocalizationSettings($invoice->client);
|
||||
$this->info('Sending Invoice');
|
||||
$this->mailer->sendInvoice($invoice);
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,6 @@ use Cache;
|
||||
use Response;
|
||||
use parseCSV;
|
||||
use Request;
|
||||
|
||||
use App\Models\Affiliate;
|
||||
use App\Models\License;
|
||||
use App\Models\User;
|
||||
@ -37,6 +36,7 @@ use App\Models\Gateway;
|
||||
use App\Models\Timezone;
|
||||
use App\Models\Industry;
|
||||
use App\Models\InvoiceDesign;
|
||||
use App\Models\TaxRate;
|
||||
use App\Ninja\Repositories\AccountRepository;
|
||||
use App\Ninja\Mailers\UserMailer;
|
||||
use App\Ninja\Mailers\ContactMailer;
|
||||
@ -129,9 +129,9 @@ class AccountController extends BaseController
|
||||
Session::put("show_trash:{$entityType}", $visible == 'true');
|
||||
|
||||
if ($entityType == 'user') {
|
||||
return Redirect::to('company/'.ACCOUNT_ADVANCED_SETTINGS.'/'.ACCOUNT_USER_MANAGEMENT);
|
||||
return Redirect::to('settings/'.ACCOUNT_USER_MANAGEMENT);
|
||||
} elseif ($entityType == 'token') {
|
||||
return Redirect::to('company/'.ACCOUNT_ADVANCED_SETTINGS.'/'.ACCOUNT_TOKEN_MANAGEMENT);
|
||||
return Redirect::to('settings/'.ACCOUNT_API_TOKENS);
|
||||
} else {
|
||||
return Redirect::to("{$entityType}s");
|
||||
}
|
||||
@ -143,10 +143,80 @@ class AccountController extends BaseController
|
||||
return Response::json($data);
|
||||
}
|
||||
|
||||
public function showSection($section = ACCOUNT_DETAILS, $subSection = false)
|
||||
public function showSection($section = false)
|
||||
{
|
||||
if ($section == ACCOUNT_DETAILS) {
|
||||
if (!$section) {
|
||||
return Redirect::to('/settings/' . ACCOUNT_COMPANY_DETAILS, 301);
|
||||
}
|
||||
|
||||
if ($section == ACCOUNT_COMPANY_DETAILS) {
|
||||
return self::showCompanyDetails();
|
||||
} elseif ($section == ACCOUNT_USER_DETAILS) {
|
||||
return self::showUserDetails();
|
||||
} elseif ($section == ACCOUNT_LOCALIZATION) {
|
||||
return self::showLocalization();
|
||||
} elseif ($section == ACCOUNT_PAYMENTS) {
|
||||
return self::showOnlinePayments();
|
||||
} elseif ($section == ACCOUNT_INVOICE_SETTINGS) {
|
||||
return self::showInvoiceSettings();
|
||||
} elseif ($section == ACCOUNT_IMPORT_EXPORT) {
|
||||
return View::make('accounts.import_export', ['title' => trans('texts.import_export')]);
|
||||
} elseif ($section == ACCOUNT_INVOICE_DESIGN || $section == ACCOUNT_CUSTOMIZE_DESIGN) {
|
||||
return self::showInvoiceDesign($section);
|
||||
} elseif ($section === ACCOUNT_TEMPLATES_AND_REMINDERS) {
|
||||
return self::showTemplates();
|
||||
} elseif ($section === ACCOUNT_PRODUCTS) {
|
||||
return self::showProducts();
|
||||
} elseif ($section === ACCOUNT_TAX_RATES) {
|
||||
return self::showTaxRates();
|
||||
} else {
|
||||
$data = [
|
||||
'account' => Account::with('users')->findOrFail(Auth::user()->account_id),
|
||||
'title' => trans("texts.{$section}"),
|
||||
'section' => $section
|
||||
];
|
||||
return View::make("accounts.{$section}", $data);
|
||||
}
|
||||
}
|
||||
|
||||
private function showInvoiceSettings()
|
||||
{
|
||||
$account = Auth::user()->account;
|
||||
$recurringHours = [];
|
||||
|
||||
for ($i=0; $i<24; $i++) {
|
||||
if ($account->military_time) {
|
||||
$format = 'H:i';
|
||||
} else {
|
||||
$format = 'g:i a';
|
||||
}
|
||||
$recurringHours[$i] = date($format, strtotime("{$i}:00"));
|
||||
}
|
||||
|
||||
$data = [
|
||||
'account' => Account::with('users')->findOrFail(Auth::user()->account_id),
|
||||
'title' => trans("texts.invoice_settings"),
|
||||
'section' => ACCOUNT_INVOICE_SETTINGS,
|
||||
'recurringHours' => $recurringHours
|
||||
];
|
||||
return View::make("accounts.invoice_settings", $data);
|
||||
}
|
||||
|
||||
private function showCompanyDetails()
|
||||
{
|
||||
$data = [
|
||||
'account' => Account::with('users')->findOrFail(Auth::user()->account_id),
|
||||
'countries' => Cache::get('countries'),
|
||||
'sizes' => Cache::get('sizes'),
|
||||
'industries' => Cache::get('industries'),
|
||||
'title' => trans('texts.company_details'),
|
||||
];
|
||||
|
||||
return View::make('accounts.details', $data);
|
||||
}
|
||||
|
||||
private function showUserDetails()
|
||||
{
|
||||
$oauthLoginUrls = [];
|
||||
foreach (AuthService::$providers as $provider) {
|
||||
$oauthLoginUrls[] = ['label' => $provider, 'url' => '/auth/' . strtolower($provider)];
|
||||
@ -154,23 +224,32 @@ class AccountController extends BaseController
|
||||
|
||||
$data = [
|
||||
'account' => Account::with('users')->findOrFail(Auth::user()->account_id),
|
||||
'countries' => Cache::get('countries'),
|
||||
'sizes' => Cache::get('sizes'),
|
||||
'industries' => Cache::get('industries'),
|
||||
'timezones' => Cache::get('timezones'),
|
||||
'dateFormats' => Cache::get('dateFormats'),
|
||||
'datetimeFormats' => Cache::get('datetimeFormats'),
|
||||
'currencies' => Cache::get('currencies'),
|
||||
'languages' => Cache::get('languages'),
|
||||
'title' => trans('texts.company_details'),
|
||||
'title' => trans('texts.user_details'),
|
||||
'user' => Auth::user(),
|
||||
'oauthProviderName' => AuthService::getProviderName(Auth::user()->oauth_provider_id),
|
||||
'oauthLoginUrls' => $oauthLoginUrls,
|
||||
];
|
||||
|
||||
return View::make('accounts.details', $data);
|
||||
} elseif ($section == ACCOUNT_PAYMENTS) {
|
||||
return View::make('accounts.user_details', $data);
|
||||
}
|
||||
|
||||
private function showLocalization()
|
||||
{
|
||||
$data = [
|
||||
'account' => Account::with('users')->findOrFail(Auth::user()->account_id),
|
||||
'timezones' => Cache::get('timezones'),
|
||||
'dateFormats' => Cache::get('dateFormats'),
|
||||
'datetimeFormats' => Cache::get('datetimeFormats'),
|
||||
'currencies' => Cache::get('currencies'),
|
||||
'languages' => Cache::get('languages'),
|
||||
'title' => trans('texts.localization'),
|
||||
];
|
||||
|
||||
return View::make('accounts.localization', $data);
|
||||
}
|
||||
|
||||
private function showOnlinePayments()
|
||||
{
|
||||
$account = Auth::user()->account;
|
||||
$account->load('account_gateways');
|
||||
$count = count($account->account_gateways);
|
||||
@ -183,25 +262,39 @@ class AccountController extends BaseController
|
||||
'title' => trans('texts.online_payments')
|
||||
]);
|
||||
}
|
||||
} elseif ($section == ACCOUNT_NOTIFICATIONS) {
|
||||
}
|
||||
|
||||
private function showProducts()
|
||||
{
|
||||
$columns = ['product', 'description', 'unit_cost'];
|
||||
if (Auth::user()->account->invoice_item_taxes) {
|
||||
$columns[] = 'tax_rate';
|
||||
}
|
||||
$columns[] = 'action';
|
||||
|
||||
$data = [
|
||||
'account' => Account::with('users')->findOrFail(Auth::user()->account_id),
|
||||
'title' => trans('texts.notifications'),
|
||||
'account' => Auth::user()->account,
|
||||
'title' => trans('texts.product_library'),
|
||||
'columns' => Utils::trans($columns),
|
||||
];
|
||||
|
||||
return View::make('accounts.notifications', $data);
|
||||
} elseif ($section == ACCOUNT_IMPORT_EXPORT) {
|
||||
return View::make('accounts.import_export', ['title' => trans('texts.import_export')]);
|
||||
} elseif ($section == ACCOUNT_ADVANCED_SETTINGS) {
|
||||
return View::make('accounts.products', $data);
|
||||
}
|
||||
|
||||
private function showTaxRates()
|
||||
{
|
||||
$data = [
|
||||
'account' => Auth::user()->account,
|
||||
'title' => trans('texts.tax_rates'),
|
||||
'taxRates' => TaxRate::scope()->get(['id', 'name', 'rate']),
|
||||
];
|
||||
|
||||
return View::make('accounts.tax_rates', $data);
|
||||
}
|
||||
|
||||
private function showInvoiceDesign($section)
|
||||
{
|
||||
$account = Auth::user()->account->load('country');
|
||||
$data = [
|
||||
'account' => $account,
|
||||
'feature' => $subSection,
|
||||
'title' => trans('texts.invoice_settings'),
|
||||
];
|
||||
|
||||
if ($subSection == ACCOUNT_INVOICE_DESIGN
|
||||
|| $subSection == ACCOUNT_CUSTOMIZE_DESIGN) {
|
||||
$invoice = new stdClass();
|
||||
$client = new stdClass();
|
||||
$contact = new stdClass();
|
||||
@ -215,7 +308,7 @@ class AccountController extends BaseController
|
||||
$client->work_phone = '';
|
||||
$client->work_email = '';
|
||||
|
||||
$invoice->invoice_number = $account->getNextInvoiceNumber();
|
||||
$invoice->invoice_number = '0000';
|
||||
$invoice->invoice_date = Utils::fromSqlDate(date('Y-m-d'));
|
||||
$invoice->account = json_decode($account->toJson());
|
||||
$invoice->amount = $invoice->balance = 100;
|
||||
@ -239,6 +332,7 @@ class AccountController extends BaseController
|
||||
$data['invoiceLabels'] = json_decode($account->invoice_labels) ?: [];
|
||||
$data['title'] = trans('texts.invoice_design');
|
||||
$data['invoiceDesigns'] = InvoiceDesign::getDesigns();
|
||||
$data['section'] = $section;
|
||||
|
||||
$design = false;
|
||||
foreach ($data['invoiceDesigns'] as $item) {
|
||||
@ -248,10 +342,16 @@ class AccountController extends BaseController
|
||||
}
|
||||
}
|
||||
|
||||
if ($subSection == ACCOUNT_CUSTOMIZE_DESIGN) {
|
||||
if ($section == ACCOUNT_CUSTOMIZE_DESIGN) {
|
||||
$data['customDesign'] = ($account->custom_design && !$design) ? $account->custom_design : $design;
|
||||
}
|
||||
} else if ($subSection == ACCOUNT_TEMPLATES_AND_REMINDERS) {
|
||||
return View::make("accounts.{$section}", $data);
|
||||
}
|
||||
|
||||
private function showTemplates()
|
||||
{
|
||||
$account = Auth::user()->account->load('country');
|
||||
$data['account'] = $account;
|
||||
$data['templates'] = [];
|
||||
$data['defaultTemplates'] = [];
|
||||
foreach ([ENTITY_INVOICE, ENTITY_QUOTE, ENTITY_PAYMENT, REMINDER1, REMINDER2, REMINDER3] as $type) {
|
||||
@ -266,45 +366,37 @@ class AccountController extends BaseController
|
||||
}
|
||||
$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.templates_and_reminders', $data);
|
||||
}
|
||||
|
||||
return View::make("accounts.{$subSection}", $data);
|
||||
} elseif ($section == ACCOUNT_PRODUCTS) {
|
||||
$data = [
|
||||
'account' => Auth::user()->account,
|
||||
'title' => trans('texts.product_library'),
|
||||
];
|
||||
|
||||
return View::make('accounts.products', $data);
|
||||
}
|
||||
}
|
||||
|
||||
public function doSection($section = ACCOUNT_DETAILS, $subSection = false)
|
||||
public function doSection($section = ACCOUNT_COMPANY_DETAILS)
|
||||
{
|
||||
if ($section == ACCOUNT_DETAILS) {
|
||||
if ($section === ACCOUNT_COMPANY_DETAILS) {
|
||||
return AccountController::saveDetails();
|
||||
} elseif ($section == ACCOUNT_IMPORT_EXPORT) {
|
||||
} elseif ($section === ACCOUNT_USER_DETAILS) {
|
||||
return AccountController::saveUserDetails();
|
||||
} elseif ($section === ACCOUNT_LOCALIZATION) {
|
||||
return AccountController::saveLocalization();
|
||||
} elseif ($section === ACCOUNT_IMPORT_EXPORT) {
|
||||
return AccountController::importFile();
|
||||
} elseif ($section == ACCOUNT_MAP) {
|
||||
} elseif ($section === ACCOUNT_MAP) {
|
||||
return AccountController::mapFile();
|
||||
} elseif ($section == ACCOUNT_NOTIFICATIONS) {
|
||||
} elseif ($section === ACCOUNT_NOTIFICATIONS) {
|
||||
return AccountController::saveNotifications();
|
||||
} elseif ($section == ACCOUNT_EXPORT) {
|
||||
} elseif ($section === ACCOUNT_EXPORT) {
|
||||
return AccountController::export();
|
||||
} elseif ($section == ACCOUNT_ADVANCED_SETTINGS) {
|
||||
if ($subSection == ACCOUNT_INVOICE_SETTINGS) {
|
||||
} elseif ($section === ACCOUNT_INVOICE_SETTINGS) {
|
||||
return AccountController::saveInvoiceSettings();
|
||||
} elseif ($subSection == ACCOUNT_INVOICE_DESIGN) {
|
||||
} elseif ($section === ACCOUNT_INVOICE_DESIGN) {
|
||||
return AccountController::saveInvoiceDesign();
|
||||
} elseif ($subSection == ACCOUNT_CUSTOMIZE_DESIGN) {
|
||||
} elseif ($section === ACCOUNT_CUSTOMIZE_DESIGN) {
|
||||
return AccountController::saveCustomizeDesign();
|
||||
} elseif ($subSection == ACCOUNT_TEMPLATES_AND_REMINDERS) {
|
||||
} elseif ($section === ACCOUNT_TEMPLATES_AND_REMINDERS) {
|
||||
return AccountController::saveEmailTemplates();
|
||||
}
|
||||
} elseif ($section == ACCOUNT_PRODUCTS) {
|
||||
} elseif ($section === ACCOUNT_PRODUCTS) {
|
||||
return AccountController::saveProducts();
|
||||
} elseif ($section === ACCOUNT_TAX_RATES) {
|
||||
return AccountController::saveTaxRates();
|
||||
}
|
||||
}
|
||||
|
||||
@ -318,7 +410,7 @@ class AccountController extends BaseController
|
||||
Session::flash('message', trans('texts.updated_settings'));
|
||||
}
|
||||
|
||||
return Redirect::to('company/advanced_settings/customize_design');
|
||||
return Redirect::to('settings/' . ACCOUNT_CUSTOMIZE_DESIGN);
|
||||
}
|
||||
|
||||
private function saveEmailTemplates()
|
||||
@ -351,7 +443,21 @@ class AccountController extends BaseController
|
||||
Session::flash('message', trans('texts.updated_settings'));
|
||||
}
|
||||
|
||||
return Redirect::to('company/advanced_settings/templates_and_reminders');
|
||||
return Redirect::to('settings/' . ACCOUNT_TEMPLATES_AND_REMINDERS);
|
||||
}
|
||||
|
||||
private function saveTaxRates()
|
||||
{
|
||||
$account = Auth::user()->account;
|
||||
|
||||
$account->invoice_taxes = Input::get('invoice_taxes') ? true : false;
|
||||
$account->invoice_item_taxes = Input::get('invoice_item_taxes') ? true : false;
|
||||
$account->show_item_taxes = Input::get('show_item_taxes') ? true : false;
|
||||
$account->default_tax_rate_id = Input::get('default_tax_rate_id');
|
||||
$account->save();
|
||||
|
||||
Session::flash('message', trans('texts.updated_settings'));
|
||||
return Redirect::to('settings/' . ACCOUNT_TAX_RATES);
|
||||
}
|
||||
|
||||
private function saveProducts()
|
||||
@ -363,14 +469,18 @@ class AccountController extends BaseController
|
||||
$account->save();
|
||||
|
||||
Session::flash('message', trans('texts.updated_settings'));
|
||||
return Redirect::to('company/products');
|
||||
return Redirect::to('settings/' . ACCOUNT_PRODUCTS);
|
||||
}
|
||||
|
||||
private function saveInvoiceSettings()
|
||||
{
|
||||
if (Auth::user()->account->isPro()) {
|
||||
|
||||
$rules = [];
|
||||
$rules = [
|
||||
'invoice_number_pattern' => 'has_counter',
|
||||
'quote_number_pattern' => 'has_counter',
|
||||
];
|
||||
|
||||
$user = Auth::user();
|
||||
$iframeURL = preg_replace('/[^a-zA-Z0-9_\-\:\/\.]/', '', substr(strtolower(Input::get('iframe_url')), 0, MAX_IFRAME_URL_LENGTH));
|
||||
$iframeURL = rtrim($iframeURL, "/");
|
||||
@ -386,7 +496,7 @@ class AccountController extends BaseController
|
||||
$validator = Validator::make(Input::all(), $rules);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return Redirect::to('company/details')
|
||||
return Redirect::to('settings/' . ACCOUNT_INVOICE_SETTINGS)
|
||||
->withErrors($validator)
|
||||
->withInput();
|
||||
} else {
|
||||
@ -406,22 +516,39 @@ class AccountController extends BaseController
|
||||
$account->custom_invoice_text_label1 = trim(Input::get('custom_invoice_text_label1'));
|
||||
$account->custom_invoice_text_label2 = trim(Input::get('custom_invoice_text_label2'));
|
||||
|
||||
$account->invoice_number_prefix = Input::get('invoice_number_prefix');
|
||||
$account->invoice_number_counter = Input::get('invoice_number_counter');
|
||||
$account->quote_number_prefix = Input::get('quote_number_prefix');
|
||||
$account->share_counter = Input::get('share_counter') ? true : false;
|
||||
|
||||
$account->pdf_email_attachment = Input::get('pdf_email_attachment') ? true : false;
|
||||
$account->auto_wrap = Input::get('auto_wrap') ? true : false;
|
||||
|
||||
if (Input::has('recurring_hour')) {
|
||||
$account->recurring_hour = Input::get('recurring_hour');
|
||||
}
|
||||
|
||||
if (!$account->share_counter) {
|
||||
$account->quote_number_counter = Input::get('quote_number_counter');
|
||||
}
|
||||
|
||||
if (Input::get('invoice_number_type') == 'prefix') {
|
||||
$account->invoice_number_prefix = trim(Input::get('invoice_number_prefix'));
|
||||
$account->invoice_number_pattern = null;
|
||||
} else {
|
||||
$account->invoice_number_pattern = trim(Input::get('invoice_number_pattern'));
|
||||
$account->invoice_number_prefix = null;
|
||||
}
|
||||
|
||||
if (Input::get('quote_number_type') == 'prefix') {
|
||||
$account->quote_number_prefix = trim(Input::get('quote_number_prefix'));
|
||||
$account->quote_number_pattern = null;
|
||||
} else {
|
||||
$account->quote_number_pattern = trim(Input::get('quote_number_pattern'));
|
||||
$account->quote_number_prefix = null;
|
||||
}
|
||||
|
||||
if (!$account->share_counter && $account->invoice_number_prefix == $account->quote_number_prefix) {
|
||||
Session::flash('error', trans('texts.invalid_counter'));
|
||||
|
||||
return Redirect::to('company/advanced_settings/invoice_settings')->withInput();
|
||||
return Redirect::to('settings/' . ACCOUNT_INVOICE_SETTINGS)->withInput();
|
||||
} else {
|
||||
$account->save();
|
||||
Session::flash('message', trans('texts.updated_settings'));
|
||||
@ -429,7 +556,7 @@ class AccountController extends BaseController
|
||||
}
|
||||
}
|
||||
|
||||
return Redirect::to('company/advanced_settings/invoice_settings');
|
||||
return Redirect::to('settings/' . ACCOUNT_INVOICE_SETTINGS);
|
||||
}
|
||||
|
||||
private function saveInvoiceDesign()
|
||||
@ -447,7 +574,7 @@ class AccountController extends BaseController
|
||||
}
|
||||
|
||||
$labels = [];
|
||||
foreach (['item', 'description', 'unit_cost', 'quantity'] as $field) {
|
||||
foreach (['item', 'description', 'unit_cost', 'quantity', 'line_total'] as $field) {
|
||||
$labels[$field] = trim(Input::get("labels_{$field}"));
|
||||
}
|
||||
$account->invoice_labels = json_encode($labels);
|
||||
@ -457,7 +584,7 @@ class AccountController extends BaseController
|
||||
Session::flash('message', trans('texts.updated_settings'));
|
||||
}
|
||||
|
||||
return Redirect::to('company/advanced_settings/invoice_design');
|
||||
return Redirect::to('settings/' . ACCOUNT_INVOICE_DESIGN);
|
||||
}
|
||||
|
||||
private function export()
|
||||
@ -568,7 +695,7 @@ class AccountController extends BaseController
|
||||
if ($file == null) {
|
||||
Session::flash('error', trans('texts.select_file'));
|
||||
|
||||
return Redirect::to('company/import_export');
|
||||
return Redirect::to('settings/' . ACCOUNT_IMPORT_EXPORT);
|
||||
}
|
||||
|
||||
$name = $file->getRealPath();
|
||||
@ -582,7 +709,7 @@ class AccountController extends BaseController
|
||||
$message = trans('texts.limit_clients', ['count' => Auth::user()->getMaxNumClients()]);
|
||||
Session::flash('error', $message);
|
||||
|
||||
return Redirect::to('company/import_export');
|
||||
return Redirect::to('settings/' . ACCOUNT_IMPORT_EXPORT);
|
||||
}
|
||||
|
||||
Session::put('data', $csv->data);
|
||||
@ -680,26 +807,20 @@ class AccountController extends BaseController
|
||||
|
||||
Session::flash('message', trans('texts.updated_settings'));
|
||||
|
||||
return Redirect::to('company/notifications');
|
||||
return Redirect::to('settings/' . ACCOUNT_NOTIFICATIONS);
|
||||
}
|
||||
|
||||
private function saveDetails()
|
||||
{
|
||||
$rules = array(
|
||||
'name' => 'required',
|
||||
'logo' => 'sometimes|max:1024|mimes:jpeg,gif,png',
|
||||
'logo' => 'sometimes|max:512|mimes:jpeg,gif,png',
|
||||
);
|
||||
|
||||
$user = Auth::user()->account->users()->orderBy('id')->first();
|
||||
|
||||
if (Auth::user()->id === $user->id) {
|
||||
$rules['email'] = 'email|required|unique:users,email,'.$user->id.',id';
|
||||
}
|
||||
|
||||
$validator = Validator::make(Input::all(), $rules);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return Redirect::to('company/details')
|
||||
return Redirect::to('settings/' . ACCOUNT_COMPANY_DETAILS)
|
||||
->withErrors($validator)
|
||||
->withInput();
|
||||
} else {
|
||||
@ -717,30 +838,8 @@ class AccountController extends BaseController
|
||||
$account->country_id = Input::get('country_id') ? Input::get('country_id') : null;
|
||||
$account->size_id = Input::get('size_id') ? Input::get('size_id') : null;
|
||||
$account->industry_id = Input::get('industry_id') ? Input::get('industry_id') : null;
|
||||
$account->timezone_id = Input::get('timezone_id') ? Input::get('timezone_id') : null;
|
||||
$account->date_format_id = Input::get('date_format_id') ? Input::get('date_format_id') : null;
|
||||
$account->datetime_format_id = Input::get('datetime_format_id') ? Input::get('datetime_format_id') : null;
|
||||
$account->currency_id = Input::get('currency_id') ? Input::get('currency_id') : 1; // US Dollar
|
||||
$account->language_id = Input::get('language_id') ? Input::get('language_id') : 1; // English
|
||||
$account->military_time = Input::get('military_time') ? true : false;
|
||||
$account->save();
|
||||
|
||||
$user = Auth::user();
|
||||
$user->first_name = trim(Input::get('first_name'));
|
||||
$user->last_name = trim(Input::get('last_name'));
|
||||
$user->username = trim(Input::get('email'));
|
||||
$user->email = trim(strtolower(Input::get('email')));
|
||||
$user->phone = trim(Input::get('phone'));
|
||||
if (Utils::isNinja()) {
|
||||
if (Input::get('referral_code') && !$user->referral_code) {
|
||||
$user->referral_code = $this->accountRepo->getReferralCode();
|
||||
}
|
||||
}
|
||||
if (Utils::isNinjaDev()) {
|
||||
$user->dark_mode = Input::get('dark_mode') ? true : false;
|
||||
}
|
||||
$user->save();
|
||||
|
||||
/* Logo image file */
|
||||
if ($file = Input::file('logo')) {
|
||||
$path = Input::file('logo')->getRealPath();
|
||||
@ -770,10 +869,61 @@ class AccountController extends BaseController
|
||||
Event::fire(new UserSettingsChanged());
|
||||
|
||||
Session::flash('message', trans('texts.updated_settings'));
|
||||
return Redirect::to('company/details');
|
||||
return Redirect::to('settings/' . ACCOUNT_COMPANY_DETAILS);
|
||||
}
|
||||
}
|
||||
|
||||
private function saveUserDetails()
|
||||
{
|
||||
$user = Auth::user();
|
||||
$rules = ['email' => 'email|required|unique:users,email,'.$user->id.',id'];
|
||||
$validator = Validator::make(Input::all(), $rules);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return Redirect::to('settings/' . ACCOUNT_USER_DETAILS)
|
||||
->withErrors($validator)
|
||||
->withInput();
|
||||
} else {
|
||||
$user->first_name = trim(Input::get('first_name'));
|
||||
$user->last_name = trim(Input::get('last_name'));
|
||||
$user->username = trim(Input::get('email'));
|
||||
$user->email = trim(strtolower(Input::get('email')));
|
||||
$user->phone = trim(Input::get('phone'));
|
||||
|
||||
if (Utils::isNinja()) {
|
||||
if (Input::get('referral_code') && !$user->referral_code) {
|
||||
$user->referral_code = $this->accountRepo->getReferralCode();
|
||||
}
|
||||
}
|
||||
if (Utils::isNinjaDev()) {
|
||||
$user->dark_mode = Input::get('dark_mode') ? true : false;
|
||||
}
|
||||
|
||||
$user->save();
|
||||
|
||||
Event::fire(new UserSettingsChanged());
|
||||
Session::flash('message', trans('texts.updated_settings'));
|
||||
return Redirect::to('settings/' . ACCOUNT_USER_DETAILS);
|
||||
}
|
||||
}
|
||||
|
||||
private function saveLocalization()
|
||||
{
|
||||
$account = Auth::user()->account;
|
||||
$account->timezone_id = Input::get('timezone_id') ? Input::get('timezone_id') : null;
|
||||
$account->date_format_id = Input::get('date_format_id') ? Input::get('date_format_id') : null;
|
||||
$account->datetime_format_id = Input::get('datetime_format_id') ? Input::get('datetime_format_id') : null;
|
||||
$account->currency_id = Input::get('currency_id') ? Input::get('currency_id') : 1; // US Dollar
|
||||
$account->language_id = Input::get('language_id') ? Input::get('language_id') : 1; // English
|
||||
$account->military_time = Input::get('military_time') ? true : false;
|
||||
$account->save();
|
||||
|
||||
Event::fire(new UserSettingsChanged());
|
||||
|
||||
Session::flash('message', trans('texts.updated_settings'));
|
||||
return Redirect::to('settings/' . ACCOUNT_LOCALIZATION);
|
||||
}
|
||||
|
||||
public function removeLogo()
|
||||
{
|
||||
File::delete('logo/'.Auth::user()->account->account_key.'.jpg');
|
||||
@ -781,7 +931,7 @@ class AccountController extends BaseController
|
||||
|
||||
Session::flash('message', trans('texts.removed_logo'));
|
||||
|
||||
return Redirect::to('company/details');
|
||||
return Redirect::to('settings/' . ACCOUNT_COMPANY_DETAILS);
|
||||
}
|
||||
|
||||
public function checkEmail()
|
||||
@ -864,7 +1014,10 @@ class AccountController extends BaseController
|
||||
$this->userMailer->sendTo(CONTACT_EMAIL, $email, $name, 'Invoice Ninja Feedback [Canceled Account]', 'contact', $data);
|
||||
}
|
||||
|
||||
$user = Auth::user();
|
||||
$account = Auth::user()->account;
|
||||
\Log::info("Canceled Account: {$account->name} - {$user->email}");
|
||||
|
||||
$this->accountRepo->unlinkAccount($account);
|
||||
$account->forceDelete();
|
||||
|
||||
@ -879,6 +1032,26 @@ class AccountController extends BaseController
|
||||
$user = Auth::user();
|
||||
$this->userMailer->sendConfirmation($user);
|
||||
|
||||
return Redirect::to('/company/details')->with('message', trans('texts.confirmation_resent'));
|
||||
return Redirect::to('/settings/' . ACCOUNT_COMPANY_DETAILS)->with('message', trans('texts.confirmation_resent'));
|
||||
}
|
||||
|
||||
public function redirectLegacy($section, $subSection = false)
|
||||
{
|
||||
if ($section === 'details') {
|
||||
$section = ACCOUNT_COMPANY_DETAILS;
|
||||
} elseif ($section === 'payments') {
|
||||
$section = ACCOUNT_PAYMENTS;
|
||||
} elseif ($section === 'advanced_settings') {
|
||||
$section = $subSection;
|
||||
if ($section === 'token_management') {
|
||||
$section = ACCOUNT_API_TOKENS;
|
||||
}
|
||||
}
|
||||
|
||||
if (!in_array($section, array_merge(Account::$basicSettings, Account::$advancedSettings))) {
|
||||
$section = ACCOUNT_COMPANY_DETAILS;
|
||||
}
|
||||
|
||||
return Redirect::to("/settings/$section/", 301);
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,11 @@ use App\Ninja\Repositories\AccountRepository;
|
||||
|
||||
class AccountGatewayController extends BaseController
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return Redirect::to('settings/' . ACCOUNT_PAYMENTS);
|
||||
}
|
||||
|
||||
public function getDatatable()
|
||||
{
|
||||
$query = DB::table('account_gateways')
|
||||
@ -159,7 +164,6 @@ class AccountGatewayController extends BaseController
|
||||
'gateways' => $gateways,
|
||||
'creditCardTypes' => $creditCards,
|
||||
'tokenBillingOptions' => $tokenBillingOptions,
|
||||
'showBreadcrumbs' => false,
|
||||
'countGateways' => count($currentGateways)
|
||||
];
|
||||
}
|
||||
@ -173,7 +177,7 @@ class AccountGatewayController extends BaseController
|
||||
|
||||
Session::flash('message', trans('texts.deleted_gateway'));
|
||||
|
||||
return Redirect::to('company/payments');
|
||||
return Redirect::to('settings/' . ACCOUNT_PAYMENTS);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -56,7 +56,7 @@ class AppController extends BaseController
|
||||
$test = Input::get('test');
|
||||
|
||||
$app = Input::get('app');
|
||||
$app['key'] = str_random(RANDOM_KEY_LENGTH);
|
||||
$app['key'] = env('APP_KEY') ?: str_random(RANDOM_KEY_LENGTH);
|
||||
|
||||
$database = Input::get('database');
|
||||
$dbType = $database['default'];
|
||||
@ -94,7 +94,7 @@ class AppController extends BaseController
|
||||
"MAIL_USERNAME={$mail['username']}\n".
|
||||
"MAIL_FROM_NAME={$mail['from']['name']}\n".
|
||||
"MAIL_PASSWORD={$mail['password']}\n\n".
|
||||
"#PHANTOMJS_CLOUD_KEY='a-demo-key-with-low-quota-per-ip-address'";
|
||||
"PHANTOMJS_CLOUD_KEY='a-demo-key-with-low-quota-per-ip-address'";
|
||||
|
||||
// Write Config Settings
|
||||
$fp = fopen(base_path()."/.env", 'w');
|
||||
|
@ -61,7 +61,7 @@ class AuthController extends Controller {
|
||||
$this->accountRepo->unlinkUserFromOauth(Auth::user());
|
||||
|
||||
Session::flash('message', trans('texts.updated_settings'));
|
||||
return redirect()->to('/company/details');
|
||||
return redirect()->to('/settings/' . ACCOUNT_USER_DETAILS);
|
||||
}
|
||||
|
||||
public function getLoginWrapper()
|
||||
@ -92,7 +92,7 @@ class AuthController extends Controller {
|
||||
// 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'));
|
||||
Session::flash('warning', trans('texts.associated_accounts'));
|
||||
// check if other accounts are linked
|
||||
} else {
|
||||
$users = $this->accountRepo->loadAccounts(Auth::user()->id);
|
||||
|
@ -258,6 +258,13 @@ class ClientController extends BaseController
|
||||
$client->payment_terms = Input::get('payment_terms') ?: 0;
|
||||
$client->website = trim(Input::get('website'));
|
||||
|
||||
if (Input::has('invoice_number_counter')) {
|
||||
$client->invoice_number_counter = (int) Input::get('invoice_number_counter');
|
||||
}
|
||||
if (Input::has('quote_number_counter')) {
|
||||
$client->invoice_number_counter = (int) Input::get('quote_number_counter');
|
||||
}
|
||||
|
||||
$client->save();
|
||||
|
||||
$data = json_decode(Input::get('data'));
|
||||
|
@ -59,16 +59,6 @@ class InvoiceApiController extends Controller
|
||||
$data = Input::all();
|
||||
$error = null;
|
||||
|
||||
// check if the invoice number is set and unique
|
||||
if (!isset($data['invoice_number']) && !isset($data['id'])) {
|
||||
$data['invoice_number'] = Auth::user()->account->getNextInvoiceNumber();
|
||||
} else if (isset($data['invoice_number'])) {
|
||||
$invoice = Invoice::scope()->where('invoice_number', '=', $data['invoice_number'])->first();
|
||||
if ($invoice) {
|
||||
$error = trans('validation.unique', ['attribute' => 'texts.invoice_number']);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($data['email'])) {
|
||||
$client = Client::scope()->whereHas('contacts', function($query) use ($data) {
|
||||
$query->where('email', '=', $data['email']);
|
||||
@ -95,6 +85,16 @@ class InvoiceApiController extends Controller
|
||||
$client = Client::scope($data['client_id'])->first();
|
||||
}
|
||||
|
||||
// check if the invoice number is set and unique
|
||||
if (!isset($data['invoice_number']) && !isset($data['id'])) {
|
||||
// do nothing... invoice number will be set automatically
|
||||
} else if (isset($data['invoice_number'])) {
|
||||
$invoice = Invoice::scope()->where('invoice_number', '=', $data['invoice_number'])->first();
|
||||
if ($invoice) {
|
||||
$error = trans('validation.unique', ['attribute' => 'texts.invoice_number']);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$error) {
|
||||
if (!isset($data['client_id']) && !isset($data['email'])) {
|
||||
$error = trans('validation.', ['attribute' => 'client_id or email']);
|
||||
|
@ -31,7 +31,6 @@ use App\Models\Gateway;
|
||||
use App\Ninja\Mailers\ContactMailer as Mailer;
|
||||
use App\Ninja\Repositories\InvoiceRepository;
|
||||
use App\Ninja\Repositories\ClientRepository;
|
||||
use App\Ninja\Repositories\TaxRateRepository;
|
||||
use App\Events\InvoiceViewed;
|
||||
|
||||
class InvoiceController extends BaseController
|
||||
@ -39,16 +38,14 @@ class InvoiceController extends BaseController
|
||||
protected $mailer;
|
||||
protected $invoiceRepo;
|
||||
protected $clientRepo;
|
||||
protected $taxRateRepo;
|
||||
|
||||
public function __construct(Mailer $mailer, InvoiceRepository $invoiceRepo, ClientRepository $clientRepo, TaxRateRepository $taxRateRepo)
|
||||
public function __construct(Mailer $mailer, InvoiceRepository $invoiceRepo, ClientRepository $clientRepo)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->mailer = $mailer;
|
||||
$this->invoiceRepo = $invoiceRepo;
|
||||
$this->clientRepo = $clientRepo;
|
||||
$this->taxRateRepo = $taxRateRepo;
|
||||
}
|
||||
|
||||
public function index()
|
||||
@ -131,13 +128,22 @@ class InvoiceController extends BaseController
|
||||
|
||||
public function view($invitationKey)
|
||||
{
|
||||
$invitation = $this->invoiceRepo->findInvoiceByInvitation($invitationKey);
|
||||
if (!$invitation = $this->invoiceRepo->findInvoiceByInvitation($invitationKey)) {
|
||||
return response()->view('error', [
|
||||
'error' => trans('texts.invoice_not_found'),
|
||||
'hideHeader' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
$invoice = $invitation->invoice;
|
||||
$client = $invoice->client;
|
||||
$account = $invoice->account;
|
||||
|
||||
if (!$account->checkSubdomain(Request::server('HTTP_HOST'))) {
|
||||
app()->abort(404, trans('texts.invoice_not_found'));
|
||||
return response()->view('error', [
|
||||
'error' => trans('texts.invoice_not_found'),
|
||||
'hideHeader' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
if (!Input::has('phantomjs') && !Session::has($invitationKey) && (!Auth::check() || Auth::user()->account_id != $invoice->account_id)) {
|
||||
@ -159,9 +165,7 @@ class InvoiceController extends BaseController
|
||||
} else {
|
||||
$invoice->invoice_design->javascript = $invoice->invoice_design->pdfmake;
|
||||
}
|
||||
|
||||
$contact = $invitation->contact;
|
||||
$contact->setVisible([
|
||||
$contact = $invitation->contact; $contact->setVisible([
|
||||
'first_name',
|
||||
'last_name',
|
||||
'email',
|
||||
@ -229,6 +233,7 @@ class InvoiceController extends BaseController
|
||||
|
||||
public function edit($publicId, $clone = false)
|
||||
{
|
||||
$account = Auth::user()->account;
|
||||
$invoice = Invoice::scope($publicId)->withTrashed()->with('invitations', 'account.country', 'client.contacts', 'client.country', 'invoice_items')->firstOrFail();
|
||||
$entityType = $invoice->getEntityType();
|
||||
|
||||
@ -241,7 +246,7 @@ class InvoiceController extends BaseController
|
||||
|
||||
if ($clone) {
|
||||
$invoice->id = null;
|
||||
$invoice->invoice_number = Auth::user()->account->getNextInvoiceNumber($invoice->is_quote);
|
||||
$invoice->invoice_number = $account->getNextInvoiceNumber($invoice);
|
||||
$invoice->balance = $invoice->amount;
|
||||
$invoice->invoice_status_id = 0;
|
||||
$invoice->invoice_date = date_create()->format('Y-m-d');
|
||||
@ -299,7 +304,6 @@ class InvoiceController extends BaseController
|
||||
'entityType' => $entityType,
|
||||
'showBreadcrumbs' => $clone,
|
||||
'invoice' => $invoice,
|
||||
'data' => false,
|
||||
'method' => $method,
|
||||
'invitationContactIds' => $contactIds,
|
||||
'url' => $url,
|
||||
@ -327,7 +331,7 @@ class InvoiceController extends BaseController
|
||||
if ($invitation->contact_id == $contact->id) {
|
||||
$contact->email_error = $invitation->email_error;
|
||||
$contact->invitation_link = $invitation->getLink();
|
||||
$contact->invitation_viewed = $invitation->viewed_date;
|
||||
$contact->invitation_viewed = $invitation->viewed_date && $invitation->viewed_date != '0000-00-00 00:00:00' ? $invitation->viewed_date : false;
|
||||
$contact->invitation_status = $contact->email_error ? false : $invitation->getStatus();
|
||||
}
|
||||
}
|
||||
@ -342,23 +346,21 @@ class InvoiceController extends BaseController
|
||||
|
||||
public function create($clientPublicId = 0, $isRecurring = false)
|
||||
{
|
||||
$client = null;
|
||||
$invoiceNumber = $isRecurring ? microtime(true) : Auth::user()->account->getNextInvoiceNumber();
|
||||
|
||||
$account = Auth::user()->account;
|
||||
$clientId = null;
|
||||
if ($clientPublicId) {
|
||||
$client = Client::scope($clientPublicId)->firstOrFail();
|
||||
$clientId = Client::getPrivateId($clientPublicId);
|
||||
}
|
||||
$entityType = $isRecurring ? ENTITY_RECURRING_INVOICE : ENTITY_INVOICE;
|
||||
$invoice = $account->createInvoice($entityType, $clientId);
|
||||
|
||||
$data = array(
|
||||
'entityType' => ENTITY_INVOICE,
|
||||
'invoice' => null,
|
||||
'data' => Input::old('data'),
|
||||
'invoiceNumber' => $invoiceNumber,
|
||||
$data = [
|
||||
'entityType' => $invoice->getEntityType(),
|
||||
'invoice' => $invoice,
|
||||
'method' => 'POST',
|
||||
'url' => 'invoices',
|
||||
'title' => trans('texts.new_invoice'),
|
||||
'isRecurring' => $isRecurring,
|
||||
'client' => $client);
|
||||
];
|
||||
$data = array_merge($data, self::getViewModel());
|
||||
|
||||
return View::make('invoices.edit', $data);
|
||||
@ -383,8 +385,9 @@ class InvoiceController extends BaseController
|
||||
}
|
||||
|
||||
return [
|
||||
'data' => Input::old('data'),
|
||||
'account' => Auth::user()->account->load('country'),
|
||||
'products' => Product::scope()->orderBy('id')->get(array('product_key', 'notes', 'cost', 'qty')),
|
||||
'products' => Product::scope()->with('default_tax_rate')->orderBy('id')->get(),
|
||||
'countries' => Cache::get('countries'),
|
||||
'clients' => Client::scope()->with('contacts', 'country')->orderBy('name')->get(),
|
||||
'taxRates' => TaxRate::scope()->orderBy('name')->get(),
|
||||
@ -432,9 +435,8 @@ class InvoiceController extends BaseController
|
||||
|
||||
if ($errors = $this->invoiceRepo->getErrors($input->invoice)) {
|
||||
Session::flash('error', trans('texts.invoice_error'));
|
||||
|
||||
return Redirect::to("{$entityType}s/create")
|
||||
->withInput()->withErrors($errors);
|
||||
$url = "{$entityType}s/" . ($publicId ?: 'create');
|
||||
return Redirect::to($url)->withInput()->withErrors($errors);
|
||||
} else {
|
||||
$invoice = $this->saveInvoice($publicId, $input, $entityType);
|
||||
$url = "{$entityType}s/".$invoice->public_id.'/edit';
|
||||
@ -443,8 +445,8 @@ class InvoiceController extends BaseController
|
||||
// check if we created a new client with the invoice
|
||||
if ($input->invoice->client->public_id == '-1') {
|
||||
$message = $message.' '.trans('texts.and_created_client');
|
||||
$url = URL::to('clients/'.$input->invoice->client->public_id);
|
||||
Utils::trackViewed($client->getDisplayName(), ENTITY_CLIENT, $url);
|
||||
$trackUrl = URL::to('clients/'.$invoice->client->public_id);
|
||||
Utils::trackViewed($invoice->client->getDisplayName(), ENTITY_CLIENT, $trackUrl);
|
||||
}
|
||||
|
||||
if ($action == 'clone') {
|
||||
@ -468,8 +470,7 @@ class InvoiceController extends BaseController
|
||||
if (!Auth::user()->confirmed) {
|
||||
$errorMessage = trans(Auth::user()->registered ? 'texts.confirmation_required' : 'texts.registration_required');
|
||||
Session::flash('error', $errorMessage);
|
||||
Session::flash('message', $message);
|
||||
return Redirect::to($url);
|
||||
return Redirect::to('invoices/'.$invoice->public_id.'/edit');
|
||||
}
|
||||
|
||||
if ($invoice->is_recurring) {
|
||||
@ -491,7 +492,13 @@ class InvoiceController extends BaseController
|
||||
private function emailRecurringInvoice(&$invoice)
|
||||
{
|
||||
if (!$invoice->shouldSendToday()) {
|
||||
return trans('texts.recurring_too_soon');
|
||||
if ($date = $invoice->getNextSendDate()) {
|
||||
$date = $invoice->account->formatDate($date);
|
||||
$date .= ' ' . DEFAULT_SEND_RECURRING_HOUR . ':00 am ' . $invoice->account->getTimezone();
|
||||
return trans('texts.recurring_too_soon', ['date' => $date]);
|
||||
} else {
|
||||
return trans('texts.no_longer_running');
|
||||
}
|
||||
}
|
||||
|
||||
// switch from the recurring invoice to the generated invoice
|
||||
@ -509,8 +516,6 @@ class InvoiceController extends BaseController
|
||||
{
|
||||
$invoice = $input->invoice;
|
||||
|
||||
$this->taxRateRepo->save($input->tax_rates);
|
||||
|
||||
$clientData = (array) $invoice->client;
|
||||
$client = $this->clientRepo->save($invoice->client->public_id, $clientData);
|
||||
|
||||
@ -518,18 +523,6 @@ class InvoiceController extends BaseController
|
||||
$invoiceData['client_id'] = $client->id;
|
||||
$invoice = $this->invoiceRepo->save($publicId, $invoiceData, $entityType);
|
||||
|
||||
$account = Auth::user()->account;
|
||||
if ($account->invoice_taxes != $input->invoice_taxes
|
||||
|| $account->invoice_item_taxes != $input->invoice_item_taxes
|
||||
|| $account->invoice_design_id != $input->invoice->invoice_design_id
|
||||
|| $account->show_item_taxes != $input->show_item_taxes) {
|
||||
$account->invoice_taxes = $input->invoice_taxes;
|
||||
$account->invoice_item_taxes = $input->invoice_item_taxes;
|
||||
$account->invoice_design_id = $input->invoice->invoice_design_id;
|
||||
$account->show_item_taxes = $input->show_item_taxes;
|
||||
$account->save();
|
||||
}
|
||||
|
||||
$client->load('contacts');
|
||||
$sendInvoiceIds = [];
|
||||
|
||||
|
@ -174,7 +174,8 @@ class PaymentController extends BaseController
|
||||
$acceptedCreditCardTypes = $accountGateway->getCreditcardTypes();
|
||||
|
||||
// Handle offsite payments
|
||||
if ($useToken || $paymentType != PAYMENT_TYPE_CREDIT_CARD || $gateway->id == GATEWAY_EWAY) {
|
||||
if ($useToken || $paymentType != PAYMENT_TYPE_CREDIT_CARD
|
||||
|| $gateway->id == GATEWAY_EWAY || $gateway->id == GATEWAY_TWO_CHECKOUT) {
|
||||
if (Session::has('error')) {
|
||||
Session::reflash();
|
||||
return Redirect::to('view/'.$invitationKey);
|
||||
@ -418,7 +419,7 @@ class PaymentController extends BaseController
|
||||
}
|
||||
|
||||
$gateway = $this->paymentService->createGateway($accountGateway);
|
||||
$details = $this->paymentService->getPaymentDetails($invitation, $data);
|
||||
$details = $this->paymentService->getPaymentDetails($invitation, $accountGateway, $data);
|
||||
|
||||
// check if we're creating/using a billing token
|
||||
if ($accountGateway->gateway_id == GATEWAY_STRIPE) {
|
||||
@ -439,7 +440,8 @@ class PaymentController extends BaseController
|
||||
|
||||
if ($accountGateway->gateway_id == GATEWAY_EWAY) {
|
||||
$ref = $response->getData()['AccessCode'];
|
||||
$token = $response->getCardReference();
|
||||
} elseif ($accountGateway->gateway_id == GATEWAY_TWO_CHECKOUT) {
|
||||
$ref = $response->getData()['cart_order_id'];
|
||||
} else {
|
||||
$ref = $response->getTransactionReference();
|
||||
}
|
||||
@ -467,7 +469,6 @@ class PaymentController extends BaseController
|
||||
} elseif ($response->isRedirect()) {
|
||||
$invitation->transaction_reference = $ref;
|
||||
$invitation->save();
|
||||
|
||||
Session::put('transaction_reference', $ref);
|
||||
Session::save();
|
||||
$response->redirect();
|
||||
@ -513,8 +514,8 @@ class PaymentController extends BaseController
|
||||
}
|
||||
|
||||
try {
|
||||
if (method_exists($gateway, 'completePurchase')) {
|
||||
$details = $this->paymentService->getPaymentDetails($invitation);
|
||||
if (method_exists($gateway, 'completePurchase') && !$accountGateway->isGateway(GATEWAY_TWO_CHECKOUT)) {
|
||||
$details = $this->paymentService->getPaymentDetails($invitation, $accountGateway);
|
||||
$response = $gateway->completePurchase($details)->send();
|
||||
$ref = $response->getTransactionReference();
|
||||
|
||||
|
@ -12,21 +12,38 @@ use Session;
|
||||
use Redirect;
|
||||
|
||||
use App\Models\Product;
|
||||
use App\Models\TaxRate;
|
||||
|
||||
class ProductController extends BaseController
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return Redirect::to('settings/' . ACCOUNT_PRODUCTS);
|
||||
}
|
||||
|
||||
public function getDatatable()
|
||||
{
|
||||
$account = Auth::user()->account;
|
||||
|
||||
$query = DB::table('products')
|
||||
->leftJoin('tax_rates', function($join){
|
||||
$join->on('tax_rates.id', '=', 'products.default_tax_rate_id')
|
||||
->whereNull('tax_rates.deleted_at');
|
||||
})
|
||||
->where('products.account_id', '=', Auth::user()->account_id)
|
||||
->where('products.deleted_at', '=', null)
|
||||
->select('products.public_id', 'products.product_key', 'products.notes', 'products.cost');
|
||||
->select('products.public_id', 'products.product_key', 'products.notes', 'products.cost', 'tax_rates.name as tax_name', 'tax_rates.rate as tax_rate');
|
||||
|
||||
return Datatable::query($query)
|
||||
$datatable = Datatable::query($query)
|
||||
->addColumn('product_key', function ($model) { return link_to('products/'.$model->public_id.'/edit', $model->product_key); })
|
||||
->addColumn('notes', function ($model) { return nl2br(Str::limit($model->notes, 100)); })
|
||||
->addColumn('cost', function ($model) { return Utils::formatMoney($model->cost); })
|
||||
->addColumn('dropdown', function ($model) {
|
||||
->addColumn('cost', function ($model) { return Utils::formatMoney($model->cost); });
|
||||
|
||||
if ($account->invoice_item_taxes) {
|
||||
$datatable->addColumn('tax_rate', function ($model) { return $model->tax_rate ? ($model->tax_name . ' ' . $model->tax_rate . '%') : ''; });
|
||||
}
|
||||
|
||||
return $datatable->addColumn('dropdown', function ($model) {
|
||||
return '<div class="btn-group tr-action" style="visibility:hidden;">
|
||||
<button type="button" class="btn btn-xs btn-default dropdown-toggle" data-toggle="dropdown">
|
||||
'.trans('texts.select').' <span class="caret"></span>
|
||||
@ -44,8 +61,11 @@ class ProductController extends BaseController
|
||||
|
||||
public function edit($publicId)
|
||||
{
|
||||
$account = Auth::user()->account;
|
||||
|
||||
$data = [
|
||||
'showBreadcrumbs' => false,
|
||||
'account' => $account,
|
||||
'taxRates' => $account->invoice_item_taxes ? TaxRate::scope()->get(['id', 'name', 'rate']) : null,
|
||||
'product' => Product::scope($publicId)->firstOrFail(),
|
||||
'method' => 'PUT',
|
||||
'url' => 'products/'.$publicId,
|
||||
@ -57,8 +77,11 @@ class ProductController extends BaseController
|
||||
|
||||
public function create()
|
||||
{
|
||||
$account = Auth::user()->account;
|
||||
|
||||
$data = [
|
||||
'showBreadcrumbs' => false,
|
||||
'account' => $account,
|
||||
'taxRates' => $account->invoice_item_taxes ? TaxRate::scope()->get(['id', 'name', 'rate']) : null,
|
||||
'product' => null,
|
||||
'method' => 'POST',
|
||||
'url' => 'products',
|
||||
@ -89,12 +112,14 @@ class ProductController extends BaseController
|
||||
$product->product_key = trim(Input::get('product_key'));
|
||||
$product->notes = trim(Input::get('notes'));
|
||||
$product->cost = trim(Input::get('cost'));
|
||||
$product->default_tax_rate_id = Input::get('default_tax_rate_id');
|
||||
|
||||
$product->save();
|
||||
|
||||
$message = $productPublicId ? trans('texts.updated_product') : trans('texts.created_product');
|
||||
Session::flash('message', $message);
|
||||
|
||||
return Redirect::to('company/products');
|
||||
return Redirect::to('settings/' . ACCOUNT_PRODUCTS);
|
||||
}
|
||||
|
||||
public function archive($publicId)
|
||||
@ -104,6 +129,6 @@ class ProductController extends BaseController
|
||||
|
||||
Session::flash('message', trans('texts.archived_product'));
|
||||
|
||||
return Redirect::to('company/products');
|
||||
return Redirect::to('settings/' . ACCOUNT_PRODUCTS);
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,9 @@ class PublicClientController extends BaseController
|
||||
|
||||
public function dashboard()
|
||||
{
|
||||
$invitation = $this->getInvitation();
|
||||
if (!$invitation = $this->getInvitation()) {
|
||||
return $this->returnError();
|
||||
}
|
||||
$account = $invitation->account;
|
||||
$invoice = $invitation->invoice;
|
||||
$client = $invoice->client;
|
||||
@ -32,6 +34,7 @@ class PublicClientController extends BaseController
|
||||
'color' => $color,
|
||||
'account' => $account,
|
||||
'client' => $client,
|
||||
'hideLogo' => $account->isWhiteLabel(),
|
||||
];
|
||||
|
||||
return response()->view('invited.dashboard', $data);
|
||||
@ -39,7 +42,9 @@ class PublicClientController extends BaseController
|
||||
|
||||
public function activityDatatable()
|
||||
{
|
||||
$invitation = $this->getInvitation();
|
||||
if (!$invitation = $this->getInvitation()) {
|
||||
return false;
|
||||
}
|
||||
$invoice = $invitation->invoice;
|
||||
|
||||
$query = DB::table('activities')
|
||||
@ -58,7 +63,9 @@ class PublicClientController extends BaseController
|
||||
|
||||
public function invoiceIndex()
|
||||
{
|
||||
$invitation = $this->getInvitation();
|
||||
if (!$invitation = $this->getInvitation()) {
|
||||
return $this->returnError();
|
||||
}
|
||||
$account = $invitation->account;
|
||||
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
|
||||
|
||||
@ -75,7 +82,9 @@ class PublicClientController extends BaseController
|
||||
|
||||
public function invoiceDatatable()
|
||||
{
|
||||
$invitation = $this->getInvitation();
|
||||
if (!$invitation = $this->getInvitation()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->invoiceRepo->getClientDatatable($invitation->contact_id, ENTITY_INVOICE, Input::get('sSearch'));
|
||||
}
|
||||
@ -83,7 +92,9 @@ class PublicClientController extends BaseController
|
||||
|
||||
public function paymentIndex()
|
||||
{
|
||||
$invitation = $this->getInvitation();
|
||||
if (!$invitation = $this->getInvitation()) {
|
||||
return $this->returnError();
|
||||
}
|
||||
$account = $invitation->account;
|
||||
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
|
||||
|
||||
@ -100,7 +111,9 @@ class PublicClientController extends BaseController
|
||||
|
||||
public function paymentDatatable()
|
||||
{
|
||||
$invitation = $this->getInvitation();
|
||||
if (!$invitation = $this->getInvitation()) {
|
||||
return false;
|
||||
}
|
||||
$payments = $this->paymentRepo->findForContact($invitation->contact->id, Input::get('sSearch'));
|
||||
|
||||
return Datatable::query($payments)
|
||||
@ -114,7 +127,9 @@ class PublicClientController extends BaseController
|
||||
|
||||
public function quoteIndex()
|
||||
{
|
||||
$invitation = $this->getInvitation();
|
||||
if (!$invitation = $this->getInvitation()) {
|
||||
return $this->returnError();
|
||||
}
|
||||
$account = $invitation->account;
|
||||
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
|
||||
|
||||
@ -132,29 +147,39 @@ class PublicClientController extends BaseController
|
||||
|
||||
public function quoteDatatable()
|
||||
{
|
||||
$invitation = $this->getInvitation();
|
||||
if (!$invitation = $this->getInvitation()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->invoiceRepo->getClientDatatable($invitation->contact_id, ENTITY_QUOTE, Input::get('sSearch'));
|
||||
}
|
||||
|
||||
private function returnError()
|
||||
{
|
||||
return response()->view('error', [
|
||||
'error' => trans('texts.invoice_not_found'),
|
||||
'hideHeader' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
private function getInvitation()
|
||||
{
|
||||
$invitationKey = session('invitation_key');
|
||||
|
||||
if (!$invitationKey) {
|
||||
app()->abort(404);
|
||||
return false;
|
||||
}
|
||||
|
||||
$invitation = Invitation::where('invitation_key', '=', $invitationKey)->first();
|
||||
|
||||
if (!$invitation || $invitation->is_deleted) {
|
||||
app()->abort(404);
|
||||
return false;
|
||||
}
|
||||
|
||||
$invoice = $invitation->invoice;
|
||||
|
||||
if (!$invoice || $invoice->is_deleted) {
|
||||
app()->abort(404);
|
||||
return false;
|
||||
}
|
||||
|
||||
return $invitation;
|
||||
|
@ -81,23 +81,21 @@ class QuoteController extends BaseController
|
||||
return Redirect::to('/invoices/create');
|
||||
}
|
||||
|
||||
$client = null;
|
||||
$invoiceNumber = Auth::user()->account->getNextInvoiceNumber(true);
|
||||
$account = Account::with('country')->findOrFail(Auth::user()->account_id);
|
||||
|
||||
$account = Auth::user()->account;
|
||||
$clientId = null;
|
||||
if ($clientPublicId) {
|
||||
$client = Client::scope($clientPublicId)->firstOrFail();
|
||||
$clientId = Client::getPrivateId($clientPublicId);
|
||||
}
|
||||
$invoice = $account->createInvoice(ENTITY_QUOTE, $clientId);
|
||||
|
||||
$data = array(
|
||||
'account' => $account,
|
||||
'invoice' => null,
|
||||
$data = [
|
||||
'entityType' => $invoice->getEntityType(),
|
||||
'invoice' => $invoice,
|
||||
'data' => Input::old('data'),
|
||||
'invoiceNumber' => $invoiceNumber,
|
||||
'method' => 'POST',
|
||||
'url' => 'invoices',
|
||||
'title' => trans('texts.new_quote'),
|
||||
'client' => $client, );
|
||||
];
|
||||
$data = array_merge($data, self::getViewModel());
|
||||
|
||||
return View::make('invoices.edit', $data);
|
||||
|
@ -33,7 +33,6 @@ class ReportController extends BaseController
|
||||
}
|
||||
|
||||
$data = [
|
||||
'feature' => ACCOUNT_DATA_VISUALIZATIONS,
|
||||
'clients' => $clients,
|
||||
'message' => $message,
|
||||
];
|
||||
@ -276,7 +275,6 @@ class ReportController extends BaseController
|
||||
'startDate' => $startDate->format(Session::get(SESSION_DATE_FORMAT)),
|
||||
'endDate' => $endDate->format(Session::get(SESSION_DATE_FORMAT)),
|
||||
'groupBy' => $groupBy,
|
||||
'feature' => ACCOUNT_CHART_BUILDER,
|
||||
'displayData' => $displayData,
|
||||
'columns' => $columns,
|
||||
'reportTotals' => $reportTotals,
|
||||
|
110
app/Http/Controllers/TaxRateController.php
Normal file
110
app/Http/Controllers/TaxRateController.php
Normal file
@ -0,0 +1,110 @@
|
||||
<?php namespace App\Http\Controllers;
|
||||
|
||||
use Auth;
|
||||
use Str;
|
||||
use DB;
|
||||
use Datatable;
|
||||
use Utils;
|
||||
use URL;
|
||||
use View;
|
||||
use Input;
|
||||
use Session;
|
||||
use Redirect;
|
||||
|
||||
use App\Models\TaxRate;
|
||||
|
||||
class TaxRateController extends BaseController
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return Redirect::to('settings/' . ACCOUNT_TAX_RATES);
|
||||
}
|
||||
|
||||
public function getDatatable()
|
||||
{
|
||||
$query = DB::table('tax_rates')
|
||||
->where('tax_rates.account_id', '=', Auth::user()->account_id)
|
||||
->where('tax_rates.deleted_at', '=', null)
|
||||
->select('tax_rates.public_id', 'tax_rates.name', 'tax_rates.rate');
|
||||
|
||||
return Datatable::query($query)
|
||||
->addColumn('name', function ($model) { return link_to('tax_rates/'.$model->public_id.'/edit', $model->name); })
|
||||
->addColumn('rate', function ($model) { return $model->rate . '%'; })
|
||||
->addColumn('dropdown', function ($model) {
|
||||
return '<div class="btn-group tr-action" style="visibility:hidden;">
|
||||
<button type="button" class="btn btn-xs btn-default dropdown-toggle" data-toggle="dropdown">
|
||||
'.trans('texts.select').' <span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a href="'.URL::to('tax_rates/'.$model->public_id).'/edit">'.uctrans('texts.edit_tax_rate').'</a></li>
|
||||
<li class="divider"></li>
|
||||
<li><a href="'.URL::to('tax_rates/'.$model->public_id).'/archive">'.uctrans('texts.archive_tax_rate').'</a></li>
|
||||
</ul>
|
||||
</div>';
|
||||
})
|
||||
->orderColumns(['name', 'rate'])
|
||||
->make();
|
||||
}
|
||||
|
||||
public function edit($publicId)
|
||||
{
|
||||
$data = [
|
||||
'taxRate' => TaxRate::scope($publicId)->firstOrFail(),
|
||||
'method' => 'PUT',
|
||||
'url' => 'tax_rates/'.$publicId,
|
||||
'title' => trans('texts.edit_tax_rate'),
|
||||
];
|
||||
|
||||
return View::make('accounts.tax_rate', $data);
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
$data = [
|
||||
'taxRate' => null,
|
||||
'method' => 'POST',
|
||||
'url' => 'tax_rates',
|
||||
'title' => trans('texts.create_tax_rate'),
|
||||
];
|
||||
|
||||
return View::make('accounts.tax_rate', $data);
|
||||
}
|
||||
|
||||
public function store()
|
||||
{
|
||||
return $this->save();
|
||||
}
|
||||
|
||||
public function update($publicId)
|
||||
{
|
||||
return $this->save($publicId);
|
||||
}
|
||||
|
||||
private function save($publicId = false)
|
||||
{
|
||||
if ($publicId) {
|
||||
$taxRate = TaxRate::scope($publicId)->firstOrFail();
|
||||
} else {
|
||||
$taxRate = TaxRate::createNew();
|
||||
}
|
||||
|
||||
$taxRate->name = trim(Input::get('name'));
|
||||
$taxRate->rate = Utils::parseFloat(Input::get('rate'));
|
||||
$taxRate->save();
|
||||
|
||||
$message = $publicId ? trans('texts.updated_tax_rate') : trans('texts.created_tax_rate');
|
||||
Session::flash('message', $message);
|
||||
|
||||
return Redirect::to('settings/' . ACCOUNT_TAX_RATES);
|
||||
}
|
||||
|
||||
public function archive($publicId)
|
||||
{
|
||||
$tax_rate = TaxRate::scope($publicId)->firstOrFail();
|
||||
$tax_rate->delete();
|
||||
|
||||
Session::flash('message', trans('texts.archived_tax_rate'));
|
||||
|
||||
return Redirect::to('settings/' . ACCOUNT_TAX_RATES);
|
||||
}
|
||||
}
|
@ -25,6 +25,11 @@ use App\Ninja\Repositories\AccountRepository;
|
||||
|
||||
class TokenController extends BaseController
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return Redirect::to('settings/' . ACCOUNT_API_TOKENS);
|
||||
}
|
||||
|
||||
public function getDatatable()
|
||||
{
|
||||
$query = DB::table('account_tokens')
|
||||
@ -67,7 +72,6 @@ class TokenController extends BaseController
|
||||
->where('public_id', '=', $publicId)->firstOrFail();
|
||||
|
||||
$data = [
|
||||
'showBreadcrumbs' => false,
|
||||
'token' => $token,
|
||||
'method' => 'PUT',
|
||||
'url' => 'tokens/'.$publicId,
|
||||
@ -94,12 +98,10 @@ class TokenController extends BaseController
|
||||
public function create()
|
||||
{
|
||||
$data = [
|
||||
'showBreadcrumbs' => false,
|
||||
'token' => null,
|
||||
'method' => 'POST',
|
||||
'url' => 'tokens',
|
||||
'title' => trans('texts.add_token'),
|
||||
'feature' => 'tokens',
|
||||
];
|
||||
|
||||
return View::make('accounts.token', $data);
|
||||
@ -115,7 +117,7 @@ class TokenController extends BaseController
|
||||
|
||||
Session::flash('message', trans('texts.deleted_token'));
|
||||
|
||||
return Redirect::to('company/advanced_settings/token_management');
|
||||
return Redirect::to('settings/' . ACCOUNT_API_TOKENS);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -163,7 +165,7 @@ class TokenController extends BaseController
|
||||
Session::flash('message', $message);
|
||||
}
|
||||
|
||||
return Redirect::to('company/advanced_settings/token_management');
|
||||
return Redirect::to('settings/' . ACCOUNT_API_TOKENS);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -35,6 +35,11 @@ class UserController extends BaseController
|
||||
$this->userMailer = $userMailer;
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
return Redirect::to('settings/' . ACCOUNT_USER_MANAGEMENT);
|
||||
}
|
||||
|
||||
public function getDatatable()
|
||||
{
|
||||
$query = DB::table('users')
|
||||
@ -106,7 +111,6 @@ class UserController extends BaseController
|
||||
->where('public_id', '=', $publicId)->firstOrFail();
|
||||
|
||||
$data = [
|
||||
'showBreadcrumbs' => false,
|
||||
'user' => $user,
|
||||
'method' => 'PUT',
|
||||
'url' => 'users/'.$publicId,
|
||||
@ -134,24 +138,22 @@ class UserController extends BaseController
|
||||
{
|
||||
if (!Auth::user()->registered) {
|
||||
Session::flash('error', trans('texts.register_to_add_user'));
|
||||
return Redirect::to('company/advanced_settings/user_management');
|
||||
return Redirect::to('settings/' . ACCOUNT_USER_MANAGEMENT);
|
||||
}
|
||||
if (!Auth::user()->confirmed) {
|
||||
Session::flash('error', trans('texts.confirmation_required'));
|
||||
return Redirect::to('company/advanced_settings/user_management');
|
||||
return Redirect::to('settings/' . ACCOUNT_USER_MANAGEMENT);
|
||||
}
|
||||
|
||||
if (Utils::isNinja()) {
|
||||
$count = User::where('account_id', '=', Auth::user()->account_id)->count();
|
||||
if ($count >= MAX_NUM_USERS) {
|
||||
Session::flash('error', trans('texts.limit_users'));
|
||||
|
||||
return Redirect::to('company/advanced_settings/user_management');
|
||||
return Redirect::to('settings/' . ACCOUNT_USER_MANAGEMENT);
|
||||
}
|
||||
}
|
||||
|
||||
$data = [
|
||||
'showBreadcrumbs' => false,
|
||||
'user' => null,
|
||||
'method' => 'POST',
|
||||
'url' => 'users',
|
||||
@ -171,7 +173,7 @@ class UserController extends BaseController
|
||||
|
||||
Session::flash('message', trans('texts.deleted_user'));
|
||||
|
||||
return Redirect::to('company/advanced_settings/user_management');
|
||||
return Redirect::to('settings/' . ACCOUNT_USER_MANAGEMENT);
|
||||
}
|
||||
|
||||
public function restoreUser($userPublicId)
|
||||
@ -184,7 +186,7 @@ class UserController extends BaseController
|
||||
|
||||
Session::flash('message', trans('texts.restored_user'));
|
||||
|
||||
return Redirect::to('company/advanced_settings/user_management');
|
||||
return Redirect::to('settings/' . ACCOUNT_USER_MANAGEMENT);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -247,7 +249,7 @@ class UserController extends BaseController
|
||||
Session::flash('message', $message);
|
||||
}
|
||||
|
||||
return Redirect::to('company/advanced_settings/user_management');
|
||||
return Redirect::to('settings/' . ACCOUNT_USER_MANAGEMENT);
|
||||
}
|
||||
|
||||
public function sendConfirmation($userPublicId)
|
||||
@ -258,7 +260,7 @@ class UserController extends BaseController
|
||||
$this->userMailer->sendConfirmation($user, Auth::user());
|
||||
Session::flash('message', trans('texts.sent_invite'));
|
||||
|
||||
return Redirect::to('company/advanced_settings/user_management');
|
||||
return Redirect::to('settings/' . ACCOUNT_USER_MANAGEMENT);
|
||||
}
|
||||
|
||||
|
||||
|
@ -27,11 +27,11 @@ class StartupCheck
|
||||
{
|
||||
// Set up trusted X-Forwarded-Proto proxies
|
||||
// TRUSTED_PROXIES accepts a comma delimited list of subnets
|
||||
//
|
||||
// TRUSTED_PROXIES='10.0.0.0/8,172.16.0.0/12,192.168.0.0/16'
|
||||
// ie, TRUSTED_PROXIES='10.0.0.0/8,172.16.0.0/12,192.168.0.0/16'
|
||||
if (isset($_ENV['TRUSTED_PROXIES'])) {
|
||||
Request::setTrustedProxies(array_map('trim',explode(",",env('TRUSTED_PROXIES'))));
|
||||
Request::setTrustedProxies(array_map('trim', explode(',', env('TRUSTED_PROXIES'))));
|
||||
}
|
||||
|
||||
// Ensure all request are over HTTPS in production
|
||||
if (App::environment() == ENV_PRODUCTION && !Request::secure()) {
|
||||
return Redirect::secure(Request::getRequestUri());
|
||||
|
@ -21,10 +21,10 @@
|
||||
//Log::error('test');
|
||||
|
||||
// Application setup
|
||||
Route::get('setup', 'AppController@showSetup');
|
||||
Route::post('setup', 'AppController@doSetup');
|
||||
Route::get('install', 'AppController@install');
|
||||
Route::get('update', 'AppController@update');
|
||||
Route::get('/setup', 'AppController@showSetup');
|
||||
Route::post('/setup', 'AppController@doSetup');
|
||||
Route::get('/install', 'AppController@install');
|
||||
Route::get('/update', 'AppController@update');
|
||||
|
||||
/*
|
||||
// Codeception code coverage
|
||||
@ -35,11 +35,11 @@ Route::get('/c3.php', function () {
|
||||
|
||||
// Public pages
|
||||
Route::get('/', 'HomeController@showIndex');
|
||||
Route::get('terms', 'HomeController@showTerms');
|
||||
Route::get('log_error', 'HomeController@logError');
|
||||
Route::get('invoice_now', 'HomeController@invoiceNow');
|
||||
Route::get('keep_alive', 'HomeController@keepAlive');
|
||||
Route::post('get_started', 'AccountController@getStarted');
|
||||
Route::get('/terms', 'HomeController@showTerms');
|
||||
Route::get('/log_error', 'HomeController@logError');
|
||||
Route::get('/invoice_now', 'HomeController@invoiceNow');
|
||||
Route::get('/keep_alive', 'HomeController@keepAlive');
|
||||
Route::post('/get_started', 'AccountController@getStarted');
|
||||
|
||||
// Client visible pages
|
||||
Route::get('view/{invitation_key}', 'InvoiceController@view');
|
||||
@ -64,21 +64,14 @@ Route::get('claim_license', 'PaymentController@claim_license');
|
||||
Route::post('signup/validate', 'AccountController@checkEmail');
|
||||
Route::post('signup/submit', 'AccountController@submitSignup');
|
||||
|
||||
Route::get('auth/{provider}', 'Auth\AuthController@authLogin');
|
||||
Route::get('auth_unlink', 'Auth\AuthController@authUnlink');
|
||||
Route::get('/auth/{provider}', 'Auth\AuthController@authLogin');
|
||||
Route::get('/auth_unlink', 'Auth\AuthController@authUnlink');
|
||||
|
||||
Route::post('hook/email_bounced', 'AppController@emailBounced');
|
||||
Route::post('hook/email_opened', 'AppController@emailOpened');
|
||||
Route::post('/hook/email_bounced', 'AppController@emailBounced');
|
||||
Route::post('/hook/email_opened', 'AppController@emailOpened');
|
||||
|
||||
|
||||
// Laravel auth routes
|
||||
/*
|
||||
Route::controllers([
|
||||
'auth' => 'Auth\AuthController',
|
||||
'password' => 'Auth\PasswordController',
|
||||
]);
|
||||
*/
|
||||
|
||||
get('/signup', array('as' => 'signup', 'uses' => 'Auth\AuthController@getRegister'));
|
||||
post('/signup', array('as' => 'signup', 'uses' => 'Auth\AuthController@postRegister'));
|
||||
get('/login', array('as' => 'login', 'uses' => 'Auth\AuthController@getLoginWrapper'));
|
||||
@ -121,14 +114,20 @@ Route::group(['middleware' => 'auth'], function() {
|
||||
Route::resource('products', 'ProductController');
|
||||
Route::get('products/{product_id}/archive', 'ProductController@archive');
|
||||
|
||||
Route::get('company/advanced_settings/data_visualizations', 'ReportController@d3');
|
||||
Route::get('company/advanced_settings/charts_and_reports', 'ReportController@showReports');
|
||||
Route::post('company/advanced_settings/charts_and_reports', 'ReportController@showReports');
|
||||
Route::get('api/tax_rates', array('as'=>'api.tax_rates', 'uses'=>'TaxRateController@getDatatable'));
|
||||
Route::resource('tax_rates', 'TaxRateController');
|
||||
Route::get('tax_rates/{tax_rates_id}/archive', 'TaxRateController@archive');
|
||||
|
||||
Route::get('company/{section}/{subSection?}', 'AccountController@redirectLegacy');
|
||||
Route::get('settings/data_visualizations', 'ReportController@d3');
|
||||
Route::get('settings/charts_and_reports', 'ReportController@showReports');
|
||||
Route::post('settings/charts_and_reports', 'ReportController@showReports');
|
||||
|
||||
Route::post('settings/cancel_account', 'AccountController@cancelAccount');
|
||||
Route::get('settings/{section?}', 'AccountController@showSection');
|
||||
Route::post('settings/{section?}', 'AccountController@doSection');
|
||||
|
||||
Route::post('company/cancel_account', 'AccountController@cancelAccount');
|
||||
Route::get('account/getSearchData', array('as' => 'getSearchData', 'uses' => 'AccountController@getSearchData'));
|
||||
Route::get('company/{section?}/{sub_section?}', 'AccountController@showSection');
|
||||
Route::post('company/{section?}/{sub_section?}', 'AccountController@doSection');
|
||||
Route::post('user/setTheme', 'UserController@setTheme');
|
||||
Route::post('remove_logo', 'AccountController@removeLogo');
|
||||
Route::post('account/go_pro', 'AccountController@enableProPlan');
|
||||
@ -183,7 +182,6 @@ Route::group(['middleware' => 'auth'], function() {
|
||||
Route::post('credits/bulk', 'CreditController@bulk');
|
||||
|
||||
get('/resend_confirmation', 'AccountController@resendConfirmation');
|
||||
//Route::resource('timesheets', 'TimesheetController');
|
||||
});
|
||||
|
||||
// Route group for API
|
||||
@ -253,21 +251,27 @@ if (!defined('CONTACT_EMAIL')) {
|
||||
define('PERSON_CONTACT', 'contact');
|
||||
define('PERSON_USER', 'user');
|
||||
|
||||
define('ACCOUNT_DETAILS', 'details');
|
||||
define('BASIC_SETTINGS', 'basic_settings');
|
||||
define('ADVANCED_SETTINGS', 'advanced_settings');
|
||||
|
||||
define('ACCOUNT_COMPANY_DETAILS', 'company_details');
|
||||
define('ACCOUNT_USER_DETAILS', 'user_details');
|
||||
define('ACCOUNT_LOCALIZATION', 'localization');
|
||||
define('ACCOUNT_NOTIFICATIONS', 'notifications');
|
||||
define('ACCOUNT_IMPORT_EXPORT', 'import_export');
|
||||
define('ACCOUNT_PAYMENTS', 'payments');
|
||||
define('ACCOUNT_PAYMENTS', 'online_payments');
|
||||
define('ACCOUNT_MAP', 'import_map');
|
||||
define('ACCOUNT_EXPORT', 'export');
|
||||
define('ACCOUNT_TAX_RATES', 'tax_rates');
|
||||
define('ACCOUNT_PRODUCTS', 'products');
|
||||
define('ACCOUNT_ADVANCED_SETTINGS', 'advanced_settings');
|
||||
define('ACCOUNT_INVOICE_SETTINGS', 'invoice_settings');
|
||||
define('ACCOUNT_INVOICE_DESIGN', 'invoice_design');
|
||||
define('ACCOUNT_CHART_BUILDER', 'chart_builder');
|
||||
define('ACCOUNT_CHARTS_AND_REPORTS', 'charts_and_reports');
|
||||
define('ACCOUNT_USER_MANAGEMENT', 'user_management');
|
||||
define('ACCOUNT_DATA_VISUALIZATIONS', 'data_visualizations');
|
||||
define('ACCOUNT_TEMPLATES_AND_REMINDERS', 'templates_and_reminders');
|
||||
define('ACCOUNT_TOKEN_MANAGEMENT', 'token_management');
|
||||
define('ACCOUNT_API_TOKENS', 'api_tokens');
|
||||
define('ACCOUNT_CUSTOMIZE_DESIGN', 'customize_design');
|
||||
|
||||
|
||||
@ -310,12 +314,16 @@ if (!defined('CONTACT_EMAIL')) {
|
||||
define('RECENTLY_VIEWED_LIMIT', 8);
|
||||
define('LOGGED_ERROR_LIMIT', 100);
|
||||
define('RANDOM_KEY_LENGTH', 32);
|
||||
define('MAX_NUM_CLIENTS', 500);
|
||||
define('MAX_NUM_CLIENTS_PRO', 20000);
|
||||
define('MAX_NUM_USERS', 20);
|
||||
define('MAX_SUBDOMAIN_LENGTH', 30);
|
||||
define('MAX_IFRAME_URL_LENGTH', 250);
|
||||
define('DEFAULT_FONT_SIZE', 9);
|
||||
define('DEFAULT_SEND_RECURRING_HOUR', 8);
|
||||
|
||||
define('MAX_NUM_CLIENTS', 100);
|
||||
define('MAX_NUM_CLIENTS_PRO', 20000);
|
||||
define('MAX_NUM_CLIENTS_LEGACY', 500);
|
||||
define('LEGACY_CUTOFF', 57800);
|
||||
|
||||
define('INVOICE_STATUS_DRAFT', 1);
|
||||
define('INVOICE_STATUS_SENT', 2);
|
||||
@ -391,16 +399,16 @@ if (!defined('CONTACT_EMAIL')) {
|
||||
define('NINJA_GATEWAY_CONFIG', 'NINJA_GATEWAY_CONFIG');
|
||||
define('NINJA_WEB_URL', 'https://www.invoiceninja.com');
|
||||
define('NINJA_APP_URL', 'https://app.invoiceninja.com');
|
||||
define('NINJA_VERSION', '2.4.2');
|
||||
define('NINJA_VERSION', '2.4.3');
|
||||
define('NINJA_DATE', '2000-01-01');
|
||||
|
||||
define('NINJA_FROM_EMAIL', 'maildelivery@invoiceninja.com');
|
||||
define('RELEASES_URL', 'https://github.com/hillelcoren/invoice-ninja/releases/');
|
||||
define('RELEASES_URL', 'https://trello.com/b/63BbiVVe/invoice-ninja');
|
||||
define('ZAPIER_URL', 'https://zapier.com/zapbook/invoice-ninja');
|
||||
define('OUTDATE_BROWSER_URL', 'http://browsehappy.com/');
|
||||
define('PDFMAKE_DOCS', 'http://pdfmake.org/playground.html');
|
||||
define('PHANTOMJS_CLOUD', 'http://api.phantomjscloud.com/single/browser/v1/');
|
||||
define('GITHUB_RELEASES', 'https://github.com/hillelcoren/invoice-ninja/releases');
|
||||
define('PHP_DATE_FORMATS', 'http://php.net/manual/en/function.date.php');
|
||||
define('REFERRAL_PROGRAM_URL', false);
|
||||
|
||||
define('COUNT_FREE_DESIGNS', 4);
|
||||
|
@ -259,6 +259,10 @@ class Utils
|
||||
|
||||
public static function dateToString($date)
|
||||
{
|
||||
if (!$date) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$dateTime = new DateTime($date);
|
||||
$timestamp = $dateTime->getTimestamp();
|
||||
$format = Session::get(SESSION_DATE_FORMAT, DEFAULT_DATE_FORMAT);
|
||||
|
@ -15,6 +15,27 @@ class Account extends Eloquent
|
||||
protected $dates = ['deleted_at'];
|
||||
protected $hidden = ['ip'];
|
||||
|
||||
public static $basicSettings = [
|
||||
ACCOUNT_COMPANY_DETAILS,
|
||||
ACCOUNT_USER_DETAILS,
|
||||
ACCOUNT_LOCALIZATION,
|
||||
ACCOUNT_PAYMENTS,
|
||||
ACCOUNT_TAX_RATES,
|
||||
ACCOUNT_PRODUCTS,
|
||||
ACCOUNT_NOTIFICATIONS,
|
||||
ACCOUNT_IMPORT_EXPORT,
|
||||
];
|
||||
|
||||
public static $advancedSettings = [
|
||||
ACCOUNT_INVOICE_SETTINGS,
|
||||
ACCOUNT_INVOICE_DESIGN,
|
||||
ACCOUNT_TEMPLATES_AND_REMINDERS,
|
||||
ACCOUNT_CHARTS_AND_REPORTS,
|
||||
ACCOUNT_DATA_VISUALIZATIONS,
|
||||
ACCOUNT_USER_MANAGEMENT,
|
||||
ACCOUNT_API_TOKENS,
|
||||
];
|
||||
|
||||
/*
|
||||
protected $casts = [
|
||||
'invoice_settings' => 'object',
|
||||
@ -86,6 +107,11 @@ class Account extends Eloquent
|
||||
return $this->belongsTo('App\Models\Industry');
|
||||
}
|
||||
|
||||
public function default_tax_rate()
|
||||
{
|
||||
return $this->belongsTo('App\Models\TaxRate');
|
||||
}
|
||||
|
||||
public function isGatewayConfigured($gatewayId = 0)
|
||||
{
|
||||
$this->load('account_gateways');
|
||||
@ -140,6 +166,25 @@ class Account extends Eloquent
|
||||
}
|
||||
}
|
||||
|
||||
public function getDateTime($date = 'now')
|
||||
{
|
||||
return new \DateTime($date, new \DateTimeZone($this->getTimezone()));
|
||||
}
|
||||
|
||||
public function getCustomDateFormat()
|
||||
{
|
||||
return $this->date_format ? $this->date_format->format : DEFAULT_DATE_FORMAT;
|
||||
}
|
||||
|
||||
public function formatDate($date)
|
||||
{
|
||||
if (!$date) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $date->format($this->getCustomDateFormat());
|
||||
}
|
||||
|
||||
public function getGatewayByType($type = PAYMENT_TYPE_ANY)
|
||||
{
|
||||
foreach ($this->account_gateways as $gateway) {
|
||||
@ -198,10 +243,131 @@ class Account extends Eloquent
|
||||
return $height;
|
||||
}
|
||||
|
||||
public function getNextInvoiceNumber($isQuote = false, $prefix = '')
|
||||
public function createInvoice($entityType, $clientId = null)
|
||||
{
|
||||
$counter = $isQuote && !$this->share_counter ? $this->quote_number_counter : $this->invoice_number_counter;
|
||||
$prefix .= $isQuote ? $this->quote_number_prefix : $this->invoice_number_prefix;
|
||||
$invoice = Invoice::createNew();
|
||||
|
||||
$invoice->invoice_date = Utils::today();
|
||||
$invoice->start_date = Utils::today();
|
||||
$invoice->invoice_design_id = $this->invoice_design_id;
|
||||
$invoice->client_id = $clientId;
|
||||
|
||||
if ($entityType === ENTITY_RECURRING_INVOICE) {
|
||||
$invoice->invoice_number = microtime(true);
|
||||
$invoice->is_recurring = true;
|
||||
} else {
|
||||
if ($entityType == ENTITY_QUOTE) {
|
||||
$invoice->is_quote = true;
|
||||
}
|
||||
|
||||
if ($this->hasClientNumberPattern($invoice) && !$clientId) {
|
||||
// do nothing, we don't yet know the value
|
||||
} else {
|
||||
$invoice->invoice_number = $this->getNextInvoiceNumber($invoice);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$clientId) {
|
||||
$invoice->client = Client::createNew();
|
||||
$invoice->client->public_id = 0;
|
||||
}
|
||||
|
||||
return $invoice;
|
||||
}
|
||||
|
||||
public function hasNumberPattern($isQuote)
|
||||
{
|
||||
return $isQuote ? ($this->quote_number_pattern ? true : false) : ($this->invoice_number_pattern ? true : false);
|
||||
}
|
||||
|
||||
public function hasClientNumberPattern($invoice)
|
||||
{
|
||||
$pattern = $invoice->is_quote ? $this->quote_number_pattern : $this->invoice_number_pattern;
|
||||
|
||||
return strstr($pattern, '$custom');
|
||||
}
|
||||
|
||||
public function getNumberPattern($invoice)
|
||||
{
|
||||
$pattern = $invoice->is_quote ? $this->quote_number_pattern : $this->invoice_number_pattern;
|
||||
|
||||
if (!$pattern) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$search = ['{$year}'];
|
||||
$replace = [date('Y')];
|
||||
|
||||
$search[] = '{$counter}';
|
||||
$replace[] = str_pad($this->getCounter($invoice->is_quote), 4, '0', STR_PAD_LEFT);
|
||||
|
||||
if (strstr($pattern, '{$userId}')) {
|
||||
$search[] = '{$userId}';
|
||||
$replace[] = str_pad($invoice->user->public_id, 2, '0', STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
$matches = false;
|
||||
preg_match('/{\$date:(.*?)}/', $pattern, $matches);
|
||||
if (count($matches) > 1) {
|
||||
$format = $matches[1];
|
||||
$search[] = $matches[0];
|
||||
$replace[] = str_replace($format, date($format), $matches[1]);
|
||||
}
|
||||
|
||||
$pattern = str_replace($search, $replace, $pattern);
|
||||
|
||||
if ($invoice->client->id) {
|
||||
$pattern = $this->getClientInvoiceNumber($pattern, $invoice);
|
||||
}
|
||||
|
||||
return $pattern;
|
||||
}
|
||||
|
||||
private function getClientInvoiceNumber($pattern, $invoice)
|
||||
{
|
||||
if (!$invoice->client) {
|
||||
return $pattern;
|
||||
}
|
||||
|
||||
$search = [
|
||||
//'{$clientId}',
|
||||
'{$custom1}',
|
||||
'{$custom2}',
|
||||
];
|
||||
|
||||
$replace = [
|
||||
//str_pad($client->public_id, 3, '0', STR_PAD_LEFT),
|
||||
$invoice->client->custom_value1,
|
||||
$invoice->client->custom_value2,
|
||||
];
|
||||
|
||||
return str_replace($search, $replace, $pattern);
|
||||
}
|
||||
|
||||
// if we're using a pattern we don't know the next number until a client
|
||||
// is selected, to support this the default value is blank
|
||||
public function getDefaultInvoiceNumber($invoice = false)
|
||||
{
|
||||
if ($this->hasClientNumberPattern($invoice)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->getNextInvoiceNumber($invoice);
|
||||
}
|
||||
|
||||
public function getCounter($isQuote)
|
||||
{
|
||||
return $isQuote && !$this->share_counter ? $this->quote_number_counter : $this->invoice_number_counter;
|
||||
}
|
||||
|
||||
public function getNextInvoiceNumber($invoice)
|
||||
{
|
||||
if ($this->hasNumberPattern($invoice->is_quote)) {
|
||||
return $this->getNumberPattern($invoice);
|
||||
}
|
||||
|
||||
$counter = $this->getCounter($invoice->is_quote);
|
||||
$prefix = $invoice->is_quote ? $this->quote_number_prefix : $this->invoice_number_prefix;
|
||||
$counterOffset = 0;
|
||||
|
||||
// confirm the invoice number isn't already taken
|
||||
@ -214,7 +380,7 @@ class Account extends Eloquent
|
||||
|
||||
// update the invoice counter to be caught up
|
||||
if ($counterOffset > 1) {
|
||||
if ($isQuote && !$this->share_counter) {
|
||||
if ($invoice->is_quote && !$this->share_counter) {
|
||||
$this->quote_number_counter += $counterOffset - 1;
|
||||
} else {
|
||||
$this->invoice_number_counter += $counterOffset - 1;
|
||||
@ -226,9 +392,9 @@ class Account extends Eloquent
|
||||
return $number;
|
||||
}
|
||||
|
||||
public function incrementCounter($isQuote = false)
|
||||
public function incrementCounter($invoice)
|
||||
{
|
||||
if ($isQuote && !$this->share_counter) {
|
||||
if ($invoice->is_quote && !$this->share_counter) {
|
||||
$this->quote_number_counter += 1;
|
||||
} else {
|
||||
$this->invoice_number_counter += 1;
|
||||
@ -237,18 +403,13 @@ class Account extends Eloquent
|
||||
$this->save();
|
||||
}
|
||||
|
||||
public function getLocale()
|
||||
{
|
||||
$language = Language::where('id', '=', $this->account->language_id)->first();
|
||||
|
||||
return $language->locale;
|
||||
}
|
||||
|
||||
public function loadLocalizationSettings($client = false)
|
||||
{
|
||||
$this->load('timezone', 'date_format', 'datetime_format', 'language');
|
||||
|
||||
Session::put(SESSION_TIMEZONE, $this->timezone ? $this->timezone->name : DEFAULT_TIMEZONE);
|
||||
$timezone = $this->timezone ? $this->timezone->name : DEFAULT_TIMEZONE;
|
||||
Session::put(SESSION_TIMEZONE, $timezone);
|
||||
|
||||
Session::put(SESSION_DATE_FORMAT, $this->date_format ? $this->date_format->format : DEFAULT_DATE_FORMAT);
|
||||
Session::put(SESSION_DATE_PICKER_FORMAT, $this->date_format ? $this->date_format->picker_format : DEFAULT_DATE_PICKER_FORMAT);
|
||||
|
||||
|
@ -25,6 +25,11 @@ class Client extends EntityModel
|
||||
return $this->belongsTo('App\Models\Account');
|
||||
}
|
||||
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo('App\Models\User');
|
||||
}
|
||||
|
||||
public function invoices()
|
||||
{
|
||||
return $this->hasMany('App\Models\Invoice');
|
||||
@ -168,6 +173,11 @@ class Client extends EntityModel
|
||||
|
||||
return $this->account->currency_id ?: DEFAULT_CURRENCY;
|
||||
}
|
||||
|
||||
public function getCounter($isQuote)
|
||||
{
|
||||
return $isQuote ? $this->quote_number_counter : $this->invoice_number_counter;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -9,14 +9,14 @@ class EntityModel extends Eloquent
|
||||
public $timestamps = true;
|
||||
protected $hidden = ['id'];
|
||||
|
||||
public static function createNew($parent = false)
|
||||
public static function createNew($context = null)
|
||||
{
|
||||
$className = get_called_class();
|
||||
$entity = new $className();
|
||||
|
||||
if ($parent) {
|
||||
$entity->user_id = $parent instanceof User ? $parent->id : $parent->user_id;
|
||||
$entity->account_id = $parent->account_id;
|
||||
if ($context) {
|
||||
$entity->user_id = $context instanceof User ? $context->id : $context->user_id;
|
||||
$entity->account_id = $context->account_id;
|
||||
} elseif (Auth::check()) {
|
||||
$entity->user_id = Auth::user()->id;
|
||||
$entity->account_id = Auth::user()->account_id;
|
||||
|
@ -57,7 +57,7 @@ class Invitation extends EntityModel
|
||||
foreach ($statuses as $status) {
|
||||
$field = "{$status}_date";
|
||||
$date = '';
|
||||
if ($this->$field) {
|
||||
if ($this->$field && $this->field != '0000-00-00 00:00:00') {
|
||||
$date = Utils::dateToString($this->$field);
|
||||
$hasValue = true;
|
||||
}
|
||||
|
@ -6,7 +6,10 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class Invoice extends EntityModel
|
||||
{
|
||||
use SoftDeletes;
|
||||
use SoftDeletes {
|
||||
SoftDeletes::trashed as parentTrashed;
|
||||
}
|
||||
|
||||
protected $dates = ['deleted_at'];
|
||||
|
||||
protected $casts = [
|
||||
@ -15,6 +18,24 @@ class Invoice extends EntityModel
|
||||
'auto_bill' => 'boolean',
|
||||
];
|
||||
|
||||
public static $patternFields = [
|
||||
'counter',
|
||||
'custom1',
|
||||
'custom2',
|
||||
'userId',
|
||||
'year',
|
||||
'date:',
|
||||
];
|
||||
|
||||
public function trashed()
|
||||
{
|
||||
if ($this->client && $this->client->trashed()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return self::parentTrashed();
|
||||
}
|
||||
|
||||
public function account()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Account');
|
||||
@ -216,6 +237,117 @@ class Invoice extends EntityModel
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSchedule()
|
||||
{
|
||||
if (!$this->start_date || !$this->is_recurring || !$this->frequency_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$startDate = $this->getOriginal('last_sent_date') ?: $this->getOriginal('start_date');
|
||||
$startDate .= ' ' . $this->account->recurring_hour . ':00:00';
|
||||
$startDate = $this->account->getDateTime($startDate);
|
||||
$endDate = $this->end_date ? $this->account->getDateTime($this->getOriginal('end_date')) : null;
|
||||
$timezone = $this->account->getTimezone();
|
||||
|
||||
$rule = $this->getRecurrenceRule();
|
||||
$rule = new \Recurr\Rule("{$rule}", $startDate, $endDate, $timezone);
|
||||
|
||||
// Fix for months with less than 31 days
|
||||
$transformerConfig = new \Recurr\Transformer\ArrayTransformerConfig();
|
||||
$transformerConfig->enableLastDayOfMonthFix();
|
||||
|
||||
$transformer = new \Recurr\Transformer\ArrayTransformer();
|
||||
$transformer->setConfig($transformerConfig);
|
||||
$dates = $transformer->transform($rule);
|
||||
|
||||
if (count($dates) < 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $dates;
|
||||
}
|
||||
|
||||
public function getNextSendDate()
|
||||
{
|
||||
if ($this->start_date && !$this->last_sent_date) {
|
||||
$startDate = $this->getOriginal('start_date') . ' ' . $this->account->recurring_hour . ':00:00';
|
||||
return $this->account->getDateTime($startDate);
|
||||
}
|
||||
|
||||
if (!$schedule = $this->getSchedule()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (count($schedule) < 2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $schedule[1]->getStart();
|
||||
}
|
||||
|
||||
public function getPrettySchedule($min = 1, $max = 10)
|
||||
{
|
||||
if (!$schedule = $this->getSchedule($max)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$dates = [];
|
||||
|
||||
for ($i=$min; $i<min($max, count($schedule)); $i++) {
|
||||
$date = $schedule[$i];
|
||||
$date = $this->account->formatDate($date->getStart());
|
||||
$dates[] = $date;
|
||||
}
|
||||
|
||||
return implode('<br/>', $dates);
|
||||
}
|
||||
|
||||
private function getRecurrenceRule()
|
||||
{
|
||||
$rule = '';
|
||||
|
||||
switch ($this->frequency_id) {
|
||||
case FREQUENCY_WEEKLY:
|
||||
$rule = 'FREQ=WEEKLY;';
|
||||
break;
|
||||
case FREQUENCY_TWO_WEEKS:
|
||||
$rule = 'FREQ=WEEKLY;INTERVAL=2;';
|
||||
break;
|
||||
case FREQUENCY_FOUR_WEEKS:
|
||||
$rule = 'FREQ=WEEKLY;INTERVAL=4;';
|
||||
break;
|
||||
case FREQUENCY_MONTHLY:
|
||||
$rule = 'FREQ=MONTHLY;';
|
||||
break;
|
||||
case FREQUENCY_THREE_MONTHS:
|
||||
$rule = 'FREQ=MONTHLY;INTERVAL=3;';
|
||||
break;
|
||||
case FREQUENCY_SIX_MONTHS:
|
||||
$rule = 'FREQ=MONTHLY;INTERVAL=6;';
|
||||
break;
|
||||
case FREQUENCY_ANNUALLY:
|
||||
$rule = 'FREQ=YEARLY;';
|
||||
break;
|
||||
}
|
||||
|
||||
if ($this->end_date) {
|
||||
$rule .= 'UNTIL=' . $this->end_date;
|
||||
}
|
||||
|
||||
return $rule;
|
||||
}
|
||||
|
||||
/*
|
||||
public function shouldSendToday()
|
||||
{
|
||||
if (!$nextSendDate = $this->getNextSendDate()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->account->getDateTime() >= $nextSendDate;
|
||||
}
|
||||
*/
|
||||
|
||||
public function shouldSendToday()
|
||||
{
|
||||
if (!$this->start_date || strtotime($this->start_date) > strtotime('now')) {
|
||||
@ -268,7 +400,8 @@ class Invoice extends EntityModel
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getReminder() {
|
||||
public function getReminder()
|
||||
{
|
||||
for ($i=1; $i<=3; $i++) {
|
||||
$field = "enable_reminder{$i}";
|
||||
if (!$this->account->$field) {
|
||||
@ -320,7 +453,7 @@ class Invoice extends EntityModel
|
||||
|
||||
Invoice::creating(function ($invoice) {
|
||||
if (!$invoice->is_recurring) {
|
||||
$invoice->account->incrementCounter($invoice->is_quote);
|
||||
$invoice->account->incrementCounter($invoice);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -11,4 +11,9 @@ class Product extends EntityModel
|
||||
{
|
||||
return Product::scope()->where('product_key', '=', $key)->first();
|
||||
}
|
||||
|
||||
public function default_tax_rate()
|
||||
{
|
||||
return $this->belongsTo('App\Models\TaxRate');
|
||||
}
|
||||
}
|
||||
|
@ -142,7 +142,15 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
|
||||
|
||||
public function getMaxNumClients()
|
||||
{
|
||||
return $this->isPro() ? MAX_NUM_CLIENTS_PRO : MAX_NUM_CLIENTS;
|
||||
if ($this->isPro()) {
|
||||
return MAX_NUM_CLIENTS_PRO;
|
||||
}
|
||||
|
||||
if ($this->id < LEGACY_CUTOFF) {
|
||||
return MAX_NUM_CLIENTS_LEGACY;
|
||||
}
|
||||
|
||||
return MAX_NUM_CLIENTS;
|
||||
}
|
||||
|
||||
public function getRememberToken()
|
||||
@ -195,7 +203,8 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
|
||||
{
|
||||
if (!$user->getOriginal('email')
|
||||
|| $user->getOriginal('email') == TEST_USERNAME
|
||||
|| $user->getOriginal('username') == TEST_USERNAME) {
|
||||
|| $user->getOriginal('username') == TEST_USERNAME
|
||||
|| $user->getOriginal('email') == 'tests@bitrock.com') {
|
||||
event(new UserSignedUp());
|
||||
}
|
||||
|
||||
|
@ -145,7 +145,6 @@ class ContactMailer extends Mailer
|
||||
|
||||
$subject = $this->processVariables($emailSubject, $variables);
|
||||
$data['invoice_id'] = $payment->invoice->id;
|
||||
$invoice->updateCachedPDF();
|
||||
|
||||
if ($user->email && $contact->email) {
|
||||
$this->sendTo($contact->email, $user->email, $accountName, $subject, $view, $data);
|
||||
|
@ -9,6 +9,10 @@ class Mailer
|
||||
{
|
||||
public function sendTo($toEmail, $fromEmail, $fromName, $subject, $view, $data = [])
|
||||
{
|
||||
if (stristr($toEmail, '@example.com')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isset($_ENV['POSTMARK_API_TOKEN'])) {
|
||||
$views = 'emails.'.$view.'_html';
|
||||
} else {
|
||||
@ -63,7 +67,7 @@ class Mailer
|
||||
|
||||
private function handleFailure($exception)
|
||||
{
|
||||
if (isset($_ENV['POSTMARK_API_TOKEN'])) {
|
||||
if (isset($_ENV['POSTMARK_API_TOKEN']) && $exception->getResponse()) {
|
||||
$response = $exception->getResponse()->getBody()->getContents();
|
||||
$response = json_decode($response);
|
||||
$emailError = nl2br($response->Message);
|
||||
|
@ -139,7 +139,7 @@ class AccountRepository
|
||||
$invoice->user_id = $account->users()->first()->id;
|
||||
$invoice->public_id = $publicId;
|
||||
$invoice->client_id = $client->id;
|
||||
$invoice->invoice_number = $account->getNextInvoiceNumber();
|
||||
$invoice->invoice_number = $account->getNextInvoiceNumber($invoice);
|
||||
$invoice->invoice_date = date_create()->format('Y-m-d');
|
||||
$invoice->amount = PRO_PLAN_PRICE;
|
||||
$invoice->balance = PRO_PLAN_PRICE;
|
||||
|
@ -250,18 +250,17 @@ class InvoiceRepository
|
||||
|
||||
public function save($publicId, $data, $entityType)
|
||||
{
|
||||
$account = \Auth::user()->account;
|
||||
|
||||
if ($publicId) {
|
||||
$invoice = Invoice::scope($publicId)->firstOrFail();
|
||||
} else {
|
||||
$invoice = Invoice::createNew();
|
||||
|
||||
if ($entityType == ENTITY_QUOTE) {
|
||||
$invoice->is_quote = true;
|
||||
if ($data['is_recurring']) {
|
||||
$entityType = ENTITY_RECURRING_INVOICE;
|
||||
}
|
||||
$invoice = $account->createInvoice($entityType, $data['client_id']);
|
||||
}
|
||||
|
||||
$account = \Auth::user()->account;
|
||||
|
||||
if ((isset($data['set_default_terms']) && $data['set_default_terms'])
|
||||
|| (isset($data['set_default_footer']) && $data['set_default_footer'])) {
|
||||
if (isset($data['set_default_terms']) && $data['set_default_terms']) {
|
||||
@ -273,7 +272,7 @@ class InvoiceRepository
|
||||
$account->save();
|
||||
}
|
||||
|
||||
if (isset($data['invoice_number'])) {
|
||||
if (isset($data['invoice_number']) && !$invoice->is_recurring) {
|
||||
$invoice->invoice_number = trim($data['invoice_number']);
|
||||
}
|
||||
|
||||
@ -283,11 +282,6 @@ class InvoiceRepository
|
||||
$invoice->invoice_date = isset($data['invoice_date_sql']) ? $data['invoice_date_sql'] : Utils::toSqlDate($data['invoice_date']);
|
||||
$invoice->has_tasks = isset($data['has_tasks']) ? $data['has_tasks'] : false;
|
||||
|
||||
if (!$publicId) {
|
||||
$invoice->client_id = $data['client_id'];
|
||||
$invoice->is_recurring = $data['is_recurring'] ? true : false;
|
||||
}
|
||||
|
||||
if ($invoice->is_recurring) {
|
||||
if ($invoice->start_date && $invoice->start_date != Utils::toSqlDate($data['start_date'])) {
|
||||
$invoice->last_sent_date = null;
|
||||
@ -478,7 +472,7 @@ class InvoiceRepository
|
||||
}
|
||||
$clone->invoice_number = $account->invoice_number_prefix.$invoiceNumber;
|
||||
} else {
|
||||
$clone->invoice_number = $account->getNextInvoiceNumber();
|
||||
$clone->invoice_number = $account->getNextInvoiceNumber($invoice);
|
||||
}
|
||||
|
||||
foreach ([
|
||||
@ -579,20 +573,21 @@ class InvoiceRepository
|
||||
public function findInvoiceByInvitation($invitationKey)
|
||||
{
|
||||
$invitation = Invitation::where('invitation_key', '=', $invitationKey)->first();
|
||||
|
||||
if (!$invitation) {
|
||||
app()->abort(404, trans('texts.invoice_not_found'));
|
||||
return false;
|
||||
}
|
||||
|
||||
$invoice = $invitation->invoice;
|
||||
if (!$invoice || $invoice->is_deleted) {
|
||||
app()->abort(404, trans('texts.invoice_not_found'));
|
||||
return false;
|
||||
}
|
||||
|
||||
$invoice->load('user', 'invoice_items', 'invoice_design', 'account.country', 'client.contacts', 'client.country');
|
||||
$client = $invoice->client;
|
||||
|
||||
if (!$client || $client->is_deleted) {
|
||||
app()->abort(404, trans('texts.invoice_not_found'));
|
||||
return false;
|
||||
}
|
||||
|
||||
return $invitation;
|
||||
@ -630,7 +625,7 @@ class InvoiceRepository
|
||||
$invoice = Invoice::createNew($recurInvoice);
|
||||
$invoice->client_id = $recurInvoice->client_id;
|
||||
$invoice->recurring_invoice_id = $recurInvoice->id;
|
||||
$invoice->invoice_number = $recurInvoice->account->getNextInvoiceNumber(false, 'R');
|
||||
$invoice->invoice_number = 'R' . $recurInvoice->account->getNextInvoiceNumber($recurInvoice);
|
||||
$invoice->amount = $recurInvoice->amount;
|
||||
$invoice->balance = $recurInvoice->amount;
|
||||
$invoice->invoice_date = date_create()->format('Y-m-d');
|
||||
|
@ -5,6 +5,7 @@ use Utils;
|
||||
|
||||
class TaxRateRepository
|
||||
{
|
||||
/*
|
||||
public function save($taxRates)
|
||||
{
|
||||
$taxRateIds = [];
|
||||
@ -39,4 +40,5 @@ class TaxRateRepository
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
@ -144,6 +144,10 @@ class AppServiceProvider extends ServiceProvider {
|
||||
Validator::replacer('less_than', function($message, $attribute, $rule, $parameters) {
|
||||
return str_replace(':value', $parameters[0], $message);
|
||||
});
|
||||
|
||||
Validator::extend('has_counter', function($attribute, $value, $parameters) {
|
||||
return !$value || strstr($value, '{$counter}');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -46,10 +46,10 @@ class AuthService
|
||||
if ($result === true) {
|
||||
if (!$isRegistered) {
|
||||
event(new UserSignedUp());
|
||||
Session::flash('warning', trans('texts.success_message'));
|
||||
Session::flash('message', trans('texts.success_message'));
|
||||
} else {
|
||||
Session::flash('message', trans('texts.updated_settings'));
|
||||
return redirect()->to('/company/details');
|
||||
return redirect()->to('/settings/' . ACCOUNT_USER_DETAILS);
|
||||
}
|
||||
} else {
|
||||
Session::flash('error', $result);
|
||||
|
@ -36,7 +36,7 @@ class PaymentService {
|
||||
$gateway->$function($val);
|
||||
}
|
||||
|
||||
if ($accountGateway->gateway->id == GATEWAY_DWOLLA) {
|
||||
if ($accountGateway->isGateway(GATEWAY_DWOLLA)) {
|
||||
if ($gateway->getSandbox() && isset($_ENV['DWOLLA_SANDBOX_KEY']) && isset($_ENV['DWOLLA_SANSBOX_SECRET'])) {
|
||||
$gateway->setKey($_ENV['DWOLLA_SANDBOX_KEY']);
|
||||
$gateway->setSecret($_ENV['DWOLLA_SANSBOX_SECRET']);
|
||||
@ -49,7 +49,7 @@ class PaymentService {
|
||||
return $gateway;
|
||||
}
|
||||
|
||||
public function getPaymentDetails($invitation, $input = null)
|
||||
public function getPaymentDetails($invitation, $accountGateway, $input = null)
|
||||
{
|
||||
$invoice = $invitation->invoice;
|
||||
$account = $invoice->account;
|
||||
@ -66,8 +66,7 @@ class PaymentService {
|
||||
}
|
||||
|
||||
$card = new CreditCard($data);
|
||||
|
||||
return [
|
||||
$data = [
|
||||
'amount' => $invoice->getRequestedAmount(),
|
||||
'card' => $card,
|
||||
'currency' => $currencyCode,
|
||||
@ -77,6 +76,12 @@ class PaymentService {
|
||||
'transactionId' => $invoice->invoice_number,
|
||||
'transactionType' => 'Purchase',
|
||||
];
|
||||
|
||||
if ($accountGateway->isGateway(GATEWAY_PAYPAL_EXPRESS) || $accountGateway->isGateway(GATEWAY_PAYPAL_PRO)) {
|
||||
$data['ButtonSource'] = 'InvoiceNinja_SP';
|
||||
};
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function convertInputForOmnipay($input)
|
||||
@ -222,7 +227,7 @@ class PaymentService {
|
||||
|
||||
// setup the gateway/payment info
|
||||
$gateway = $this->createGateway($accountGateway);
|
||||
$details = $this->getPaymentDetails($invitation);
|
||||
$details = $this->getPaymentDetails($invitation, $accountGateway);
|
||||
$details['cardReference'] = $token;
|
||||
|
||||
// submit purchase/get response
|
||||
|
@ -29,7 +29,7 @@
|
||||
"coatesap/omnipay-datacash": "~2.0",
|
||||
"alfaproject/omnipay-neteller": "1.0.*@dev",
|
||||
"mfauveau/omnipay-pacnet": "~2.0",
|
||||
"coatesap/omnipay-paymentsense": "~2.0",
|
||||
"coatesap/omnipay-paymentsense": "2.0.0",
|
||||
"coatesap/omnipay-realex": "~2.0",
|
||||
"fruitcakestudio/omnipay-sisow": "~2.0",
|
||||
"alfaproject/omnipay-skrill": "dev-master",
|
||||
@ -38,7 +38,8 @@
|
||||
"laravelcollective/html": "~5.0",
|
||||
"wildbit/laravel-postmark-provider": "dev-master",
|
||||
"Dwolla/omnipay-dwolla": "dev-master",
|
||||
"laravel/socialite": "~2.0"
|
||||
"laravel/socialite": "~2.0",
|
||||
"simshaun/recurr": "dev-master"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.0",
|
||||
|
7171
composer.lock
generated
7171
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -39,25 +39,25 @@ return [
|
||||
'github' => [
|
||||
'client_id' => env('GITHUB_CLIENT_ID'),
|
||||
'client_secret' => env('GITHUB_CLIENT_SECRET'),
|
||||
'redirect' => 'http://ninja.dev/auth/github'
|
||||
'redirect' => env('GITHUB_OAUTH_REDIRECT'),
|
||||
],
|
||||
|
||||
'google' => [
|
||||
'client_id' => '640903115046-dd09j2q24lcc3ilrrv5f2ft2i3n0sreg.apps.googleusercontent.com',
|
||||
'client_secret' => 'Vsfhldq7mRxsCXQTQI8U_4Ua',
|
||||
'redirect' => 'http://ninja.dev/auth/google',
|
||||
'client_id' => env('GOOGLE_CLIENT_ID'),
|
||||
'client_secret' => env('GOOGLE_CLIENT_SECRET'),
|
||||
'redirect' => env('GOOGLE_OAUTH_REDIRECT'),
|
||||
],
|
||||
|
||||
'facebook' => [
|
||||
'client_id' => '635126583203143',
|
||||
'client_secret' => '7aa7c391019f2ece3c6aa90f4c9b1485',
|
||||
'redirect' => 'http://ninja.dev/auth/facebook',
|
||||
'client_id' => env('FACEBOOK_CLIENT_ID'),
|
||||
'client_secret' => env('FACEBOOK_CLIENT_SECRET'),
|
||||
'redirect' => env('FACEBOOK_OAUTH_REDIRECT'),
|
||||
],
|
||||
|
||||
'linkedin' => [
|
||||
'client_id' => '778is2j21w25xj',
|
||||
'client_secret' => 'DvDExxfBLXUtxc81',
|
||||
'redirect' => 'http://ninja.dev/auth/linkedin',
|
||||
'client_id' => env('LINKEDIN_CLIENT_ID'),
|
||||
'client_secret' => env('LINKEDIN_CLIENT_SECRET'),
|
||||
'redirect' => env('LINKEDIN_OAUTH_REDIRECT'),
|
||||
],
|
||||
|
||||
];
|
||||
|
@ -14,10 +14,10 @@ class AddInvoiceNumberSettings extends Migration {
|
||||
{
|
||||
Schema::table('accounts', function($table)
|
||||
{
|
||||
$table->text('invoice_number_prefix')->nullable();
|
||||
$table->string('invoice_number_prefix')->nullable();
|
||||
$table->integer('invoice_number_counter')->default(1)->nullable();
|
||||
|
||||
$table->text('quote_number_prefix')->nullable();
|
||||
$table->string('quote_number_prefix')->nullable();
|
||||
$table->integer('quote_number_counter')->default(1)->nullable();
|
||||
|
||||
$table->boolean('share_counter')->default(true);
|
||||
|
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class AddDefaultTaxRates extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('accounts', function ($table) {
|
||||
$table->unsignedInteger('default_tax_rate_id')->nullable();
|
||||
$table->smallInteger('recurring_hour')->default(DEFAULT_SEND_RECURRING_HOUR);
|
||||
});
|
||||
|
||||
Schema::table('products', function ($table) {
|
||||
$table->unsignedInteger('default_tax_rate_id')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('accounts', function ($table) {
|
||||
$table->dropColumn('default_tax_rate_id');
|
||||
$table->dropColumn('recurring_hour');
|
||||
});
|
||||
|
||||
Schema::table('products', function ($table) {
|
||||
$table->dropColumn('default_tax_rate_id');
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class AddInvoiceNumberPattern extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('accounts', function ($table) {
|
||||
$table->string('invoice_number_pattern')->nullable();
|
||||
$table->string('quote_number_pattern')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('accounts', function ($table) {
|
||||
$table->dropColumn('invoice_number_pattern');
|
||||
$table->dropColumn('quote_number_pattern');
|
||||
});
|
||||
}
|
||||
}
|
@ -95,6 +95,8 @@ class PaymentLibrariesSeeder extends Seeder
|
||||
['name' => 'United Arab Emirates Dirham', 'code' => 'AED', 'symbol' => 'DH ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
|
||||
['name' => 'Hong Kong Dollar', 'code' => 'HKD', 'symbol' => '$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
|
||||
['name' => 'Indonesian Rupiah', 'code' => 'IDR', 'symbol' => 'Rp', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
|
||||
['name' => 'Mexican Peso', 'code' => 'MXN', 'symbol' => '$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
|
||||
['name' => 'Egyptian Pound', 'code' => 'EGP', 'symbol' => '£', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
|
||||
];
|
||||
|
||||
foreach ($currencies as $currency) {
|
||||
|
BIN
public/apple-touch-icon-120x120-precomposed.png
Normal file
BIN
public/apple-touch-icon-120x120-precomposed.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.3 KiB |
50
public/css/built.css
vendored
50
public/css/built.css
vendored
@ -2352,6 +2352,9 @@ body { background: #f8f8f8 !important;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-size: 15px;
|
||||
}
|
||||
html {
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.bold { font-weight: 700; }
|
||||
a {color:#0b4d78;}
|
||||
/*a:hover { text-decoration: none; color: #0a3857;}*/
|
||||
@ -3105,23 +3108,45 @@ box-shadow: 0px 0px 15px 0px rgba(0, 5, 5, 0.2);
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 992px) {
|
||||
.hide-desktop {display: none;}
|
||||
|
||||
/* Custom, iPhone Retina */
|
||||
@media only screen and (min-width : 320px) {
|
||||
|
||||
}
|
||||
|
||||
@media (max-width: 992px) {
|
||||
.hide-phone {
|
||||
display: none !important;
|
||||
/* Extra Small Devices, Phones */
|
||||
@media only screen and (min-width : 480px) {
|
||||
|
||||
}
|
||||
|
||||
/* Small Devices, Tablets */
|
||||
@media only screen and (min-width : 768px) {
|
||||
.form-padding-right {
|
||||
padding-right: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 992px) {
|
||||
/* Medium Devices, Desktops */
|
||||
@media only screen and (min-width : 992px) {
|
||||
.form-padding-right {
|
||||
padding-right: 100px;
|
||||
}
|
||||
.medium-dialog {
|
||||
width: 760px;
|
||||
}
|
||||
.large-dialog {
|
||||
width: 960px;
|
||||
}
|
||||
.hide-desktop
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 992px) {
|
||||
.hide-phone {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
@ -3337,7 +3362,18 @@ ul.user-accounts a:hover div.remove {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.tooltip-inner {
|
||||
.invoice-contact .tooltip-inner {
|
||||
text-align:left;
|
||||
width: 350px;
|
||||
}
|
||||
|
||||
/* Show selected section in settings nav */
|
||||
.list-group-item.selected:before {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 2px;
|
||||
content: "";
|
||||
background-color: #e37329;
|
||||
}
|
20
public/css/built.public.css
vendored
20
public/css/built.public.css
vendored
@ -785,7 +785,9 @@ body {
|
||||
font-size: 14px;
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
html {
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 700px) {
|
||||
.navbar-header {
|
||||
@ -837,7 +839,7 @@ body {
|
||||
display: inline-block;
|
||||
width: 9px;
|
||||
height: 15px;
|
||||
background: url({{ asset('images/social/facebook.svg') }}) no-repeat;
|
||||
background: url('../images/social/facebook.svg') no-repeat;
|
||||
margin: 0 6px 0 0;
|
||||
position: relative;
|
||||
top: 3px;
|
||||
@ -848,7 +850,7 @@ body {
|
||||
display: inline-block;
|
||||
width: 19px;
|
||||
height: 16px;
|
||||
background: url({{ asset('images/social/twitter.svg') }}) no-repeat;
|
||||
background: url('../images/social/twitter.svg') no-repeat;
|
||||
margin: 0 6px 0 0;
|
||||
position: relative;
|
||||
top: 3px;
|
||||
@ -859,18 +861,18 @@ body {
|
||||
display: inline-block;
|
||||
width: 19px;
|
||||
height: 16px;
|
||||
background: url({{ asset('images/social/github.png') }}) no-repeat;
|
||||
background: url('../images/social/github.png') no-repeat;
|
||||
margin: 0 6px 0 0;
|
||||
position: relative;
|
||||
top: 3px;
|
||||
}
|
||||
|
||||
/* Hide bootstrap sort header icons */
|
||||
table.data-table thead .sorting:after { content: '' !important }
|
||||
table.data-table thead .sorting_asc:after { content: '' !important }
|
||||
table.data-table thead .sorting_desc:after { content: '' !important}
|
||||
table.data-table thead .sorting_asc_disabled:after { content: '' !important }
|
||||
table.data-table thead .sorting_desc_disabled:after { content: '' !important }
|
||||
table.table thead .sorting:after { content: '' !important }
|
||||
table.table thead .sorting_asc:after { content: '' !important }
|
||||
table.table thead .sorting_desc:after { content: '' !important }
|
||||
table.table thead .sorting_asc_disabled:after { content: '' !important }
|
||||
table.table thead .sorting_desc_disabled:after { content: '' !important }
|
||||
|
||||
.dataTables_length {
|
||||
padding-left: 20px;
|
||||
|
10
public/css/public.style.css
vendored
10
public/css/public.style.css
vendored
@ -3,7 +3,9 @@ body {
|
||||
font-size: 14px;
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
html {
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 700px) {
|
||||
.navbar-header {
|
||||
@ -55,7 +57,7 @@ body {
|
||||
display: inline-block;
|
||||
width: 9px;
|
||||
height: 15px;
|
||||
background: url({{ asset('images/social/facebook.svg') }}) no-repeat;
|
||||
background: url('../images/social/facebook.svg') no-repeat;
|
||||
margin: 0 6px 0 0;
|
||||
position: relative;
|
||||
top: 3px;
|
||||
@ -66,7 +68,7 @@ body {
|
||||
display: inline-block;
|
||||
width: 19px;
|
||||
height: 16px;
|
||||
background: url({{ asset('images/social/twitter.svg') }}) no-repeat;
|
||||
background: url('../images/social/twitter.svg') no-repeat;
|
||||
margin: 0 6px 0 0;
|
||||
position: relative;
|
||||
top: 3px;
|
||||
@ -77,7 +79,7 @@ body {
|
||||
display: inline-block;
|
||||
width: 19px;
|
||||
height: 16px;
|
||||
background: url({{ asset('images/social/github.png') }}) no-repeat;
|
||||
background: url('../images/social/github.png') no-repeat;
|
||||
margin: 0 6px 0 0;
|
||||
position: relative;
|
||||
top: 3px;
|
||||
|
50
public/css/style.css
vendored
50
public/css/style.css
vendored
@ -2,6 +2,9 @@ body { background: #f8f8f8 !important;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-size: 15px;
|
||||
}
|
||||
html {
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.bold { font-weight: 700; }
|
||||
a {color:#0b4d78;}
|
||||
/*a:hover { text-decoration: none; color: #0a3857;}*/
|
||||
@ -755,23 +758,45 @@ box-shadow: 0px 0px 15px 0px rgba(0, 5, 5, 0.2);
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 992px) {
|
||||
.hide-desktop {display: none;}
|
||||
|
||||
/* Custom, iPhone Retina */
|
||||
@media only screen and (min-width : 320px) {
|
||||
|
||||
}
|
||||
|
||||
@media (max-width: 992px) {
|
||||
.hide-phone {
|
||||
display: none !important;
|
||||
/* Extra Small Devices, Phones */
|
||||
@media only screen and (min-width : 480px) {
|
||||
|
||||
}
|
||||
|
||||
/* Small Devices, Tablets */
|
||||
@media only screen and (min-width : 768px) {
|
||||
.form-padding-right {
|
||||
padding-right: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 992px) {
|
||||
/* Medium Devices, Desktops */
|
||||
@media only screen and (min-width : 992px) {
|
||||
.form-padding-right {
|
||||
padding-right: 100px;
|
||||
}
|
||||
.medium-dialog {
|
||||
width: 760px;
|
||||
}
|
||||
.large-dialog {
|
||||
width: 960px;
|
||||
}
|
||||
.hide-desktop
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 992px) {
|
||||
.hide-phone {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
@ -987,7 +1012,18 @@ ul.user-accounts a:hover div.remove {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.tooltip-inner {
|
||||
.invoice-contact .tooltip-inner {
|
||||
text-align:left;
|
||||
width: 350px;
|
||||
}
|
||||
|
||||
/* Show selected section in settings nav */
|
||||
.list-group-item.selected:before {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 2px;
|
||||
content: "";
|
||||
background-color: #e37329;
|
||||
}
|
@ -32060,6 +32060,7 @@ NINJA.clientDetails = function(invoice) {
|
||||
if (!client) {
|
||||
return;
|
||||
}
|
||||
var account = invoice.account;
|
||||
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;
|
||||
@ -32070,6 +32071,11 @@ NINJA.clientDetails = function(invoice) {
|
||||
cityStatePostal = formatAddress(client.city, client.state, client.postal_code, swap);
|
||||
}
|
||||
|
||||
// if a custom field is used in the invoice/quote number then we'll hide it from the PDF
|
||||
var pattern = invoice.is_quote ? account.quote_number_pattern : account.invoice_number_pattern;
|
||||
var custom1InPattern = (pattern && pattern.indexOf('{$custom1}') >= 0);
|
||||
var custom2InPattern = (pattern && pattern.indexOf('{$custom2}') >= 0);
|
||||
|
||||
data = [
|
||||
{text:clientName || ' ', style: ['clientName']},
|
||||
{text:client.id_number},
|
||||
@ -32079,8 +32085,8 @@ NINJA.clientDetails = function(invoice) {
|
||||
{text:cityStatePostal},
|
||||
{text:client.country ? client.country.name : ''},
|
||||
{text:clientEmail},
|
||||
{text: invoice.client.custom_value1 ? invoice.account.custom_client_label1 + ' ' + invoice.client.custom_value1 : false},
|
||||
{text: invoice.client.custom_value2 ? invoice.account.custom_client_label2 + ' ' + invoice.client.custom_value2 : false}
|
||||
{text: client.custom_value1 && !custom1InPattern ? account.custom_client_label1 + ' ' + client.custom_value1 : false},
|
||||
{text: client.custom_value2 && !custom2InPattern ? account.custom_client_label2 + ' ' + client.custom_value2 : false}
|
||||
];
|
||||
|
||||
return NINJA.prepareDataList(data, 'clientDetails');
|
||||
|
7928
public/js/pdf.built.js
Normal file
7928
public/js/pdf.built.js
Normal file
File diff suppressed because one or more lines are too long
@ -487,6 +487,7 @@ NINJA.clientDetails = function(invoice) {
|
||||
if (!client) {
|
||||
return;
|
||||
}
|
||||
var account = invoice.account;
|
||||
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;
|
||||
@ -497,6 +498,11 @@ NINJA.clientDetails = function(invoice) {
|
||||
cityStatePostal = formatAddress(client.city, client.state, client.postal_code, swap);
|
||||
}
|
||||
|
||||
// if a custom field is used in the invoice/quote number then we'll hide it from the PDF
|
||||
var pattern = invoice.is_quote ? account.quote_number_pattern : account.invoice_number_pattern;
|
||||
var custom1InPattern = (pattern && pattern.indexOf('{$custom1}') >= 0);
|
||||
var custom2InPattern = (pattern && pattern.indexOf('{$custom2}') >= 0);
|
||||
|
||||
data = [
|
||||
{text:clientName || ' ', style: ['clientName']},
|
||||
{text:client.id_number},
|
||||
@ -506,8 +512,8 @@ NINJA.clientDetails = function(invoice) {
|
||||
{text:cityStatePostal},
|
||||
{text:client.country ? client.country.name : ''},
|
||||
{text:clientEmail},
|
||||
{text: invoice.client.custom_value1 ? invoice.account.custom_client_label1 + ' ' + invoice.client.custom_value1 : false},
|
||||
{text: invoice.client.custom_value2 ? invoice.account.custom_client_label2 + ' ' + invoice.client.custom_value2 : false}
|
||||
{text: client.custom_value1 && !custom1InPattern ? account.custom_client_label1 + ' ' + client.custom_value1 : false},
|
||||
{text: client.custom_value2 && !custom2InPattern ? account.custom_client_label2 + ' ' + client.custom_value2 : false}
|
||||
];
|
||||
|
||||
return NINJA.prepareDataList(data, 'clientDetails');
|
||||
|
11
readme.md
11
readme.md
@ -7,14 +7,13 @@
|
||||
|
||||
[![Join the chat at https://gitter.im/hillelcoren/invoice-ninja](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/hillelcoren/invoice-ninja?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
Please help our project by voting for us on [Product Hunt](http://www.producthunt.com/tech/invoice-ninja).
|
||||
|
||||
If you'd like to use our code to sell your own invoicing app email us for details about our affiliate program.
|
||||
|
||||
### Installation Options
|
||||
* [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)
|
||||
* [Self-Host Zip](https://www.invoiceninja.com/knowledgebase/self-host/) - Free
|
||||
* [Docker File](https://github.com/rollbrettler/Dockerfiles/blob/master/invoice-ninja/Dockerfile) - Free
|
||||
* [Bitnami](https://bitnami.com/stack/invoice-ninja) - Free
|
||||
* [Softaculous](https://www.softaculous.com/apps/ecommerce/Invoice_Ninja) - $30
|
||||
|
||||
### Features
|
||||
* Built using Laravel 5
|
||||
@ -26,6 +25,7 @@ If you'd like to use our code to sell your own invoicing app email us for detail
|
||||
* Tax rates and payment terms
|
||||
* Reminder emails
|
||||
* Partial payments
|
||||
* Client portal
|
||||
* Custom email templates
|
||||
* [Zapier](https://zapier.com/) integration
|
||||
* [D3.js](http://d3js.org/) visualizations
|
||||
@ -78,3 +78,4 @@ If you'd like to use our code to sell your own invoicing app email us for detail
|
||||
* [bgrins/spectrum](https://github.com/bgrins/spectrum) - The No Hassle JavaScript Colorpicker
|
||||
* [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
|
||||
* [simshaun/recurr](https://github.com/simshaun/recurr) - PHP library for working with recurrence rules
|
@ -262,7 +262,7 @@
|
||||
'email_salutation' => 'Kære :name,',
|
||||
'email_signature' => 'Med venlig hilsen,',
|
||||
'email_from' => 'Invoice Ninja Teamet',
|
||||
'user_email_footer' => 'For at justere varslings indstillingene besøg venligst'.SITE_URL.'/company/notifications',
|
||||
'user_email_footer' => 'For at justere varslings indstillingene besøg venligst'.SITE_URL.'/settings/notifications',
|
||||
'invoice_link_message' => 'Hvis du vil se din klient faktura klik på linket under:',
|
||||
'notification_invoice_paid_subject' => 'Faktura :invoice betalt af :client',
|
||||
'notification_invoice_sent_subject' => 'Faktura :invoice sendt til :client',
|
||||
@ -271,15 +271,14 @@
|
||||
'notification_invoice_sent' => 'En e-mail er blevet sendt til :client med faktura :invoice pålydende :amount.',
|
||||
'notification_invoice_viewed' => ':client har set faktura :invoice pålydende :amount.',
|
||||
'reset_password' => 'Du kan nulstille din adgangskode ved at besøge følgende link:',
|
||||
'reset_password_footer' => 'Hvis du ikke bad om at få nulstillet din adgangskode kontakt venligst kundeservice: ' . CONTACT_EMAIL,
|
||||
|
||||
'reset_password_footer' => 'Hvis du ikke bad om at få nulstillet din adgangskode kontakt venligst kundeservice: '.CONTACT_EMAIL,
|
||||
|
||||
// Payment page
|
||||
'secure_payment' => 'Sikker betaling',
|
||||
'card_number' => 'Kortnummer',
|
||||
'expiration_month' => 'Udløbsdato',
|
||||
'expiration_year' => 'Udløbsår',
|
||||
'cvv' =>'Kontrolcifre',
|
||||
'cvv' => 'Kontrolcifre',
|
||||
|
||||
// Security alerts
|
||||
'security' => [
|
||||
@ -300,7 +299,7 @@
|
||||
|
||||
'logout' => 'Log ud',
|
||||
'sign_up_to_save' => 'Registrer dig for at gemme dit arbejde',
|
||||
'agree_to_terms' =>'Jeg accepterer Invoice Ninja :terms',
|
||||
'agree_to_terms' => 'Jeg accepterer Invoice Ninja :terms',
|
||||
'terms_of_service' => 'Vilkår for brug',
|
||||
'email_taken' => 'E-mailadressen er allerede registreret',
|
||||
'working' => 'Arbejder',
|
||||
@ -420,7 +419,7 @@
|
||||
'active' => 'Aktiv',
|
||||
'pending' => 'Afventer',
|
||||
'deleted_user' => 'Bruger slettet',
|
||||
'limit_users' => 'Desværre, dette vil overstige grænsen på ' . MAX_NUM_USERS . ' brugere',
|
||||
'limit_users' => 'Desværre, dette vil overstige grænsen på '.MAX_NUM_USERS.' brugere',
|
||||
|
||||
'confirm_email_invoice' => 'Er du sikker på at du vil sende en e-mail med denne faktura?',
|
||||
'confirm_email_quote' => 'Er du sikker på du ville sende en e-mail med dette tilbud?',
|
||||
@ -746,7 +745,6 @@
|
||||
'current_user' => 'Nuværende bruger',
|
||||
'new_recurring_invoice' => 'Ny gentaget fakture',
|
||||
'recurring_invoice' => 'Gentaget faktura',
|
||||
'recurring_too_soon' => 'Det er for tidligt at generere den næste faktura',
|
||||
'created_by_invoice' => 'Oprettet fra :invoice',
|
||||
'primary_user' => 'Primær bruger',
|
||||
'help' => 'Hjælp',
|
||||
@ -818,6 +816,15 @@
|
||||
'custom_invoice_link' => 'Custom Invoice Link',
|
||||
'total_invoiced' => 'Total Invoiced',
|
||||
'open_balance' => 'Open Balance',
|
||||
'verify_email' => 'Please visit the link in the account confirmation email to verify your email address.',
|
||||
'basic_settings' => 'Basic Settings',
|
||||
'pro' => 'Pro',
|
||||
'gateways' => 'Payment Gateways',
|
||||
'recurring_too_soon' => 'Det er for tidligt at generere den næste faktura, it\'s scheduled for :date',
|
||||
|
||||
'next_send_on' => 'Send Next: :date',
|
||||
'no_longer_running' => 'This invoice is not scheduled to run',
|
||||
'general_settings' => 'General Settings',
|
||||
'customize' => 'Customize',
|
||||
|
||||
);
|
@ -77,6 +77,7 @@ return array(
|
||||
"has_credit" => "The client does not have enough credit.",
|
||||
"notmasked" => "The values are masked",
|
||||
"less_than" => 'The :attribute must be less than :value',
|
||||
"has_counter" => 'The value must contain {$counter}',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
22
resources/lang/de/passwords.php
Normal file
22
resources/lang/de/passwords.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Password Reminder Language Lines
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following language lines are the default lines which match reasons
|
||||
| that are given by the password broker for a password update attempt
|
||||
| has failed, such as for an invalid token or invalid new password.
|
||||
|
|
||||
*/
|
||||
|
||||
"password" => "Beide Passwörter müssen übereinstimmen und mindestens 6 Zeichen lang sein.",
|
||||
"user" => "Wir können keinen Nutzer mit dieser E-Mail Adresse finden.",
|
||||
"token" => "Der Code zum Zurücksetzen des Passworts ist ungültig oder abgelaufen.",
|
||||
"sent" => "Es wurde soeben eine E-Mail verschickt, die einen Link zum Zurücksetzen des Passworts enthält!",
|
||||
"reset" => "Das Passwort wurde zurückgesetzt!",
|
||||
|
||||
];
|
@ -46,7 +46,7 @@ return array(
|
||||
'line_total' => 'Summe',
|
||||
'subtotal' => 'Zwischensumme',
|
||||
'paid_to_date' => 'Bereits gezahlt',
|
||||
'balance_due' => 'Geschuldeter Betrag',
|
||||
'balance_due' => 'Offener Betrag',
|
||||
'invoice_design_id' => 'Design',
|
||||
'terms' => 'Bedingungen',
|
||||
'your_invoice' => 'Ihre Rechnung',
|
||||
@ -262,7 +262,7 @@ return array(
|
||||
'email_salutation' => 'Sehr geehrte/r :name,',
|
||||
'email_signature' => 'Mit freundlichen Grüßen,',
|
||||
'email_from' => 'Das InvoiceNinja Team',
|
||||
'user_email_footer' => 'Um deine E-Mail-Benachrichtigungen anzupassen besuche bitte '.SITE_URL.'/company/notifications',
|
||||
'user_email_footer' => 'Um deine E-Mail-Benachrichtigungen anzupassen besuche bitte '.SITE_URL.'/settings/notifications',
|
||||
'invoice_link_message' => 'Um deine Kundenrechnung anzuschauen, klicke auf den folgenden Link:',
|
||||
'notification_invoice_paid_subject' => 'Die Rechnung :invoice wurde von :client bezahlt.',
|
||||
'notification_invoice_sent_subject' => 'Die Rechnung :invoice wurde an :client versendet.',
|
||||
@ -308,7 +308,6 @@ return array(
|
||||
'success_message' => 'Du hast dich erfolgreich registriert. Bitte besuche den Link in deiner Bestätigungsmail um deine E-Mail-Adresse zu verifizieren.',
|
||||
'erase_data' => 'Diese Aktion wird deine Daten dauerhaft löschen.',
|
||||
'password' => 'Passwort',
|
||||
'close' => 'Schließen',
|
||||
|
||||
'pro_plan_product' => 'Pro Plan',
|
||||
'pro_plan_description' => 'Jahresmitgliedschaft beim Invoice Ninja Pro Plan.',
|
||||
@ -574,7 +573,8 @@ return array(
|
||||
'recover_password' => 'Passwort wiederherstellen',
|
||||
'forgot_password' => 'Passwort vergessen?',
|
||||
'email_address' => 'E-Mail-Adresse',
|
||||
'lets_go' => "Auf geht's",
|
||||
'lets_go' => 'Auf geht\'s',
|
||||
//'lets_go' => 'Login',
|
||||
'password_recovery' => 'Passwort-Wiederherstellung',
|
||||
'send_email' => 'E-Mail verschicken',
|
||||
'set_password' => 'Passwort festlegen',
|
||||
@ -745,14 +745,14 @@ return array(
|
||||
'current_user' => 'Aktueller Benutzer',
|
||||
'new_recurring_invoice' => 'Neue wiederkehrende Rechnung',
|
||||
'recurring_invoice' => 'Wiederkehrende Rechnung',
|
||||
'recurring_too_soon' => 'Es ist zu früh, um die nächste wiederkehrende Rechnung zu erstellen',
|
||||
'recurring_too_soon' => 'Es ist zu früh die nächste wiederkehrende Rechnung zu erstellen, die nächste ist am :date geplant',
|
||||
'created_by_invoice' => 'Erstellt durch :invoice',
|
||||
'primary_user' => 'Primärer Benutzer',
|
||||
'help' => 'Hilfe',
|
||||
'customize_help' => '<p>We use <a href="http://pdfmake.org/" target="_blank">pdfmake</a> to define the invoice designs declaratively. The pdfmake <a href="http://pdfmake.org/playground.html" target="_blank">playground</a> provide\'s a great way to see the library in action.</p>
|
||||
<p>You can access any invoice field by adding <code>Value</code> to the end. For example <code>$invoiceNumberValue</code> displays the invoice number.</p>
|
||||
<p>To access a child property using dot notation. For example to show the client name you could use <code>$client.nameValue</code>.</p>
|
||||
<p>If you need help figuring something out post a question to our <a href="https://www.invoiceninja.com/forums/forum/support/" target="_blank">support forum</a>.</p>',
|
||||
'customize_help' => '<p>Wir benutzen zur deklarativen Definition der Rechnungsdesigns <a href="http://pdfmake.org/" target="_blank">pdfmake</a>. Der pdfmake <a href="http://pdfmake.org/playground.html" target="_blank">playground</a> bietet Gelegenheit die Bibliothek in Aktion zu sehen.</p>
|
||||
<p>Man kann jedes Rechnungsfeld nutzen, in dem man <code>Value</code> hinten anhängt. Zum Beispiel zeigt <code>$invoiceNumberValue</code> die Rechnungsnummer.</p>
|
||||
<p>Mit der <i>dot notation</i> kann auf Kind-Eigenschaften zugegriffen werden. Für den Kundennamen kann man zum Beispiel <code>$client.nameValue</code> benutzen.</p>
|
||||
<p>Wenn du Hilfe brauchst schreibe uns gern im <a href="https://www.invoiceninja.com/forums/forum/support/" target="_blank">Support Forum</a> (Englisch).</p>',
|
||||
|
||||
'invoice_due_date' => 'Fällig am',
|
||||
'quote_due_date' => 'Gültig bis',
|
||||
@ -767,11 +767,11 @@ return array(
|
||||
'status_paid' => 'Bezahlt',
|
||||
'show_line_item_tax' => '<b>Steuern für Belegpositionen</b> in der jeweiligen Zeile anzeigen',
|
||||
|
||||
'iframe_url' => 'Website',
|
||||
'iframe_url' => 'Webseite',
|
||||
'iframe_url_help1' => 'Kopiere den folgenden Code in eine Seite auf deiner Website.',
|
||||
'iframe_url_help2' => 'You can test the feature by clicking \'View as recipient\' for an invoice.',
|
||||
'iframe_url_help2' => 'Du kannst diese Funktion testen, in dem du für eine Rechnung \'Als Empfänger betrachten\'. anklickst.',
|
||||
|
||||
'auto_bill' => 'Auto Bill',
|
||||
'auto_bill' => 'Auto-Rechnung',
|
||||
'military_time' => '24-Stunden-Zeit',
|
||||
'last_sent' => 'Zuletzt gesendet',
|
||||
|
||||
@ -792,31 +792,53 @@ return array(
|
||||
'last_sent_on' => 'Zuletzt versendet am :date',
|
||||
|
||||
'page_expire' => 'Diese Seite wird bald ablaufen, :click_here um weiter zu arbeiten',
|
||||
'upcoming_quotes' => 'Upcoming Quotes',
|
||||
'expired_quotes' => 'Expired Quotes',
|
||||
'upcoming_quotes' => 'Kommende Angebote',
|
||||
'expired_quotes' => 'Abgelaufene Angebote',
|
||||
|
||||
'sign_up_using' => 'Sign up using',
|
||||
'invalid_credentials' => 'These credentials do not match our records',
|
||||
'show_all_options' => 'Show all options',
|
||||
'user_details' => 'User Details',
|
||||
'sign_up_using' => 'Anmelden mit',
|
||||
'invalid_credentials' => 'Diese Zugangsdaten können wir nicht finden.',
|
||||
'show_all_options' => 'Zeige alle Optionen',
|
||||
'user_details' => 'Nutzer Details',
|
||||
'oneclick_login' => 'One-Click Login',
|
||||
'disable' => 'Disable',
|
||||
'invoice_quote_number' => 'Invoice and Quote Numbers',
|
||||
'invoice_charges' => 'Invoice Charges',
|
||||
'disable' => 'Deaktivieren',
|
||||
'invoice_quote_number' => 'Rechnungs- und Angebotsnummern',
|
||||
'invoice_charges' => 'Rechnungs-Gebühren',
|
||||
|
||||
'invitation_status' => [
|
||||
'sent' => 'Email Sent',
|
||||
'opened' => 'Email Openend',
|
||||
'viewed' => 'Invoice Viewed',
|
||||
'sent' => 'E-Mail versandt',
|
||||
'opened' => 'E-Mail geöffnet',
|
||||
'viewed' => 'Rechnung angesehen',
|
||||
],
|
||||
'notification_invoice_bounced' => 'We were unable to deliver Invoice :invoice to :contact.',
|
||||
'notification_invoice_bounced_subject' => 'Unable to deliver Invoice :invoice',
|
||||
'notification_quote_bounced' => 'We were unable to deliver Quote :invoice to :contact.',
|
||||
'notification_quote_bounced_subject' => 'Unable to deliver Quote :invoice',
|
||||
'notification_invoice_bounced' => 'Die Rechnung :invoice an :contact konnte nicht zugestellt werden.',
|
||||
'notification_invoice_bounced_subject' => 'Rechnung :invoice nicht zugestellt.',
|
||||
'notification_quote_bounced' => 'Das Angebot :invoice an :contact konnte nicht zugestellt werden.',
|
||||
'notification_quote_bounced_subject' => 'Angebot :invoice wurde nicht zugestellt.',
|
||||
|
||||
'custom_invoice_link' => 'Custom Invoice Link',
|
||||
'total_invoiced' => 'Total Invoiced',
|
||||
'open_balance' => 'Open Balance',
|
||||
'custom_invoice_link' => 'Manueller Rechnungs-Link',
|
||||
'total_invoiced' => 'Rechnungs-Betrag',
|
||||
'open_balance' => 'Offener Betrag',
|
||||
'verify_email' => 'Bitte klicken sie auf den Link in der Bestätigungsmail, um die E-Mail-Adresse zu verifizieren.',
|
||||
'basic_settings' => 'Allgemeine Einstellungen',
|
||||
'pro' => 'Pro',
|
||||
'gateways' => 'Payment Gateways',
|
||||
|
||||
'next_send_on' => 'Nächster Versand: :date',
|
||||
'no_longer_running' => 'Diese Rechnung wird momentan nicht automatisch erstellt.',
|
||||
'general_settings' => 'Allgemeine Einstellungen',
|
||||
'customize' => 'Anpassen',
|
||||
|
||||
'oneclick_login_help' => 'Connect an account to login without a password',
|
||||
'referral_code_help' => 'Earn money by sharing our app online',
|
||||
|
||||
'enable_with_stripe' => 'Enable | Requires Stripe',
|
||||
'tax_settings' => 'Steuer Einstellungen',
|
||||
'create_tax_rate' => 'Neuer Steuersatz',
|
||||
'updated_tax_rate' => 'Steuersatz aktualisiert',
|
||||
'created_tax_rate' => 'Steuersatz erstellt',
|
||||
'edit_tax_rate' => 'Steuersatz bearbeiten',
|
||||
'archive_tax_rate' => 'Steuersatz archivieren',
|
||||
'archived_tax_rate' => 'Steuersatz archiviert',
|
||||
'default_tax_rate_id' => 'Standard Steuersatz',
|
||||
'tax_rate' => 'Steuersatz',
|
||||
|
||||
);
|
||||
|
@ -75,6 +75,7 @@ return array(
|
||||
"has_credit" => "Der Kunde hat nicht genug Guthaben.",
|
||||
"notmasked" => "The values are masked",
|
||||
"less_than" => 'The :attribute must be less than :value',
|
||||
"has_counter" => 'The value must contain {$counter}',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
@ -262,7 +262,7 @@ return array(
|
||||
'email_salutation' => 'Dear :name,',
|
||||
'email_signature' => 'Regards,',
|
||||
'email_from' => 'The Invoice Ninja Team',
|
||||
'user_email_footer' => 'To adjust your email notification settings please visit '.SITE_URL.'/company/notifications',
|
||||
'user_email_footer' => 'To adjust your email notification settings please visit '.SITE_URL.'/settings/notifications',
|
||||
'invoice_link_message' => 'To view your client invoice click the link below:',
|
||||
'notification_invoice_paid_subject' => 'Invoice :invoice was paid by :client',
|
||||
'notification_invoice_sent_subject' => 'Invoice :invoice was sent to :client',
|
||||
@ -337,7 +337,7 @@ return array(
|
||||
'fill_products_help' => 'Selecting a product will automatically <b>fill in the description and cost</b>',
|
||||
'update_products' => 'Auto-update products',
|
||||
'update_products_help' => 'Updating an invoice will automatically <b>update the product library</b>',
|
||||
'create_product' => 'Create Product',
|
||||
'create_product' => 'Add Product',
|
||||
'edit_product' => 'Edit Product',
|
||||
'archive_product' => 'Archive Product',
|
||||
'updated_product' => 'Successfully updated product',
|
||||
@ -557,7 +557,7 @@ return array(
|
||||
'created_gateway' => 'Successfully created gateway',
|
||||
'deleted_gateway' => 'Successfully deleted gateway',
|
||||
'pay_with_paypal' => 'PayPal',
|
||||
'pay_with_card' => 'Credit card',
|
||||
'pay_with_card' => 'Credit Card',
|
||||
|
||||
'change_password' => 'Change password',
|
||||
'current_password' => 'Current password',
|
||||
@ -587,7 +587,7 @@ return array(
|
||||
'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.',
|
||||
'payment_type_credit_card' => 'Credit card',
|
||||
'payment_type_credit_card' => 'Credit Card',
|
||||
'payment_type_paypal' => 'PayPal',
|
||||
'payment_type_bitcoin' => 'Bitcoin',
|
||||
'knowledge_base' => 'Knowledge Base',
|
||||
@ -745,7 +745,7 @@ return array(
|
||||
'current_user' => 'Current User',
|
||||
'new_recurring_invoice' => 'New Recurring Invoice',
|
||||
'recurring_invoice' => 'Recurring Invoice',
|
||||
'recurring_too_soon' => 'It\'s too soon to create the next recurring invoice',
|
||||
'recurring_too_soon' => 'It\'s too soon to create the next recurring invoice, it\'s scheduled for :date',
|
||||
'created_by_invoice' => 'Created by :invoice',
|
||||
'primary_user' => 'Primary User',
|
||||
'help' => 'Help',
|
||||
@ -789,7 +789,7 @@ return array(
|
||||
|
||||
'referral_program' => 'Referral Program',
|
||||
'referral_code' => 'Referral Code',
|
||||
'last_sent_on' => 'Last sent on :date',
|
||||
'last_sent_on' => 'Sent Last: :date',
|
||||
|
||||
'page_expire' => 'This page will expire soon, :click_here to keep working',
|
||||
'upcoming_quotes' => 'Upcoming Quotes',
|
||||
@ -809,6 +809,7 @@ return array(
|
||||
'opened' => 'Email Openend',
|
||||
'viewed' => 'Invoice Viewed',
|
||||
],
|
||||
|
||||
'notification_invoice_bounced' => 'We were unable to deliver Invoice :invoice to :contact.',
|
||||
'notification_invoice_bounced_subject' => 'Unable to deliver Invoice :invoice',
|
||||
'notification_quote_bounced' => 'We were unable to deliver Quote :invoice to :contact.',
|
||||
@ -818,6 +819,37 @@ return array(
|
||||
'total_invoiced' => 'Total Invoiced',
|
||||
'open_balance' => 'Open Balance',
|
||||
'verify_email' => 'Please visit the link in the account confirmation email to verify your email address.',
|
||||
'basic_settings' => 'Basic Settings',
|
||||
'pro' => 'Pro',
|
||||
'gateways' => 'Payment Gateways',
|
||||
|
||||
'next_send_on' => 'Send Next: :date',
|
||||
'no_longer_running' => 'This invoice is not scheduled to run',
|
||||
'general_settings' => 'General Settings',
|
||||
'customize' => 'Customize',
|
||||
|
||||
'oneclick_login_help' => 'Connect an account to login without a password',
|
||||
'referral_code_help' => 'Earn money by sharing our app online',
|
||||
|
||||
'enable_with_stripe' => 'Enable | Requires Stripe',
|
||||
'tax_settings' => 'Tax Settings',
|
||||
'create_tax_rate' => 'Add Tax Rate',
|
||||
'updated_tax_rate' => 'Successfully updated tax rate',
|
||||
'created_tax_rate' => 'Successfully created tax rate',
|
||||
'edit_tax_rate' => 'Edit tax rate',
|
||||
'archive_tax_rate' => 'Archive tax rate',
|
||||
'archived_tax_rate' => 'Successfully archived the tax rate',
|
||||
'default_tax_rate_id' => 'Default Tax Rate',
|
||||
'tax_rate' => 'Tax Rate',
|
||||
'recurring_hour' => 'Recurring Hour',
|
||||
'pattern' => 'Pattern',
|
||||
'pattern_help_title' => 'Pattern Help',
|
||||
'pattern_help_1' => 'Create custom invoice and quote numbers by specifying a pattern',
|
||||
'pattern_help_2' => 'Available variables:',
|
||||
'pattern_help_3' => 'For example, :example would be converted to :value',
|
||||
'see_options' => 'See options',
|
||||
'invoice_counter' => 'Invoice Counter',
|
||||
'quote_counter' => 'Quote Counter',
|
||||
'type' => 'Type',
|
||||
|
||||
);
|
||||
|
||||
|
@ -73,6 +73,7 @@ return array(
|
||||
"has_credit" => "The client does not have enough credit.",
|
||||
"notmasked" => "The values are masked",
|
||||
"less_than" => 'The :attribute must be less than :value',
|
||||
"has_counter" => 'The value must contain {$counter}',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
@ -256,7 +256,7 @@ return array(
|
||||
'email_salutation' => 'Estimado :name,',
|
||||
'email_signature' => 'Un saludo cordial,',
|
||||
'email_from' => 'El equipo de Invoice Ninja ',
|
||||
'user_email_footer' => 'Para ajustar la configuración de las notificaciones de tu correo, visita '.SITE_URL.'/company/notifications',
|
||||
'user_email_footer' => 'Para ajustar la configuración de las notificaciones de tu correo, visita '.SITE_URL.'/settings/notifications',
|
||||
'invoice_link_message' => 'Para visualizar la factura de cliente, haz clic en el enlace abajo:',
|
||||
'notification_invoice_paid_subject' => 'La factura :invoice ha sido pagada por el cliente :client',
|
||||
'notification_invoice_sent_subject' => 'La factura :invoice ha sido enviada a el cliente :client',
|
||||
@ -723,7 +723,6 @@ return array(
|
||||
'current_user' => 'Usuario Actual',
|
||||
'new_recurring_invoice' => 'Nueva Factura Recurrente',
|
||||
'recurring_invoice' => 'Factura Recurrente',
|
||||
'recurring_too_soon' => 'Es my pronto para crear la siguiente factura recurrente',
|
||||
'created_by_invoice' => 'Creado por :invoice',
|
||||
'primary_user' => 'Usuario Primario',
|
||||
'help' => 'Ayuda',
|
||||
@ -795,6 +794,16 @@ return array(
|
||||
'custom_invoice_link' => 'Custom Invoice Link',
|
||||
'total_invoiced' => 'Total Invoiced',
|
||||
'open_balance' => 'Open Balance',
|
||||
'verify_email' => 'Please visit the link in the account confirmation email to verify your email address.',
|
||||
'basic_settings' => 'Basic Settings',
|
||||
'pro' => 'Pro',
|
||||
'gateways' => 'Payment Gateways',
|
||||
'recurring_too_soon' => 'Es my pronto para crear la siguiente factura recurrente, it\'s scheduled for :date',
|
||||
|
||||
'next_send_on' => 'Send Next: :date',
|
||||
'no_longer_running' => 'This invoice is not scheduled to run',
|
||||
'general_settings' => 'General Settings',
|
||||
'customize' => 'Customize',
|
||||
|
||||
|
||||
);
|
||||
|
@ -74,6 +74,7 @@ return array(
|
||||
"has_credit" => "el cliente no tiene crédito suficiente.",
|
||||
"notmasked" => "The values are masked",
|
||||
"less_than" => 'The :attribute must be less than :value',
|
||||
"has_counter" => 'The value must contain {$counter}',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?php
|
||||
<?php
|
||||
|
||||
return array(
|
||||
|
||||
@ -271,7 +271,7 @@ return array(
|
||||
'email_salutation' => 'Estimado :name,',
|
||||
'email_signature' => 'Un cordial saludo,',
|
||||
'email_from' => 'El equipo de Invoice Ninja ',
|
||||
'user_email_footer' => 'Para ajustar la configuración de las notificaciones de tu email, visita '.SITE_URL.'/company/notifications',
|
||||
'user_email_footer' => 'Para ajustar la configuración de las notificaciones de tu email, visita '.SITE_URL.'/settings/notifications',
|
||||
'invoice_link_message' => 'Para visualizar la factura de cliente, haz clic en el enlace de abajo:',
|
||||
'notification_invoice_paid_subject' => 'La factura :invoice ha sido pagada por el cliente :client',
|
||||
'notification_invoice_sent_subject' => 'La factura :invoice ha sido enviada a el cliente :client',
|
||||
@ -280,7 +280,7 @@ return array(
|
||||
'notification_invoice_sent' => 'La factura :invoice por importe de :amount fue enviada al cliente :cliente.',
|
||||
'notification_invoice_viewed' => 'La factura :invoice por importe de :amount fue visualizada por el cliente :client.',
|
||||
'reset_password' => 'Puedes reconfigurar la contraseña de tu cuenta haciendo clic en el siguiente enlace:',
|
||||
'reset_password_footer' => 'Si no has solicitado un cambio de contraseña, por favor contactate con nosostros: ' . CONTACT_EMAIL,
|
||||
'reset_password_footer' => 'Si no has solicitado un cambio de contraseña, por favor contactate con nosostros: '.CONTACT_EMAIL,
|
||||
|
||||
// Payment page
|
||||
'secure_payment' => 'Pago seguro',
|
||||
@ -307,7 +307,7 @@ return array(
|
||||
],
|
||||
'logout' => 'Cerrar sesión',
|
||||
'sign_up_to_save' => 'Registrate para guardar tu trabajo',
|
||||
'agree_to_terms' =>'Estoy de acuerdo con los términos de Invoice Ninja :terms',
|
||||
'agree_to_terms' => 'Estoy de acuerdo con los términos de Invoice Ninja :terms',
|
||||
'terms_of_service' => 'Términos de servicio',
|
||||
'email_taken' => 'Esta dirección de correo electrónico ya se ha registrado',
|
||||
'working' => 'Procesando',
|
||||
@ -414,7 +414,7 @@ return array(
|
||||
'active' => 'Activo',
|
||||
'pending' => 'Pendiente',
|
||||
'deleted_user' => 'Usario eliminado con éxito',
|
||||
'limit_users' => 'Lo sentimos, esta acción excederá el límite de ' . MAX_NUM_USERS . ' usarios',
|
||||
'limit_users' => 'Lo sentimos, esta acción excederá el límite de '.MAX_NUM_USERS.' usarios',
|
||||
'confirm_email_invoice' => '¿Estás seguro que quieres enviar esta factura?',
|
||||
'confirm_email_quote' => '¿Estás seguro que quieres enviar este presupuesto?',
|
||||
'confirm_recurring_email_invoice' => 'Se ha marcado esta factura como recurrente, estás seguro que quieres enviar esta factura?',
|
||||
@ -435,7 +435,6 @@ return array(
|
||||
'invalid_counter' => 'Para evitar posibles conflictos, por favor crea un prefijo de facturación y de presupuesto.',
|
||||
'mark_sent' => 'Marcar como enviado',
|
||||
|
||||
|
||||
'gateway_help_1' => ':link para registrarse en Authorize.net.',
|
||||
'gateway_help_2' => ':link para registrarse en Authorize.net.',
|
||||
'gateway_help_17' => ':link para obtener su firma API de PayPal.',
|
||||
@ -745,7 +744,7 @@ return array(
|
||||
'current_user' => 'Current User',
|
||||
'new_recurring_invoice' => 'New Recurring Invoice',
|
||||
'recurring_invoice' => 'Recurring Invoice',
|
||||
'recurring_too_soon' => 'It\'s too soon to create the next recurring invoice',
|
||||
'recurring_too_soon' => 'It\'s too soon to create the next recurring invoice, it\'s scheduled for :date',
|
||||
'created_by_invoice' => 'Created by :invoice',
|
||||
'primary_user' => 'Primary User',
|
||||
'help' => 'Help',
|
||||
@ -817,6 +816,14 @@ return array(
|
||||
'custom_invoice_link' => 'Custom Invoice Link',
|
||||
'total_invoiced' => 'Total Invoiced',
|
||||
'open_balance' => 'Open Balance',
|
||||
'verify_email' => 'Please visit the link in the account confirmation email to verify your email address.',
|
||||
'basic_settings' => 'Basic Settings',
|
||||
'pro' => 'Pro',
|
||||
'gateways' => 'Payment Gateways',
|
||||
|
||||
'next_send_on' => 'Send Next: :date',
|
||||
'no_longer_running' => 'This invoice is not scheduled to run',
|
||||
'general_settings' => 'General Settings',
|
||||
'customize' => 'Customize',
|
||||
|
||||
);
|
@ -74,6 +74,7 @@ return array(
|
||||
"has_credit" => "el cliente no tiene crédito suficiente.",
|
||||
"notmasked" => "The values are masked",
|
||||
"less_than" => 'The :attribute must be less than :value',
|
||||
"has_counter" => 'The value must contain {$counter}',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
@ -262,7 +262,7 @@ return array(
|
||||
'email_salutation' => 'Cher :name,',
|
||||
'email_signature' => 'Cordialement,',
|
||||
'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.'/settings/notifications',
|
||||
'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_sent_subject' => 'La facture :invoice a été envoyée au client :client',
|
||||
@ -532,16 +532,16 @@ return array(
|
||||
'invoice_footer' => 'Pied de facture',
|
||||
'save_as_default_footer' => 'Définir comme pied de facture par défatu',
|
||||
|
||||
'token_management' => 'Token Management',
|
||||
'tokens' => 'Tokens',
|
||||
'add_token' => 'Add Token',
|
||||
'show_deleted_tokens' => 'Show deleted tokens',
|
||||
'deleted_token' => 'Successfully deleted token',
|
||||
'created_token' => 'Successfully created token',
|
||||
'updated_token' => 'Successfully updated token',
|
||||
'edit_token' => 'Edit Token',
|
||||
'delete_token' => 'Delete Token',
|
||||
'token' => 'Token',
|
||||
'token_management' => 'Gestion des jetons',
|
||||
'tokens' => 'Jetons',
|
||||
'add_token' => 'Ajouter jeton',
|
||||
'show_deleted_tokens' => 'Voir les jetons supprimés',
|
||||
'deleted_token' => 'Jeton supprimé avec succès',
|
||||
'created_token' => 'Jeton crée avec succès',
|
||||
'updated_token' => 'Jeton mis à jour avec succès',
|
||||
'edit_token' => 'Editer jeton',
|
||||
'delete_token' => 'Supprimer jeton',
|
||||
'token' => 'Jeton',
|
||||
|
||||
'add_gateway' => 'Ajouter passerelle',
|
||||
'delete_gateway' => 'Supprimer passerelle',
|
||||
@ -560,17 +560,17 @@ return array(
|
||||
'password_error_invalid' => 'Le nouveau mot de passe est invalide',
|
||||
'updated_password' => 'Mot de passe mis à jour avec succès',
|
||||
|
||||
'api_tokens' => 'API Tokens',
|
||||
'users_and_tokens' => 'Users & Tokens',
|
||||
'account_login' => 'Account Login',
|
||||
'api_tokens' => 'Jetons d\'API',
|
||||
'users_and_tokens' => 'Utilisateurs & jetons',
|
||||
'account_login' => 'Connexion à votre compte',
|
||||
'recover_password' => 'Recover your password',
|
||||
'forgot_password' => 'Mot de passe oublié ?',
|
||||
'email_address' => 'Adresse email',
|
||||
'lets_go' => 'Allons-y !',
|
||||
'password_recovery' => 'Password Recovery',
|
||||
'send_email' => 'Send email',
|
||||
'set_password' => 'Set Password',
|
||||
'converted' => 'Converted',
|
||||
'password_recovery' => 'Récupération du mot de passe',
|
||||
'send_email' => 'Envoyer email',
|
||||
'set_password' => 'Ajouter mot de passe',
|
||||
'converted' => 'Converti',
|
||||
|
||||
'email_approved' => 'Email me when a quote is <b>approved</b>',
|
||||
'notification_quote_approved_subject' => 'Quote :invoice was approved by :client',
|
||||
@ -730,14 +730,13 @@ return array(
|
||||
'invoice_to' => 'Facture pour',
|
||||
'invoice_no' => 'Facture n°',
|
||||
'recent_payments' => 'Paiements récents',
|
||||
'outstanding' => 'Extraordinaire',
|
||||
'outstanding' => 'Impayé',
|
||||
'manage_companies' => 'Gérer les sociétés',
|
||||
'total_revenue' => 'Revenu total',
|
||||
|
||||
'current_user' => 'Utilisateur actuel',
|
||||
'new_recurring_invoice' => 'Nouvelle facture récurrente',
|
||||
'recurring_invoice' => 'Facture récurrente',
|
||||
'recurring_too_soon' => 'Il est trop tôt pour créer la prochaine facture récurrente',
|
||||
'created_by_invoice' => 'Créé par :invoice',
|
||||
'primary_user' => 'Utilisateur principal',
|
||||
'help' => 'Aide',
|
||||
@ -763,17 +762,17 @@ return array(
|
||||
'iframe_url_help1' => 'Copy the following code to a page on your site.',
|
||||
'iframe_url_help2' => 'You can test the feature by clicking \'View as recipient\' for an invoice.',
|
||||
|
||||
'auto_bill' => 'Auto Bill',
|
||||
'auto_bill' => 'Facturation automatique',
|
||||
'military_time' => '24 Hour Time',
|
||||
'last_sent' => 'Last Sent',
|
||||
'last_sent' => 'Dernier envoi',
|
||||
|
||||
'reminder_emails' => 'Reminder Emails',
|
||||
'reminder_emails' => 'Emails de rappel',
|
||||
'templates_and_reminders' => 'Templates & Reminders',
|
||||
'subject' => 'Subject',
|
||||
'body' => 'Body',
|
||||
'first_reminder' => 'First Reminder',
|
||||
'second_reminder' => 'Second Reminder',
|
||||
'third_reminder' => 'Third Reminder',
|
||||
'subject' => 'Sujet',
|
||||
'body' => 'Corps',
|
||||
'first_reminder' => 'Premier rappel',
|
||||
'second_reminder' => 'Second rappel',
|
||||
'third_reminder' => 'Troisième rappel',
|
||||
'num_days_reminder' => 'Days after due date',
|
||||
'reminder_subject' => 'Reminder: Invoice :invoice from :account',
|
||||
'reset' => 'Reset',
|
||||
@ -784,8 +783,8 @@ return array(
|
||||
'last_sent_on' => 'Last sent on :date',
|
||||
|
||||
'page_expire' => 'This page will expire soon, :click_here to keep working',
|
||||
'upcoming_quotes' => 'Upcoming Quotes',
|
||||
'expired_quotes' => 'Expired Quotes',
|
||||
'upcoming_quotes' => 'Devis à venir',
|
||||
'expired_quotes' => 'Devis expirés',
|
||||
|
||||
'sign_up_using' => 'Sign up using',
|
||||
'invalid_credentials' => 'These credentials do not match our records',
|
||||
@ -797,9 +796,9 @@ return array(
|
||||
'invoice_charges' => 'Invoice Charges',
|
||||
|
||||
'invitation_status' => [
|
||||
'sent' => 'Email Sent',
|
||||
'opened' => 'Email Openend',
|
||||
'viewed' => 'Invoice Viewed',
|
||||
'sent' => 'Email envoyé',
|
||||
'opened' => 'Email ouvert',
|
||||
'viewed' => 'Facture vue',
|
||||
],
|
||||
'notification_invoice_bounced' => 'We were unable to deliver Invoice :invoice to :contact.',
|
||||
'notification_invoice_bounced_subject' => 'Unable to deliver Invoice :invoice',
|
||||
@ -809,6 +808,16 @@ return array(
|
||||
'custom_invoice_link' => 'Custom Invoice Link',
|
||||
'total_invoiced' => 'Total Invoiced',
|
||||
'open_balance' => 'Open Balance',
|
||||
'verify_email' => 'Please visit the link in the account confirmation email to verify your email address.',
|
||||
'basic_settings' => 'Basic Settings',
|
||||
'pro' => 'Pro',
|
||||
'gateways' => 'Passerelles de paiement',
|
||||
'recurring_too_soon' => 'Il est trop tôt pour créer la prochaine facture récurrente, it\'s scheduled for :date',
|
||||
|
||||
'next_send_on' => 'Send Next: :date',
|
||||
'no_longer_running' => 'This invoice is not scheduled to run',
|
||||
'general_settings' => 'General Settings',
|
||||
'customize' => 'Customize',
|
||||
|
||||
|
||||
);
|
||||
|
@ -75,6 +75,7 @@ return array(
|
||||
"has_credit" => "The client does not have enough credit.",
|
||||
"notmasked" => "The values are masked",
|
||||
"less_than" => 'The :attribute must be less than :value',
|
||||
"has_counter" => 'The value must contain {$counter}',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
@ -262,7 +262,7 @@ return array(
|
||||
'email_salutation' => 'Cher :name,',
|
||||
'email_signature' => 'Cordialement,',
|
||||
'email_from' => 'L\'équipe InvoiceNinja',
|
||||
'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.'/settings/notifications',
|
||||
'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_sent_subject' => 'La facture :invoice a été envoyée au client :client',
|
||||
@ -738,7 +738,7 @@ return array(
|
||||
'current_user' => 'Current User',
|
||||
'new_recurring_invoice' => 'New Recurring Invoice',
|
||||
'recurring_invoice' => 'Recurring Invoice',
|
||||
'recurring_too_soon' => 'It\'s too soon to create the next recurring invoice',
|
||||
'recurring_too_soon' => 'It\'s too soon to create the next recurring invoice, it\'s scheduled for :date',
|
||||
'created_by_invoice' => 'Created by :invoice',
|
||||
'primary_user' => 'Primary User',
|
||||
'help' => 'Help',
|
||||
@ -810,6 +810,15 @@ return array(
|
||||
'custom_invoice_link' => 'Custom Invoice Link',
|
||||
'total_invoiced' => 'Total Invoiced',
|
||||
'open_balance' => 'Open Balance',
|
||||
'verify_email' => 'Please visit the link in the account confirmation email to verify your email address.',
|
||||
'basic_settings' => 'Basic Settings',
|
||||
'pro' => 'Pro',
|
||||
'gateways' => 'Payment Gateways',
|
||||
|
||||
'next_send_on' => 'Send Next: :date',
|
||||
'no_longer_running' => 'This invoice is not scheduled to run',
|
||||
'general_settings' => 'General Settings',
|
||||
'customize' => 'Customize',
|
||||
|
||||
|
||||
);
|
||||
|
@ -75,6 +75,7 @@ return array(
|
||||
"has_credit" => "Le client n'a pas un crédit suffisant.",
|
||||
"notmasked" => "Les valeurs sont masquées",
|
||||
"less_than" => 'The :attribute must be less than :value',
|
||||
"has_counter" => 'The value must contain {$counter}',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
@ -262,7 +262,7 @@ return array(
|
||||
'email_salutation' => 'Caro :name,',
|
||||
'email_signature' => 'Distinti saluti,',
|
||||
'email_from' => 'Il Team di InvoiceNinja',
|
||||
'user_email_footer' => 'Per modificare le impostazioni di notifiche via email per favore accedi a: '.SITE_URL.'/company/notifications',
|
||||
'user_email_footer' => 'Per modificare le impostazioni di notifiche via email per favore accedi a: '.SITE_URL.'/settings/notifications',
|
||||
'invoice_link_message' => 'Per visualizzare la tua fattura del cliente clicca sul link qui sotto:',
|
||||
'notification_invoice_paid_subject' => 'La fattura :invoice è stata pagata da :client',
|
||||
'notification_invoice_sent_subject' => 'La fattura :invoice è stata inviata a :client',
|
||||
@ -740,7 +740,7 @@ return array(
|
||||
'current_user' => 'Current User',
|
||||
'new_recurring_invoice' => 'New Recurring Invoice',
|
||||
'recurring_invoice' => 'Recurring Invoice',
|
||||
'recurring_too_soon' => 'It\'s too soon to create the next recurring invoice',
|
||||
'recurring_too_soon' => 'It\'s too soon to create the next recurring invoice, it\'s scheduled for :date',
|
||||
'created_by_invoice' => 'Created by :invoice',
|
||||
'primary_user' => 'Primary User',
|
||||
'help' => 'Help',
|
||||
@ -812,5 +812,14 @@ return array(
|
||||
'custom_invoice_link' => 'Custom Invoice Link',
|
||||
'total_invoiced' => 'Total Invoiced',
|
||||
'open_balance' => 'Open Balance',
|
||||
'verify_email' => 'Please visit the link in the account confirmation email to verify your email address.',
|
||||
'basic_settings' => 'Basic Settings',
|
||||
'pro' => 'Pro',
|
||||
'gateways' => 'Payment Gateways',
|
||||
|
||||
'next_send_on' => 'Send Next: :date',
|
||||
'no_longer_running' => 'This invoice is not scheduled to run',
|
||||
'general_settings' => 'General Settings',
|
||||
'customize' => 'Customize',
|
||||
|
||||
);
|
||||
|
@ -74,6 +74,7 @@ return array(
|
||||
"has_credit" => "The client does not have enough credit.",
|
||||
"notmasked" => "The values are masked",
|
||||
"less_than" => 'The :attribute must be less than :value',
|
||||
"has_counter" => 'The value must contain {$counter}',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
@ -262,7 +262,7 @@ return array(
|
||||
'email_salutation' => 'Dear :name,',
|
||||
'email_signature' => 'Regards,',
|
||||
'email_from' => 'The Invoice Ninja Team',
|
||||
'user_email_footer' => 'To adjust your email notification settings please visit '.SITE_URL.'/company/notifications',
|
||||
'user_email_footer' => 'To adjust your email notification settings please visit '.SITE_URL.'/settings/notifications',
|
||||
'invoice_link_message' => 'To view your client invoice click the link below:',
|
||||
'notification_invoice_paid_subject' => 'Invoice :invoice was paid by :client',
|
||||
'notification_invoice_sent_subject' => 'Invoice :invoice was sent to :client',
|
||||
@ -337,7 +337,7 @@ return array(
|
||||
'fill_products_help' => 'Selecting a product will automatically <b>fill in the description and cost</b>',
|
||||
'update_products' => 'Auto-update products',
|
||||
'update_products_help' => 'Updating an invoice will automatically <b>update the product library</b>',
|
||||
'create_product' => 'Create Product',
|
||||
'create_product' => 'Add Product',
|
||||
'edit_product' => 'Edit Product',
|
||||
'archive_product' => 'Archive Product',
|
||||
'updated_product' => 'Successfully updated product',
|
||||
@ -747,7 +747,7 @@ return array(
|
||||
'current_user' => 'Current User',
|
||||
'new_recurring_invoice' => 'New Recurring Invoice',
|
||||
'recurring_invoice' => 'Recurring Invoice',
|
||||
'recurring_too_soon' => 'It\'s too soon to create the next recurring invoice',
|
||||
'recurring_too_soon' => 'It\'s too soon to create the next recurring invoice, it\'s scheduled for :date',
|
||||
'created_by_invoice' => 'Created by :invoice',
|
||||
'primary_user' => 'Primary User',
|
||||
'help' => 'Help',
|
||||
@ -819,6 +819,15 @@ return array(
|
||||
'custom_invoice_link' => 'Custom Invoice Link',
|
||||
'total_invoiced' => 'Total Invoiced',
|
||||
'open_balance' => 'Open Balance',
|
||||
'verify_email' => 'Please visit the link in the account confirmation email to verify your email address.',
|
||||
'basic_settings' => 'Basic Settings',
|
||||
'pro' => 'Pro',
|
||||
'gateways' => 'Payment Gateways',
|
||||
|
||||
'next_send_on' => 'Send Next: :date',
|
||||
'no_longer_running' => 'This invoice is not scheduled to run',
|
||||
'general_settings' => 'General Settings',
|
||||
'customize' => 'Customize',
|
||||
|
||||
);
|
||||
|
||||
|
@ -262,7 +262,7 @@ return array(
|
||||
'email_salutation' => 'Kjære :name,',
|
||||
'email_signature' => 'Med vennlig hilsen,',
|
||||
'email_from' => 'The Invoice Ninja Team',
|
||||
'user_email_footer' => 'For å justere varslingsinnstillingene vennligst besøk '.SITE_URL.'/company/notifications',
|
||||
'user_email_footer' => 'For å justere varslingsinnstillingene vennligst besøk '.SITE_URL.'/settings/notifications',
|
||||
'invoice_link_message' => 'Hvis du vil se din klientfaktura klikk på linken under:',
|
||||
'notification_invoice_paid_subject' => 'Faktura :invoice betalt av :client',
|
||||
'notification_invoice_sent_subject' => 'Faktura :invoice sendt til :client',
|
||||
@ -745,7 +745,7 @@ return array(
|
||||
'current_user' => 'Current User',
|
||||
'new_recurring_invoice' => 'New Recurring Invoice',
|
||||
'recurring_invoice' => 'Recurring Invoice',
|
||||
'recurring_too_soon' => 'It\'s too soon to create the next recurring invoice',
|
||||
'recurring_too_soon' => 'It\'s too soon to create the next recurring invoice, it\'s scheduled for :date',
|
||||
'created_by_invoice' => 'Created by :invoice',
|
||||
'primary_user' => 'Primary User',
|
||||
'help' => 'Help',
|
||||
@ -817,5 +817,14 @@ return array(
|
||||
'custom_invoice_link' => 'Custom Invoice Link',
|
||||
'total_invoiced' => 'Total Invoiced',
|
||||
'open_balance' => 'Open Balance',
|
||||
'verify_email' => 'Please visit the link in the account confirmation email to verify your email address.',
|
||||
'basic_settings' => 'Basic Settings',
|
||||
'pro' => 'Pro',
|
||||
'gateways' => 'Payment Gateways',
|
||||
|
||||
'next_send_on' => 'Send Next: :date',
|
||||
'no_longer_running' => 'This invoice is not scheduled to run',
|
||||
'general_settings' => 'General Settings',
|
||||
'customize' => 'Customize',
|
||||
|
||||
);
|
@ -73,6 +73,7 @@ return array(
|
||||
"has_credit" => "Klienten har ikke høy nok kreditt.",
|
||||
"notmasked" => "Verdiene er skjult",
|
||||
"less_than" => 'The :attribute must be less than :value',
|
||||
"has_counter" => 'The value must contain {$counter}',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
@ -260,7 +260,7 @@ return array(
|
||||
'email_salutation' => 'Beste :name,',
|
||||
'email_signature' => 'Met vriendelijke groeten,',
|
||||
'email_from' => 'Het InvoiceNinja Team',
|
||||
'user_email_footer' => 'Ga alstublieft naar '.SITE_URL.'/company/notifications om je e-mail notificatie instellingen aan te passen ',
|
||||
'user_email_footer' => 'Ga alstublieft naar '.SITE_URL.'/settings/notifications om je e-mail notificatie instellingen aan te passen ',
|
||||
'invoice_link_message' => 'Klik op volgende link om de Factuur van je klant te bekijken:',
|
||||
'notification_invoice_paid_subject' => 'Factuur :invoice is betaald door :client',
|
||||
'notification_invoice_sent_subject' => 'Factuur :invoice is gezonden door :client',
|
||||
@ -740,7 +740,6 @@ return array(
|
||||
'current_user' => 'Huidige gebruiker',
|
||||
'new_recurring_invoice' => 'Nieuwe wederkerende factuur',
|
||||
'recurring_invoice' => 'Wederkerende factuur',
|
||||
'recurring_too_soon' => 'Het is te vroeg om de volgende wederkerende factuur aan te maken',
|
||||
'created_by_invoice' => 'Aangemaakt door :invoice',
|
||||
'primary_user' => 'Primaire gebruiker',
|
||||
'help' => 'Help',
|
||||
@ -812,5 +811,15 @@ return array(
|
||||
'custom_invoice_link' => 'Custom Invoice Link',
|
||||
'total_invoiced' => 'Total Invoiced',
|
||||
'open_balance' => 'Open Balance',
|
||||
'verify_email' => 'Please visit the link in the account confirmation email to verify your email address.',
|
||||
'basic_settings' => 'Basic Settings',
|
||||
'pro' => 'Pro',
|
||||
'gateways' => 'Payment Gateways',
|
||||
'recurring_too_soon' => 'Het is te vroeg om de volgende wederkerende factuur aan te maken, it\'s scheduled for :date',
|
||||
|
||||
'next_send_on' => 'Send Next: :date',
|
||||
'no_longer_running' => 'This invoice is not scheduled to run',
|
||||
'general_settings' => 'General Settings',
|
||||
'customize' => 'Customize',
|
||||
|
||||
);
|
||||
|
@ -75,6 +75,7 @@ return array(
|
||||
"has_credit" => "De klant heeft niet voldoende krediet.",
|
||||
"notmasked" => "De waarden zijn verborgen",
|
||||
"less_than" => 'Het :attribute moet minder zijn dan :value',
|
||||
"has_counter" => 'The value must contain {$counter}',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
@ -15,10 +15,10 @@ return array(
|
||||
|
||||
"password" => "Senhas devem possuir no mínimo seis caracteres e devem ser iguais.",
|
||||
|
||||
"user" => "Não achamos um usuário com o endereço de e-mail informado.",
|
||||
"user" => "Não foi encontrado um usuário com o endereço de e-mail informado.",
|
||||
|
||||
"token" => "Este token de redefinição de senha é inválido.",
|
||||
|
||||
"sent" => "Lmebrete de senha enviado!",
|
||||
"sent" => "Lembrete de senha enviado!",
|
||||
|
||||
);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -17,17 +17,17 @@ return array(
|
||||
"active_url" => ":attribute não é uma URL válida.",
|
||||
"after" => ":attribute deve ser uma data maior que :date.",
|
||||
"alpha" => ":attribute deve conter apenas letras.",
|
||||
"alpha_dash" => ":attribute pode conter apenas letras, número e traços",
|
||||
"alpha_dash" => ":attribute pode conter apenas letras, número e hífens",
|
||||
"alpha_num" => ":attribute pode conter apenas letras e números.",
|
||||
"array" => ":attribute deve ser um array.",
|
||||
"array" => ":attribute deve ser uma lista.",
|
||||
"before" => ":attribute deve ser uma data anterior a :date.",
|
||||
"between" => array(
|
||||
"numeric" => ":attribute deve ser entre :min - :max.",
|
||||
"file" => ":attribute deve ser entre :min - :max kilobytes.",
|
||||
"string" => ":attribute deve ser entre :min - :max caracteres.",
|
||||
"numeric" => ":attribute deve estar entre :min - :max.",
|
||||
"file" => ":attribute deve estar entre :min - :max kilobytes.",
|
||||
"string" => ":attribute deve estar entre :min - :max caracteres.",
|
||||
"array" => ":attribute deve conter entre :min - :max itens.",
|
||||
),
|
||||
"confirmed" => ":attribute confirmação não correponde.",
|
||||
"confirmed" => ":attribute confirmação não corresponde.",
|
||||
"date" => ":attribute não é uma data válida.",
|
||||
"date_format" => ":attribute não satisfaz o formato :format.",
|
||||
"different" => ":attribute e :other devem ser diferentes.",
|
||||
@ -71,8 +71,9 @@ return array(
|
||||
|
||||
"positive" => ":attribute deve ser maior que zero.",
|
||||
"has_credit" => "O cliente não possui crédito suficiente.",
|
||||
"notmasked" => "The values are masked",
|
||||
"less_than" => 'The :attribute must be less than :value',
|
||||
"notmasked" => "Os valores são mascarados",
|
||||
"less_than" => ':attribute deve ser menor que :value',
|
||||
"has_counter" => 'O valor deve conter {$counter}',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
@ -262,7 +262,7 @@ return array(
|
||||
'email_salutation' => 'Hej :name,',
|
||||
'email_signature' => 'Vänliga hälsningar,',
|
||||
'email_from' => 'Invoice Ninja teamet',
|
||||
'user_email_footer' => 'För att anpassa dina e-post notifieringar gå till '.SITE_URL.'/company/notifications',
|
||||
'user_email_footer' => 'För att anpassa dina e-post notifieringar gå till '.SITE_URL.'/settings/notifications',
|
||||
'invoice_link_message' => 'För att se din kundfaktura klicka på länken nedan:',
|
||||
'notification_invoice_paid_subject' => 'Faktura :invoice är betald av :client',
|
||||
'notification_invoice_sent_subject' => 'Faktura :invoice är skickad till :client',
|
||||
@ -743,7 +743,7 @@ return array(
|
||||
'current_user' => 'Current User',
|
||||
'new_recurring_invoice' => 'New Recurring Invoice',
|
||||
'recurring_invoice' => 'Recurring Invoice',
|
||||
'recurring_too_soon' => 'It\'s too soon to create the next recurring invoice',
|
||||
'recurring_too_soon' => 'It\'s too soon to create the next recurring invoice, it\'s scheduled for :date',
|
||||
'created_by_invoice' => 'Created by :invoice',
|
||||
'primary_user' => 'Primary User',
|
||||
'help' => 'Help',
|
||||
@ -815,5 +815,14 @@ return array(
|
||||
'custom_invoice_link' => 'Custom Invoice Link',
|
||||
'total_invoiced' => 'Total Invoiced',
|
||||
'open_balance' => 'Open Balance',
|
||||
'verify_email' => 'Please visit the link in the account confirmation email to verify your email address.',
|
||||
'basic_settings' => 'Basic Settings',
|
||||
'pro' => 'Pro',
|
||||
'gateways' => 'Payment Gateways',
|
||||
|
||||
'next_send_on' => 'Send Next: :date',
|
||||
'no_longer_running' => 'This invoice is not scheduled to run',
|
||||
'general_settings' => 'General Settings',
|
||||
'customize' => 'Customize',
|
||||
|
||||
);
|
||||
|
@ -77,6 +77,7 @@ return [
|
||||
"has_credit" => "The client does not have enough credit.",
|
||||
"notmasked" => "The values are masked",
|
||||
"less_than" => 'The :attribute must be less than :value',
|
||||
"has_counter" => 'The value must contain {$counter}',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
@ -1,9 +1,11 @@
|
||||
@extends('accounts.nav')
|
||||
@extends('header')
|
||||
|
||||
@section('content')
|
||||
@parent
|
||||
|
||||
{!! Former::open($url)->method($method)->rule()->addClass('col-md-8 col-md-offset-2 warn-on-exit') !!}
|
||||
@include('accounts.nav', ['selected' => ACCOUNT_PAYMENTS])
|
||||
|
||||
{!! Former::open($url)->method($method)->rule()->addClass('warn-on-exit') !!}
|
||||
{!! Former::populate($account) !!}
|
||||
|
||||
|
||||
@ -11,7 +13,7 @@
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{!! trans($title) !!}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="panel-body form-padding-right">
|
||||
|
||||
@if ($accountGateway)
|
||||
{!! Former::populateField('gateway_id', $accountGateway->gateway_id) !!}
|
||||
@ -106,7 +108,7 @@
|
||||
<p/> <p/>
|
||||
|
||||
{!! Former::actions(
|
||||
$countGateways > 0 ? Button::normal(trans('texts.cancel'))->large()->asLinkTo(URL::to('/company/payments'))->appendIcon(Icon::create('remove-circle')) : false,
|
||||
$countGateways > 0 ? Button::normal(trans('texts.cancel'))->large()->asLinkTo(URL::to('/settings/online_payments'))->appendIcon(Icon::create('remove-circle')) : false,
|
||||
Button::success(trans('texts.save'))->submit()->large()->appendIcon(Icon::create('floppy-disk'))) !!}
|
||||
{!! Former::close() !!}
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
@extends('accounts.nav')
|
||||
@extends('header')
|
||||
|
||||
@section('content')
|
||||
@parent
|
||||
@include('accounts.nav_advanced')
|
||||
@include('accounts.nav', ['selected' => ACCOUNT_API_TOKENS, 'advanced' => true])
|
||||
|
||||
{!! Former::open('tokens/delete')->addClass('user-form') !!}
|
||||
|
@ -1,16 +1,13 @@
|
||||
@extends('accounts.nav')
|
||||
@extends('header')
|
||||
|
||||
@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>
|
||||
|
||||
<script src="{{ asset('js/pdf.built.js') }}" type="text/javascript"></script>
|
||||
|
||||
<style type="text/css">
|
||||
|
||||
@ -28,9 +25,6 @@
|
||||
|
||||
@section('content')
|
||||
@parent
|
||||
@include('accounts.nav_advanced')
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
var invoiceDesigns = {!! $invoiceDesigns !!};
|
||||
@ -155,17 +149,15 @@
|
||||
{!! 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.help'))->withAttributes(['onclick' => 'showHelp()'])->appendIcon(Icon::create('question-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
|
||||
{!! Button::normal(trans('texts.cancel'))->asLinkTo(URL::to('/settings/invoice_design'))->appendIcon(Icon::create('remove-circle')) !!}
|
||||
{!! Button::success(trans('texts.save'))->withAttributes(['onclick' => 'submitForm()'])->appendIcon(Icon::create('floppy-disk'))->withAttributes(['class' => 'save-button']) !!}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
@if (!Auth::user()->isPro())
|
||||
$(function() {
|
||||
$('form.warn-on-exit input').prop('disabled', true);
|
||||
$('form.warn-on-exit input, .save-button').prop('disabled', true);
|
||||
});
|
||||
@endif
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
@extends('accounts.nav')
|
||||
@extends('header')
|
||||
|
||||
@section('content')
|
||||
@parent
|
||||
@ -13,27 +13,20 @@
|
||||
|
||||
{!! Former::open_for_files()->addClass('warn-on-exit')->rules(array(
|
||||
'name' => 'required',
|
||||
'email' => 'email|required'
|
||||
)) !!}
|
||||
|
||||
{{ Former::populate($account) }}
|
||||
{{ Former::populateField('military_time', intval($account->military_time)) }}
|
||||
{{ Former::populateField('first_name', $user->first_name) }}
|
||||
{{ Former::populateField('last_name', $user->last_name) }}
|
||||
{{ Former::populateField('email', $user->email) }}
|
||||
{{ Former::populateField('phone', $user->phone) }}
|
||||
@if (Utils::isNinjaDev())
|
||||
{{ Former::populateField('dark_mode', intval($user->dark_mode)) }}
|
||||
@endif
|
||||
|
||||
@include('accounts.nav', ['selected' => ACCOUNT_COMPANY_DETAILS])
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="col-md-12">
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{!! trans('texts.details') !!}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="panel-body form-padding-right">
|
||||
|
||||
{!! Former::text('name') !!}
|
||||
{!! Former::text('id_number') !!}
|
||||
@ -58,7 +51,7 @@
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{!! trans('texts.address') !!}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="panel-body form-padding-right">
|
||||
|
||||
{!! Former::text('address1') !!}
|
||||
{!! Former::text('address2') !!}
|
||||
@ -72,133 +65,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{!! trans('texts.user_details') !!}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{!! Former::text('first_name') !!}
|
||||
{!! Former::text('last_name') !!}
|
||||
{!! Former::text('email') !!}
|
||||
{!! Former::text('phone') !!}
|
||||
|
||||
@if (Utils::isNinja())
|
||||
{!! Former::plaintext('oneclick_login')->value(
|
||||
$user->oauth_provider_id ?
|
||||
$oauthProviderName . ' - ' . link_to('#', trans('texts.disable'), ['onclick' => 'disableSocialLogin()']) :
|
||||
DropdownButton::primary(trans('texts.enable'))->withContents($oauthLoginUrls)->small()
|
||||
) !!}
|
||||
@endif
|
||||
|
||||
@if (Utils::isNinja() && $user->confirmed)
|
||||
@if ($user->referral_code)
|
||||
{!! Former::plaintext('referral_code')
|
||||
->value($user->referral_code . ' <a href="'.REFERRAL_PROGRAM_URL.'" target="_blank" title="'.trans('texts.learn_more').'">' . Icon::create('question-sign') . '</a>') !!}
|
||||
@else
|
||||
{!! Former::checkbox('referral_code')
|
||||
->text(trans('texts.enable') . ' <a href="'.REFERRAL_PROGRAM_URL.'" target="_blank" title="'.trans('texts.learn_more').'">' . Icon::create('question-sign') . '</a>') !!}
|
||||
@endif
|
||||
@endif
|
||||
|
||||
@if (false && Utils::isNinjaDev())
|
||||
{!! Former::checkbox('dark_mode')->text(trans('texts.dark_mode_help')) !!}
|
||||
@endif
|
||||
|
||||
@if (Utils::isNinja())
|
||||
<br/>
|
||||
@if (Auth::user()->confirmed)
|
||||
{!! Former::actions( Button::primary(trans('texts.change_password'))->small()->withAttributes(['onclick'=>'showChangePassword()'])) !!}
|
||||
@elseif (Auth::user()->registered)
|
||||
{!! Former::actions( Button::primary(trans('texts.resend_confirmation'))->asLinkTo(URL::to('/resend_confirmation'))->small() ) !!}
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{!! trans('texts.localization') !!}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
|
||||
{!! Former::select('currency_id')->addOption('','')
|
||||
->fromQuery($currencies, 'name', 'id') !!}
|
||||
{!! Former::select('language_id')->addOption('','')
|
||||
->fromQuery($languages, 'name', 'id') !!}
|
||||
{!! Former::select('timezone_id')->addOption('','')
|
||||
->fromQuery($timezones, 'location', 'id') !!}
|
||||
{!! Former::select('date_format_id')->addOption('','')
|
||||
->fromQuery($dateFormats, 'label', 'id') !!}
|
||||
{!! Former::select('datetime_format_id')->addOption('','')
|
||||
->fromQuery($datetimeFormats, 'label', 'id') !!}
|
||||
{!! Former::checkbox('military_time')->text(trans('texts.enable')) !!}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<center>
|
||||
{!! Button::success(trans('texts.save'))->submit()->large()->appendIcon(Icon::create('floppy-disk')) !!}
|
||||
</center>
|
||||
|
||||
|
||||
|
||||
<div class="modal fade" id="passwordModal" tabindex="-1" role="dialog" aria-labelledby="passwordModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title" id="passwordModalLabel">{{ trans('texts.change_password') }}</h4>
|
||||
</div>
|
||||
|
||||
<div style="background-color: #fff" id="changePasswordDiv" onkeyup="validateChangePassword()" onclick="validateChangePassword()" onkeydown="checkForEnter(event)">
|
||||
|
||||
|
||||
{!! Former::password('current_password')->style('width:300px') !!}
|
||||
{!! Former::password('newer_password')->style('width:300px')->label(trans('texts.new_password')) !!}
|
||||
{!! Former::password('confirm_password')->style('width:300px') !!}
|
||||
|
||||
|
||||
<br/>
|
||||
<center>
|
||||
<div id="changePasswordError"></div>
|
||||
</center>
|
||||
<br/>
|
||||
</div>
|
||||
|
||||
<div style="padding-left:40px;padding-right:40px;display:none;min-height:130px" id="working">
|
||||
<h3>{{ trans('texts.working') }}...</h3>
|
||||
<div class="progress progress-striped active">
|
||||
<div class="progress-bar" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="background-color: #fff; padding-right:20px;padding-left:20px; display:none" id="successDiv">
|
||||
<br/>
|
||||
<h3>{{ trans('texts.success') }}</h3>
|
||||
{{ trans('texts.updated_password') }}
|
||||
<br/>
|
||||
|
||||
<br/>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer" style="margin-top: 0px" id="changePasswordFooter">
|
||||
<button type="button" class="btn btn-default" id="cancelChangePasswordButton" data-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-success" onclick="submitChangePassword()" id="changePasswordButton" disabled>
|
||||
{{ trans('texts.save') }}
|
||||
<i class="glyphicon glyphicon-floppy-disk"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{!! Former::close() !!}
|
||||
|
||||
{!! Form::open(['url' => 'remove_logo', 'class' => 'removeLogoForm']) !!}
|
||||
@ -209,21 +82,6 @@
|
||||
|
||||
$(function() {
|
||||
$('#country_id').combobox();
|
||||
|
||||
$('#passwordModal').on('hidden.bs.modal', function () {
|
||||
$(['current_password', 'newer_password', 'confirm_password']).each(function(i, field) {
|
||||
var $input = $('form #'+field);
|
||||
$input.val('');
|
||||
$input.closest('div.form-group').removeClass('has-success');
|
||||
});
|
||||
$('#changePasswordButton').prop('disabled', true);
|
||||
})
|
||||
|
||||
$('#passwordModal').on('shown.bs.modal', function () {
|
||||
$('#current_password').focus();
|
||||
})
|
||||
|
||||
localStorage.setItem('auth_provider', '{{ strtolower($oauthProviderName) }}');
|
||||
});
|
||||
|
||||
function deleteLogo() {
|
||||
@ -232,84 +90,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
function showChangePassword() {
|
||||
$('#passwordModal').modal('show');
|
||||
}
|
||||
|
||||
function checkForEnter(event)
|
||||
{
|
||||
if (event.keyCode === 13){
|
||||
event.preventDefault();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function validateChangePassword(showError)
|
||||
{
|
||||
var isFormValid = true;
|
||||
$(['current_password', 'newer_password', 'confirm_password']).each(function(i, field) {
|
||||
var $input = $('form #'+field),
|
||||
val = $.trim($input.val());
|
||||
var isValid = val && val.length >= 6;
|
||||
|
||||
if (isValid && field == 'confirm_password') {
|
||||
isValid = val == $.trim($('#newer_password').val());
|
||||
}
|
||||
|
||||
if (isValid) {
|
||||
$input.closest('div.form-group').removeClass('has-error').addClass('has-success');
|
||||
} else {
|
||||
isFormValid = false;
|
||||
$input.closest('div.form-group').removeClass('has-success');
|
||||
if (showError) {
|
||||
$input.closest('div.form-group').addClass('has-error');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$('#changePasswordButton').prop('disabled', !isFormValid);
|
||||
|
||||
return isFormValid;
|
||||
}
|
||||
|
||||
function submitChangePassword()
|
||||
{
|
||||
if (!validateChangePassword(true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$('#changePasswordDiv, #changePasswordFooter').hide();
|
||||
$('#working').show();
|
||||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: '{{ URL::to('/users/change_password') }}',
|
||||
data: 'current_password=' + encodeURIComponent($('form #current_password').val()) +
|
||||
'&new_password=' + encodeURIComponent($('form #newer_password').val()) +
|
||||
'&confirm_password=' + encodeURIComponent($('form #confirm_password').val()),
|
||||
success: function(result) {
|
||||
if (result == 'success') {
|
||||
NINJA.formIsChanged = false;
|
||||
$('#changePasswordButton').hide();
|
||||
$('#successDiv').show();
|
||||
$('#cancelChangePasswordButton').html('{{ trans('texts.close') }}');
|
||||
} else {
|
||||
$('#changePasswordError').html(result);
|
||||
$('#changePasswordDiv').show();
|
||||
}
|
||||
$('#changePasswordFooter').show();
|
||||
$('#working').hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function disableSocialLogin() {
|
||||
if (!confirm("{!! trans('texts.are_you_sure') !!}")) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.location = '{{ URL::to('/auth_unlink') }}';
|
||||
}
|
||||
</script>
|
||||
|
||||
@stop
|
||||
|
@ -1,7 +1,8 @@
|
||||
@extends('accounts.nav')
|
||||
@extends('header')
|
||||
|
||||
@section('content')
|
||||
@parent
|
||||
@include('accounts.nav', ['selected' => ACCOUNT_IMPORT_EXPORT])
|
||||
|
||||
{{ Former::open()->addClass('col-md-9 col-md-offset-1') }}
|
||||
{{ Former::legend('Export Client Data') }}
|
||||
|
@ -1,9 +1,11 @@
|
||||
@extends('accounts.nav')
|
||||
@extends('header')
|
||||
|
||||
@section('content')
|
||||
@parent
|
||||
|
||||
{!! Former::open_for_files('company/import_map')->addClass('col-md-8 col-md-offset-2') !!}
|
||||
@include('accounts.nav', ['selected' => ACCOUNT_IMPORT_EXPORT])
|
||||
|
||||
{!! Former::open_for_files('settings/' . ACCOUNT_MAP) !!}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{!! trans('texts.import_clients') !!}</h3>
|
||||
@ -16,7 +18,7 @@
|
||||
{!! Former::close() !!}
|
||||
|
||||
|
||||
{!! Former::open('company/export')->addClass('col-md-8 col-md-offset-2') !!}
|
||||
{!! Former::open('settings/' . ACCOUNT_EXPORT) !!}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{!! trans('texts.export_clients') !!}</h3>
|
||||
@ -28,7 +30,7 @@
|
||||
{!! Former::close() !!}
|
||||
|
||||
|
||||
{!! Former::open('company/cancel_account')->addClass('col-md-8 col-md-offset-2 cancel-account') !!}
|
||||
{!! Former::open('settings/cancel_account')->addClass('cancel-account') !!}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{!! trans('texts.cancel_account') !!}</h3>
|
||||
|
@ -1,9 +1,11 @@
|
||||
@extends('accounts.nav')
|
||||
@extends('header')
|
||||
|
||||
@section('content')
|
||||
@parent
|
||||
|
||||
{!! Former::open('company/import_export')->addClass('col-md-8 col-md-offset-2 warn-on-exit') !!}
|
||||
@include('accounts.nav', ['selected' => ACCOUNT_IMPORT_EXPORT])
|
||||
|
||||
{!! Former::open('settings/' . ACCOUNT_IMPORT_EXPORT)->addClass('warn-on-exit') !!}
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
@ -46,7 +48,7 @@
|
||||
|
||||
|
||||
{!! Former::actions(
|
||||
Button::normal(trans('texts.cancel'))->large()->asLinkTo(URL::to('/company/import_export'))->appendIcon(Icon::create('remove-circle')),
|
||||
Button::normal(trans('texts.cancel'))->large()->asLinkTo(URL::to('/settings/import_export'))->appendIcon(Icon::create('remove-circle')),
|
||||
Button::success(trans('texts.import'))->submit()->large()->appendIcon(Icon::create('floppy-disk'))) !!}
|
||||
{!! Former::close() !!}
|
||||
|
||||
|
@ -1,18 +1,15 @@
|
||||
@extends('accounts.nav')
|
||||
@extends('header')
|
||||
|
||||
@section('head')
|
||||
@parent
|
||||
|
||||
<script src="{{ asset('js/pdf_viewer.js') }}" type="text/javascript"></script>
|
||||
<script src="{{ asset('js/compatibility.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>
|
||||
<script src="{{ asset('js/pdf.built.js') }}" type="text/javascript"></script>
|
||||
|
||||
@stop
|
||||
|
||||
@section('content')
|
||||
@parent
|
||||
@include('accounts.nav_advanced')
|
||||
@include('accounts.nav', ['selected' => ACCOUNT_INVOICE_DESIGN, 'advanced' => true])
|
||||
|
||||
<script>
|
||||
var invoiceDesigns = {!! $invoiceDesigns !!};
|
||||
@ -40,7 +37,7 @@
|
||||
NINJA.secondaryColor = $('#secondary_color').val();
|
||||
NINJA.fontSize = parseInt($('#font_size').val());
|
||||
|
||||
var fields = ['item', 'description', 'unit_cost', 'quantity'];
|
||||
var fields = ['item', 'description', 'unit_cost', 'quantity', 'line_total'];
|
||||
invoiceLabels.old = {};
|
||||
for (var i=0; i<fields.length; i++) {
|
||||
var field = fields[i];
|
||||
@ -76,7 +73,7 @@
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="col-md-12">
|
||||
|
||||
{!! Former::open()->addClass('warn-on-exit')->onchange('refreshPDF()') !!}
|
||||
{!! Former::populate($account) !!}
|
||||
@ -91,58 +88,74 @@
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{!! trans('texts.invoice_design') !!}</h3>
|
||||
</div>
|
||||
|
||||
<div class="panel-body form-padding-right">
|
||||
<div role="tabpanel">
|
||||
<ul class="nav nav-tabs" role="tablist" style="border: none">
|
||||
<li role="presentation" class="active"><a href="#generalSettings" aria-controls="generalSettings" role="tab" data-toggle="tab">{{ trans('texts.general_settings') }}</a></li>
|
||||
<li role="presentation"><a href="#invoiceLabels" aria-controls="invoiceLabels" role="tab" data-toggle="tab">{{ trans('texts.invoice_labels') }}</a></li>
|
||||
<li role="presentation"><a href="#invoiceOptions" aria-controls="invoiceOptions" role="tab" data-toggle="tab">{{ trans('texts.invoice_options') }}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="tab-content">
|
||||
<div role="tabpanel" class="tab-pane active" id="generalSettings">
|
||||
<div class="panel-body">
|
||||
|
||||
|
||||
@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')->fromQuery($invoiceDesigns, 'name', 'id')->addOption(trans('texts.more_designs') . '...', '-1') !!}
|
||||
@else
|
||||
{!! Former::select('invoice_design_id')->style('display:inline;width:120px')->fromQuery($invoiceDesigns, 'name', 'id') !!}
|
||||
{!! Former::select('invoice_design_id')->style('display:inline')->fromQuery($invoiceDesigns, 'name', 'id') !!}
|
||||
@endif
|
||||
|
||||
{!! Former::text('font_size')->type('number')->min('0')->step('1')->style('width:120px') !!}
|
||||
{!! Former::text('font_size')->type('number')->min('0')->step('1') !!}
|
||||
{!! Former::text('primary_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 class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{!! trans('texts.invoice_labels') !!}</h3>
|
||||
</div>
|
||||
<div role="tabpanel" class="tab-pane" id="invoiceLabels">
|
||||
<div class="panel-body">
|
||||
|
||||
|
||||
{!! Former::text('labels_item')->label(trans('texts.item')) !!}
|
||||
{!! Former::text('labels_description')->label(trans('texts.description')) !!}
|
||||
{!! Former::text('labels_unit_cost')->label(trans('texts.unit_cost')) !!}
|
||||
{!! Former::text('labels_quantity')->label(trans('texts.quantity')) !!}
|
||||
{!! Former::text('labels_line_total')->label(trans('texts.line_total')) !!}
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{!! trans('texts.invoice_options') !!}</h3>
|
||||
</div>
|
||||
<div role="tabpanel" class="tab-pane" id="invoiceOptions">
|
||||
<div class="panel-body">
|
||||
|
||||
{!! Former::checkbox('hide_quantity')->text(trans('texts.hide_quantity_help')) !!}
|
||||
{!! Former::checkbox('hide_paid_to_date')->text(trans('texts.hide_paid_to_date_help')) !!}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@if (Auth::user()->isPro())
|
||||
{!! Former::actions( Button::success(trans('texts.save'))->submit()->large()->appendIcon(Icon::create('floppy-disk'))) !!}
|
||||
@else
|
||||
<br/>
|
||||
{!! Former::actions(
|
||||
Button::primary(trans('texts.customize'))
|
||||
->appendIcon(Icon::create('edit'))
|
||||
->asLinkTo(URL::to('/settings/customize_design'))
|
||||
->large(),
|
||||
Button::success(trans('texts.save'))
|
||||
->submit()->large()
|
||||
->appendIcon(Icon::create('floppy-disk'))
|
||||
->withAttributes(['class' => 'save-button'])
|
||||
) !!}
|
||||
<br/>
|
||||
|
||||
@if (!Auth::user()->isPro())
|
||||
<script>
|
||||
$(function() {
|
||||
$('form.warn-on-exit input').prop('disabled', true);
|
||||
$('form.warn-on-exit input, .save-button').prop('disabled', true);
|
||||
});
|
||||
</script>
|
||||
@endif
|
||||
@ -150,11 +163,10 @@
|
||||
{!! Former::close() !!}
|
||||
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
</div>
|
||||
|
||||
|
||||
@include('invoices.pdf', ['account' => Auth::user()->account, 'pdfHeight' => 800])
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@stop
|
@ -1,4 +1,4 @@
|
||||
@extends('accounts.nav')
|
||||
@extends('header')
|
||||
|
||||
@section('head')
|
||||
@parent
|
||||
@ -10,7 +10,7 @@
|
||||
.input-group-addon div.checkbox {
|
||||
display: inline;
|
||||
}
|
||||
span.input-group-addon {
|
||||
.tab-content .pad-checkbox span.input-group-addon {
|
||||
padding-right: 30px;
|
||||
}
|
||||
</style>
|
||||
@ -18,9 +18,9 @@
|
||||
|
||||
@section('content')
|
||||
@parent
|
||||
@include('accounts.nav_advanced')
|
||||
@include('accounts.nav', ['selected' => ACCOUNT_INVOICE_SETTINGS, 'advanced' => true])
|
||||
|
||||
{!! Former::open()->addClass('col-md-8 col-md-offset-2 warn-on-exit') !!}
|
||||
{!! Former::open()->rules(['iframe_url' => 'url'])->addClass('warn-on-exit') !!}
|
||||
{{ Former::populate($account) }}
|
||||
{{ Former::populateField('custom_invoice_taxes1', intval($account->custom_invoice_taxes1)) }}
|
||||
{{ Former::populateField('custom_invoice_taxes2', intval($account->custom_invoice_taxes2)) }}
|
||||
@ -32,9 +32,11 @@
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{!! trans('texts.email_settings') !!}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="panel-body form-padding-right">
|
||||
{!! Former::checkbox('pdf_email_attachment')->text(trans('texts.enable')) !!}
|
||||
@if (Utils::isNinja())
|
||||
|
||||
{{-- Former::select('recurring_hour')->options($recurringHours) --}}
|
||||
|
||||
{!! Former::inline_radios('custom_invoice_link')
|
||||
->onchange('onCustomLinkChange()')
|
||||
->radios([
|
||||
@ -42,17 +44,18 @@
|
||||
trans('texts.website') => ['value' => 'website', 'name' => 'custom_link'],
|
||||
])->check($account->iframe_url ? 'website' : 'subdomain') !!}
|
||||
{{ Former::setOption('capitalize_translations', false) }}
|
||||
|
||||
{!! Former::text('subdomain')
|
||||
->placeholder(trans('texts.www'))
|
||||
->onchange('onSubdomainChange()')
|
||||
->addGroupClass('subdomain')
|
||||
->label(' ') !!}
|
||||
|
||||
{!! Former::text('iframe_url')
|
||||
->placeholder('http://www.example.com/invoice')
|
||||
->appendIcon('question-sign')
|
||||
->addGroupClass('iframe_url')
|
||||
->label(' ') !!}
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -60,7 +63,8 @@
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{!! trans('texts.invoice_quote_number') !!}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="panel-body form-padding-right">
|
||||
|
||||
<div role="tabpanel">
|
||||
<ul class="nav nav-tabs" role="tablist" style="border: none">
|
||||
<li role="presentation" class="active"><a href="#invoiceNumber" aria-controls="invoiceNumber" role="tab" data-toggle="tab">{{ trans('texts.invoice_number') }}</a></li>
|
||||
@ -70,18 +74,56 @@
|
||||
<div class="tab-content">
|
||||
<div role="tabpanel" class="tab-pane active" id="invoiceNumber">
|
||||
<div class="panel-body">
|
||||
{!! Former::text('invoice_number_prefix')->label(trans('texts.prefix')) !!}
|
||||
{!! Former::text('invoice_number_counter')->label(trans('texts.counter')) !!}
|
||||
{!! Former::inline_radios('invoice_number_type')
|
||||
->onchange('onInvoiceNumberTypeChange()')
|
||||
->label(trans('texts.type'))
|
||||
->radios([
|
||||
trans('texts.prefix') => ['value' => 'prefix', 'name' => 'invoice_number_type'],
|
||||
trans('texts.pattern') => ['value' => 'pattern', 'name' => 'invoice_number_type'],
|
||||
])->check($account->invoice_number_pattern ? 'pattern' : 'prefix') !!}
|
||||
|
||||
{!! Former::text('invoice_number_prefix')
|
||||
->addGroupClass('invoice-prefix')
|
||||
->label(' ') !!}
|
||||
{!! Former::text('invoice_number_pattern')
|
||||
->appendIcon('question-sign')
|
||||
->addGroupClass('invoice-pattern')
|
||||
->label(' ')
|
||||
->addGroupClass('number-pattern') !!}
|
||||
{!! Former::text('invoice_number_counter')
|
||||
->label(trans('texts.counter')) !!}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div role="tabpanel" class="tab-pane" id="quoteNumber">
|
||||
<div class="panel-body">
|
||||
{!! Former::text('quote_number_prefix')->label(trans('texts.prefix')) !!}
|
||||
{!! Former::text('quote_number_counter')->label(trans('texts.counter'))
|
||||
->append(Former::checkbox('share_counter')->raw()->onclick('setQuoteNumberEnabled()') . ' ' . trans('texts.share_invoice_counter')) !!}
|
||||
{!! Former::inline_radios('quote_number_type')
|
||||
->onchange('onQuoteNumberTypeChange()')
|
||||
->label(trans('texts.type'))
|
||||
->radios([
|
||||
trans('texts.prefix') => ['value' => 'prefix', 'name' => 'quote_number_type'],
|
||||
trans('texts.pattern') => ['value' => 'pattern', 'name' => 'quote_number_type'],
|
||||
])->check($account->quote_number_pattern ? 'pattern' : 'prefix') !!}
|
||||
|
||||
{!! Former::text('quote_number_prefix')
|
||||
->addGroupClass('quote-prefix')
|
||||
->label(' ') !!}
|
||||
{!! Former::text('quote_number_pattern')
|
||||
->appendIcon('question-sign')
|
||||
->addGroupClass('quote-pattern')
|
||||
->addGroupClass('number-pattern')
|
||||
->label(' ') !!}
|
||||
{!! Former::text('quote_number_counter')
|
||||
->label(trans('texts.counter'))
|
||||
->addGroupClass('pad-checkbox')
|
||||
->append(Former::checkbox('share_counter')->raw()
|
||||
->onclick('setQuoteNumberEnabled()') . ' ' . trans('texts.share_invoice_counter')) !!}
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -90,7 +132,7 @@
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{!! trans('texts.custom_fields') !!}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="panel-body form-padding-right">
|
||||
|
||||
<div role="tabpanel">
|
||||
<ul class="nav nav-tabs" role="tablist" style="border: none">
|
||||
@ -131,10 +173,16 @@
|
||||
<div role="tabpanel" class="tab-pane" id="invoiceCharges">
|
||||
<div class="panel-body">
|
||||
|
||||
{!! Former::text('custom_invoice_label1')->label(trans('texts.field_label'))
|
||||
->append(Former::checkbox('custom_invoice_taxes1')->raw() . trans('texts.charge_taxes')) !!}
|
||||
{!! Former::text('custom_invoice_label2')->label(trans('texts.field_label'))
|
||||
->append(Former::checkbox('custom_invoice_taxes2')->raw() . trans('texts.charge_taxes')) !!}
|
||||
{!! Former::text('custom_invoice_label1')
|
||||
->label(trans('texts.field_label'))
|
||||
->addGroupClass('pad-checkbox')
|
||||
->append(Former::checkbox('custom_invoice_taxes1')
|
||||
->raw() . trans('texts.charge_taxes')) !!}
|
||||
{!! Former::text('custom_invoice_label2')
|
||||
->label(trans('texts.field_label'))
|
||||
->addGroupClass('pad-checkbox')
|
||||
->append(Former::checkbox('custom_invoice_taxes2')
|
||||
->raw() . trans('texts.charge_taxes')) !!}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@ -147,12 +195,6 @@
|
||||
<center>
|
||||
{!! Button::success(trans('texts.save'))->large()->submit()->appendIcon(Icon::create('floppy-disk')) !!}
|
||||
</center>
|
||||
@else
|
||||
<script>
|
||||
$(function() {
|
||||
$('form.warn-on-exit input').prop('disabled', true);
|
||||
});
|
||||
</script>
|
||||
@endif
|
||||
|
||||
|
||||
@ -185,6 +227,40 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="patternHelpModal" tabindex="-1" role="dialog" aria-labelledby="patternHelpModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog" style="min-width:150px">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title" id="patternHelpModalLabel">{{ trans('texts.pattern_help_title') }}</h4>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<p>{{ trans('texts.pattern_help_1') }}</p>
|
||||
<p>{{ trans('texts.pattern_help_2') }}</p>
|
||||
<ul>
|
||||
@foreach (\App\Models\Invoice::$patternFields as $field)
|
||||
@if ($field == 'date:')
|
||||
<li>{$date:format} - {!! link_to(PHP_DATE_FORMATS, trans('texts.see_options'), ['target' => '_blank']) !!}</li>
|
||||
@else
|
||||
<li>{${{ $field }}}</li>
|
||||
@endif
|
||||
@endforeach
|
||||
</ul>
|
||||
<p>{{ trans('texts.pattern_help_3', [
|
||||
'example' => '{$year}-{$counter}',
|
||||
'value' => date('Y') . '-0001'
|
||||
]) }}</p>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer" style="margin-top: 0px">
|
||||
<button type="button" class="btn btn-primary" data-dismiss="modal">{{ trans('texts.close') }}</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{!! Former::close() !!}
|
||||
|
||||
@ -216,13 +292,41 @@
|
||||
}
|
||||
}
|
||||
|
||||
function onInvoiceNumberTypeChange() {
|
||||
var val = $('input[name=invoice_number_type]:checked').val()
|
||||
if (val == 'prefix') {
|
||||
$('.invoice-prefix').show();
|
||||
$('.invoice-pattern').hide();
|
||||
} else {
|
||||
$('.invoice-prefix').hide();
|
||||
$('.invoice-pattern').show();
|
||||
}
|
||||
}
|
||||
|
||||
function onQuoteNumberTypeChange() {
|
||||
var val = $('input[name=quote_number_type]:checked').val()
|
||||
if (val == 'prefix') {
|
||||
$('.quote-prefix').show();
|
||||
$('.quote-pattern').hide();
|
||||
} else {
|
||||
$('.quote-prefix').hide();
|
||||
$('.quote-pattern').show();
|
||||
}
|
||||
}
|
||||
|
||||
$('.iframe_url .input-group-addon').click(function() {
|
||||
$('#iframeHelpModal').modal('show');
|
||||
});
|
||||
|
||||
$('.number-pattern .input-group-addon').click(function() {
|
||||
$('#patternHelpModal').modal('show');
|
||||
});
|
||||
|
||||
$(function() {
|
||||
setQuoteNumberEnabled();
|
||||
onCustomLinkChange();
|
||||
onInvoiceNumberTypeChange();
|
||||
onQuoteNumberTypeChange();
|
||||
|
||||
$('#subdomain').change(function() {
|
||||
$('#iframe_url').val('');
|
||||
|
46
resources/views/accounts/localization.blade.php
Normal file
46
resources/views/accounts/localization.blade.php
Normal file
@ -0,0 +1,46 @@
|
||||
@extends('header')
|
||||
|
||||
@section('content')
|
||||
@parent
|
||||
|
||||
{!! Former::open_for_files()->addClass('warn-on-exit') !!}
|
||||
{{ Former::populate($account) }}
|
||||
{{ Former::populateField('military_time', intval($account->military_time)) }}
|
||||
|
||||
@include('accounts.nav', ['selected' => ACCOUNT_LOCALIZATION])
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{!! trans('texts.localization') !!}</h3>
|
||||
</div>
|
||||
<div class="panel-body form-padding-right">
|
||||
|
||||
{!! Former::select('currency_id')->addOption('','')
|
||||
->fromQuery($currencies, 'name', 'id') !!}
|
||||
{!! Former::select('language_id')->addOption('','')
|
||||
->fromQuery($languages, 'name', 'id') !!}
|
||||
{!! Former::select('timezone_id')->addOption('','')
|
||||
->fromQuery($timezones, 'location', 'id') !!}
|
||||
{!! Former::select('date_format_id')->addOption('','')
|
||||
->fromQuery($dateFormats, 'label', 'id') !!}
|
||||
{!! Former::select('datetime_format_id')->addOption('','')
|
||||
->fromQuery($datetimeFormats, 'label', 'id') !!}
|
||||
{!! Former::checkbox('military_time')->text(trans('texts.enable')) !!}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<center>
|
||||
{!! Button::success(trans('texts.save'))->submit()->large()->appendIcon(Icon::create('floppy-disk')) !!}
|
||||
</center>
|
||||
|
||||
{!! Former::close() !!}
|
||||
|
||||
@stop
|
||||
|
||||
@section('onReady')
|
||||
$('#currency_id').focus();
|
||||
@stop
|
@ -1,16 +1,33 @@
|
||||
@extends('header')
|
||||
@if (!Utils::isPro() && isset($advanced) && $advanced)
|
||||
<div class="alert alert-warning" style="font-size:larger;">
|
||||
<center>
|
||||
{!! trans('texts.pro_plan_advanced_settings', ['link'=>'<a href="#" onclick="showProPlan(\''.$selected.'\')">'.trans('texts.pro_plan.remove_logo_link').'</a>']) !!}
|
||||
</center>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@section('content')
|
||||
<div class="row">
|
||||
|
||||
<ul class="nav nav-tabs nav nav-justified">
|
||||
{!! HTML::nav_link('company/details', 'company_details') !!}
|
||||
{!! HTML::nav_link('company/payments', 'online_payments', 'gateways') !!}
|
||||
{!! HTML::nav_link('company/products', 'product_library') !!}
|
||||
{!! HTML::nav_link('company/notifications', 'notifications') !!}
|
||||
{!! HTML::nav_link('company/import_export', 'import_export', 'company/import_map') !!}
|
||||
{!! HTML::nav_link('company/advanced_settings/invoice_design', 'advanced_settings', '*/advanced_settings/*') !!}
|
||||
</ul>
|
||||
<div class="col-md-3">
|
||||
@foreach([
|
||||
BASIC_SETTINGS => \App\Models\Account::$basicSettings,
|
||||
ADVANCED_SETTINGS => \App\Models\Account::$advancedSettings,
|
||||
] as $type => $settings)
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading" style="color:white">
|
||||
{{ trans("texts.{$type}") }}
|
||||
@if ($type == ADVANCED_SETTINGS && !Utils::isPro())
|
||||
<sup>{{ strtoupper(trans('texts.pro')) }}</sup>
|
||||
@endif
|
||||
</div>
|
||||
<div class="list-group">
|
||||
@foreach ($settings as $section)
|
||||
<a href="{{ URL::to("settings/{$section}") }}" class="list-group-item {{ $selected === $section ? 'selected' : '' }}"
|
||||
style="width:100%;text-align:left">{{ trans("texts.{$section}") }}</a>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
|
||||
@stop
|
||||
<div class="col-md-9">
|
@ -1,9 +1,11 @@
|
||||
@extends('accounts.nav')
|
||||
@extends('header')
|
||||
|
||||
@section('content')
|
||||
@parent
|
||||
|
||||
{!! Former::open()->addClass('col-md-8 col-md-offset-2 warn-on-exit') !!}
|
||||
@include('accounts.nav', ['selected' => ACCOUNT_NOTIFICATIONS])
|
||||
|
||||
{!! Former::open()->addClass('warn-on-exit') !!}
|
||||
{{ Former::populate($account) }}
|
||||
{{ Former::populateField('notify_sent', intval(Auth::user()->notify_sent)) }}
|
||||
{{ Former::populateField('notify_viewed', intval(Auth::user()->notify_viewed)) }}
|
||||
@ -41,13 +43,12 @@
|
||||
|
||||
<div class="fb-follow" data-href="https://www.facebook.com/invoiceninja" data-colorscheme="light" data-layout="button" data-show-faces="false"></div>
|
||||
|
||||
<a href="https://twitter.com/invoiceninja" class="twitter-follow-button" data-show-count="false" data-related="hillelcoren" data-size="medium">Follow @invoiceninja</a>
|
||||
<a href="https://twitter.com/invoiceninja" class="twitter-follow-button" data-show-count="false" data-related="hillelcoren" data-size="large">Follow @invoiceninja</a>
|
||||
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');</script>
|
||||
|
||||
</div></div>
|
||||
</div>
|
||||
</div>
|
||||
-->
|
||||
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{!! trans('texts.custom_messages') !!}</h3>
|
||||
|
@ -1,7 +1,8 @@
|
||||
@extends('accounts.nav')
|
||||
@extends('header')
|
||||
|
||||
@section('content')
|
||||
@parent
|
||||
@include('accounts.nav', ['selected' => ACCOUNT_PAYMENTS])
|
||||
|
||||
{!! Former::open('gateways/delete')->addClass('user-form') !!}
|
||||
|
||||
|
@ -1,18 +1,20 @@
|
||||
@extends('accounts.nav')
|
||||
@extends('header')
|
||||
|
||||
@section('content')
|
||||
@parent
|
||||
|
||||
@include('accounts.nav', ['selected' => ACCOUNT_PRODUCTS])
|
||||
|
||||
{!! Former::open($url)->method($method)
|
||||
->rules(['product_key' => 'required|max:255'])
|
||||
->addClass('col-md-8 col-md-offset-2 warn-on-exit') !!}
|
||||
->addClass('warn-on-exit') !!}
|
||||
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{!! $title !!}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="panel-body form-padding-right">
|
||||
|
||||
@if ($product)
|
||||
{{ Former::populate($product) }}
|
||||
@ -23,11 +25,18 @@
|
||||
{!! Former::textarea('notes') !!}
|
||||
{!! Former::text('cost') !!}
|
||||
|
||||
@if ($account->invoice_item_taxes)
|
||||
{!! Former::select('default_tax_rate_id')
|
||||
->addOption('', '')
|
||||
->label(trans('texts.tax_rate'))
|
||||
->fromQuery($taxRates, function($model) { return $model->name . ' ' . $model->rate . '%'; }, 'id') !!}
|
||||
@endif
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{!! Former::actions(
|
||||
Button::normal(trans('texts.cancel'))->large()->asLinkTo(URL::to('/company/products'))->appendIcon(Icon::create('remove-circle')),
|
||||
Button::normal(trans('texts.cancel'))->large()->asLinkTo(URL::to('/settings/products'))->appendIcon(Icon::create('remove-circle')),
|
||||
Button::success(trans('texts.save'))->submit()->large()->appendIcon(Icon::create('floppy-disk'))
|
||||
) !!}
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
@extends('accounts.nav')
|
||||
@extends('header')
|
||||
|
||||
@section('content')
|
||||
@parent
|
||||
|
||||
@include('accounts.nav', ['selected' => ACCOUNT_PRODUCTS])
|
||||
|
||||
{!! Former::open()->addClass('warn-on-exit') !!}
|
||||
{{ Former::populateField('fill_products', intval($account->fill_products)) }}
|
||||
{{ Former::populateField('update_products', intval($account->update_products)) }}
|
||||
@ -17,7 +19,7 @@
|
||||
{!! Former::checkbox('fill_products')->text(trans('texts.fill_products_help')) !!}
|
||||
{!! Former::checkbox('update_products')->text(trans('texts.update_products_help')) !!}
|
||||
|
||||
{!! Former::actions( Button::success(trans('texts.save'))->submit()->large()->appendIcon(Icon::create('floppy-disk')) ) !!}
|
||||
{!! Former::actions( Button::success(trans('texts.save'))->submit()->appendIcon(Icon::create('floppy-disk')) ) !!}
|
||||
{!! Former::close() !!}
|
||||
</div>
|
||||
</div>
|
||||
@ -28,16 +30,12 @@
|
||||
->appendIcon(Icon::create('plus-sign')) !!}
|
||||
|
||||
{!! Datatable::table()
|
||||
->addColumn(
|
||||
trans('texts.product'),
|
||||
trans('texts.description'),
|
||||
trans('texts.unit_cost'),
|
||||
trans('texts.action'))
|
||||
->addColumn($columns)
|
||||
->setUrl(url('api/products/'))
|
||||
->setOptions('sPaginationType', 'bootstrap')
|
||||
->setOptions('bFilter', false)
|
||||
->setOptions('bAutoWidth', false)
|
||||
->setOptions('aoColumns', [[ "sWidth"=> "20%" ], [ "sWidth"=> "45%" ], ["sWidth"=> "20%"], ["sWidth"=> "15%" ]])
|
||||
//->setOptions('aoColumns', [[ "sWidth"=> "15%" ], [ "sWidth"=> "35%" ]])
|
||||
->setOptions('aoColumnDefs', [['bSortable'=>false, 'aTargets'=>[3]]])
|
||||
->render('datatable') !!}
|
||||
|
||||
|
47
resources/views/accounts/tax_rate.blade.php
Normal file
47
resources/views/accounts/tax_rate.blade.php
Normal file
@ -0,0 +1,47 @@
|
||||
@extends('header')
|
||||
|
||||
@section('content')
|
||||
@parent
|
||||
|
||||
@include('accounts.nav', ['selected' => ACCOUNT_TAX_RATES])
|
||||
|
||||
{!! Former::open($url)->method($method)
|
||||
->rules([
|
||||
'name' => 'required',
|
||||
'rate' => 'required'
|
||||
])
|
||||
->addClass('warn-on-exit') !!}
|
||||
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{!! $title !!}</h3>
|
||||
</div>
|
||||
<div class="panel-body form-padding-right">
|
||||
|
||||
@if ($taxRate)
|
||||
{{ Former::populate($taxRate) }}
|
||||
@endif
|
||||
|
||||
{!! Former::text('name')->label('texts.name') !!}
|
||||
{!! Former::text('rate')->label('texts.rate')->append('%') !!}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{!! Former::actions(
|
||||
Button::normal(trans('texts.cancel'))->large()->asLinkTo(URL::to('/settings/tax_rates'))->appendIcon(Icon::create('remove-circle')),
|
||||
Button::success(trans('texts.save'))->submit()->large()->appendIcon(Icon::create('floppy-disk'))
|
||||
) !!}
|
||||
|
||||
{!! Former::close() !!}
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
$(function() {
|
||||
$('#name').focus();
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
@stop
|
79
resources/views/accounts/tax_rates.blade.php
Normal file
79
resources/views/accounts/tax_rates.blade.php
Normal file
@ -0,0 +1,79 @@
|
||||
@extends('header')
|
||||
|
||||
@section('content')
|
||||
@parent
|
||||
|
||||
@include('accounts.nav', ['selected' => ACCOUNT_TAX_RATES])
|
||||
|
||||
{!! Former::open()->addClass('warn-on-exit') !!}
|
||||
{{ Former::populate($account) }}
|
||||
{{ Former::populateField('invoice_taxes', intval($account->invoice_taxes)) }}
|
||||
{{ Former::populateField('invoice_item_taxes', intval($account->invoice_item_taxes)) }}
|
||||
{{ Former::populateField('show_item_taxes', intval($account->show_item_taxes)) }}
|
||||
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{!! trans('texts.tax_settings') !!}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
|
||||
{!! Former::checkbox('invoice_taxes')
|
||||
->text(trans('texts.enable_invoice_tax'))
|
||||
->label(' ') !!}
|
||||
|
||||
{!! Former::checkbox('invoice_item_taxes')
|
||||
->text(trans('texts.enable_line_item_tax'))
|
||||
->label(' ') !!}
|
||||
|
||||
{!! Former::checkbox('show_item_taxes')
|
||||
->text(trans('texts.show_line_item_tax'))
|
||||
->label(' ') !!}
|
||||
|
||||
|
||||
|
||||
{!! Former::select('default_tax_rate_id')
|
||||
->style('max-width: 250px')
|
||||
->addOption('', '')
|
||||
->fromQuery($taxRates, function($model) { return $model->name . ': ' . $model->rate . '%'; }, 'id') !!}
|
||||
|
||||
|
||||
|
||||
{!! Former::actions( Button::success(trans('texts.save'))->submit()->appendIcon(Icon::create('floppy-disk')) ) !!}
|
||||
{!! Former::close() !!}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{!! Button::primary(trans('texts.create_tax_rate'))
|
||||
->asLinkTo(URL::to('/tax_rates/create'))
|
||||
->withAttributes(['class' => 'pull-right'])
|
||||
->appendIcon(Icon::create('plus-sign')) !!}
|
||||
|
||||
{!! Datatable::table()
|
||||
->addColumn(
|
||||
trans('texts.name'),
|
||||
trans('texts.rate'),
|
||||
trans('texts.action'))
|
||||
->setUrl(url('api/tax_rates/'))
|
||||
->setOptions('sPaginationType', 'bootstrap')
|
||||
->setOptions('bFilter', false)
|
||||
->setOptions('bAutoWidth', false)
|
||||
->setOptions('aoColumns', [[ "sWidth"=> "40%" ], [ "sWidth"=> "40%" ], ["sWidth"=> "20%"]])
|
||||
->setOptions('aoColumnDefs', [['bSortable'=>false, 'aTargets'=>[2]]])
|
||||
->render('datatable') !!}
|
||||
|
||||
<script>
|
||||
window.onDatatableReady = function() {
|
||||
$('tbody tr').mouseover(function() {
|
||||
$(this).closest('tr').find('.tr-action').css('visibility','visible');
|
||||
}).mouseout(function() {
|
||||
$dropdown = $(this).closest('tr').find('.tr-action');
|
||||
if (!$dropdown.hasClass('open')) {
|
||||
$dropdown.css('visibility','hidden');
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@stop
|
@ -1,4 +1,4 @@
|
||||
@extends('accounts.nav')
|
||||
@extends('header')
|
||||
|
||||
@section('head')
|
||||
@parent
|
||||
@ -13,9 +13,9 @@
|
||||
|
||||
@section('content')
|
||||
@parent
|
||||
@include('accounts.nav_advanced')
|
||||
@include('accounts.nav', ['selected' => ACCOUNT_TEMPLATES_AND_REMINDERS, 'advanced' => true])
|
||||
|
||||
{!! Former::vertical_open()->addClass('col-md-10 col-md-offset-1 warn-on-exit') !!}
|
||||
{!! Former::vertical_open()->addClass('warn-on-exit') !!}
|
||||
{!! Former::populate($account) !!}
|
||||
|
||||
@foreach ([ENTITY_INVOICE, ENTITY_QUOTE, ENTITY_PAYMENT, REMINDER1, REMINDER2, REMINDER3] as $type)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user