diff --git a/Gruntfile.js b/Gruntfile.js index 8138daefb2..29183b40ec 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -39,6 +39,16 @@ module.exports = function(grunt) { dest: 'public/built.js', nonull: true }, + js_public: { + src: [ + 'public/js/simpleexpand.js', + 'public/js/valign.js', + 'public/js/bootstrap.min.js', + 'public/js/simpleexpand.js', + ], + dest: 'public/js/built.public.js', + nonull: true + }, css: { src: [ 'public/vendor/bootstrap/dist/css/bootstrap.min.css', diff --git a/app/controllers/AccountController.php b/app/controllers/AccountController.php index f6d9ee245c..91c39b60c4 100755 --- a/app/controllers/AccountController.php +++ b/app/controllers/AccountController.php @@ -36,20 +36,9 @@ class AccountController extends \BaseController { public function update() { if (!Utils::isNinja()) { - // populate migrations if the application was initially setup using database.sql - $migrations = DB::table('migrations')->get(); - if (Schema::hasTable('accounts') && count($migrations) == 0) { - $migrations = ['2013_11_05_180133_confide_setup_users_table', '2013_11_28_195703_setup_countries_table', '2014_02_13_151500_add_cascase_drops', '2014_02_19_151817_add_support_for_invoice_designs', '2014_03_03_155556_add_phone_to_account', '2014_03_19_201454_add_language_support', '2014_03_20_200300_create_payment_libraries', '2014_03_23_051736_enable_forcing_jspdf', '2014_03_25_102200_add_sort_and_recommended_to_gateways', '2014_04_03_191105_add_pro_plan', '2014_04_17_100523_add_remember_token', '2014_04_17_145108_add_custom_fields', '2014_04_23_170909_add_products_settings', '2014_04_29_174315_add_advanced_settings', '2014_05_17_175626_add_quotes', '2014_06_17_131940_add_accepted_credit_cards_to_account_gateways', '2014_07_13_142654_one_click_install', '2014_07_17_205900_support_hiding_quantity', '2014_07_24_171214_add_zapier_support']; - foreach ($migrations as $migration) { - DB::table('migrations')->insert([ - 'migration' => $migration, - 'batch' => 1 - ]); - } - } - try { - Artisan::call('migrate'); + Artisan::call('migrate'); + Cache::flush(); } catch (Exception $e) { Response::make($e->getMessage(), 500); } @@ -262,6 +251,31 @@ class AccountController extends \BaseController { 'feature' => $subSection ]; + if ($subSection == ACCOUNT_INVOICE_DESIGN) + { + $invoice = new stdClass(); + $client = new stdClass(); + $invoiceItem = new stdClass(); + + $client->name = 'Sample Client'; + + $invoice->invoice_number = Auth::user()->account->getNextInvoiceNumber(); + $invoice->invoice_date = date_create()->format('Y-m-d'); + $invoice->account = Auth::user()->account; + $invoice->amount = $invoice->balance = 100; + + $invoiceItem->cost = 100; + $invoiceItem->qty = 1; + $invoiceItem->notes = 'Notes'; + $invoiceItem->product_key = 'Item'; + + $invoice->client = $client; + $invoice->invoice_items = [$invoiceItem]; + + $data['invoice'] = $invoice; + $data['invoiceDesigns'] = InvoiceDesign::remember(DEFAULT_QUERY_CACHE)->orderBy('id')->get(); + } + return View::make("accounts.{$subSection}", $data); } else if ($section == ACCOUNT_PRODUCTS) @@ -302,9 +316,9 @@ class AccountController extends \BaseController { } else if ($section == ACCOUNT_ADVANCED_SETTINGS) { - if ($subSection == ACCOUNT_CUSTOM_FIELDS) + if ($subSection == ACCOUNT_INVOICE_SETTINGS) { - return AccountController::saveCustomFields(); + return AccountController::saveInvoiceSettings(); } else if ($subSection == ACCOUNT_INVOICE_DESIGN) { @@ -329,11 +343,12 @@ class AccountController extends \BaseController { return Redirect::to('company/products'); } - private function saveCustomFields() + private function saveInvoiceSettings() { if (Auth::user()->account->isPro()) { $account = Auth::user()->account; + $account->custom_label1 = trim(Input::get('custom_label1')); $account->custom_value1 = trim(Input::get('custom_value1')); $account->custom_label2 = trim(Input::get('custom_label2')); @@ -344,12 +359,26 @@ class AccountController extends \BaseController { $account->custom_invoice_label2 = trim(Input::get('custom_invoice_label2')); $account->custom_invoice_taxes1 = Input::get('custom_invoice_taxes1') ? true : false; $account->custom_invoice_taxes2 = Input::get('custom_invoice_taxes2') ? true : false; - $account->save(); - Session::flash('message', trans('texts.updated_settings')); + $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; + + if (!$account->share_counter) { + $account->quote_number_counter = Input::get('quote_number_counter'); + } + + 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(); + } else { + $account->save(); + Session::flash('message', trans('texts.updated_settings')); + } } - return Redirect::to('company/advanced_settings/custom_fields'); + return Redirect::to('company/advanced_settings/invoice_settings'); } private function saveInvoiceDesign() @@ -359,8 +388,9 @@ class AccountController extends \BaseController { $account = Auth::user()->account; $account->hide_quantity = Input::get('hide_quantity') ? true : false; $account->hide_paid_to_date = Input::get('hide_paid_to_date') ? true : false; - $account->primary_color = Input::get('primary_color');// ? Input::get('primary_color') : null; - $account->secondary_color = Input::get('secondary_color');// ? Input::get('secondary_color') : null; + $account->primary_color = Input::get('primary_color'); + $account->secondary_color = Input::get('secondary_color'); + $account->invoice_design_id = Input::get('invoice_design_id'); $account->save(); Session::flash('message', trans('texts.updated_settings')); diff --git a/app/controllers/HomeController.php b/app/controllers/HomeController.php index b9415d58bf..8389a36980 100755 --- a/app/controllers/HomeController.php +++ b/app/controllers/HomeController.php @@ -128,6 +128,29 @@ class HomeController extends BaseController { } } + public function newsFeed($userType, $version) + { + $response = Utils::getNewsFeedResponse($userType); + + return Response::json($response); + } + + public function hideMessage() + { + if (Auth::check() && Session::has('news_feed_id')) { + $newsFeedId = Session::get('news_feed_id'); + if ($newsFeedId != NEW_VERSION_AVAILABLE && $newsFeedId > Auth::user()->news_feed_id) { + $user = Auth::user(); + $user->news_feed_id = $newsFeedId; + $user->save(); + } + + Session::forget('news_feed_message'); + } + + return 'success'; + } + public function logError() { return Utils::logError(Input::get('error'), 'JavaScript'); diff --git a/app/controllers/InvoiceController.php b/app/controllers/InvoiceController.php index 019dc223a4..585a774f6e 100755 --- a/app/controllers/InvoiceController.php +++ b/app/controllers/InvoiceController.php @@ -104,7 +104,7 @@ class InvoiceController extends \BaseController { } } - $invoice->load('user', 'invoice_items', 'account.country', 'client.contacts', 'client.country'); + $invoice->load('user', 'invoice_items', 'invoice_design', 'account.country', 'client.contacts', 'client.country'); $client = $invoice->client; @@ -151,7 +151,7 @@ class InvoiceController extends \BaseController { if ($clone) { $invoice->id = null; - $invoice->invoice_number = Auth::user()->account->getNextInvoiceNumber(); + $invoice->invoice_number = Auth::user()->account->getNextInvoiceNumber($invoice->is_quote); $invoice->balance = $invoice->amount; $method = 'POST'; $url = "{$entityType}s"; @@ -244,7 +244,6 @@ class InvoiceController extends \BaseController { 'paymentTerms' => PaymentTerm::remember(DEFAULT_QUERY_CACHE)->orderBy('num_days')->get(['name', 'num_days']), 'industries' => Industry::remember(DEFAULT_QUERY_CACHE)->orderBy('name')->get(), 'invoiceDesigns' => InvoiceDesign::remember(DEFAULT_QUERY_CACHE)->orderBy('id')->get(), - 'invoiceLabels' => Auth::user()->account->getInvoiceLabels(), 'frequencies' => array( 1 => 'Weekly', 2 => 'Two weeks', @@ -272,7 +271,7 @@ class InvoiceController extends \BaseController { $action = Input::get('action'); $entityType = Input::get('entityType'); - if ($action == 'archive' || $action == 'delete') + if ($action == 'archive' || $action == 'delete' || $action == 'mark') { return InvoiceController::bulk($entityType); } @@ -414,12 +413,14 @@ class InvoiceController extends \BaseController { public function bulk($entityType = ENTITY_INVOICE) { $action = Input::get('action'); + $statusId = Input::get('statusId'); $ids = Input::get('id') ? Input::get('id') : Input::get('ids'); - $count = $this->invoiceRepo->bulk($ids, $action); + $count = $this->invoiceRepo->bulk($ids, $action, $statusId); if ($count > 0) { - $message = Utils::pluralize("{$action}d_{$entityType}", $count); + $key = $action == 'mark' ? "updated_{$entityType}" : "{$action}d_{$entityType}"; + $message = Utils::pluralize($key, $count); Session::flash('message', $message); } diff --git a/app/controllers/QuoteController.php b/app/controllers/QuoteController.php index 3dee961af8..683cc0bf00 100644 --- a/app/controllers/QuoteController.php +++ b/app/controllers/QuoteController.php @@ -60,7 +60,7 @@ class QuoteController extends \BaseController { } $client = null; - $invoiceNumber = Auth::user()->account->getNextInvoiceNumber(); + $invoiceNumber = Auth::user()->account->getNextInvoiceNumber(true); $account = Account::with('country')->findOrFail(Auth::user()->account_id); if ($clientPublicId) diff --git a/app/controllers/UserController.php b/app/controllers/UserController.php index a62c30e5de..bfe710c12a 100755 --- a/app/controllers/UserController.php +++ b/app/controllers/UserController.php @@ -463,6 +463,9 @@ class UserController extends BaseController { } } + Session::forget('news_feed_id'); + Session::forget('news_feed_message'); + Confide::logout(); return Redirect::to('/')->with('clearGuestKey', true); diff --git a/app/database/migrations/2014_10_05_141856_track_last_seen_message.php b/app/database/migrations/2014_10_05_141856_track_last_seen_message.php new file mode 100644 index 0000000000..7446782a6a --- /dev/null +++ b/app/database/migrations/2014_10_05_141856_track_last_seen_message.php @@ -0,0 +1,46 @@ +unsignedInteger('news_feed_id')->nullable(); + }); + + if (DB::table('payment_libraries')->count() > 0) { + DB::table('gateways')->update(['recommended' => 0]); + DB::table('gateways')->insert([ + 'name' => 'moolah', + 'provider' => 'AuthorizeNet_AIM', + 'sort_order' => 1, + 'recommended' => 1, + 'site_url' => 'https://invoiceninja.mymoolah.com/', + 'payment_library_id' => 1 + ]); + } + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('users', function($table) + { + $table->dropColumn('news_feed_id'); + }); + } + +} diff --git a/app/database/migrations/2014_10_06_195330_add_invoice_design_table.php b/app/database/migrations/2014_10_06_195330_add_invoice_design_table.php new file mode 100644 index 0000000000..d97a063649 --- /dev/null +++ b/app/database/migrations/2014_10_06_195330_add_invoice_design_table.php @@ -0,0 +1,515 @@ +text('javascript')->nullable(); + }); + + Schema::table('accounts', function($table) + { + $table->text('invoice_design')->nullable(); + }); + + DB::table('invoice_designs')->where('id', 1)->update([ + 'javascript' => "var GlobalY=0;//Y position of line at current page + + var client = invoice.client; + var account = invoice.account; + var currencyId = client.currency_id; + + layout.headerRight = 550; + layout.rowHeight = 15; + + doc.setFontSize(9); + + if (invoice.image) + { + var left = layout.headerRight - invoice.imageWidth; + doc.addImage(invoice.image, 'JPEG', layout.marginLeft, 30); + } + + if (!invoice.is_pro && logoImages.imageLogo1) + { + pageHeight=820; + y=pageHeight-logoImages.imageLogoHeight1; + doc.addImage(logoImages.imageLogo1, 'JPEG', layout.marginLeft, y, logoImages.imageLogoWidth1, logoImages.imageLogoHeight1); + } + + doc.setFontSize(9); + SetPdfColor('LightBlue', doc, 'primary'); + displayAccount(doc, invoice, 220, layout.accountTop, layout); + + SetPdfColor('LightBlue', doc, 'primary'); + doc.setFontSize('11'); + doc.text(50, layout.headerTop, (invoice.is_quote ? invoiceLabels.quote : invoiceLabels.invoice).toUpperCase()); + + + SetPdfColor('Black',doc); //set black color + doc.setFontSize(9); + + var invoiceHeight = displayInvoice(doc, invoice, 50, 170, layout); + var clientHeight = displayClient(doc, invoice, 220, 170, layout); + var detailsHeight = Math.max(invoiceHeight, clientHeight); + layout.tableTop = Math.max(layout.tableTop, layout.headerTop + detailsHeight + (3 * layout.rowHeight)); + + doc.setLineWidth(0.3); + doc.setDrawColor(200,200,200); + doc.line(layout.marginLeft - layout.tablePadding, layout.headerTop + 6, layout.marginRight + layout.tablePadding, layout.headerTop + 6); + doc.line(layout.marginLeft - layout.tablePadding, layout.headerTop + detailsHeight + 14, layout.marginRight + layout.tablePadding, layout.headerTop + detailsHeight + 14); + + doc.setFontSize(10); + doc.setFontType('bold'); + displayInvoiceHeader(doc, invoice, layout); + var y = displayInvoiceItems(doc, invoice, layout); + + doc.setFontSize(9); + doc.setFontType('bold'); + + GlobalY=GlobalY+25; + + + doc.setLineWidth(0.3); + doc.setDrawColor(241,241,241); + doc.setFillColor(241,241,241); + var x1 = layout.marginLeft - 12; + var y1 = GlobalY-layout.tablePadding; + + var w2 = 510 + 24; + var h2 = doc.internal.getFontSize()*3+layout.tablePadding*2; + + if (invoice.discount) { + h2 += doc.internal.getFontSize()*2; + } + if (invoice.tax_amount) { + h2 += doc.internal.getFontSize()*2; + } + + //doc.rect(x1, y1, w2, h2, 'FD'); + + doc.setFontSize(9); + displayNotesAndTerms(doc, layout, invoice, y); + y += displaySubtotals(doc, layout, invoice, y, layout.unitCostRight); + + + doc.setFontSize(10); + Msg = invoice.is_quote ? invoiceLabels.total : invoiceLabels.balance_due; + var TmpMsgX = layout.unitCostRight-(doc.getStringUnitWidth(Msg) * doc.internal.getFontSize()); + + doc.text(TmpMsgX, y, Msg); + + SetPdfColor('LightBlue', doc, 'primary'); + AmountText = formatMoney(invoice.balance_amount, currencyId); + headerLeft=layout.headerRight+400; + var AmountX = layout.lineTotalRight - (doc.getStringUnitWidth(AmountText) * doc.internal.getFontSize()); + doc.text(AmountX, y, AmountText);" + ]); + + DB::table('invoice_designs')->where('id', 2)->update([ + 'javascript' => " var GlobalY=0;//Y position of line at current page + + var client = invoice.client; + var account = invoice.account; + var currencyId = client.currency_id; + + layout.headerRight = 150; + layout.rowHeight = 15; + layout.headerTop = 125; + layout.tableTop = 300; + + doc.setLineWidth(0.5); + + if (NINJA.primaryColor) { + setDocHexFill(doc, NINJA.primaryColor); + setDocHexDraw(doc, NINJA.primaryColor); + } else { + doc.setFillColor(46,43,43); + } + + var x1 =0; + var y1 = 0; + var w2 = 595; + var h2 = 100; + doc.rect(x1, y1, w2, h2, 'FD'); + + if (invoice.image) + { + var left = layout.headerRight - invoice.imageWidth; + doc.addImage(invoice.image, 'JPEG', layout.marginLeft, 30); + } + + doc.setLineWidth(0.5); + if (NINJA.primaryColor) { + setDocHexFill(doc, NINJA.primaryColor); + setDocHexDraw(doc, NINJA.primaryColor); + } else { + doc.setFillColor(46,43,43); + doc.setDrawColor(46,43,43); + } + + // return doc.setTextColor(240,240,240);//select color Custom Report GRAY Colour + var x1 = 0;//tableLeft-tablePadding ; + var y1 = 750; + var w2 = 596; + var h2 = 94;//doc.internal.getFontSize()*length+length*1.1;//+h;//+tablePadding; + + doc.rect(x1, y1, w2, h2, 'FD'); + if (!invoice.is_pro && logoImages.imageLogo2) + { + pageHeight=820; + var left = 250;//headerRight ; + y=pageHeight-logoImages.imageLogoHeight2; + var headerRight=370; + + var left = headerRight - logoImages.imageLogoWidth2; + doc.addImage(logoImages.imageLogo2, 'JPEG', left, y, logoImages.imageLogoWidth2, logoImages.imageLogoHeight2); + } + + doc.setFontSize(7); + doc.setFontType('bold'); + SetPdfColor('White',doc); + + displayAccount(doc, invoice, 300, layout.accountTop, layout); + + + var y = layout.accountTop; + var left = layout.marginLeft; + var headerY = layout.headerTop; + + SetPdfColor('GrayLogo',doc); //set black color + doc.setFontSize(7); + + //show left column + SetPdfColor('Black',doc); //set black color + doc.setFontType('normal'); + + //publish filled box + doc.setDrawColor(200,200,200); + + if (NINJA.secondaryColor) { + setDocHexFill(doc, NINJA.secondaryColor); + } else { + doc.setFillColor(54,164,152); + } + + GlobalY=190; + doc.setLineWidth(0.5); + + var BlockLenght=220; + var x1 =595-BlockLenght; + var y1 = GlobalY-12; + var w2 = BlockLenght; + var h2 = getInvoiceDetailsHeight(invoice, layout) + layout.tablePadding + 2; + + doc.rect(x1, y1, w2, h2, 'FD'); + + SetPdfColor('SomeGreen', doc, 'secondary'); + doc.setFontSize('14'); + doc.setFontType('bold'); + doc.text(50, GlobalY, (invoice.is_quote ? invoiceLabels.your_quote : invoiceLabels.your_invoice).toUpperCase()); + + + var z=GlobalY; + z=z+30; + + doc.setFontSize('8'); + SetPdfColor('Black',doc); + var clientHeight = displayClient(doc, invoice, layout.marginLeft, z, layout); + layout.tableTop += Math.max(0, clientHeight - 75); + marginLeft2=395; + + //publish left side information + SetPdfColor('White',doc); + doc.setFontSize('8'); + var detailsHeight = displayInvoice(doc, invoice, marginLeft2, z-25, layout) + 75; + layout.tableTop = Math.max(layout.tableTop, layout.headerTop + detailsHeight + (2 * layout.tablePadding)); + + y=z+60; + x = GlobalY + 100; + doc.setFontType('bold'); + + doc.setFontSize(12); + doc.setFontType('bold'); + SetPdfColor('Black',doc); + displayInvoiceHeader(doc, invoice, layout); + + var y = displayInvoiceItems(doc, invoice, layout); + doc.setLineWidth(0.3); + displayNotesAndTerms(doc, layout, invoice, y); + y += displaySubtotals(doc, layout, invoice, y, layout.unitCostRight); + + doc.setFontType('bold'); + + doc.setFontSize(12); + x += doc.internal.getFontSize()*4; + Msg = invoice.is_quote ? invoiceLabels.total : invoiceLabels.balance_due; + var TmpMsgX = layout.unitCostRight-(doc.getStringUnitWidth(Msg) * doc.internal.getFontSize()); + + doc.text(TmpMsgX, y, Msg); + + //SetPdfColor('LightBlue',doc); + AmountText = formatMoney(invoice.balance_amount , currencyId); + headerLeft=layout.headerRight+400; + var AmountX = headerLeft - (doc.getStringUnitWidth(AmountText) * doc.internal.getFontSize()); + SetPdfColor('SomeGreen', doc, 'secondary'); + doc.text(AmountX, y, AmountText);" + ]); + + DB::table('invoice_designs')->where('id', 3)->update([ + 'javascript' => " var client = invoice.client; + var account = invoice.account; + var currencyId = client.currency_id; + + layout.headerRight = 400; + layout.rowHeight = 15; + + + doc.setFontSize(7); + + // add header + doc.setLineWidth(0.5); + + if (NINJA.primaryColor) { + setDocHexFill(doc, NINJA.primaryColor); + setDocHexDraw(doc, NINJA.primaryColor); + } else { + doc.setDrawColor(242,101,34); + doc.setFillColor(242,101,34); + } + + var x1 =0; + var y1 = 0; + var w2 = 595; + var h2 = Math.max(110, getInvoiceDetailsHeight(invoice, layout) + 30); + doc.rect(x1, y1, w2, h2, 'FD'); + + SetPdfColor('White',doc); + + //second column + doc.setFontType('bold'); + var name = invoice.account.name; + if (name) { + doc.setFontSize('30'); + doc.setFontType('bold'); + doc.text(40, 50, name); + } + + if (invoice.image) + { + y=130; + var left = layout.headerRight - invoice.imageWidth; + doc.addImage(invoice.image, 'JPEG', layout.marginLeft, y); + } + + // add footer + doc.setLineWidth(0.5); + + if (NINJA.primaryColor) { + setDocHexFill(doc, NINJA.primaryColor); + setDocHexDraw(doc, NINJA.primaryColor); + } else { + doc.setDrawColor(242,101,34); + doc.setFillColor(242,101,34); + } + + var x1 = 0;//tableLeft-tablePadding ; + var y1 = 750; + var w2 = 596; + var h2 = 94;//doc.internal.getFontSize()*length+length*1.1;//+h;//+tablePadding; + + doc.rect(x1, y1, w2, h2, 'FD'); + + if (!invoice.is_pro && logoImages.imageLogo3) + { + pageHeight=820; + // var left = 25;//250;//headerRight ; + y=pageHeight-logoImages.imageLogoHeight3; + //var headerRight=370; + + //var left = headerRight - invoice.imageLogoWidth3; + doc.addImage(logoImages.imageLogo3, 'JPEG', 40, y, logoImages.imageLogoWidth3, logoImages.imageLogoHeight3); + } + + doc.setFontSize(10); + var marginLeft = 340; + displayAccount(doc, invoice, marginLeft, 780, layout); + + + SetPdfColor('White',doc); + doc.setFontSize('8'); + var detailsHeight = displayInvoice(doc, invoice, layout.headerRight, layout.accountTop-10, layout); + layout.headerTop = Math.max(layout.headerTop, detailsHeight + 50); + layout.tableTop = Math.max(layout.tableTop, detailsHeight + 150); + + SetPdfColor('Black',doc); //set black color + doc.setFontSize(7); + doc.setFontType('normal'); + displayClient(doc, invoice, layout.headerRight, layout.headerTop, layout); + + + + SetPdfColor('White',doc); + doc.setFontType('bold'); + + doc.setLineWidth(0.3); + if (NINJA.secondaryColor) { + setDocHexFill(doc, NINJA.secondaryColor); + setDocHexDraw(doc, NINJA.secondaryColor); + } else { + doc.setDrawColor(63,60,60); + doc.setFillColor(63,60,60); + } + + var left = layout.marginLeft - layout.tablePadding; + var top = layout.tableTop - layout.tablePadding; + var width = layout.marginRight - (2 * layout.tablePadding); + var height = 20; + doc.rect(left, top, width, height, 'FD'); + + + displayInvoiceHeader(doc, invoice, layout); + SetPdfColor('Black',doc); + var y = displayInvoiceItems(doc, invoice, layout); + + + var height1 = displayNotesAndTerms(doc, layout, invoice, y); + var height2 = displaySubtotals(doc, layout, invoice, y, layout.unitCostRight); + y += Math.max(height1, height2); + + + var left = layout.marginLeft - layout.tablePadding; + var top = y - layout.tablePadding; + var width = layout.marginRight - (2 * layout.tablePadding); + var height = 20; + if (NINJA.secondaryColor) { + setDocHexFill(doc, NINJA.secondaryColor); + setDocHexDraw(doc, NINJA.secondaryColor); + } else { + doc.setDrawColor(63,60,60); + doc.setFillColor(63,60,60); + } + doc.rect(left, top, width, height, 'FD'); + + doc.setFontType('bold'); + SetPdfColor('White', doc); + doc.setFontSize(12); + + var label = invoice.is_quote ? invoiceLabels.total : invoiceLabels.balance_due; + var labelX = layout.unitCostRight-(doc.getStringUnitWidth(label) * doc.internal.getFontSize()); + doc.text(labelX, y+2, label); + + + doc.setFontType('normal'); + var amount = formatMoney(invoice.balance_amount , currencyId); + headerLeft=layout.headerRight+400; + var amountX = layout.lineTotalRight - (doc.getStringUnitWidth(amount) * doc.internal.getFontSize()); + doc.text(amountX, y+2, amount);" + ]); + + DB::table('invoice_designs')->where('id', 4)->update([ + 'javascript' => " var client = invoice.client; + var account = invoice.account; + var currencyId = client.currency_id; + + if (invoice.image) + { + var left = layout.headerRight - invoice.imageWidth; + doc.addImage(invoice.image, 'JPEG', left, 30); + } + + /* table header */ + doc.setDrawColor(200,200,200); + doc.setFillColor(230,230,230); + + var detailsHeight = getInvoiceDetailsHeight(invoice, layout); + var left = layout.headerLeft - layout.tablePadding; + var top = layout.headerTop + detailsHeight - layout.rowHeight - layout.tablePadding; + var width = layout.headerRight - layout.headerLeft + (2 * layout.tablePadding); + var height = layout.rowHeight + 1; + doc.rect(left, top, width, height, 'FD'); + + doc.setFontSize(10); + doc.setFontType('normal'); + + displayAccount(doc, invoice, layout.marginLeft, layout.accountTop, layout); + displayClient(doc, invoice, layout.marginLeft, layout.headerTop, layout); + + displayInvoice(doc, invoice, layout.headerLeft, layout.headerTop, layout, layout.headerRight); + layout.tableTop = Math.max(layout.tableTop, layout.headerTop + detailsHeight + (2 * layout.tablePadding)); + + var headerY = layout.headerTop; + var total = 0; + + doc.setDrawColor(200,200,200); + doc.setFillColor(230,230,230); + var left = layout.marginLeft - layout.tablePadding; + var top = layout.tableTop - layout.tablePadding; + var width = layout.headerRight - layout.marginLeft + (2 * layout.tablePadding); + var height = layout.rowHeight + 2; + doc.rect(left, top, width, height, 'FD'); + + displayInvoiceHeader(doc, invoice, layout); + var y = displayInvoiceItems(doc, invoice, layout); + + doc.setFontSize(10); + + displayNotesAndTerms(doc, layout, invoice, y+20); + + y += displaySubtotals(doc, layout, invoice, y+20, 480) + 20; + + doc.setDrawColor(200,200,200); + doc.setFillColor(230,230,230); + + var left = layout.footerLeft - layout.tablePadding; + var top = y - layout.tablePadding; + var width = layout.headerRight - layout.footerLeft + (2 * layout.tablePadding); + var height = layout.rowHeight + 2; + doc.rect(left, top, width, height, 'FD'); + + doc.setFontType('bold'); + doc.text(layout.footerLeft, y, invoice.is_quote ? invoiceLabels.total : invoiceLabels.balance_due); + + total = formatMoney(invoice.balance_amount, currencyId); + var totalX = layout.headerRight - (doc.getStringUnitWidth(total) * doc.internal.getFontSize()); + doc.text(totalX, y, total); + + if (!invoice.is_pro) { + doc.setFontType('normal'); + doc.text(layout.marginLeft, 790, 'Created by InvoiceNinja.com'); + }" + + ]); + + + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('invoice_designs', function($table) + { + $table->dropColumn('javascript'); + }); + + Schema::table('accounts', function($table) + { + $table->dropColumn('invoice_design'); + }); + } + +} diff --git a/app/database/migrations/2014_10_13_054100_add_invoice_number_settings.php b/app/database/migrations/2014_10_13_054100_add_invoice_number_settings.php new file mode 100644 index 0000000000..27abab49d1 --- /dev/null +++ b/app/database/migrations/2014_10_13_054100_add_invoice_number_settings.php @@ -0,0 +1,63 @@ +text('invoice_number_prefix')->nullable(); + $table->integer('invoice_number_counter')->default(1)->nullable(); + + $table->text('quote_number_prefix')->nullable(); + $table->integer('quote_number_counter')->default(1)->nullable(); + + $table->boolean('share_counter')->default(true); + }); + + // set initial counter value for accounts with invoices + $accounts = DB::table('accounts')->lists('id'); + + foreach ($accounts as $accountId) { + + $invoiceNumbers = DB::table('invoices')->where('account_id', $accountId)->lists('invoice_number'); + $max = 0; + + foreach ($invoiceNumbers as $invoiceNumber) { + $number = intval(preg_replace('/[^0-9]/', '', $invoiceNumber)); + $max = max($max, $number); + } + + DB::table('accounts')->where('id', $accountId)->update(['invoice_number_counter' => ++$max]); + } + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('accounts', function($table) + { + $table->dropColumn('invoice_number_prefix'); + $table->dropColumn('invoice_number_counter'); + + $table->dropColumn('quote_number_prefix'); + $table->dropColumn('quote_number_counter'); + + $table->dropColumn('share_counter'); + }); + + } + +} diff --git a/app/database/seeds/PaymentLibrariesSeeder.php b/app/database/seeds/PaymentLibrariesSeeder.php index 24a958228e..b9dbf578be 100644 --- a/app/database/seeds/PaymentLibrariesSeeder.php +++ b/app/database/seeds/PaymentLibrariesSeeder.php @@ -17,13 +17,18 @@ class PaymentLibrariesSeeder extends Seeder Gateway::create($gateway); } - Gateway::create([ - 'name' => 'moolah', - 'provider' => 'AuthorizeNet_AIM', - 'sort_order' => 1, - 'recommended' => 1, - 'site_url' => 'https://invoiceninja.mymoolah.com/', - ]); + // check that moolah exists + if (!DB::table('gateways')->where('name', '=', 'moolah')->get()) { + DB::table('gateways')->update(['recommended' => 0]); + DB::table('gateways')->insert([ + 'name' => 'moolah', + 'provider' => 'AuthorizeNet_AIM', + 'sort_order' => 1, + 'recommended' => 1, + 'site_url' => 'https://invoiceninja.mymoolah.com/', + 'payment_library_id' => 1 + ]); + } /* $updateProviders = array( diff --git a/app/filters.php b/app/filters.php index 80e02cdf72..9c252974fa 100755 --- a/app/filters.php +++ b/app/filters.php @@ -13,12 +13,6 @@ App::before(function($request) { - if (Auth::check()) - { - $count = Session::get(SESSION_COUNTER, 0); - Session::put(SESSION_COUNTER, ++$count); - } - if (App::environment() == ENV_PRODUCTION) { if (!Request::secure()) @@ -27,6 +21,41 @@ App::before(function($request) } } + if (Auth::check()) + { + $count = Session::get(SESSION_COUNTER, 0); + Session::put(SESSION_COUNTER, ++$count); + + // check the application is up to date and for any news feed messages + if (!Utils::startsWith($_SERVER['REQUEST_URI'], '/news_feed') && !Session::has('news_feed_id')) { + $data = false; + if (Utils::isNinja()) { + $data = Utils::getNewsFeedResponse(); + } else { + $file = @file_get_contents(NINJA_URL . '/news_feed/' . Utils::getUserType() . '/' . NINJA_VERSION); + $data = @json_decode($file); + } + if ($data) { + if ($data->version != NINJA_VERSION) { + $params = [ + 'user_version' => NINJA_VERSION, + 'latest_version'=> $data->version, + 'releases_link' => link_to(RELEASES_URL, 'Invoice Ninja', ['target' => '_blank']) + ]; + Session::put('news_feed_id', NEW_VERSION_AVAILABLE); + Session::put('news_feed_message', trans('texts.new_version_available', $params)); + } else { + Session::put('news_feed_id', $data->id); + if ($data->message && $data->id > Auth::user()->news_feed_id) { + Session::put('news_feed_message', $data->message); + } + } + } else { + Session::put('news_feed_id', true); + } + } + } + if (Input::has('lang')) { $locale = Input::get('lang'); diff --git a/app/lang/de/texts.php b/app/lang/de/texts.php index c4c44257cf..76067bbccb 100644 --- a/app/lang/de/texts.php +++ b/app/lang/de/texts.php @@ -422,5 +422,17 @@ return array( 'data_visualizations' => 'Data Visualizations', 'sample_data' => 'Sample data shown', - + 'hide' => 'Hide', + 'new_version_available' => 'A new version of :releases_link is available. You\'re running v:user_version, the latest is v:latest_version', + + 'invoice_settings' => 'Invoice Settings', + 'invoice_number_prefix' => 'Invoice Number Prefix', + 'invoice_number_counter' => 'Invoice Number Counter', + 'quote_number_prefix' => 'Quote Number Prefix', + 'quote_number_counter' => 'Quote Number Counter', + 'share_invoice_counter' => 'Share invoice counter', + 'invoice_issued_to' => 'Invoice issued to', + 'invalid_counter' => 'To prevent a possible conflict please set either an invoice or quote number prefix', + 'mark_sent' => 'Mark sent', + ); diff --git a/app/lang/en/texts.php b/app/lang/en/texts.php index f7a2e0295b..0b87b7cd9f 100644 --- a/app/lang/en/texts.php +++ b/app/lang/en/texts.php @@ -422,7 +422,7 @@ return array( 'confirm_email_invoice' => 'Are you sure you want to email this invoice?', 'confirm_email_quote' => 'Are you sure you want to email this quote?', - 'confirm_recurring_email_invoice' => 'Recurring is enabled,re you sure you want this invoice emailed?', + 'confirm_recurring_email_invoice' => 'Recurring is enabled, are you sure you want this invoice emailed?', 'cancel_account' => 'Cancel Account', 'cancel_account_message' => 'Warning: This will permanently erase all of your data, there is no undo.', @@ -430,6 +430,19 @@ return array( 'data_visualizations' => 'Data Visualizations', 'sample_data' => 'Sample data shown', + 'hide' => 'Hide', + 'new_version_available' => 'A new version of :releases_link is available. You\'re running v:user_version, the latest is v:latest_version', + 'invoice_settings' => 'Invoice Settings', + 'invoice_number_prefix' => 'Invoice Number Prefix', + 'invoice_number_counter' => 'Invoice Number Counter', + 'quote_number_prefix' => 'Quote Number Prefix', + 'quote_number_counter' => 'Quote Number Counter', + 'share_invoice_counter' => 'Share invoice counter', + 'invoice_issued_to' => 'Invoice issued to', + 'invalid_counter' => 'To prevent a possible conflict please set either an invoice or quote number prefix', + 'mark_sent' => 'Mark sent', + + ); \ No newline at end of file diff --git a/app/lang/es/texts.php b/app/lang/es/texts.php index 05a63547e3..961b7bd1f6 100644 --- a/app/lang/es/texts.php +++ b/app/lang/es/texts.php @@ -420,5 +420,18 @@ return array( 'data_visualizations' => 'Data Visualizations', 'sample_data' => 'Sample data shown', + 'hide' => 'Hide', + 'new_version_available' => 'A new version of :releases_link is available. You\'re running v:user_version, the latest is v:latest_version', + + 'invoice_settings' => 'Invoice Settings', + 'invoice_number_prefix' => 'Invoice Number Prefix', + 'invoice_number_counter' => 'Invoice Number Counter', + 'quote_number_prefix' => 'Quote Number Prefix', + 'quote_number_counter' => 'Quote Number Counter', + 'share_invoice_counter' => 'Share invoice counter', + 'invoice_issued_to' => 'Invoice issued to', + 'invalid_counter' => 'To prevent a possible conflict please set either an invoice or quote number prefix', + 'mark_sent' => 'Mark sent', + ); diff --git a/app/lang/fr/texts.php b/app/lang/fr/texts.php index 5565e5be70..72ec38a62e 100644 --- a/app/lang/fr/texts.php +++ b/app/lang/fr/texts.php @@ -422,6 +422,19 @@ return array( 'data_visualizations' => 'Data Visualizations', 'sample_data' => 'Sample data shown', + 'hide' => 'Hide', + 'new_version_available' => 'A new version of :releases_link is available. You\'re running v:user_version, the latest is v:latest_version', + + 'invoice_settings' => 'Invoice Settings', + 'invoice_number_prefix' => 'Invoice Number Prefix', + 'invoice_number_counter' => 'Invoice Number Counter', + 'quote_number_prefix' => 'Quote Number Prefix', + 'quote_number_counter' => 'Quote Number Counter', + 'share_invoice_counter' => 'Share invoice counter', + 'invoice_issued_to' => 'Invoice issued to', + 'invalid_counter' => 'To prevent a possible conflict please set either an invoice or quote number prefix', + 'mark_sent' => 'Mark sent', + ); diff --git a/app/lang/it/texts.php b/app/lang/it/texts.php index a2c8ad2dec..a9720c5bf8 100644 --- a/app/lang/it/texts.php +++ b/app/lang/it/texts.php @@ -422,5 +422,19 @@ return array( 'data_visualizations' => 'Data Visualizations', 'sample_data' => 'Sample data shown', + 'hide' => 'Hide', + 'new_version_available' => 'A new version of :releases_link is available. You\'re running v:user_version, the latest is v:latest_version', + + 'invoice_settings' => 'Invoice Settings', + 'invoice_number_prefix' => 'Invoice Number Prefix', + 'invoice_number_counter' => 'Invoice Number Counter', + 'quote_number_prefix' => 'Quote Number Prefix', + 'quote_number_counter' => 'Quote Number Counter', + 'share_invoice_counter' => 'Share invoice counter', + 'invoice_issued_to' => 'Invoice issued to', + 'invalid_counter' => 'To prevent a possible conflict please set either an invoice or quote number prefix', + 'mark_sent' => 'Mark sent', + + ); diff --git a/app/lang/lt/texts.php b/app/lang/lt/texts.php index 9364251271..a6b6670089 100644 --- a/app/lang/lt/texts.php +++ b/app/lang/lt/texts.php @@ -430,7 +430,20 @@ return array( 'data_visualizations' => 'Data Visualizations', 'sample_data' => 'Sample data shown', + 'hide' => 'Hide', + 'new_version_available' => 'A new version of :releases_link is available. You\'re running v:user_version, the latest is v:latest_version', + 'invoice_settings' => 'Invoice Settings', + 'invoice_number_prefix' => 'Invoice Number Prefix', + 'invoice_number_counter' => 'Invoice Number Counter', + 'quote_number_prefix' => 'Quote Number Prefix', + 'quote_number_counter' => 'Quote Number Counter', + 'share_invoice_counter' => 'Share invoice counter', + 'invoice_issued_to' => 'Invoice issued to', + 'invalid_counter' => 'To prevent a possible conflict please set either an invoice or quote number prefix', + 'mark_sent' => 'Mark sent', + + ); diff --git a/app/lang/nb_NO/texts.php b/app/lang/nb_NO/texts.php index e590a2cb4e..b292a6916d 100644 --- a/app/lang/nb_NO/texts.php +++ b/app/lang/nb_NO/texts.php @@ -430,6 +430,19 @@ return array( 'data_visualizations' => 'Data Visualizations', 'sample_data' => 'Sample data shown', + 'hide' => 'Hide', + 'new_version_available' => 'A new version of :releases_link is available. You\'re running v:user_version, the latest is v:latest_version', + + 'invoice_settings' => 'Invoice Settings', + 'invoice_number_prefix' => 'Invoice Number Prefix', + 'invoice_number_counter' => 'Invoice Number Counter', + 'quote_number_prefix' => 'Quote Number Prefix', + 'quote_number_counter' => 'Quote Number Counter', + 'share_invoice_counter' => 'Share invoice counter', + 'invoice_issued_to' => 'Invoice issued to', + 'invalid_counter' => 'To prevent a possible conflict please set either an invoice or quote number prefix', + 'mark_sent' => 'Mark sent', + ); \ No newline at end of file diff --git a/app/lang/nl/texts.php b/app/lang/nl/texts.php index f5b3718995..59f6d7b185 100644 --- a/app/lang/nl/texts.php +++ b/app/lang/nl/texts.php @@ -423,6 +423,19 @@ return array( 'data_visualizations' => 'Data Visualizations', 'sample_data' => 'Sample data shown', + 'hide' => 'Hide', + 'new_version_available' => 'A new version of :releases_link is available. You\'re running v:user_version, the latest is v:latest_version', + + 'invoice_settings' => 'Invoice Settings', + 'invoice_number_prefix' => 'Invoice Number Prefix', + 'invoice_number_counter' => 'Invoice Number Counter', + 'quote_number_prefix' => 'Quote Number Prefix', + 'quote_number_counter' => 'Quote Number Counter', + 'share_invoice_counter' => 'Share invoice counter', + 'invoice_issued_to' => 'Invoice issued to', + 'invalid_counter' => 'To prevent a possible conflict please set either an invoice or quote number prefix', + 'mark_sent' => 'Mark sent', + ); diff --git a/app/lang/pt_BR/texts.php b/app/lang/pt_BR/texts.php index 5084cff31f..fe13583744 100644 --- a/app/lang/pt_BR/texts.php +++ b/app/lang/pt_BR/texts.php @@ -411,6 +411,19 @@ return array( 'data_visualizations' => 'Data Visualizations', 'sample_data' => 'Sample data shown', + 'hide' => 'Hide', + 'new_version_available' => 'A new version of :releases_link is available. You\'re running v:user_version, the latest is v:latest_version', + + 'invoice_settings' => 'Invoice Settings', + 'invoice_number_prefix' => 'Invoice Number Prefix', + 'invoice_number_counter' => 'Invoice Number Counter', + 'quote_number_prefix' => 'Quote Number Prefix', + 'quote_number_counter' => 'Quote Number Counter', + 'share_invoice_counter' => 'Share invoice counter', + 'invoice_issued_to' => 'Invoice issued to', + 'invalid_counter' => 'To prevent a possible conflict please set either an invoice or quote number prefix', + 'mark_sent' => 'Mark sent', + ); diff --git a/app/libraries/utils.php b/app/libraries/utils.php index 41f10c4222..493a9168b7 100755 --- a/app/libraries/utils.php +++ b/app/libraries/utils.php @@ -37,6 +37,29 @@ class Utils return Auth::check() && Auth::user()->isPro(); } + public static function getUserType() + { + if (Utils::isNinja()) { + return USER_TYPE_CLOUD_HOST; + } else { + return USER_TYPE_SELF_HOST; + } + } + + public static function getNewsFeedResponse($userType = false) + { + if (!$userType) { + $userType = Utils::getUserType(); + } + + $response = new stdClass; + $response->message = isset($_ENV["{$userType}_MESSAGE"]) ? $_ENV["{$userType}_MESSAGE"] : ''; + $response->id = isset($_ENV["{$userType}_ID"]) ? $_ENV["{$userType}_ID"] : ''; + $response->version = NINJA_VERSION; + + return $response; + } + public static function getProLabel($feature) { if (Auth::check() @@ -535,4 +558,15 @@ class Utils //'X-Rate-Limit-Reset' - The number of seconds left in the current period, ]; } + + public static function startsWith($haystack, $needle) + { + return $needle === "" || strpos($haystack, $needle) === 0; + } + + public static function endsWith($haystack, $needle) + { + return $needle === "" || substr($haystack, -strlen($needle)) === $needle; + } + } \ No newline at end of file diff --git a/app/models/Account.php b/app/models/Account.php index c8327c8d66..cf80925b01 100755 --- a/app/models/Account.php +++ b/app/models/Account.php @@ -141,28 +141,25 @@ class Account extends Eloquent return $height; } - public function getNextInvoiceNumber() - { - $invoices = Invoice::withTrashed()->scope(false, $this->id)->get(['invoice_number']); + public function getNextInvoiceNumber($isQuote = false) + { + $counter = $isQuote && !$this->share_counter ? $this->quote_number_counter : $this->invoice_number_counter; + $prefix = $isQuote ? $this->quote_number_prefix : $this->invoice_number_prefix; - $max = 0; - - foreach ($invoices as $invoice) - { - $number = intval(preg_replace("/[^0-9]/", "", $invoice->invoice_number)); - $max = max($max, $number); - } - - if ($max > 0) - { - return str_pad($max+1, 4, "0", STR_PAD_LEFT); - } - else - { - return DEFAULT_INVOICE_NUMBER; - } + return $prefix . str_pad($counter, 4, "0", STR_PAD_LEFT); } + public function incrementCounter($isQuote = false) + { + if ($isQuote && !$this->share_counter) { + $this->quote_number_counter += 1; + } else { + $this->invoice_number_counter += 1; + } + + $this->save(); + } + public function getLocale() { $language = Language::remember(DEFAULT_QUERY_CACHE)->where('id', '=', $this->account->language_id)->first(); @@ -208,6 +205,7 @@ class Account extends Eloquent 'quote_date', 'quote_number', 'total', + 'invoice_issued_to', ]; foreach ($fields as $field) @@ -290,7 +288,11 @@ class Account extends Eloquent foreach ($client->contacts as $contact) { - $contact->setVisible(['public_id']); + $contact->setVisible([ + 'public_id', + 'first_name', + 'last_name', + 'email']); } } diff --git a/app/models/Invoice.php b/app/models/Invoice.php index a951b5a1ef..4438fef6b9 100755 --- a/app/models/Invoice.php +++ b/app/models/Invoice.php @@ -27,6 +27,11 @@ class Invoice extends EntityModel return $this->belongsTo('InvoiceStatus'); } + public function invoice_design() + { + return $this->belongsTo('InvoiceDesign'); + } + public function invitations() { return $this->hasMany('Invitation'); @@ -79,6 +84,7 @@ class Invoice extends EntityModel 'tax_name', 'tax_rate', 'account', + 'invoice_design', 'invoice_design_id', 'is_pro', 'is_quote', @@ -211,6 +217,7 @@ class Invoice extends EntityModel Invoice::created(function($invoice) { + $invoice->account->incrementCounter($invoice->is_quote); Activity::createInvoice($invoice); }); diff --git a/app/ninja/repositories/InvoiceRepository.php b/app/ninja/repositories/InvoiceRepository.php index dad05fbd6f..c4b3638dab 100755 --- a/app/ninja/repositories/InvoiceRepository.php +++ b/app/ninja/repositories/InvoiceRepository.php @@ -20,7 +20,7 @@ class InvoiceRepository ->where('contacts.deleted_at', '=', null) ->where('invoices.is_recurring', '=', false) ->where('contacts.is_primary', '=', true) - ->select('clients.public_id as client_public_id', 'invoice_number', 'clients.name as client_name', 'invoices.public_id', 'amount', 'invoices.balance', 'invoice_date', 'due_date', 'invoice_statuses.name as invoice_status_name', 'clients.currency_id', 'contacts.first_name', 'contacts.last_name', 'contacts.email', 'quote_id', 'quote_invoice_id'); + ->select('clients.public_id as client_public_id', 'invoice_number', 'invoice_status_id', 'clients.name as client_name', 'invoices.public_id', 'amount', 'invoices.balance', 'invoice_date', 'due_date', 'invoice_statuses.name as invoice_status_name', 'clients.currency_id', 'contacts.first_name', 'contacts.last_name', 'contacts.email', 'quote_id', 'quote_invoice_id'); if (!\Session::get('show_trash:invoice')) { @@ -121,32 +121,40 @@ class InvoiceRepository - '; - }) - ->make(); + else if ($entityType == ENTITY_QUOTE) + { + if ($model->quote_invoice_id) + { + $str .= '
  • quote_invoice_id}/edit") . '">' . trans("texts.view_invoice") . '
  • '; + } + } + + return $str . '
  • +
  • '.trans("texts.archive_{$entityType}").'
  • +
  • '.trans("texts.delete_{$entityType}").'
  • + + '; + }) + ->make(); } @@ -359,12 +367,11 @@ class InvoiceRepository $clone = Invoice::createNew($invoice); $clone->balance = $invoice->amount; - $clone->invoice_number = $invoice->account->getNextInvoiceNumber(); + $clone->invoice_number = $invoice->account->getNextInvoiceNumber($invoice->is_quote); foreach ([ 'client_id', 'discount', - //'shipping', 'invoice_date', 'po_number', 'due_date', @@ -378,7 +385,11 @@ class InvoiceRepository 'tax_name', 'tax_rate', 'amount', - 'is_quote'] as $field) + 'is_quote', + 'custom_value1', + 'custom_value2', + 'custom_taxes1', + 'custom_taxes2'] as $field) { $clone->$field = $invoice->$field; } @@ -428,7 +439,7 @@ class InvoiceRepository } - public function bulk($ids, $action) + public function bulk($ids, $action, $statusId = false) { if (!$ids) { @@ -439,13 +450,21 @@ class InvoiceRepository foreach ($invoices as $invoice) { - if ($action == 'delete') - { - $invoice->is_deleted = true; - $invoice->save(); - } + if ($action == 'mark') + { + $invoice->invoice_status_id = $statusId; + $invoice->save(); + } + else + { + if ($action == 'delete') + { + $invoice->is_deleted = true; + $invoice->save(); + } - $invoice->delete(); + $invoice->delete(); + } } return count($invoices); diff --git a/app/routes.php b/app/routes.php index 4afaa5980a..84874dfcc9 100755 --- a/app/routes.php +++ b/app/routes.php @@ -1,5 +1,6 @@ 'auth'), function() { Route::get('dashboard', 'DashboardController@index'); Route::get('view_archive/{entity_type}/{visible}', 'AccountController@setTrashVisible'); + Route::get('hide_message', 'HomeController@hideMessage'); Route::get('force_inline_pdf', 'UserController@forcePDFJS'); Route::get('api/users', array('as'=>'api.users', 'uses'=>'UserController@getDatatable')); @@ -167,7 +171,7 @@ define('ACCOUNT_MAP', 'import_map'); define('ACCOUNT_EXPORT', 'export'); define('ACCOUNT_PRODUCTS', 'products'); define('ACCOUNT_ADVANCED_SETTINGS', 'advanced_settings'); -define('ACCOUNT_CUSTOM_FIELDS', 'custom_fields'); +define('ACCOUNT_INVOICE_SETTINGS', 'invoice_settings'); define('ACCOUNT_INVOICE_DESIGN', 'invoice_design'); define('ACCOUNT_CHART_BUILDER', 'chart_builder'); define('ACCOUNT_USER_MANAGEMENT', 'user_management'); @@ -236,11 +240,16 @@ define('NINJA_ACCOUNT_KEY', 'zg4ylmzDkdkPOT8yoKQw9LTWaoZJx79h'); define('NINJA_GATEWAY_ID', GATEWAY_AUTHORIZE_NET); define('NINJA_GATEWAY_CONFIG', '{"apiLoginId":"626vWcD5","transactionKey":"4bn26TgL9r4Br4qJ","testMode":"","developerMode":""}'); define('NINJA_URL', 'https://www.invoiceninja.com'); -define('NINJA_VERSION', '1.3.3'); +define('NINJA_VERSION', '1.4.0'); +define('RELEASES_URL', 'https://github.com/hillelcoren/invoice-ninja/releases/'); define('PRO_PLAN_PRICE', 50); define('LICENSE_PRICE', 30.00); +define('USER_TYPE_SELF_HOST', 'SELF_HOST'); +define('USER_TYPE_CLOUD_HOST', 'CLOUD_HOST'); +define('NEW_VERSION_AVAILABLE', 'NEW_VERSION_AVAILABLE'); + /* define('GATEWAY_AMAZON', 30); define('GATEWAY_BLUEPAY', 31); diff --git a/app/views/accounts/invoice_design.blade.php b/app/views/accounts/invoice_design.blade.php index 31c122e59c..b004dd7865 100644 --- a/app/views/accounts/invoice_design.blade.php +++ b/app/views/accounts/invoice_design.blade.php @@ -1,49 +1,103 @@ @extends('accounts.nav') +@section('head') + @parent + + + +@stop + @section('content') @parent @include('accounts.nav_advanced') - {{ Former::open()->addClass('col-md-8 col-md-offset-2 warn-on-exit') }} - {{ Former::populate($account) }} - {{ Former::populateField('hide_quantity', intval($account->hide_quantity)) }} - {{ Former::populateField('hide_paid_to_date', intval($account->hide_paid_to_date)) }} + - @endif + var doc = generatePDF(invoice, getDesignJavascript(), true); + if (!doc) { + return; + } + return doc.output('datauristring'); + } - {{ Former::close() }} + $(function() { + var options = { + preferredFormat: 'hex', + disabled: {{ Auth::user()->isPro() ? 'false' : 'true' }}, + showInitial: false, + showInput: true, + allowEmpty: true, + clickoutFiresChange: true, + }; - + $('#primary_color').spectrum(options); + $('#secondary_color').spectrum(options); + refreshPDF(); + }); + + + + +
    +
    + + {{ Former::open()->addClass('warn-on-exit')->onchange('refreshPDF()') }} + {{ Former::populate($account) }} + {{ Former::populateField('hide_quantity', intval($account->hide_quantity)) }} + {{ Former::populateField('hide_paid_to_date', intval($account->hide_paid_to_date)) }} + + {{ Former::legend('invoice_design') }} + {{ Former::select('invoice_design_id')->style('display:inline;width:120px') + ->fromQuery($invoiceDesigns, 'name', 'id') }} + + {{ Former::text('primary_color') }} + {{ Former::text('secondary_color') }} + +

     

    +

     

    + + {{ Former::legend('invoice_options') }} + {{ Former::checkbox('hide_quantity')->text(trans('texts.hide_quantity_help')) }} + {{ Former::checkbox('hide_paid_to_date')->text(trans('texts.hide_paid_to_date_help')) }} + +

     

    +

     

    + + @if (Auth::user()->isPro()) + {{ Former::actions( Button::lg_success_submit(trans('texts.save'))->append_with_icon('floppy-disk') ) }} + @else + + @endif + + {{ Former::close() }} + +
    +
    + + @include('invoices.pdf', ['account' => Auth::user()->account, 'pdfHeight' => 800]) + +
    +
    @stop \ No newline at end of file diff --git a/app/views/accounts/custom_fields.blade.php b/app/views/accounts/invoice_settings.blade.php similarity index 57% rename from app/views/accounts/custom_fields.blade.php rename to app/views/accounts/invoice_settings.blade.php index b856a53379..bf789be9be 100644 --- a/app/views/accounts/custom_fields.blade.php +++ b/app/views/accounts/invoice_settings.blade.php @@ -8,6 +8,8 @@ {{ Former::populate($account) }} {{ Former::populateField('custom_invoice_taxes1', intval($account->custom_invoice_taxes1)) }} {{ Former::populateField('custom_invoice_taxes2', intval($account->custom_invoice_taxes2)) }} + {{ Former::populateField('share_counter', intval($account->share_counter)) }} + {{ Former::legend('invoice_fields') }} {{ Former::text('custom_invoice_label1')->label(trans('texts.field_label')) @@ -27,17 +29,45 @@

     

    {{ Former::text('custom_label2')->label(trans('texts.field_label')) }} {{ Former::text('custom_value2')->label(trans('texts.field_value')) }} +

     

    + + {{ Former::legend('invoice_number') }} + {{ Former::text('invoice_number_prefix')->label(trans('texts.invoice_number_prefix')) }} + {{ Former::text('invoice_number_counter')->label(trans('texts.invoice_number_counter')) }} +

     

    + + {{ Former::legend('quote_number') }} + {{ Former::text('quote_number_prefix')->label(trans('texts.quote_number_prefix')) }} + {{ Former::text('quote_number_counter')->label(trans('texts.quote_number_counter')) + ->append(Former::checkbox('share_counter')->raw()->onclick('setQuoteNumberEnabled()') . ' ' . trans('texts.share_invoice_counter')) }} +

     

    @if (Auth::user()->isPro()) {{ Former::actions( Button::lg_success_submit(trans('texts.save'))->append_with_icon('floppy-disk') ) }} @else @endif {{ Former::close() }} + + + + @stop \ No newline at end of file diff --git a/app/views/accounts/nav.blade.php b/app/views/accounts/nav.blade.php index 627c0cf8ab..66fca0dcc4 100755 --- a/app/views/accounts/nav.blade.php +++ b/app/views/accounts/nav.blade.php @@ -8,7 +8,7 @@ {{ 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/custom_fields', 'advanced_settings', '*/advanced_settings/*') }} + {{ HTML::nav_link('company/advanced_settings/invoice_settings', 'advanced_settings', '*/advanced_settings/*') }}
    diff --git a/app/views/accounts/nav_advanced.blade.php b/app/views/accounts/nav_advanced.blade.php index 498a28d43b..e24ea16f09 100644 --- a/app/views/accounts/nav_advanced.blade.php +++ b/app/views/accounts/nav_advanced.blade.php @@ -1,5 +1,5 @@