1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-09-20 08:21:34 +02:00

Merge pull request #3 from hillelcoren/master

Update from master
This commit is contained in:
Paul-Vincent Roll 2015-02-13 12:50:42 +01:00
commit 5062f73054
44 changed files with 806 additions and 230 deletions

View File

@ -85,7 +85,11 @@ class AccountController extends \BaseController
{
Session::put("show_trash:{$entityType}", $visible == 'true');
return Redirect::to("{$entityType}s");
if ($entityType == 'user') {
return Redirect::to('company/'.ACCOUNT_ADVANCED_SETTINGS.'/'.ACCOUNT_USER_MANAGEMENT);
} else {
return Redirect::to("{$entityType}s");
}
}
public function getSearchData()
@ -168,7 +172,7 @@ class AccountController extends \BaseController
);
$recommendedGatewayArray['Other Options'] = $otherItem;
$gateways = Gateway::remember(DEFAULT_QUERY_CACHE)->orderBy('name')->get();
$gateways = Gateway::remember(DEFAULT_QUERY_CACHE)->where('payment_library_id', '=', 1)->orderBy('name')->get();
foreach ($gateways as $gateway) {
$paymentLibrary = $gateway->paymentlibrary;
@ -187,6 +191,7 @@ class AccountController extends \BaseController
'gateways' => $gateways,
'dropdownGateways' => Gateway::remember(DEFAULT_QUERY_CACHE)
->where('recommended', '=', '0')
->where('payment_library_id', '=', 1)
->orderBy('name')
->get(),
'recommendedGateways' => $recommendedGatewayArray,
@ -203,8 +208,9 @@ class AccountController extends \BaseController
} elseif ($section == ACCOUNT_IMPORT_EXPORT) {
return View::make('accounts.import_export');
} elseif ($section == ACCOUNT_ADVANCED_SETTINGS) {
$account = Auth::user()->account;
$data = [
'account' => Auth::user()->account,
'account' => $account,
'feature' => $subSection,
];
@ -237,6 +243,11 @@ class AccountController extends \BaseController
$data['invoice'] = $invoice;
$data['invoiceDesigns'] = InvoiceDesign::remember(DEFAULT_QUERY_CACHE, 'invoice_designs_cache_'.Auth::user()->maxInvoiceDesignId())
->where('id', '<=', Auth::user()->maxInvoiceDesignId())->orderBy('id')->get();
} else if ($subSection == ACCOUNT_EMAIL_TEMPLATES) {
$data['invoiceEmail'] = $account->getEmailTemplate(ENTITY_INVOICE);
$data['quoteEmail'] = $account->getEmailTemplate(ENTITY_QUOTE);
$data['paymentEmail'] = $account->getEmailTemplate(ENTITY_PAYMENT);
$data['emailFooter'] = $account->getEmailFooter();
}
return View::make("accounts.{$subSection}", $data);
@ -268,12 +279,31 @@ class AccountController extends \BaseController
return AccountController::saveInvoiceSettings();
} elseif ($subSection == ACCOUNT_INVOICE_DESIGN) {
return AccountController::saveInvoiceDesign();
} elseif ($subSection == ACCOUNT_EMAIL_TEMPLATES) {
return AccountController::saveEmailTemplates();
}
} elseif ($section == ACCOUNT_PRODUCTS) {
return AccountController::saveProducts();
}
}
private function saveEmailTemplates()
{
if (Auth::user()->account->isPro()) {
$account = Auth::user()->account;
$account->email_template_invoice = Input::get('email_template_invoice', $account->getEmailTemplate(ENTITY_INVOICE));
$account->email_template_quote = Input::get('email_template_quote', $account->getEmailTemplate(ENTITY_QUOTE));
$account->email_template_payment = Input::get('email_template_payment', $account->getEmailTemplate(ENTITY_PAYMENT));
$account->save();
Session::flash('message', trans('texts.updated_settings'));
}
return Redirect::to('company/advanced_settings/email_templates');
}
private function saveProducts()
{
$account = Auth::user()->account;
@ -283,7 +313,6 @@ class AccountController extends \BaseController
$account->save();
Session::flash('message', trans('texts.updated_settings'));
return Redirect::to('company/products');
}

View File

@ -59,19 +59,19 @@ class AppController extends BaseController
return Redirect::to('/setup')->withInput();
}
$content = "<?php return 'development';";
$content = "<?php return 'production';";
$fp = fopen(base_path()."/bootstrap/environment.php", 'w');
fwrite($fp, $content);
fclose($fp);
$configDir = app_path().'/config/development';
$configDir = app_path().'/config/production';
if (!file_exists($configDir)) {
mkdir($configDir);
}
foreach (['app' => $app, 'database' => $database, 'mail' => $mail] as $key => $config) {
$content = '<?php return '.var_export($config, true).';';
$fp = fopen(app_path()."/config/development/{$key}.php", 'w');
$fp = fopen(app_path()."/config/production/{$key}.php", 'w');
fwrite($fp, $content);
fclose($fp);
}

View File

@ -477,7 +477,6 @@ class InvoiceController extends \BaseController
$clone = $this->invoiceRepo->cloneInvoice($invoice, $invoice->id);
Session::flash('message', trans('texts.converted_to_invoice'));
return Redirect::to('invoices/'.$clone->public_id);
}

View File

@ -71,7 +71,9 @@ class PaymentController extends \BaseController
<ul class="dropdown-menu" role="menu">';
if (!$model->deleted_at || $model->deleted_at == '0000-00-00') {
$str .= '<li><a href="javascript:archiveEntity('.$model->public_id.')">'.trans('texts.archive_payment').'</a></li>';
$str .= '<li><a href="payments/'.$model->public_id.'/edit">'.trans('texts.edit_payment').'</a></li>
<li class="divider"></li>
<li><a href="javascript:archiveEntity('.$model->public_id.')">'.trans('texts.archive_payment').'</a></li>';
} else {
$str .= '<li><a href="javascript:restoreEntity('.$model->public_id.')">'.trans('texts.restore_payment').'</a></li>';
}
@ -141,7 +143,7 @@ class PaymentController extends \BaseController
'payment' => $payment,
'method' => 'PUT',
'url' => 'payments/'.$publicId,
'title' => 'Edit Payment',
'title' => trans('texts.edit_payment'),
//'currencies' => Currency::remember(DEFAULT_QUERY_CACHE)->orderBy('name')->get(),
'paymentTypes' => PaymentType::remember(DEFAULT_QUERY_CACHE)->orderBy('id')->get(),
'clients' => Client::scope()->with('contacts')->orderBy('name')->get(), );
@ -687,7 +689,7 @@ class PaymentController extends \BaseController
private function save($publicId = null)
{
if ($errors = $this->paymentRepo->getErrors(Input::all())) {
if (!$publicId && $errors = $this->paymentRepo->getErrors(Input::all())) {
$url = $publicId ? 'payments/'.$publicId.'/edit' : 'payments/create';
return Redirect::to($url)
@ -695,10 +697,14 @@ class PaymentController extends \BaseController
->withInput();
} else {
$this->paymentRepo->save($publicId, Input::all());
Session::flash('message', trans('texts.created_payment'));
return Redirect::to('clients/'.Input::get('client'));
if ($publicId) {
Session::flash('message', trans('texts.updated_payment'));
return Redirect::to('payments/');
} else {
Session::flash('message', trans('texts.created_payment'));
return Redirect::to('clients/'.Input::get('client'));
}
}
}

View File

@ -135,6 +135,15 @@ class QuoteController extends \BaseController
public function bulk()
{
$action = Input::get('action');
if ($action == 'convert') {
$invoice = Invoice::with('invoice_items')->scope(Input::get('id'))->firstOrFail();
$clone = $this->invoiceRepo->cloneInvoice($invoice, $invoice->id);
Session::flash('message', trans('texts.converted_to_invoice'));
return Redirect::to('invoices/'.$clone->public_id);
}
$statusId = Input::get('statusId');
$ids = Input::get('id') ? Input::get('id') : Input::get('ids');
$count = $this->invoiceRepo->bulk($ids, $action, $statusId);

View File

@ -31,26 +31,43 @@ class UserController extends BaseController
public function getDatatable()
{
$query = DB::table('users')
->where('users.account_id', '=', Auth::user()->account_id)
->where('users.deleted_at', '=', null)
->where('users.public_id', '>', 0)
->select('users.public_id', 'users.first_name', 'users.last_name', 'users.email', 'users.confirmed', 'users.public_id');
->where('users.account_id', '=', Auth::user()->account_id);
if (!Session::get('show_trash:user')) {
$query->where('users.deleted_at', '=', null);
}
$query->where('users.public_id', '>', 0)
->select('users.public_id', 'users.first_name', 'users.last_name', 'users.email', 'users.confirmed', 'users.public_id', 'users.deleted_at');
return Datatable::query($query)
->addColumn('first_name', function ($model) { return link_to('users/'.$model->public_id.'/edit', $model->first_name.' '.$model->last_name); })
->addColumn('email', function ($model) { return $model->email; })
->addColumn('confirmed', function ($model) { return $model->confirmed ? trans('texts.active') : trans('texts.pending'); })
->addColumn('confirmed', function ($model) { return $model->deleted_at ? trans('texts.deleted') : ($model->confirmed ? trans('texts.active') : trans('texts.pending')); })
->addColumn('dropdown', function ($model) {
return '<div class="btn-group tr-action" style="visibility:hidden;">
$actions = '<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('users/'.$model->public_id).'/edit">'.uctrans('texts.edit_user').'</a></li>
<li class="divider"></li>
<li><a href="javascript:deleteUser('.$model->public_id.')">'.uctrans('texts.delete_user').'</a></li>
</ul>
<ul class="dropdown-menu" role="menu">';
if ($model->deleted_at) {
$actions .= '<li><a href="'.URL::to('restore_user/'.$model->public_id).'">'.uctrans('texts.restore_user').'</a></li>';
} else {
$actions .= '<li><a href="'.URL::to('users/'.$model->public_id).'/edit">'.uctrans('texts.edit_user').'</a></li>';
if (!$model->confirmed) {
$actions .= '<li><a href="'.URL::to('send_confirmation/'.$model->public_id).'">'.uctrans('texts.send_invite').'</a></li>';
}
$actions .= '<li class="divider"></li>
<li><a href="javascript:deleteUser('.$model->public_id.')">'.uctrans('texts.delete_user').'</a></li>';
}
$actions .= '</ul>
</div>';
return $actions;
})
->orderColumns(['first_name', 'email', 'confirmed'])
->make();
@ -147,6 +164,19 @@ class UserController extends BaseController
return Redirect::to('company/advanced_settings/user_management');
}
public function restoreUser($userPublicId)
{
$user = User::where('account_id', '=', Auth::user()->account_id)
->where('public_id', '=', $userPublicId)
->withTrashed()->firstOrFail();
$user->restore();
Session::flash('message', trans('texts.restored_user'));
return Redirect::to('company/advanced_settings/user_management');
}
/**
* Stores new account
*
@ -208,6 +238,17 @@ class UserController extends BaseController
return Redirect::to('company/advanced_settings/user_management');
}
public function sendConfirmation($userPublicId)
{
$user = User::where('account_id', '=', Auth::user()->account_id)
->where('public_id', '=', $userPublicId)->firstOrFail();
$this->userMailer->sendConfirmation($user, Auth::user());
Session::flash('message', trans('texts.sent_invite'));
return Redirect::to('company/advanced_settings/user_management');
}
/**
* Displays the login form
*

View File

@ -0,0 +1,38 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddEmailTemplates extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('accounts', function($table)
{
$table->text('email_template_invoice')->nullable();
$table->text('email_template_quote')->nullable();
$table->text('email_template_payment')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('accounts', function($table)
{
$table->dropColumn('email_template_invoice');
$table->dropColumn('email_template_quote');
$table->dropColumn('email_template_payment');
});
}
}

209
app/lang/da/public.php Normal file
View File

@ -0,0 +1,209 @@
<?php
return [
'title' => 'Gratis Open-Source Online Fakturering',
'description' => 'Invoice Ninja er en gratis, open-source løsning til fakturering af kunder. Med Invoice Ninja, kan du nemt opbygge og sende smukke fakturaer fra enhver enhed, der har adgang til internettet. Dine kunder kan printe dine fakturaer, downloade dem som PDF-filer, og endda betale dig online via systemet.',
'invoice_now' => 'Fakturér nu',
'no_signup_needed' => 'Ingen tilmelding påkrævet',
'link_blog' => 'Blog',
'link_about_us' => 'Om Os',
'link_contact_us' => 'Kontakt Os',
'link_features' => 'Funktioner',
'link_plans' => 'Løsninger',
'link_compare' => 'Sammenlign',
'link_testimonials' => 'Anbefalinger',
'link_faq' => 'OSS',
'my_account' => 'Min konto',
'login' => 'Login',
'connect_with_us' => 'Forbind med os',
'safe_and_secure' => 'Safe & Secure',
'toggle_navigation' => 'Vis/Skjul navigation',
'home' => [
'header' => 'THE <span style="color:#2299c0">SIMPLE</span> &amp; <span style="color:#edd71e">FREE</span> WAY TO INVOICE CLIENTS',
'sub_header' => 'It\'s just that easy. Stop spending time on complicated and expensive invoicing.<br>No fuss, just get started and get paid.',
'footer' => '<span>Simple, Intuitive Invoicing,</span>Anywhere.',
'free_always' => 'Free, Always',
'free_always_text' => 'Send unlimited invoices to 500 clients per month and never pay a dime. You are welcome to unlock still more awesome features with our Pro Plan, but our free app is a top-notch product that will do everything you need it to do, without any subscription or fees.',
'open_source' => 'Open-Source',
'open_source_text' => 'No mysterious corporate silos here! Just full <a href="https://github.com/hillelcoren/invoice-ninja" target="_blank">source code</a> transparency and a devotion to working with anyone interested to build a better electronic invoicing platform. We even offer a handy <a href="http://hillelcoren.com/invoice-ninja/self-hosting/" target="_blank">zip download</a> for a self-hosted version of Invoice Ninja.',
'live_pdf' => 'Live .PDF View',
'live_pdf_text' => 'See how your edited invoice will look as a print-friendly pdf while you make the changes. Our pdf generator works in real time as you make your changes. You can even preview four beautiful preset designs. Just create, save, send, and youre done!',
'online_payments' => 'Online Payments',
'online_payments_text' => 'Invoices sent with our app integrate seamlessly with the gateway credit card processor of your choice, to make it super easy for your clients to send you money with just a few clicks. We play nicely with Authorize.Net, Stripe, PayPal and loads more - 23 in all!',
],
'about' => [
'header' => '<span class="thin">About</span> Invoice Ninja',
'what_is' => 'What is Invoice Ninja?',
'team_ninja' => 'Team Ninja',
'team_ninja_text' => 'Invoice Ninja is managed by a team of seasoned web workers. We launched in early 2014 and have been thrilled by the enthusiastic response weve received from our growing community of users.',
'co_founder' => 'Co-Founder',
'ceo' => 'CEO',
'cto' => '',
'designer' => 'Designer',
'marketing' => 'Marketing',
'shalom_bio' => 'Shalom has specialized in small business development for nearly 10 years. In addition to InvoiceNinja.com Shalom is CEO of a leading tour agency in Israel.',
'hillel_bio' => 'Hillel has been developing enterprise applications for 15 years. His open-source <a href="http://hillelcoren.com/flex-autocomplete/" target="_blank">AutoComplete</a> component has been used by thousands of developers around the world.',
'razi_bio' => 'Razi is a pixel nerd with a great deal of experience in design for web sites and applications. When she isn\'t busy with InvoiceNinja she runs a small web agency in Stockholm called kantorp-wegl.in',
'ben_bio' => 'A veteran digital marketer and content strategist, Ben specializes in building communities around brands that make business easier for freelancers, SMBs and micro-entrepreneurs.',
],
'contact' => [
'header' => 'Questions, special requests, or just want to say hi?',
'sub_header' => 'Fill in the form below and we\'ll get back to you as soon as possible. Hope to hear from you!',
'other_ways' => 'Other ways to reach us',
'name' => 'Name',
'name_help' => 'Please enter your name.',
'email' => 'Email Address',
'email_help' => 'Please enter a valid e-mail address.',
'message' => 'Message',
'message_help' => 'Please enter a message.',
'send_message' => 'Send Message',
],
'features' => [
'header' => '<span class="thin">The</span> Features',
'footer' => 'Like what you see?',
'footer_action' => 'Get started today!',
'open_source' => 'Open Source Platform',
'open_source_text1' => 'Set the code free! Here at Invoice Ninja, were all about creating the best possible app, and inviting scrutiny via full code transparency is a central manifestation of this value.',
'open_source_text2' => 'We firmly believe that being an open source product helps everyone involved. Were looking forward to seeing what the developers out there can do to take Invoice Ninja into new realms of usefulness.',
'free_forever' => 'FREE. Forever.',
'free_forever_text1' => 'Yeah, you read that correctly. You dont have to pay us a cent to use our tools. We know how tough it is to make ends meet as a web-based business, and were bent on providing a top-notch product that will do everything you need it to do, without any subscription or opt-in fees.',
'free_forever_text2' => 'Try Invoice Ninja out. You literally have nothing to lose. Were confident that youll find the experience so positive that youll never need to turn elsewhere.',
'secure' => 'Secure & Private',
'secure_text1' => 'Invoice Ninja has been built from the ground up to keep your data safe. Only you have access to your login & accounting details, & we will never share your transaction data to any third party.',
'secure_text2' => 'Our website operates with 256-bit encryption, which is even more secure than most banking websites. Invoice Ninja uses the TLS 1.0 cryptographic protocol, AES_256_CBC string encryption, SHA1 message authentication and DHE_RSA key exchanges. We feel safe here and have invested heavily in measures to ensure that you do too.',
'live_pdf' => 'Live .PDF View',
'live_pdf_text1' => 'With Invoice Ninja, weve done away with the need for cumbersome multi-click invoice previewing after each save.',
'live_pdf_text2' => 'When you enter the details of your customer and/or invoice in our editor, you can instantly see the results in the pdf preview pane below. Want to see what your invoice would look like in a different layout style? The live pdf can show you four beautiful preset styles in real time too.',
'live_pdf_text3' => 'Just create, save, send, and youre done!',
'online_payments' => 'Online Payments',
'online_payments_text1' => 'Invoice Ninja seamlessly integrates with all of the top internet payment processors and gateways so you can get paid for your work quickly and easily.',
'online_payments_text2' => 'Invoices created with our tools arent just for bookkeeping purposes - they bring in the Benjamins. We also make it super easy to choose the right gateway for the specific needs of your business and are happy to help you to get started working with the gateway of your choice. Whats more, were constantly working on rolling out additional gateway integrations, so if you dont see the one you use here, just let us know, and theres a good chance well add it for you.',
],
'plans' => [
'header' => '<span class="thin">The</span> Plans',
'free' => 'Free',
'unlimited' => 'Unlimited',
'pro_plan' => 'Pro Plan',
'go_pro' => 'Go Pro to Unlock Premium Invoice Ninja Features',
'go_pro_text' => 'We believe that the free version of Invoice Ninja is a truly awesome product loaded with the key features you need to bill your clients electronically. But for those who crave still more Ninja awesomeness, we\'ve unmasked the Invoice Ninja Pro plan, which offers more versatility, power and customization options for just $50 per year.',
'number_clients' => 'Number of clients per account',
'unlimited_invoices' => 'Unlimited client invoices',
'company_logo' => 'Add your company logo',
'live_pdf' => 'Live .PDF invoice creation',
'four_templates' => '4 beautiful invoice templates',
'payments' => 'Accept credit card payments',
'additional_templates' => 'Additional invoice templates',
'multi_user' => 'Multi-user support',
'quotes' => 'Quotes/pro-forma invoices',
'advanced_settings' => 'Advanced invoice settings',
'data_vizualizations' => 'Dynamic data vizualizations',
'email_support' => 'Priority email support',
'remove_created_by' => 'Remove "Created by Invoice Ninja"',
'latest_features' => 'Latest and greatest features',
'pricing' => 'Pricing',
'free_always' => 'Free<span> /Always!</span>',
'year_price' => '$50<span> /Year</span>',
],
'compare' => [
'header' => '<span class="thin">How We</span> Compare',
'free_plan_comparison' => 'Free Plan Comparison',
'paid_plan_comparison' => 'Paid Plan Comparison',
'app' => 'App',
'cost' => 'Cost',
'clients' => 'Clients',
'invoices' => 'Invoices',
'payment_gateways' => 'Payment Gateways',
'custom_logo' => 'Custom Logo',
'multiple_templates' => 'Multiple Templates',
'recurring_payments' => 'Recurring Payments',
'open_source' => 'Open Source',
'per_month' => 'per month',
'per_year' => 'per year',
'free' => 'Free',
'unlimited' => 'Unlimited',
],
'testimonials' => [
'testimonials' => 'testimonials',
'header' => 'Since we launched Invoice Ninja in March of 2014, we\'ve been overwhelmed by a deluge of user love. Here\'s a small taste of the glowing things people have to say about the great experiences the\'ve been having with our free e-invoicing app!',
],
'faq' => [
'header' => '<span class="thin">The</span> FAQs',
'question1' => 'I know it isnt standard ninja practice to reveal too many identity details, but who are you guys exactly?',
'answer1' => 'Were a small team of highly skilled digital journeymen based in Israel. We love open source, we love disrupting the big business status quo, and we love building helpful tools that are easy to use. We believe that everyone elses web-based cash flow tools are unnecessarily expensive, clunky and complicated - and were bent on proving these beliefs with Invoice Ninja.',
'question2' => 'How do I get started using Invoice Ninja?',
'answer2' => 'Just click on the big, yellow "Invoice Now" button on our homepage!',
'question3' => 'Do you offer customer support?',
'answer3' => 'We sure do. Support is super important to us. Feel free to email us at <a href="mailto:support@invoiceninja.com">support@invoiceninja.com</a> with any questions you might have. We almost always reply within one business day.',
'question4' => 'Is Invoice Ninja really free? For how long?',
'answer4' => 'Yes, our basic app is 100% free. Forever and ever. For real. We also offer a paid Pro version of Invoice Ninja (you can learn all about its awesome features <a href="https://www.invoiceninja.com/plans">here</a>), but it\'s important to us that the free version have all of the key features people need to do business.',
'question5' => 'How is Invoice Ninja able to offer this all for free? How are you making any money?',
'answer5' => 'Were mostly in this line of work because we believe its high time that a good electronic invoicing tool be available for free. There isnt much money in it - yet. We do offer a paid <a href="https://www.invoiceninja.com/plans">Pro </a> version of the app that we\'ve souped up with premium features. And when our users open up new accounts with payment processor gateways by clicking on links from our site, we make modest commissions as a gateway affiliate. So if zillions of freelancers and small businesses start running credit card charges through Invoice Ninja, or if scores of users go <a href="https://www.invoiceninja.com/plans">Pro</a>, theres a decent chance we\'ll recover our investment.',
'question6' => 'Really? So does that mean youre not collecting information about me so you can sell me stuff or so that some other company can spam me according to my interests?',
'answer6' => 'No way. Were not mining your data, and were not selling you out. That wouldnt be very ninja of us, would it?',
'question7' => 'But dont you have access to my merchant and banking accounts?',
'answer7' => 'Actually, we dont. When you link an account at a third party financial institution with your Invoice Ninja account, youre essentially giving our app permission to send money to you and nothing more. This is all managed by the tech teams at your financial service providers, who go to great lengths to ensure their integrations cant be exploited or abused.',
'question8' => 'Given that Invoice Ninja is an open source app, how can I be sure that my financial information is safe with you?',
'answer8' => 'There\'s a big difference between “open source" and “open data.” Anyone who wants to use the code that drives Invoice Ninja to create their own products or to make improvements to ours can do so. Its available for anyone who wants to download and work with. But thats just the source code - totally separate from what happens with that code on the Invoice Ninja servers. Youre the only one who has full access to what you\'re doing with our product. For more details on the security of our servers and how we handle our users\' information, please read the next question.',
'question9' => 'So just how secure is this app?',
'answer9' => 'Extremely. Data uploaded by our users runs through connections with 256-bit encryption, which is twice as many encryption bits that most bank websites use. We use the TLS 1.0 cryptographic protocol, AES_256_CBC string encryption, SHA1 message authentication and DHE_RSA key exchanges. Its fancy stuff that we put in place to make sure no one can gain access to your information except you.',
'question10' => 'How do I remove the small "Created by Invoice Ninja” image from the bottom of my invoices?',
'answer10' => 'The amazingly affordable <a href="https://www.invoiceninja.com/plans">Pro</a> version of Invoice Ninja allows you to do this and oh so much more.',
'question11' => 'Can I see what the application looks like with sample data?',
'answer11' => 'Sure, <a href="https://www.invoiceninja.com/demo">click here</a> to try out our demo account.',
'question12' => 'I hear that there\'s a version of Invoice Ninja that I can install myself on my own servers? Where can I learn more about this?',
'answer12' => 'The rumors are true! Full instructions are available <a href="http://hillelcoren.com/invoice-ninja/self-hosting/" target="_blank">here</a>.',
'question13' => 'I\'m seeing the options to assign various statuses to my invoices, clients, credits and payments. What\'s the difference between "active," "archived" and "deleted"?',
'answer13' => 'These three handy statuses for invoices, clients, credits and payments allow you to keep your own cash flow management as straightforward and accessible as possible from your Invoice Ninja dashboard. None of these statuses will actually purge any records from your account - even "deleted" can always be recovered at any point in the future. "Active" means the record will appear in the relevant queue of records. To stash a record away so it\'s still fully operational but no longer cluttering up your interface, simply set it to be "archived." To deactivate a record and render it inaccessible to your clients, mark it "deleted."',
'question14' => 'My question wasn\'t covered by any of the content on this FAQ page. How can I get in touch with you?',
'answer14' => 'Please email us at <a href="mailto:contact@invoiceninja.com">contact@invoiceninja.com</a> with any questions or comments you have. We love hearing from the people who use our app! Well do our best to reply to your email within the business day.',
'miss_something' => 'Did we miss something?',
'miss_something_text' => 'Please email us at <a href="mailto:contact@invoiceninja.com" style="font-weight: bold">contact@invoiceninja.com</a> with any questions or comments you have. We love hearing from the people who use our app! Well do our best to reply to your email within the business day.',
],
];

View File

@ -120,7 +120,7 @@ return array(
'billed_clients' => 'fakturerede klienter',
'active_client' => 'aktiv klient',
'active_clients' => 'aktive klienter',
'invoices_past_due' => 'Forfaldte fakturaer',
'invoices_past_due' => 'Forfaldne fakturaer',
'upcoming_invoices' => 'Forestående fakturaer',
'average_invoice' => 'Gennemsnitlige fakturaer',
@ -140,9 +140,9 @@ return array(
'new_payment' => 'Ny betaling',
'new_credit' => 'Ny kredit',
'contact' => 'Kontakt',
'date_created' => 'Dato oprette',
'date_created' => 'Dato oprettet',
'last_login' => 'Sidst på-logging',
'balance' => 'Balanse',
'balance' => 'Balance',
'action' => 'Handling',
'status' => 'Status',
'invoice_total' => 'Faktura total',
@ -212,7 +212,7 @@ return array(
// application messages
'created_client' => 'Klient oprettet succesfuldt',
'created_clients' => 'Klienter oprettet succesfuldt',
'updated_settings' => 'Indstiller opdateret',
'updated_settings' => 'Indstillinger opdateret',
'removed_logo' => 'Logo fjernet',
'sent_message' => 'Melding sendt',
'invoice_error' => 'Venligst vælge en klient og rette eventuelle fejl',
@ -444,7 +444,7 @@ return array(
'share_invoice_counter' => 'Del faktura nummer tæller',
'invoice_issued_to' => 'Faktura udstedt til',
'invalid_counter' => 'For at undgå mulige overlap, sæt venligst et faktura eller tilbuds nummer præfiks',
'mark_sent' => 'Markering sendt',
'mark_sent' => 'Marker som sendt',
'gateway_help_1' => ':link to sign up for Authorize.net.',
'gateway_help_2' => ':link to sign up for Authorize.net.',
@ -499,5 +499,17 @@ return array(
'select_versiony' => 'Select version',
'view_history' => 'View History',
'edit_payment' => 'Edit Payment',
'updated_payment' => 'Successfully updated payment',
'deleted' => 'Deleted',
'restore_user' => 'Restore User',
'restored_user' => 'Successfully restored user',
'show_deleted_users' => 'Show deleted users',
'email_templates' => 'Email Templates',
'invoice_email' => 'Invoice Email',
'payment_email' => 'Payment Email',
'quote_email' => 'Quote Email',
'reset_all' => 'Reset All',
);

View File

@ -489,5 +489,17 @@ return array(
'select_versiony' => 'Version auswählen',
'view_history' => 'Historie anzeigen',
'edit_payment' => 'Edit Payment',
'updated_payment' => 'Successfully updated payment',
'deleted' => 'Deleted',
'restore_user' => 'Restore User',
'restored_user' => 'Successfully restored user',
'show_deleted_users' => 'Show deleted users',
'email_templates' => 'Email Templates',
'invoice_email' => 'Invoice Email',
'payment_email' => 'Payment Email',
'quote_email' => 'Quote Email',
'reset_all' => 'Reset All',
);

View File

@ -303,7 +303,7 @@ return array(
'email_taken' => 'The email address is already registered',
'working' => 'Working',
'success' => 'Success',
'success_message' => 'You have succesfully registered. Please visit the link in the account confirmation email to verify your email address.',
'success_message' => 'You have successfully registered. Please visit the link in the account confirmation email to verify your email address.',
'erase_data' => 'This will permanently erase your data.',
'password' => 'Password',
@ -497,4 +497,16 @@ return array(
'select_versiony' => 'Select version',
'view_history' => 'View History',
'edit_payment' => 'Edit Payment',
'updated_payment' => 'Successfully updated payment',
'deleted' => 'Deleted',
'restore_user' => 'Restore User',
'restored_user' => 'Successfully restored user',
'show_deleted_users' => 'Show deleted users',
'email_templates' => 'Email Templates',
'invoice_email' => 'Invoice Email',
'payment_email' => 'Payment Email',
'quote_email' => 'Quote Email',
'reset_all' => 'Reset All',
);

View File

@ -469,5 +469,17 @@ return array(
'select_versiony' => 'Select version',
'view_history' => 'View History',
'edit_payment' => 'Edit Payment',
'updated_payment' => 'Successfully updated payment',
'deleted' => 'Deleted',
'restore_user' => 'Restore User',
'restored_user' => 'Successfully restored user',
'show_deleted_users' => 'Show deleted users',
'email_templates' => 'Email Templates',
'invoice_email' => 'Invoice Email',
'payment_email' => 'Payment Email',
'quote_email' => 'Quote Email',
'reset_all' => 'Reset All',
);

View File

@ -490,5 +490,17 @@ return array(
'select_versiony' => 'Choix de la verison',
'view_history' => 'Consulter l\'historique',
'edit_payment' => 'Edit Payment',
'updated_payment' => 'Successfully updated payment',
'deleted' => 'Deleted',
'restore_user' => 'Restore User',
'restored_user' => 'Successfully restored user',
'show_deleted_users' => 'Show deleted users',
'email_templates' => 'Email Templates',
'invoice_email' => 'Invoice Email',
'payment_email' => 'Payment Email',
'quote_email' => 'Quote Email',
'reset_all' => 'Reset All',
);

View File

@ -492,5 +492,17 @@ return array(
'select_versiony' => 'Select version',
'view_history' => 'View History',
'edit_payment' => 'Edit Payment',
'updated_payment' => 'Successfully updated payment',
'deleted' => 'Deleted',
'restore_user' => 'Restore User',
'restored_user' => 'Successfully restored user',
'show_deleted_users' => 'Show deleted users',
'email_templates' => 'Email Templates',
'invoice_email' => 'Invoice Email',
'payment_email' => 'Payment Email',
'quote_email' => 'Quote Email',
'reset_all' => 'Reset All',
);

View File

@ -499,6 +499,18 @@ return array(
'current_version' => 'Current version',
'select_versiony' => 'Select version',
'view_history' => 'View History',
'edit_payment' => 'Edit Payment',
'updated_payment' => 'Successfully updated payment',
'deleted' => 'Deleted',
'restore_user' => 'Restore User',
'restored_user' => 'Successfully restored user',
'show_deleted_users' => 'Show deleted users',
'email_templates' => 'Email Templates',
'invoice_email' => 'Invoice Email',
'payment_email' => 'Payment Email',
'quote_email' => 'Quote Email',
'reset_all' => 'Reset All',
);

View File

@ -498,6 +498,18 @@ return array(
'select_versiony' => 'Select version',
'view_history' => 'View History',
'edit_payment' => 'Edit Payment',
'updated_payment' => 'Successfully updated payment',
'deleted' => 'Deleted',
'restore_user' => 'Restore User',
'restored_user' => 'Successfully restored user',
'show_deleted_users' => 'Show deleted users',
'email_templates' => 'Email Templates',
'invoice_email' => 'Invoice Email',
'payment_email' => 'Payment Email',
'quote_email' => 'Quote Email',
'reset_all' => 'Reset All',
);

View File

@ -493,6 +493,18 @@ return array(
'select_versiony' => 'Select version',
'view_history' => 'View History',
'edit_payment' => 'Edit Payment',
'updated_payment' => 'Successfully updated payment',
'deleted' => 'Deleted',
'restore_user' => 'Restore User',
'restored_user' => 'Successfully restored user',
'show_deleted_users' => 'Show deleted users',
'email_templates' => 'Email Templates',
'invoice_email' => 'Invoice Email',
'payment_email' => 'Payment Email',
'quote_email' => 'Quote Email',
'reset_all' => 'Reset All',
);

View File

@ -480,6 +480,18 @@ return array(
'select_versiony' => 'Select version',
'view_history' => 'View History',
'edit_payment' => 'Edit Payment',
'updated_payment' => 'Successfully updated payment',
'deleted' => 'Deleted',
'restore_user' => 'Restore User',
'restored_user' => 'Successfully restored user',
'show_deleted_users' => 'Show deleted users',
'email_templates' => 'Email Templates',
'invoice_email' => 'Invoice Email',
'payment_email' => 'Payment Email',
'quote_email' => 'Quote Email',
'reset_all' => 'Reset All',
);

View File

@ -302,4 +302,36 @@ class Account extends Eloquent
return $this;
}
public function getEmailTemplate($entityType, $message = false)
{
$field = "email_template_$entityType";
$template = $this->$field;
if ($template) {
return $template;
}
$template = "<p>\$client,</p>\r\n" .
"<p>" . trans("texts.{$entityType}_message", ['amount' => '$amount']) . "</p>\r\n";
if ($entityType != ENTITY_PAYMENT) {
$template .= "<p><a href=\"\$link\">\$link</a></p>\r\n";
}
if ($message) {
$template .= "<p>$message</p>\r\n";
}
return $template . "<p>\$footer</p>";
}
public function getEmailFooter()
{
if ($this->email_footer) {
return $this->email_footer;
} else {
return "<p>" . trans('texts.email_signature') . "<br>\$account</p>";
}
}
}

View File

@ -9,12 +9,12 @@ class Invitation extends EntityModel
public function contact()
{
return $this->belongsTo('Contact');
return $this->belongsTo('Contact')->withTrashed();
}
public function user()
{
return $this->belongsTo('User');
return $this->belongsTo('User')->withTrashed();
}
public function getLink()

View File

@ -17,6 +17,8 @@ class ContactMailer extends Mailer
$view = 'invoice';
$subject = trans("texts.{$entityType}_subject", ['invoice' => $invoice->invoice_number, 'account' => $invoice->account->getDisplayName()]);
$accountName = $invoice->account->getDisplayName();
$emailTemplate = $invoice->account->getEmailTemplate($entityType);
$invoiceAmount = Utils::formatMoney($invoice->amount, $invoice->client->currency_id);
foreach ($invoice->invitations as $invitation) {
if (!$invitation->user || !$invitation->user->email) {
@ -29,17 +31,17 @@ class ContactMailer extends Mailer
$invitation->sent_date = \Carbon::now()->toDateTimeString();
$invitation->save();
$data = [
'entityType' => $entityType,
'link' => $invitation->getLink(),
'clientName' => $invoice->client->getDisplayName(),
'accountName' => $accountName,
'contactName' => $invitation->contact->getDisplayName(),
'invoiceAmount' => Utils::formatMoney($invoice->amount, $invoice->client->currency_id),
'emailFooter' => $invoice->account->email_footer,
'showNinjaFooter' => !$invoice->account->isPro(),
$variables = [
'$footer' => $invoice->account->getEmailFooter(),
'$link' => $invitation->getLink(),
'$client' => $invoice->client->getDisplayName(),
'$account' => $accountName,
'$contact' => $invitation->contact->getDisplayName(),
'$amount' => $invoiceAmount
];
$data['body'] = str_replace(array_keys($variables), array_values($variables), $emailTemplate);
$fromEmail = $invitation->user->email;
$this->sendTo($invitation->contact->email, $fromEmail, $accountName, $subject, $view, $data);
@ -56,44 +58,45 @@ class ContactMailer extends Mailer
public function sendPaymentConfirmation(Payment $payment)
{
$invoice = $payment->invoice;
$view = 'payment_confirmation';
$subject = trans('texts.payment_subject', ['invoice' => $payment->invoice->invoice_number]);
$subject = trans('texts.payment_subject', ['invoice' => $invoice->invoice_number]);
$accountName = $payment->account->getDisplayName();
$emailTemplate = $invoice->account->getEmailTemplate(ENTITY_PAYMENT);
$data = [
'accountName' => $accountName,
'clientName' => $payment->client->getDisplayName(),
'emailFooter' => $payment->account->email_footer,
'paymentAmount' => Utils::formatMoney($payment->amount, $payment->client->currency_id),
'showNinjaFooter' => !$payment->account->isPro(),
$variables = [
'$footer' => $payment->account->getEmailFooter(),
'$client' => $payment->client->getDisplayName(),
'$account' => $accountName,
'$amount' => Utils::formatMoney($payment->amount, $payment->client->currency_id)
];
$data = ['body' => str_replace(array_keys($variables), array_values($variables), $emailTemplate)];
$user = $payment->invitation->user;
$this->sendTo($payment->contact->email, $user->email, $accountName, $subject, $view, $data);
}
public function sendLicensePaymentConfirmation($name, $email, $amount, $license, $productId)
{
$view = 'payment_confirmation';
$view = 'license_confirmation';
$subject = trans('texts.payment_subject');
if ($productId == PRODUCT_ONE_CLICK_INSTALL) {
$message = "Softaculous install license: $license";
$license = "Softaculous install license: $license";
} elseif ($productId == PRODUCT_INVOICE_DESIGNS) {
$message = "Invoice designs license: $license";
$license = "Invoice designs license: $license";
} elseif ($productId == PRODUCT_WHITE_LABEL) {
$message = "White label license: $license";
$license = "White label license: $license";
}
$data = [
'accountName' => trans('texts.email_from'),
'clientName' => $name,
'emailFooter' => false,
'paymentAmount' => Utils::formatMoney($amount, 1),
'showNinjaFooter' => false,
'emailMessage' => $message,
'account' => trans('texts.email_from'),
'client' => $name,
'amount' => Utils::formatMoney($amount, 1),
'license' => $license
];
$this->sendTo($email, CONTACT_EMAIL, CONTACT_NAME, $subject, $view, $data);
}
}

View File

@ -162,6 +162,8 @@ class InvoiceRepository
} elseif ($entityType == ENTITY_QUOTE) {
if ($model->quote_invoice_id) {
$str .= '<li><a href="'.\URL::to("invoices/{$model->quote_invoice_id}/edit").'">'.trans("texts.view_invoice").'</a></li>';
} else {
$str .= '<li><a href="javascript:convertEntity('.$model->public_id.')">'.trans("texts.convert_to_invoice").'</a></li>';
}
}

View File

@ -18,6 +18,7 @@ class PaymentRepository
->where('payments.account_id', '=', \Auth::user()->account_id)
->where('clients.deleted_at', '=', null)
->where('contacts.is_primary', '=', true)
->where('contacts.deleted_at', '=', null)
->select('payments.public_id', 'payments.transaction_reference', 'clients.name as client_name', 'clients.public_id as client_public_id', 'payments.amount', 'payments.payment_date', 'invoices.public_id as invoice_public_id', 'invoices.invoice_number', 'clients.currency_id', 'contacts.first_name', 'contacts.last_name', 'contacts.email', 'payment_types.name as payment_type', 'payments.account_gateway_id', 'payments.deleted_at', 'payments.is_deleted');
if (!\Session::get('show_trash:payment')) {
@ -68,7 +69,7 @@ class PaymentRepository
$rules = array(
'client' => 'required',
'invoice' => 'required',
'amount' => 'required|positive',
'amount' => 'required',
);
if ($input['payment_type_id'] == PAYMENT_TYPE_CREDIT) {
@ -93,29 +94,33 @@ class PaymentRepository
}
$paymentTypeId = $input['payment_type_id'] ? $input['payment_type_id'] : null;
$clientId = Client::getPrivateId($input['client']);
$amount = Utils::parseFloat($input['amount']);
if ($paymentTypeId == PAYMENT_TYPE_CREDIT) {
$credits = Credit::scope()->where('client_id', '=', $clientId)
->where('balance', '>', 0)->orderBy('created_at')->get();
$applied = 0;
foreach ($credits as $credit) {
$applied += $credit->apply($amount);
if ($applied >= $amount) {
break;
}
}
}
$payment->client_id = $clientId;
$payment->invoice_id = isset($input['invoice']) && $input['invoice'] != "-1" ? Invoice::getPrivateId($input['invoice']) : null;
$payment->payment_type_id = $paymentTypeId;
$payment->payment_date = Utils::toSqlDate($input['payment_date']);
$payment->amount = $amount;
$payment->transaction_reference = trim($input['transaction_reference']);
if (!$publicId) {
$clientId = Client::getPrivateId($input['client']);
$amount = Utils::parseFloat($input['amount']);
if ($paymentTypeId == PAYMENT_TYPE_CREDIT) {
$credits = Credit::scope()->where('client_id', '=', $clientId)
->where('balance', '>', 0)->orderBy('created_at')->get();
$applied = 0;
foreach ($credits as $credit) {
$applied += $credit->apply($amount);
if ($applied >= $amount) {
break;
}
}
}
$payment->client_id = $clientId;
$payment->invoice_id = isset($input['invoice']) && $input['invoice'] != "-1" ? Invoice::getPrivateId($input['invoice']) : null;
$payment->amount = $amount;
}
$payment->save();
return $payment;

View File

@ -88,6 +88,8 @@ Route::group(array('before' => 'auth'), function() {
Route::get('api/users', array('as'=>'api.users', 'uses'=>'UserController@getDatatable'));
Route::resource('users', 'UserController');
Route::post('users/delete', 'UserController@delete');
Route::get('send_confirmation/{user_id}', 'UserController@sendConfirmation');
Route::get('restore_user/{user_id}', 'UserController@restoreUser');
Route::get('api/products', array('as'=>'api.products', 'uses'=>'ProductController@getDatatable'));
Route::resource('products', 'ProductController');
@ -132,9 +134,6 @@ Route::group(array('before' => 'auth'), function() {
Route::get('api/quotes/{client_id?}', array('as'=>'api.quotes', 'uses'=>'QuoteController@getDatatable'));
Route::post('quotes/bulk', 'QuoteController@bulk');
Route::get('payments/{id}/edit', function() {
return View::make('header');
});
Route::resource('payments', 'PaymentController');
Route::get('payments/create/{client_id?}/{invoice_id?}', 'PaymentController@create');
Route::get('api/payments/{client_id?}', array('as'=>'api.payments', 'uses'=>'PaymentController@getDatatable'));
@ -194,6 +193,7 @@ define('ACCOUNT_INVOICE_DESIGN', 'invoice_design');
define('ACCOUNT_CHART_BUILDER', 'chart_builder');
define('ACCOUNT_USER_MANAGEMENT', 'user_management');
define('ACCOUNT_DATA_VISUALIZATIONS', 'data_visualizations');
define('ACCOUNT_EMAIL_TEMPLATES', 'email_templates');
define("ACTIVITY_TYPE_CREATE_CLIENT", 1);
define("ACTIVITY_TYPE_ARCHIVE_CLIENT", 2);

View File

@ -0,0 +1,109 @@
@extends('accounts.nav')
@section('head')
@parent
<style type="text/css">
textarea {
min-height: 100px !important;
}
</style>
@stop
@section('content')
@parent
@include('accounts.nav_advanced')
{{ Former::open()->addClass('col-md-8 col-md-offset-2 warn-on-exit') }}
{{ Former::populateField('email_template_invoice', $invoiceEmail) }}
{{ Former::populateField('email_template_quote', $quoteEmail) }}
{{ Former::populateField('email_template_payment', $paymentEmail) }}
{{ Former::legend('invoice_email') }}
<div class="row">
<div class="col-md-7">
{{ Former::textarea('email_template_invoice')->raw() }}
</div>
<div class="col-md-5" id="invoice_preview"></div>
</div>
<p>&nbsp;</p>
{{ Former::legend('quote_email') }}
<div class="row">
<div class="col-md-7">
{{ Former::textarea('email_template_quote')->raw() }}
</div>
<div class="col-md-5" id="quote_preview"></div>
</div>
<p>&nbsp;</p>
{{ Former::legend('payment_email') }}
<div class="row">
<div class="col-md-7">
{{ Former::textarea('email_template_payment')->raw() }}
</div>
<div class="col-md-5" id="payment_preview"></div>
</div>
<p>&nbsp;</p>
@if (Auth::user()->isPro())
{{ Former::actions(
Button::lg_success_submit(trans('texts.save'))->append_with_icon('floppy-disk')
) }}
@else
<script>
$(function() {
$('form.warn-on-exit input').prop('disabled', true);
});
</script>
@endif
{{ Former::close() }}
<script type="text/javascript">
$(function() {
$('#email_template_invoice').keyup(refreshInvoice);
$('#email_template_quote').keyup(refreshQuote);
$('#email_template_payment').keyup(refreshPayment);
refreshInvoice();
refreshQuote();
refreshPayment();
});
function refreshInvoice() {
$('#invoice_preview').html(processVariables($('#email_template_invoice').val()));
}
function refreshQuote() {
$('#quote_preview').html(processVariables($('#email_template_quote').val()));
}
function refreshPayment() {
$('#payment_preview').html(processVariables($('#email_template_payment').val()));
}
function processVariables(str) {
if (!str) {
return '';
}
keys = ['footer', 'account', 'client', 'amount', 'link'];
vals = [{{ json_encode($emailFooter) }}, '{{ Auth::user()->account->getDisplayName() }}', 'Client Name', formatMoney(100), '{{ NINJA_WEB_URL }}']
for (var i=0; i<keys.length; i++) {
var regExp = new RegExp('\\$'+keys[i], 'g');
str = str.replace(regExp, vals[i]);
}
return str;
}
</script>
@stop

View File

@ -1,6 +1,7 @@
<ul class="nav nav-tabs nav nav-justified">
{{ HTML::nav_link('company/advanced_settings/invoice_settings', 'invoice_settings') }}
{{ HTML::nav_link('company/advanced_settings/invoice_design', 'invoice_design') }}
{{ HTML::nav_link('company/advanced_settings/email_templates', 'email_templates') }}
{{ HTML::nav_link('company/advanced_settings/data_visualizations', 'data_visualizations') }}
{{ HTML::nav_link('company/advanced_settings/chart_builder', 'chart_builder') }}
{{ HTML::nav_link('company/advanced_settings/user_management', 'user_management') }}

View File

@ -1,5 +1,26 @@
@extends('accounts.nav')
@section('head')
@parent
<style type="text/css">
/* bootstrap 3.2.0 fix */
/* https://github.com/twbs/bootstrap/issues/13984 */
.radio input[type="radio"],
.checkbox input[type="checkbox"] {
margin-left: 0;
margin-right: 5px;
height: inherit;
width: inherit;
float: left;
display: inline-block;
position: relative;
margin-top: 3px;
}
</style>
@stop
@section('content')
@parent

View File

@ -1,12 +1,14 @@
@extends('accounts.nav')
@section('content')
@section('content')
@parent
@include('accounts.nav_advanced')
{{ Former::open('users/delete')->addClass('user-form') }}
{{ Former::legend('user_management') }}
<div style="display:none">
{{ Former::text('userPublicId') }}
</div>
@ -14,34 +16,46 @@
@if (Utils::isPro())
{{ Button::success_link(URL::to('users/create'), trans("texts.add_user"), array('class' => 'pull-right'))->append_with_icon('plus-sign') }}
{{ Button::success_link(URL::to('users/create'), trans("texts.add_user"), array('class' => 'pull-right'))->append_with_icon('plus-sign') }}
@endif
{{ Datatable::table()
<label for="trashed" style="font-weight:normal; margin-left: 10px;">
<input id="trashed" type="checkbox" onclick="setTrashVisible()"
{{ Session::get('show_trash:user') ? 'checked' : ''}}/> {{ trans('texts.show_deleted_users')}}
</label>
{{ Datatable::table()
->addColumn(
trans('texts.name'),
trans('texts.email'),
trans('texts.user_state'),
trans('texts.action'))
->setUrl(url('api/users/'))
->setUrl(url('api/users/'))
->setOptions('sPaginationType', 'bootstrap')
->setOptions('bFilter', false)
->setOptions('bAutoWidth', false)
->setOptions('aoColumns', [[ "sWidth"=> "20%" ], [ "sWidth"=> "45%" ], ["sWidth"=> "20%"], ["sWidth"=> "15%" ]])
->setOptions('bFilter', false)
->setOptions('bAutoWidth', false)
->setOptions('aoColumns', [[ "sWidth"=> "20%" ], [ "sWidth"=> "45%" ], ["sWidth"=> "20%"], ["sWidth"=> "15%" ]])
->setOptions('aoColumnDefs', [['bSortable'=>false, 'aTargets'=>[3]]])
->render('datatable') }}
<script>
window.onDatatableReady = function() {
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');
}
}
});
}
}
function setTrashVisible() {
var checked = $('#trashed').is(':checked');
window.location = '{{ URL::to('view_archive/user') }}' + (checked ? '/true' : '/false');
}
function deleteUser(id) {
if (!confirm('Are you sure?')) {
@ -49,8 +63,8 @@
}
$('#userPublicId').val(id);
$('form.user-form').submit();
}
</script>
$('form.user-form').submit();
}
</script>
@stop

View File

@ -3,24 +3,5 @@
<head>
<meta charset="utf-8">
</head>
<body>
{{ $clientName }},<p/>
{{ trans("texts.{$entityType}_message", ['amount' => $invoiceAmount]) }}<p/>
<a href="{{ $link }}">{{ $link }}</a><p/>
@if ($emailFooter)
{{ nl2br($emailFooter) }}
@else
{{ trans('texts.email_signature') }}<br/>
{{ $accountName }}
@endif
@if ($showNinjaFooter)
<p/>
{{ trans('texts.ninja_email_footer', ['site' => '<a href="' . NINJA_WEB_URL . '/?utm_source=invoice_email_footer">Invoice Ninja</a>']) }}
@endif
</body>
<body>{{ $body }}</body>
</html>

View File

@ -1,16 +1 @@
{{ $clientName }},
{{ trans("texts.{$entityType}_message", ['amount' => $invoiceAmount]) }}
{{ $link }}
@if ($emailFooter)
{{ $emailFooter }}
@else
{{ trans('texts.email_signature') }}
{{ $accountName }}
@endif
@if ($showNinjaFooter)
{{ trans('texts.ninja_email_footer', ['site' => 'Invoice Ninja']) }}
{{ NINJA_WEB_URL }}
@endif
{{ strip_tags($body) }}

View File

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
{{ $client }},<p/>
{{ trans('texts.payment_message', ['amount' => $amount]) }}<p/>
{{ $license }}<p/>
{{ trans('texts.email_signature') }}<br/>
{{ $account }}
</body>
</html>

View File

@ -0,0 +1,8 @@
{{ $client }},
{{ trans('texts.payment_message', ['amount' => $amount]) }}
{{ $license }}
{{ trans('texts.email_signature') }}
{{ $account }}

View File

@ -3,27 +3,5 @@
<head>
<meta charset="utf-8">
</head>
<body>
{{ $clientName }},<p/>
{{ trans('texts.payment_message', ['amount' => $paymentAmount]) }}<p/>
@if (isset($emailMessage) && $emailMessage)
{{ $emailMessage }}<p/>
@endif
@if ($emailFooter)
{{ nl2br($emailFooter) }}
@else
{{ trans('texts.email_signature') }}<br/>
{{ $accountName }}
@endif
@if ($showNinjaFooter)
<p/>
{{ trans('texts.ninja_email_footer', ['site' => '<a href="' . NINJA_WEB_URL . '/?utm_source=payment_email_footer">Invoice Ninja</a>']) }}
@endif
</body>
<body>{{ $body }}</body>
</html>

View File

@ -1,19 +1 @@
{{ $clientName }},
{{ trans('texts.payment_message', ['amount' => $paymentAmount]) }}
@if (isset($emailMessage) && $emailMessage)
{{ $emailMessage }}
@endif
@if ($emailFooter)
{{ $emailFooter }}
@else
{{ trans('texts.email_signature') }}
{{ $accountName }}
@endif
@if ($showNinjaFooter)
{{ trans('texts.ninja_email_footer', ['site' => 'Invoice Ninja']) }}
{{ NINJA_WEB_URL }}
@endif
{{ strip_tags($body) }}

View File

@ -83,7 +83,7 @@
<div class="btn-group">
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown">
<div id="myAccountButton" class="ellipsis" style="max-width:120px">
<div id="myAccountButton" class="ellipsis" style="max-width:100px">
{{ Auth::user()->getDisplayName() }}
<span class="caret"></span>
</div>

View File

@ -289,9 +289,13 @@
<li><a href="javascript:onSaveClick()" id="saveButton">{{ trans("texts.save_{$entityType}") }}</a></li>
<li><a href="javascript:onCloneClick()">{{ trans("texts.clone_{$entityType}") }}</a></li>
<li><a href="{{ URL::to("{$entityType}s/{$entityType}_history/{$invoice->public_id}") }}">{{ trans("texts.view_history") }}</a></li>
<li class="divider"></li>
@if ($invoice->invoice_status_id < INVOICE_STATUS_SENT)
<li><a href="javascript:onMarkClick()">{{ trans("texts.mark_sent") }}</a></li>
@endif
@if ($invoice && $entityType == ENTITY_QUOTE)
<li class="divider"></li>
@if ($invoice->quote_invoice_id)
<li><a href="{{ URL::to("invoices/{$invoice->quote_invoice_id}/edit") }}">{{ trans("texts.view_invoice") }}</a></li>
@else
@ -299,16 +303,10 @@
@endif
@elseif ($invoice && $entityType == ENTITY_INVOICE)
@if ($invoice->quote_id)
<li class="divider"></li>
<li><a href="{{ URL::to("quotes/{$invoice->quote_id}/edit") }}">{{ trans("texts.view_quote") }}</a></li>
@endif
@endif
@if ($invoice->invoice_status_id < INVOICE_STATUS_SENT)
<li class="divider"></li>
<li><a href="javascript:onMarkClick()">{{ trans("texts.mark_sent") }}</a></li>
@endif
<li class="divider"></li>
<li><a href="javascript:onArchiveClick()">{{ trans("texts.archive_{$entityType}") }}</a></li>
<li><a href="javascript:onDeleteClick()">{{ trans("texts.delete_{$entityType}") }}</a></li>
@ -1348,7 +1346,7 @@
@if (Utils::isConfirmed())
if (self.invitation_link()) {
str += '<br/><a href="' + self.invitation_link() + '" target="_blank" style="padding-left:20px">{{ trans('texts.view_as_recipient') }}</a>';
str += '<br/><a href="' + self.invitation_link() + '" target="_blank">{{ trans('texts.view_as_recipient') }}</a>';
}
@endif

View File

@ -68,10 +68,14 @@
submitForm('archive');
}
function restoreEntity(id) {
$('#id').val(id);
submitForm('restore');
}
function restoreEntity(id) {
$('#id').val(id);
submitForm('restore');
}
function convertEntity(id) {
$('#id').val(id);
submitForm('convert');
}
function markEntity(id, statusId) {
$('#id').val(id);

View File

@ -30,11 +30,12 @@
NINJA.isRegistered = {{ Utils::isRegistered() ? 'true' : 'false' }};
window.onerror = function(e) {
var message = e.message ? (e.message + ' - ' + e.filename + ': ' + e.lineno) : e;
try {
$.ajax({
type: 'GET',
url: '{{ URL::to('log_error') }}',
data: 'error='+encodeURIComponent(e.message + ' - ' + e.filename + ': ' + e.lineno)+'&url='+encodeURIComponent(window.location)
data: 'error='+encodeURIComponent(message)+'&url='+encodeURIComponent(window.location)
});
} catch(err) {}
return false;

View File

@ -13,13 +13,20 @@
'invoice' => 'required',
'amount' => 'required',
)); }}
@if ($payment)
{{ Former::populate($payment) }}
@endif
<div class="row">
<div class="col-md-8">
{{ Former::select('client')->addOption('', '')->addGroupClass('client-select') }}
{{ Former::select('invoice')->addOption('', '')->addGroupClass('invoice-select') }}
{{ Former::text('amount') }}
@if (!$payment)
{{ Former::select('client')->addOption('', '')->addGroupClass('client-select') }}
{{ Former::select('invoice')->addOption('', '')->addGroupClass('invoice-select') }}
{{ Former::text('amount') }}
@endif
{{ Former::select('payment_type_id')->addOption('','')
->fromQuery($paymentTypes, 'name', 'id') }}
{{ Former::text('payment_date')->data_date_format(Session::get(SESSION_DATE_PICKER_FORMAT))->append('<i class="glyphicon glyphicon-calendar"></i>') }}
@ -35,7 +42,7 @@
<center class="buttons">
{{ Button::lg_primary_submit_success(trans('texts.save'))->append_with_icon('floppy-disk') }}
{{ Button::lg_default_link('payments/' . ($payment ? $payment->public_id : ''), trans('texts.cancel'))->append_with_icon('remove-circle'); }}
{{ Button::lg_default_link('payments/', trans('texts.cancel'))->append_with_icon('remove-circle'); }}
</center>
{{ Former::close() }}
@ -47,10 +54,14 @@
$(function() {
populateInvoiceComboboxes({{ $clientPublicId }}, {{ $invoicePublicId }});
@if ($payment)
$('#payment_date').datepicker('update', '{{ $payment->payment_date }}')
@else
$('#payment_date').datepicker('update', new Date());
populateInvoiceComboboxes({{ $clientPublicId }}, {{ $invoicePublicId }});
@endif
$('#payment_type_id').combobox();
$('#payment_date').datepicker('update', new Date());
$('#payment_type_id').combobox();
});

View File

@ -1,4 +1,4 @@
<?php
return 'development';
return 'production';

View File

@ -2880,20 +2880,6 @@ box-shadow: 0px 0px 15px 0px rgba(0, 5, 5, 0.2);
.plans-table .pro {margin-top: 40px;}
}
/* bootstrap 3.2.0 fix */
/* https://github.com/twbs/bootstrap/issues/13984 */
.radio input[type="radio"],
.checkbox input[type="checkbox"] {
margin-left: 0;
margin-right: 5px;
height: inherit;
width: inherit;
float: left;
display: inline-block;
position: relative;
margin-top: 3px;
}
label[for=recommendedGateway_id2].radio{
min-height: 60px;
}

View File

@ -32343,7 +32343,7 @@ function displayGrid(doc, invoice, data, x, y, layout, options) {
doc.text(marginLeft, y, value);
doc.setFontType('normal');
if (parseInt(invoice.is_quote)) {
if (invoice.is_quote) {
if (key == 'invoice_number') {
key = 'quote_number';
} else if (key == 'invoice_date') {

View File

@ -772,20 +772,6 @@ box-shadow: 0px 0px 15px 0px rgba(0, 5, 5, 0.2);
.plans-table .pro {margin-top: 40px;}
}
/* bootstrap 3.2.0 fix */
/* https://github.com/twbs/bootstrap/issues/13984 */
.radio input[type="radio"],
.checkbox input[type="checkbox"] {
margin-left: 0;
margin-right: 5px;
height: inherit;
width: inherit;
float: left;
display: inline-block;
position: relative;
margin-top: 3px;
}
label[for=recommendedGateway_id2].radio{
min-height: 60px;
}

View File

@ -820,7 +820,7 @@ function displayGrid(doc, invoice, data, x, y, layout, options) {
doc.text(marginLeft, y, value);
doc.setFontType('normal');
if (parseInt(invoice.is_quote)) {
if (invoice.is_quote) {
if (key == 'invoice_number') {
key = 'quote_number';
} else if (key == 'invoice_date') {