From 346dde8e97daf1b80c746c0190c290752aba2f7f Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Fri, 28 Oct 2016 14:35:32 +0300 Subject: [PATCH 01/18] Fix for parseCSV constructor error --- app/Includes/parsecsv.lib.php | 170 +++++++++++++++++----------------- 1 file changed, 85 insertions(+), 85 deletions(-) diff --git a/app/Includes/parsecsv.lib.php b/app/Includes/parsecsv.lib.php index 7fe04984db97..797beef30340 100644 --- a/app/Includes/parsecsv.lib.php +++ b/app/Includes/parsecsv.lib.php @@ -1,21 +1,21 @@ output (true, 'movies.csv', $array); ---------------- - + */ @@ -83,87 +83,87 @@ class parseCSV { * Configuration * - set these options with $object->var_name = 'value'; */ - + # use first line/entry as field names var $heading = true; - + # override field names var $fields = []; - + # sort entries by this field var $sort_by = null; var $sort_reverse = false; - + # delimiter (comma) and enclosure (double quote) var $delimiter = ','; var $enclosure = '"'; - + # basic SQL-like conditions for row matching var $conditions = null; - + # number of rows to ignore from beginning of data var $offset = null; - + # limits the number of returned rows to specified amount var $limit = null; - + # number of rows to analyze when attempting to auto-detect delimiter var $auto_depth = 15; - + # characters to ignore when attempting to auto-detect delimiter var $auto_non_chars = "a-zA-Z0-9\n\r"; - + # preferred delimiter characters, only used when all filtering method # returns multiple possible delimiters (happens very rarely) var $auto_preferred = ",;\t.:|"; - + # character encoding options var $convert_encoding = false; var $input_encoding = 'ISO-8859-1'; var $output_encoding = 'ISO-8859-1'; - + # used by unparse(), save(), and output() functions var $linefeed = "\r\n"; - + # only used by output() function var $output_delimiter = ','; var $output_filename = 'data.csv'; - - + + /** * Internal variables */ - + # current file var $file; - + # loaded file contents var $file_data; - + # array of field values in data parsed var $titles = []; - + # two dimentional array of CSV data var $data = []; - - + + /** * Constructor * @param input CSV file or string * @return nothing */ - function parseCSV ($input = null, $offset = null, $limit = null, $conditions = null) { + function __construct ($input = null, $offset = null, $limit = null, $conditions = null) { if ( $offset !== null ) $this->offset = $offset; if ( $limit !== null ) $this->limit = $limit; if ( count($conditions) > 0 ) $this->conditions = $conditions; if ( !empty($input) ) $this->parse($input); } - - + + // ============================================== // ----- [ Main Functions ] --------------------- // ============================================== - + /** * Parse CSV file or string * @param input CSV file or string @@ -184,7 +184,7 @@ class parseCSV { } return true; } - + /** * Save changes, or new file and/or data * @param file file to save to @@ -199,7 +199,7 @@ class parseCSV { $is_php = ( preg_match('/\.php$/i', $file) ) ? true : false ; return $this->_wfile($file, $this->unparse($data, $fields, $append, $is_php), $mode); } - + /** * Generate CSV based string for output * @param output if true, prints headers and strings to browser @@ -220,7 +220,7 @@ class parseCSV { } return $data; } - + /** * Convert character encoding * @param input input character encoding, uses default if left blank @@ -232,7 +232,7 @@ class parseCSV { if ( $input !== null ) $this->input_encoding = $input; if ( $output !== null ) $this->output_encoding = $output; } - + /** * Auto-Detect Delimiter: Find delimiter by analyzing a specific number of * rows to determine most probable delimiter character @@ -244,13 +244,13 @@ class parseCSV { * @return delimiter character */ function auto ($file = null, $parse = true, $search_depth = null, $preferred = null, $enclosure = null) { - + if ( $file === null ) $file = $this->file; if ( empty($search_depth) ) $search_depth = $this->auto_depth; if ( $enclosure === null ) $enclosure = $this->enclosure; - + if ( $preferred === null ) $preferred = $this->auto_preferred; - + if ( empty($this->file_data) ) { if ( $this->_check_data($file) ) { $data = &$this->file_data; @@ -258,24 +258,24 @@ class parseCSV { } else { $data = &$this->file_data; } - + $chars = []; $strlen = strlen($data); $enclosed = false; $n = 1; $to_end = true; - + // walk specific depth finding posssible delimiter characters for ( $i=0; $i < $strlen; $i++ ) { $ch = $data{$i}; $nch = ( isset($data{$i+1}) ) ? $data{$i+1} : false ; $pch = ( isset($data{$i-1}) ) ? $data{$i-1} : false ; - + // open and closing quotes if ( $ch == $enclosure && (!$enclosed || $nch != $enclosure) ) { $enclosed = ( $enclosed ) ? false : true ; - - // inline quotes + + // inline quotes } elseif ( $ch == $enclosure && $enclosed ) { $i++; @@ -287,7 +287,7 @@ class parseCSV { } else { $n++; } - + // count character } elseif (!$enclosed) { if ( !preg_match('/['.preg_quote($this->auto_non_chars, '/').']/i', $ch) ) { @@ -299,7 +299,7 @@ class parseCSV { } } } - + // filtering $depth = ( $to_end ) ? $n-1 : $n ; $filtered = []; @@ -308,24 +308,24 @@ class parseCSV { $filtered[$match] = $char; } } - + // capture most probable delimiter ksort($filtered); $delimiter = reset($filtered); $this->delimiter = $delimiter; - + // parse data if ( $parse ) $this->data = $this->parse_string(); - + return $delimiter; - + } - - + + // ============================================== // ----- [ Core Functions ] --------------------- // ============================================== - + /** * Read file to string and call parse_string() * @param file local CSV file @@ -336,7 +336,7 @@ class parseCSV { if ( empty($this->file_data) ) $this->load_data($file); return ( !empty($this->file_data) ) ? $this->parse_string() : false ; } - + /** * Parse CSV strings to arrays * @param data CSV string @@ -348,7 +348,7 @@ class parseCSV { $data = &$this->file_data; } else return false; } - + $rows = []; $row = []; $row_count = 0; @@ -358,19 +358,19 @@ class parseCSV { $enclosed = false; $was_enclosed = false; $strlen = strlen($data); - + // walk through each character for ( $i=0; $i < $strlen; $i++ ) { $ch = $data{$i}; $nch = ( isset($data{$i+1}) ) ? $data{$i+1} : false ; $pch = ( isset($data{$i-1}) ) ? $data{$i-1} : false ; - + // open and closing quotes if ( $ch == $this->enclosure && (!$enclosed || $nch != $this->enclosure) ) { $enclosed = ( $enclosed ) ? false : true ; if ( $enclosed ) $was_enclosed = true; - - // inline quotes + + // inline quotes } elseif ( $ch == $this->enclosure && $enclosed ) { $current .= $ch; $i++; @@ -382,7 +382,7 @@ class parseCSV { $row[$key] = $current; $current = ''; $col++; - + // end of row if ( $ch == "\n" || $ch == "\r" ) { if ( $this->_validate_offset($row_count) && $this->_validate_row_conditions($row, $this->conditions) ) { @@ -406,7 +406,7 @@ class parseCSV { $i = $strlen; } } - + // append character to current field } else { $current .= $ch; @@ -421,7 +421,7 @@ class parseCSV { } return $rows; } - + /** * Create CSV data from array * @param data 2D array with data @@ -436,10 +436,10 @@ class parseCSV { if ( !is_array($data) || empty($data) ) $data = &$this->data; if ( !is_array($fields) || empty($fields) ) $fields = &$this->titles; if ( $delimiter === null ) $delimiter = $this->delimiter; - + $string = ( $is_php ) ? "".$this->linefeed : '' ; $entry = []; - + // create heading if ( $this->heading && !$append ) { foreach( $fields as $key => $value ) { @@ -448,7 +448,7 @@ class parseCSV { $string .= implode($delimiter, $entry).$this->linefeed; $entry = []; } - + // create data foreach( $data as $key => $row ) { foreach( $row as $field => $value ) { @@ -457,10 +457,10 @@ class parseCSV { $string .= implode($delimiter, $entry).$this->linefeed; $entry = []; } - + return $string; } - + /** * Load local file or string * @param input local CSV file @@ -488,16 +488,16 @@ class parseCSV { } return false; } - - + + // ============================================== // ----- [ Internal Functions ] ----------------- // ============================================== - + /** * Validate a row against specified conditions * @param row array with values from a row - * @param conditions specified conditions that the row must match + * @param conditions specified conditions that the row must match * @return true of false */ function _validate_row_conditions ($row = [], $conditions = null) { @@ -523,11 +523,11 @@ class parseCSV { } return false; } - + /** * Validate a row against a single condition * @param row array with values from a row - * @param condition specified condition that the row must match + * @param condition specified condition that the row must match * @return true of false */ function _validate_row_condition ($row, $condition) { @@ -583,7 +583,7 @@ class parseCSV { } return '1'; } - + /** * Validates if the row is within the offset or not if sorting is disabled * @param current_row the current row number being processed @@ -593,7 +593,7 @@ class parseCSV { if ( $this->sort_by === null && $this->offset !== null && $current_row < $this->offset ) return false; return true; } - + /** * Enclose values if needed * - only used by unparse() @@ -611,7 +611,7 @@ class parseCSV { } return $value; } - + /** * Check file data * @param file local filename @@ -624,8 +624,8 @@ class parseCSV { } return true; } - - + + /** * Check if passed info might be delimiter * - only used by find_delimiter() @@ -656,7 +656,7 @@ class parseCSV { } else return false; } } - + /** * Read local file * @param file local filename @@ -689,7 +689,7 @@ class parseCSV { } return false; } - + } -?> \ No newline at end of file +?> From f723621df86d497534c2c789306664ea1e72349b Mon Sep 17 00:00:00 2001 From: Dustin Dauncey Date: Sat, 29 Oct 2016 00:27:30 -0700 Subject: [PATCH 02/18] Updated modern.js invoice template to fix width issues (#1128) Updated modern.js invoice template to fix width issues. This is related to PR #1104. This time it should be put against the correct branch. --- storage/templates/modern.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/storage/templates/modern.js b/storage/templates/modern.js index a4043413a2eb..f65eeebd336a 100755 --- a/storage/templates/modern.js +++ b/storage/templates/modern.js @@ -58,7 +58,7 @@ "type": "rect", "x": 0, "y": 0, - "w": 515, + "w": 532, "h": 26, "r": 0, "lineWidth": 1, @@ -260,4 +260,4 @@ } }, "pageMargins": [40, 120, 40, 50] -} \ No newline at end of file +} From 147a1b1a94c6aa18b1c812c29faea433bf731d4d Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sat, 29 Oct 2016 18:48:58 +1100 Subject: [PATCH 03/18] Add in additional fields for activities transformer (#1129) * Expense categories * add dependencies * expense categories * expense categories * expense categories * Change expense categories into a resource route * add expenses, contacts, tasks and is_system to activity transformer --- app/Ninja/Transformers/ActivityTransformer.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/Ninja/Transformers/ActivityTransformer.php b/app/Ninja/Transformers/ActivityTransformer.php index 5b25f315988e..892868bd0855 100644 --- a/app/Ninja/Transformers/ActivityTransformer.php +++ b/app/Ninja/Transformers/ActivityTransformer.php @@ -16,7 +16,7 @@ class ActivityTransformer extends EntityTransformer protected $availableIncludes = [ ]; /** - * @param Client $client + * @param Activity $activity * @return array */ public function transform(Activity $activity) @@ -29,7 +29,10 @@ class ActivityTransformer extends EntityTransformer 'invoice_id' => $activity->invoice ? $activity->invoice->public_id : null, 'payment_id' => $activity->payment ? $activity->payment->public_id : null, 'credit_id' => $activity->credit ? $activity->credit->public_id : null, - 'updated_at' => $this->getTimestamp($activity->updated_at) + 'updated_at' => $this->getTimestamp($activity->updated_at), + 'expense_id' => $activity->expense_id ? $activity->expense->public_id : null, + 'is_system' => (bool) $activity->is_system ? $activity->is_system : null, + 'contact_id' => $activity->contact_id ? $activity->contact->public_id : null ]; } } From 7b5cd9e4c153b74c000d105ca2edb358efb3832a Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Sun, 30 Oct 2016 08:50:58 +0200 Subject: [PATCH 04/18] Eager load contact with activities --- app/Ninja/Repositories/DashboardRepository.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Ninja/Repositories/DashboardRepository.php b/app/Ninja/Repositories/DashboardRepository.php index e115d963fcf7..455497d13017 100644 --- a/app/Ninja/Repositories/DashboardRepository.php +++ b/app/Ninja/Repositories/DashboardRepository.php @@ -252,7 +252,7 @@ class DashboardRepository } return $activities->orderBy('activities.created_at', 'desc') - ->with('client.contacts', 'user', 'invoice', 'payment', 'credit', 'account', 'task', 'expense') + ->with('client.contacts', 'user', 'invoice', 'payment', 'credit', 'account', 'task', 'expense', 'contact') ->take(50) ->get(); } From 2a97fc5456e5c72ed8fa3973e0ced520dad6b924 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Sun, 30 Oct 2016 11:04:08 +0200 Subject: [PATCH 05/18] Prevent deleted invoice from being paid --- app/Http/Controllers/OnlinePaymentController.php | 6 +++++- app/Models/Invoice.php | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/app/Http/Controllers/OnlinePaymentController.php b/app/Http/Controllers/OnlinePaymentController.php index 07013f2fe7b5..c49a4d666997 100644 --- a/app/Http/Controllers/OnlinePaymentController.php +++ b/app/Http/Controllers/OnlinePaymentController.php @@ -70,7 +70,7 @@ class OnlinePaymentController extends BaseController ]); } - if ( ! floatval($invitation->invoice->balance)) { + if ( ! $invitation->invoice->canBePaid()) { return redirect()->to('view/' . $invitation->invitation_key); } @@ -103,6 +103,10 @@ class OnlinePaymentController extends BaseController $gatewayTypeId = Session::get($invitation->id . 'gateway_type'); $paymentDriver = $invitation->account->paymentDriver($invitation, $gatewayTypeId); + if ( ! $invitation->invoice->canBePaid()) { + return redirect()->to('view/' . $invitation->invitation_key); + } + try { $paymentDriver->completeOnsitePurchase($request->all()); diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php index 14b3d68a90c6..ad20fc1830e2 100644 --- a/app/Models/Invoice.php +++ b/app/Models/Invoice.php @@ -514,6 +514,11 @@ class Invoice extends EntityModel implements BalanceAffecting return storage_path() . '/pdfcache/cache-' . $this->id . '.pdf'; } + public function canBePaid() + { + return floatval($this->balance) > 0 && ! $this->is_deleted; + } + /** * @param $invoice * @return string From 02c300e9f9cc369affc4e37a163206de46ae976d Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Sun, 30 Oct 2016 11:23:36 +0200 Subject: [PATCH 06/18] Prevent session history from showing as blank --- app/Http/Kernel.php | 1 - .../Middleware/SessionDataCheckMiddleware.php | 31 ------------------- app/Http/Middleware/StartupCheck.php | 4 +-- 3 files changed, 2 insertions(+), 34 deletions(-) delete mode 100644 app/Http/Middleware/SessionDataCheckMiddleware.php diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 23ed4f62cab4..b20e0b754465 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -18,7 +18,6 @@ class Kernel extends HttpKernel { 'App\Http\Middleware\VerifyCsrfToken', 'App\Http\Middleware\DuplicateSubmissionCheck', 'App\Http\Middleware\QueryLogging', - 'App\Http\Middleware\SessionDataCheckMiddleware', 'App\Http\Middleware\StartupCheck', ]; diff --git a/app/Http/Middleware/SessionDataCheckMiddleware.php b/app/Http/Middleware/SessionDataCheckMiddleware.php deleted file mode 100644 index c626fa6ee88f..000000000000 --- a/app/Http/Middleware/SessionDataCheckMiddleware.php +++ /dev/null @@ -1,31 +0,0 @@ -getLastUsed(); - - if ( ! $bag || $elapsed > $max) { - $request->session()->flush(); - Auth::logout(); - $request->session()->flash('warning', trans('texts.inactive_logout')); - } - - return $next($request); - } -} diff --git a/app/Http/Middleware/StartupCheck.php b/app/Http/Middleware/StartupCheck.php index 54d81033e1fd..776974a8946c 100644 --- a/app/Http/Middleware/StartupCheck.php +++ b/app/Http/Middleware/StartupCheck.php @@ -13,7 +13,7 @@ use Event; use Schema; use App\Models\Language; use App\Models\InvoiceDesign; -use App\Events\UserSettingsChanged; +use App\Events\UserLoggedIn; use App\Libraries\CurlUtils; /** @@ -118,7 +118,7 @@ class StartupCheck // Make sure the account/user localization settings are in the session if (Auth::check() && !Session::has(SESSION_TIMEZONE)) { - Event::fire(new UserSettingsChanged()); + Event::fire(new UserLoggedIn()); } // Check if the user is claiming a license (ie, additional invoices, white label, etc.) From 5e4c66d11708cb387134fbdb21ba71396d70f595 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Sun, 30 Oct 2016 13:04:56 +0200 Subject: [PATCH 07/18] Updated readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index df83d0e97094..8d1085e8a936 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,8 @@ ## [Hosted](https://www.invoiceninja.com) | [Self-hosted](https://www.invoiceninja.org) +**We're starting work on custom modules, join the discussion [here](https://github.com/invoiceninja/invoiceninja/issues/1131)** + All Pro and Enterprise features from our hosted app are included in both the [self-host zip](https://www.invoiceninja.com/self-host/) and the GitHub repository. Our [iPhone app](https://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=1072566815&mt=8) is now available, our Android app is up next... From 7e7b7274227069252c4d578d88de7b304b6e267d Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Sun, 30 Oct 2016 13:07:14 +0200 Subject: [PATCH 08/18] Updated readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8d1085e8a936..1fb6bfd09232 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ ## [Hosted](https://www.invoiceninja.com) | [Self-hosted](https://www.invoiceninja.org) -**We're starting work on custom modules, join the discussion [here](https://github.com/invoiceninja/invoiceninja/issues/1131)** +**We're starting work on custom modules, join the discussion [here](https://github.com/invoiceninja/invoiceninja/issues/1131).** All Pro and Enterprise features from our hosted app are included in both the [self-host zip](https://www.invoiceninja.com/self-host/) and the GitHub repository. From ad6e5cc29d0d44c52697ef0b78811bef7b8a695c Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Sun, 30 Oct 2016 13:28:01 +0200 Subject: [PATCH 09/18] Prevent textarea height from shrinking --- resources/views/invoices/edit.blade.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/resources/views/invoices/edit.blade.php b/resources/views/invoices/edit.blade.php index dac854629f01..ddf70e3cece9 100644 --- a/resources/views/invoices/edit.blade.php +++ b/resources/views/invoices/edit.blade.php @@ -341,11 +341,11 @@
{!! Former::textarea('public_notes')->data_bind("value: public_notes, valueUpdate: 'afterkeydown'") - ->label(null)->style('resize: none; width: 500px;')->rows(4) !!} + ->label(null)->style('width: 500px;')->rows(4) !!}
{!! Former::textarea('terms')->data_bind("value:terms, placeholder: terms_placeholder, valueUpdate: 'afterkeydown'") - ->label(false)->style('resize: none; width: 500px')->rows(4) + ->label(false)->style('width: 500px')->rows(4) ->help('