diff --git a/app/Http/Controllers/ImportController.php b/app/Http/Controllers/ImportController.php index eb400a5e3d9b..b078fb6f955e 100644 --- a/app/Http/Controllers/ImportController.php +++ b/app/Http/Controllers/ImportController.php @@ -22,7 +22,6 @@ class ImportController extends BaseController { $source = Input::get('source'); $files = []; - $skipped = []; foreach (ImportService::$entityTypes as $entityType) { if (Input::file("{$entityType}_file")) { @@ -38,8 +37,8 @@ class ImportController extends BaseController $data = $this->importService->mapCSV($files); return View::make('accounts.import_map', ['data' => $data]); } else { - $skipped = $this->importService->import($source, $files); - return $this->showResult($skipped); + $results = $this->importService->import($source, $files); + return $this->showResult($results); } } catch (Exception $exception) { Utils::logError($exception); @@ -52,11 +51,10 @@ class ImportController extends BaseController { $map = Input::get('map'); $headers = Input::get('headers'); - $skipped = []; try { - $skipped = $this->importService->importCSV($map, $headers); - return $this->showResult($skipped); + $results = $this->importService->importCSV($map, $headers); + return $this->showResult($results); } catch (Exception $exception) { Utils::logError($exception); Session::flash('error', $exception->getMessage()); @@ -64,16 +62,29 @@ class ImportController extends BaseController } } - private function showResult($skipped) + private function showResult($results) { - if (count($skipped)) { - $message = trans('texts.failed_to_import'); - foreach ($skipped as $skip) { - $message .= '
' . json_encode($skip); + $message = ''; + $skipped = []; + + foreach ($results as $entityType => $entityResults) { + if ($count = count($entityResults[RESULT_SUCCESS])) { + $message .= trans("texts.created_{$entityType}s", ['count' => $count]) . '
'; } + if (count($entityResults[RESULT_FAILURE])) { + $skipped = array_merge($skipped, $entityResults[RESULT_FAILURE]); + } + } + + if (count($skipped)) { + $message .= '

' . trans('texts.failed_to_import') . '
'; + foreach ($skipped as $skip) { + $message .= json_encode($skip) . '
'; + } + } + + if ($message) { Session::flash('warning', $message); - } else { - Session::flash('message', trans('texts.imported_file')); } return Redirect::to('/settings/' . ACCOUNT_IMPORT_EXPORT); diff --git a/app/Http/Controllers/PaymentController.php b/app/Http/Controllers/PaymentController.php index 989a4649174e..6476d1af98c7 100644 --- a/app/Http/Controllers/PaymentController.php +++ b/app/Http/Controllers/PaymentController.php @@ -512,21 +512,20 @@ class PaymentController extends BaseController try { if (method_exists($gateway, 'completePurchase') - && !$accountGateway->isGateway(GATEWAY_TWO_CHECKOUT) - && !$accountGateway->isGateway(GATEWAY_MOLLIE)) { // TODO: implement webhook + && !$accountGateway->isGateway(GATEWAY_TWO_CHECKOUT)) { $details = $this->paymentService->getPaymentDetails($invitation, $accountGateway); - $response = $gateway->completePurchase($details)->send(); + $response = $this->paymentService->completePurchase($gateway, $accountGateway, $details, $token); $ref = $response->getTransactionReference() ?: $token; - if ($response->isSuccessful()) { + if ($response->isCancelled()) { + // do nothing + } elseif ($response->isSuccessful()) { $payment = $this->paymentService->createPayment($invitation, $ref, $payerId); Session::flash('message', trans('texts.applied_payment')); - - return Redirect::to($invitation->getLink()); } else { $this->error('offsite', $response->getMessage(), $accountGateway); - return Redirect::to($invitation->getLink()); } + return Redirect::to($invitation->getLink()); } else { $payment = $this->paymentService->createPayment($invitation, $token, $payerId); Session::flash('message', trans('texts.applied_payment')); diff --git a/app/Http/routes.php b/app/Http/routes.php index dc981679a93d..0bab329d247c 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -63,7 +63,6 @@ Route::get('/auth_unlink', 'Auth\AuthController@authUnlink'); Route::post('/hook/email_bounced', 'AppController@emailBounced'); Route::post('/hook/email_opened', 'AppController@emailOpened'); - // Laravel auth routes get('/signup', array('as' => 'signup', 'uses' => 'Auth\AuthController@getRegister')); post('/signup', array('as' => 'signup', 'uses' => 'Auth\AuthController@postRegister')); diff --git a/app/Ninja/Mailers/ContactMailer.php b/app/Ninja/Mailers/ContactMailer.php index b92fc1811c0e..7efc52bfb8d9 100644 --- a/app/Ninja/Mailers/ContactMailer.php +++ b/app/Ninja/Mailers/ContactMailer.php @@ -25,6 +25,7 @@ class ContactMailer extends Mailer 'firstName', 'invoice', 'quote', + 'dueDate', 'viewLink', 'viewButton', 'paymentLink', @@ -234,6 +235,7 @@ class ContactMailer extends Mailer '$invoice' => $invoice->invoice_number, '$quote' => $invoice->invoice_number, '$link' => $invitation->getLink(), + '$dueDate' => $account->formatDate($invoice->due_date), '$viewLink' => $invitation->getLink(), '$viewButton' => HTML::emailViewButton($invitation->getLink(), $invoice->getEntityType()), '$paymentLink' => $invitation->getLink('payment'), diff --git a/app/Ninja/Repositories/ClientRepository.php b/app/Ninja/Repositories/ClientRepository.php index 58b4bc09b37b..3e43d8f34f5f 100644 --- a/app/Ninja/Repositories/ClientRepository.php +++ b/app/Ninja/Repositories/ClientRepository.php @@ -75,10 +75,12 @@ class ClientRepository extends BaseRepository $client->fill($data); $client->save(); + /* if ( ! isset($data['contact']) && ! isset($data['contacts'])) { return $client; } - + */ + $first = true; $contacts = isset($data['contact']) ? [$data['contact']] : $data['contacts']; $contactIds = []; diff --git a/app/Ninja/Repositories/InvoiceRepository.php b/app/Ninja/Repositories/InvoiceRepository.php index 2142588ec99a..31de427be56d 100644 --- a/app/Ninja/Repositories/InvoiceRepository.php +++ b/app/Ninja/Repositories/InvoiceRepository.php @@ -317,6 +317,7 @@ class InvoiceRepository extends BaseRepository $total -= $invoice->discount; } else { $total *= (100 - $invoice->discount) / 100; + $total = round($total, 2); } } diff --git a/app/Services/ImportService.php b/app/Services/ImportService.php index 3fd21f07192b..ef01758e17d3 100644 --- a/app/Services/ImportService.php +++ b/app/Services/ImportService.php @@ -56,35 +56,39 @@ class ImportService public function import($source, $files) { - $skipped = []; + $results = []; $imported_files = null; foreach ($files as $entityType => $file) { - $result = $this->execute($source, $entityType, $file); - $skipped = array_merge($skipped, $result); + $results[$entityType] = $this->execute($source, $entityType, $file); } - return $skipped; + return $results; } private function execute($source, $entityType, $file) { - $skipped = []; + $results = [ + RESULT_SUCCESS => [], + RESULT_FAILURE => [], + ]; - Excel::load($file, function ($reader) use ($source, $entityType, &$skipped) { + Excel::load($file, function ($reader) use ($source, $entityType, &$results) { $this->checkData($entityType, count($reader->all())); $maps = $this->createMaps(); - $reader->each(function ($row) use ($source, $entityType, $maps, &$skipped) { + $reader->each(function ($row) use ($source, $entityType, $maps, &$results) { $result = $this->saveData($source, $entityType, $row, $maps); - if ( ! $result) { - $skipped[] = $row; + if ($result) { + $results[RESULT_SUCCESS][] = $result; + } else { + $results[RESULT_FAILURE][] = $row; } }); }); - return $skipped; + return $results; } private function saveData($source, $entityType, $row, $maps) @@ -346,19 +350,21 @@ class ImportService public function importCSV($maps, $headers) { - $skipped = []; + $results = []; foreach ($maps as $entityType => $map) { - $result = $this->executeCSV($entityType, $map, $headers[$entityType]); - $skipped = array_merge($skipped, $result); + $result[$entityType] = $this->executeCSV($entityType, $map, $headers[$entityType]); } - return $skipped; + return $results; } private function executeCSV($entityType, $map, $hasHeaders) { - $skipped = []; + $results = [ + RESULT_SUCCESS => [], + RESULT_FAILURE => [], + ]; $source = IMPORT_CSV; $data = Session::get("{$entityType}-data"); @@ -374,14 +380,16 @@ class ImportService $row = $this->convertToObject($entityType, $row, $map); $result = $this->saveData($source, $entityType, $row, $maps); - if ( ! $result) { - $skipped[] = $row; + if ($result) { + $results[RESULT_SUCCESS][] = $result; + } else { + $results[RESULT_FAILURE][] = $row; } } Session::forget("{$entityType}-data"); - return $skipped; + return $results; } private function convertToObject($entityType, $data, $map) diff --git a/app/Services/PaymentService.php b/app/Services/PaymentService.php index 7f3d9c52d7a2..d09f30683c2b 100644 --- a/app/Services/PaymentService.php +++ b/app/Services/PaymentService.php @@ -224,6 +224,17 @@ class PaymentService extends BaseService return $payment; } + public function completePurchase($gateway, $accountGateway, $details, $token) + { + if ($accountGateway->isGateway(GATEWAY_MOLLIE)) { + $details['transactionReference'] = $token; + $response = $gateway->fetchTransaction($details)->send(); + return $gateway->fetchTransaction($details)->send(); + } else { + return $gateway->completePurchase($details)->send(); + } + } + public function autoBillInvoice($invoice) { $client = $invoice->client; diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 000000000000..464d8b596c2a Binary files /dev/null and b/public/favicon.ico differ diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index 1fd8be863b3d..637258ceaa00 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -88,7 +88,7 @@ return array( 'company_details' => 'Company Details', 'online_payments' => 'Online Payments', 'notifications' => 'Email Notifications', - 'import_export' => 'Import/Export', + 'import_export' => 'Import/Export/Cancel', 'done' => 'Done', 'save' => 'Save', 'create' => 'Create', @@ -212,7 +212,7 @@ return array( // application messages 'created_client' => 'Successfully created client', - 'created_clients' => 'Successfully created :count clients', + 'created_clients' => 'Successfully created :count client(s)', 'updated_settings' => 'Successfully updated settings', 'removed_logo' => 'Successfully removed logo', 'sent_message' => 'Successfully sent message', @@ -980,5 +980,7 @@ return array( 'button_confirmation_message' => 'Click to confirm your email address.', 'confirm' => 'Confirm', 'email_preferences' => 'Email Preferences', - + + 'created_invoices' => 'Successfully created :count invoice(s)', + ); diff --git a/resources/views/accounts/import_export.blade.php b/resources/views/accounts/import_export.blade.php index edb9ee60234b..4dc452c7d46a 100644 --- a/resources/views/accounts/import_export.blade.php +++ b/resources/views/accounts/import_export.blade.php @@ -97,7 +97,7 @@

diff --git a/resources/views/accounts/templates_and_reminders.blade.php b/resources/views/accounts/templates_and_reminders.blade.php index ae3602213e4d..d4b69eb0d73d 100644 --- a/resources/views/accounts/templates_and_reminders.blade.php +++ b/resources/views/accounts/templates_and_reminders.blade.php @@ -184,13 +184,14 @@ var keys = {!! json_encode(\App\Ninja\Mailers\ContactMailer::$variableFields) !!}; var vals = [ {!! json_encode($emailFooter) !!}, - "{{ Auth::user()->account->getDisplayName() }}", + "{{ $account->getDisplayName() }}", "Client Name", formatMoney(100), "Contact Name", "First Name", "0001", "0001", + "{{ $account->formatDate($account->getDateTime()) }}", "{{ URL::to('/view/...') }}", '{!! HTML::flatButton('view_invoice', '#0b4d78') !!}', "{{ URL::to('/payment/...') }}", diff --git a/resources/views/dashboard.blade.php b/resources/views/dashboard.blade.php index dcf5782dc4c2..56f9690610ec 100644 --- a/resources/views/dashboard.blade.php +++ b/resources/views/dashboard.blade.php @@ -71,7 +71,7 @@

- {{ trans('texts.notifications') }} + {{ trans('texts.activity') }}
{{ trans_choice('texts.invoices_sent', $invoicesSent) }}
diff --git a/resources/views/emails/master.blade.php b/resources/views/emails/master.blade.php index 7d4ea2329876..a45aa0add118 100644 --- a/resources/views/emails/master.blade.php +++ b/resources/views/emails/master.blade.php @@ -4,7 +4,7 @@ - @yield('markup') @@ -48,7 +48,7 @@ } -
diff --git a/resources/views/master.blade.php b/resources/views/master.blade.php index ad13a7759dc6..6d434ef08ceb 100644 --- a/resources/views/master.blade.php +++ b/resources/views/master.blade.php @@ -6,7 +6,7 @@ @else {{ isset($title) ? ($title . ' | Invoice Ninja') : ('Invoice Ninja | ' . trans('texts.app_title')) }} - + @endif diff --git a/resources/views/partials/system_settings.blade.php b/resources/views/partials/system_settings.blade.php index 81ca2ea40b16..c508ba0ee896 100644 --- a/resources/views/partials/system_settings.blade.php +++ b/resources/views/partials/system_settings.blade.php @@ -66,7 +66,7 @@ $('#dbTestResult').html('Working...').css('color', 'black'); // Send / Test Information - $.post( "/setup", data, function( data ) { + $.post( "{{ URL::to('/setup') }}", data, function( data ) { var color = 'red'; if(data == 'Success'){ color = 'green'; @@ -86,7 +86,7 @@ $('#mailTestResult').html('Working...').css('color', 'black'); // Send / Test Information - $.post( "/setup", data, function( data ) { + $.post( "{{ URL::to('/setup') }}", data, function( data ) { var color = 'red'; if(data == 'Sent'){ color = 'green';