1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-09 12:42:36 +01:00

Merge branch 'release-2.6'

Conflicts:
	.travis.yml
	CONTRIBUTING.md
	README.md
	app/Http/Controllers/AccountController.php
	app/Http/Controllers/AppController.php
	app/Http/Controllers/BaseAPIController.php
	app/Http/Controllers/CreditController.php
	app/Http/Controllers/DashboardController.php
	app/Http/Controllers/DocumentController.php
	app/Http/Controllers/PaymentController.php
	app/Http/Controllers/QuoteApiController.php
	app/Http/Requests/EntityRequest.php
	app/Http/routes.php
	app/Listeners/AnalyticsListener.php
	app/Models/Account.php
	app/Models/Credit.php
	app/Models/Document.php
	app/Models/EntityModel.php
	app/Models/Expense.php
	app/Models/Invoice.php
	app/Models/Task.php
	app/Models/VendorContact.php
	app/Ninja/Notifications/PushFactory.php
	app/Ninja/Repositories/DocumentRepository.php
	app/Ninja/Repositories/ExpenseRepository.php
	app/Ninja/Repositories/InvoiceRepository.php
	app/Services/PushService.php
	composer.json
	composer.lock
	database/migrations/2014_05_17_175626_add_quotes.php
	database/seeds/UserTableSeeder.php
	resources/lang/en/texts.php
	resources/views/accounts/customize_design.blade.php
	resources/views/accounts/invoice_design.blade.php
	resources/views/accounts/management.blade.php
	resources/views/expenses/edit.blade.php
	resources/views/header.blade.php
	resources/views/invoices/edit.blade.php
	resources/views/master.blade.php
	resources/views/payments/payment.blade.php
	resources/views/users/edit.blade.php
This commit is contained in:
Hillel Coren 2016-07-11 23:33:58 +03:00
commit b233aa0744
559 changed files with 32063 additions and 11196 deletions

View File

@ -1,7 +1,6 @@
APP_ENV=production APP_ENV=production
APP_DEBUG=false APP_DEBUG=false
APP_URL=http://ninja.dev APP_URL=http://ninja.dev
APP_CIPHER=rijndael-128
APP_KEY=SomeRandomString APP_KEY=SomeRandomString
DB_TYPE=mysql DB_TYPE=mysql
@ -20,6 +19,9 @@ MAIL_FROM_ADDRESS
MAIL_FROM_NAME MAIL_FROM_NAME
MAIL_PASSWORD MAIL_PASSWORD
MAILGUN_DOMAIN=
MAILGUN_SECRET=
#POSTMARK_API_TOKEN= #POSTMARK_API_TOKEN=
PHANTOMJS_CLOUD_KEY='a-demo-key-with-low-quota-per-ip-address' PHANTOMJS_CLOUD_KEY='a-demo-key-with-low-quota-per-ip-address'
@ -60,11 +62,21 @@ API_SECRET=password
# If this is set to anything, the URL secret will be set the next # If this is set to anything, the URL secret will be set the next
# time a file is downloaded through the client portal. # time a file is downloaded through the client portal.
# Only set this temporarily, as it slows things down. # Only set this temporarily, as it slows things down.
#RACKSPACE_TEMP_URL_SECRET_SET= #RACKSPACE_TEMP_URL_SECRET_SET=
#DOCUMENT_FILESYSTEM= #DOCUMENT_FILESYSTEM=
#MAX_DOCUMENT_SIZE # KB #MAX_DOCUMENT_SIZE # KB
#MAX_EMAIL_DOCUMENTS_SIZE # Total KB #MAX_EMAIL_DOCUMENTS_SIZE # Total KB
#MAX_ZIP_DOCUMENTS_SIZE # Total KB (uncompressed) #MAX_ZIP_DOCUMENTS_SIZE # Total KB (uncompressed)
#DOCUMENT_PREVIEW_SIZE # Pixels #DOCUMENT_PREVIEW_SIZE # Pixels
WEPAY_CLIENT_ID=
WEPAY_CLIENT_SECRET=
WEPAY_ENVIRONMENT=production # production or stage
WEPAY_AUTO_UPDATE=true # Requires permission from WePay
WEPAY_ENABLE_CANADA=true
WEPAY_FEE_PAYER=payee
WEPAY_APP_FEE_MULTIPLIER=0.002
WEPAY_APP_FEE_FIXED=0
WEPAY_THEME='{"name":"Invoice Ninja","primary_color":"0b4d78","secondary_color":"0b4d78","background_color":"f8f8f8","button_color":"33b753"}' # See https://www.wepay.com/developer/reference/structures#theme

2
.gitignore vendored
View File

@ -35,4 +35,4 @@ tests/_bootstrap.php
# composer stuff # composer stuff
/c3.php /c3.php
_ide_helper.php _ide_helper.php

18
.styleci.yml Normal file
View File

@ -0,0 +1,18 @@
preset: laravel
risky: false
enabled:
- no_useless_else
- phpdoc_align
- phpdoc_no_empty_return
- phpdoc_order
- phpdoc_separation
finder:
exclude:
- "resources"
- "storage"
- "tests"
not-path:
- "bootstrap/cache"

View File

@ -3,9 +3,10 @@ language: php
sudo: true sudo: true
php: php:
- 5.5.9 # - 5.5.9
# - 5.6 # - 5.6
# - 7.0 # - 5.6
- 7.0
# - hhvm # - hhvm
addons: addons:
@ -27,13 +28,14 @@ before_install:
# set GitHub token and update composer # set GitHub token and update composer
- if [ -n "$GH_TOKEN" ]; then composer config github-oauth.github.com ${GH_TOKEN}; fi; - if [ -n "$GH_TOKEN" ]; then composer config github-oauth.github.com ${GH_TOKEN}; fi;
- composer self-update && composer -V - composer self-update && composer -V
# - export USE_ZEND_ALLOC=0
install: install:
# install Composer dependencies # install Composer dependencies
- rm composer.lock # - rm composer.lock
# these providers require referencing git commit's which cause Travis to fail # these providers require referencing git commit's which cause Travis to fail
- sed -i '/mollie/d' composer.json # - sed -i '/mollie/d' composer.json
- sed -i '/2checkout/d' composer.json # - sed -i '/2checkout/d' composer.json
- travis_retry composer install --prefer-dist; - travis_retry composer install --prefer-dist;
before_script: before_script:
@ -66,17 +68,17 @@ before_script:
script: script:
- php ./vendor/codeception/codeception/codecept run --debug acceptance AllPagesCept.php - php ./vendor/codeception/codeception/codecept run --debug acceptance AllPagesCept.php
- php ./vendor/codeception/codeception/codecept run --debug acceptance APICest.php - php ./vendor/codeception/codeception/codecept run --debug acceptance APICest.php
#- php ./vendor/codeception/codeception/codecept run --debug acceptance CheckBalanceCest.php - php ./vendor/codeception/codeception/codecept run --debug acceptance TaxRatesCest.php
#- php ./vendor/codeception/codeception/codecept run --debug acceptance ClientCest.php - php ./vendor/codeception/codeception/codecept run --debug acceptance CheckBalanceCest.php
#- php ./vendor/codeception/codeception/codecept run --debug acceptance ExpenseCest.php - php ./vendor/codeception/codeception/codecept run --debug acceptance ClientCest.php
#- php ./vendor/codeception/codeception/codecept run --debug acceptance CreditCest.php - php ./vendor/codeception/codeception/codecept run --debug acceptance ExpenseCest.php
#- php ./vendor/codeception/codeception/codecept run --debug acceptance InvoiceCest.php - php ./vendor/codeception/codeception/codecept run --debug acceptance CreditCest.php
#- php ./vendor/codeception/codeception/codecept run --debug acceptance QuoteCest.php - php ./vendor/codeception/codeception/codecept run --debug acceptance InvoiceCest.php
#- php ./vendor/codeception/codeception/codecept run --debug acceptance InvoiceDesignCest.php - php ./vendor/codeception/codeception/codecept run --debug acceptance QuoteCest.php
#- php ./vendor/codeception/codeception/codecept run acceptance OnlinePaymentCest.php - php ./vendor/codeception/codeception/codecept run --debug acceptance InvoiceDesignCest.php
#- php ./vendor/codeception/codeception/codecept run --debug acceptance PaymentCest.php - php ./vendor/codeception/codeception/codecept run --debug acceptance OnlinePaymentCest.php
#- php ./vendor/codeception/codeception/codecept run --debug acceptance TaskCest.php - php ./vendor/codeception/codeception/codecept run --debug acceptance PaymentCest.php
#- php ./vendor/codeception/codeception/codecept run --debug acceptance TaxRatesCest.php - php ./vendor/codeception/codeception/codecept run --debug acceptance TaskCest.php
#- sed -i 's/NINJA_DEV=true/NINJA_PROD=true/g' .env #- sed -i 's/NINJA_DEV=true/NINJA_PROD=true/g' .env
#- php ./vendor/codeception/codeception/codecept run acceptance GoProCest.php #- php ./vendor/codeception/codeception/codecept run acceptance GoProCest.php
@ -90,6 +92,7 @@ after_script:
- mysql -u root -e 'select * from invoice_items;' ninja - mysql -u root -e 'select * from invoice_items;' ninja
- mysql -u root -e 'select * from payments;' ninja - mysql -u root -e 'select * from payments;' ninja
- mysql -u root -e 'select * from credits;' ninja - mysql -u root -e 'select * from credits;' ninja
- mysql -u root -e 'select * from expenses;' ninja
- cat storage/logs/laravel-error.log - cat storage/logs/laravel-error.log
- cat storage/logs/laravel-info.log - cat storage/logs/laravel-info.log
- FILES=$(find tests/_output -type f -name '*.png') - FILES=$(find tests/_output -type f -name '*.png')

19
CHANGELOG.md Normal file
View File

@ -0,0 +1,19 @@
# Changelog
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## [2.6] - 2016-07-08
### Added
- Configuration for first day of the week #950
- StyleCI configuration #929
- Added expense category
### Changed
- Removed `invoiceninja.komodoproject` from Git #932
- `APP_CIPHER` changed from `rinjdael-128` to `AES-256-CBC` #898
- Improved options when exporting data
### Fixed
- "Manual entry" untranslatable #562
- Using a database table prefix breaks the dashboard #203

View File

@ -1,9 +1,45 @@
# Contributing to Invoice Ninja # Contributing to Invoice Ninja
We welcome contributions! We'll improve this guide over time... Thanks for your contributions!
*Please note: although our application is open-source we run a for-profit hosted service at [invoiceninja.com](https://www.invoiceninja.com).* ## Submit bug reports or feature requests
Guidelines ### Submit pull requests
- Please try to follow [PSR-2 guidlines](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) * [Fork](https://github.com/invoiceninja/invoiceninja#fork-destination-box) the [Invoice Ninja repository](https://github.com/invoiceninja/invoiceninja)
- Add translations in our [Transifex](https://www.transifex.com/invoice-ninja/) project * Create a new branch with the name `#issue_number-Short-description`
* _Example:_ `#100-Add-GoogleAnalytics`
* Make your changes and commit
* Check if your branch is still in sync with the repositorys **`develop`** branch
* _Read:_ [Syncing a fork](https://help.github.com/articles/syncing-a-fork/)
* _Also read:_ [How to rebase a pull request](https://github.com/edx/edx-platform/wiki/How-to-Rebase-a-Pull-Request)
* Push your branch and create a PR against the Invoice Ninja **`develop`** branch
* Update the [Changelog](CHANGELOG.md)
### Some rules
To make the contribution process nice and easy for anyone, please follow some rules:
* Each contribution(bug or feature) should have an [issue on Github](https://github.com/invoiceninja/invoiceninja/issues)
to give a more detailed explanation.
* Only one feature/bugfix per issue. If you want to submit more, create multiple issues.
* Only one feature/bugfix per PR(pull request). Split more changes into multiple PRs.
#### Coding Style
Try to follow the [PSR-2 guidlines](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)
_Example styling:_
```php
/**
* Gets a preview of the email
*
* @param TemplateService $templateService
*
* @return \Illuminate\Http\Response
*/
public function previewEmail(TemplateService $templateService)
{
//
}
```
## Translations
For helping us with translating Invoice Ninja, please use [Transifex](https://www.transifex.com/invoice-ninja/invoice-ninja/).

View File

@ -3,14 +3,15 @@
</p> </p>
# Invoice Ninja # Invoice Ninja
### [http://www.invoiceninja.org](http://www.invoiceninja.org)
[![Build Status](https://travis-ci.org/invoiceninja/invoiceninja.svg?branch=master)](https://travis-ci.org/invoiceninja/invoiceninja) [![Build Status](https://travis-ci.org/invoiceninja/invoiceninja.svg?branch=master)](https://travis-ci.org/invoiceninja/invoiceninja)
[![Join the chat at https://gitter.im/hillelcoren/invoice-ninja](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/hillelcoren/invoice-ninja?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Join the chat at https://gitter.im/hillelcoren/invoice-ninja](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/hillelcoren/invoice-ninja?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
We're often asked to recommend PHP developers to help setup our app and make small adjustments, email us at contact@invoiceninja.com if you're interested in taking on the work. ## [Hosted](https://www.invoiceninja.com) | [Self-hosted](https://invoiceninja.org)
### Affiliates Programs We're often asked to recommend Laravel/PHP developers to help setup our app and make small adjustments, email us at contact@invoiceninja.com if you're interested in taking on the work.
## Affiliates Programs
* Referral program (we pay you): $100 per signup paid over 3 years - [Learn more](https://www.invoiceninja.com/referral-program/) * Referral program (we pay you): $100 per signup paid over 3 years - [Learn more](https://www.invoiceninja.com/referral-program/)
* White-label reseller (you pay us): 10% of revenue with a $500 sign up fee * White-label reseller (you pay us): 10% of revenue with a $500 sign up fee
@ -20,23 +21,24 @@ We're often asked to recommend PHP developers to help setup our app and make sma
* [Bitnami](https://bitnami.com/stack/invoice-ninja) - Free * [Bitnami](https://bitnami.com/stack/invoice-ninja) - Free
* [Softaculous](https://www.softaculous.com/apps/ecommerce/Invoice_Ninja) - $30 * [Softaculous](https://www.softaculous.com/apps/ecommerce/Invoice_Ninja) - $30
### Requirements ## Requirements
* PHP >= 5.5.9 * PHP >= 5.5.9
* MCrypt PHP Extension * MCrypt PHP Extension
* MySQL * MySQL
### Recommended Providers ## Recommended Providers
* [Stripe](https://stripe.com/) * [Stripe](https://stripe.com/)
* [Postmark](https://postmarkapp.com/) * [Postmark](https://postmarkapp.com/)
### Features ## Features
* Built using Laravel 5.2 * Built using Laravel 5.2
* Live PDF generation using [pdfmake](http://pdfmake.org/) * Live PDF generation using [pdfmake](http://pdfmake.org/)
* Integrates with 50+ payment providers with [OmniPay](https://github.com/thephpleague/omnipay) * Integrates with 50+ payment providers with [Omnipay](https://github.com/thephpleague/omnipay)
* Recurring invoices with auto-billing * Recurring invoices with auto-billing
* Expenses and vendors * Expenses and vendors
* Tasks with time-tracking * Tasks with time-tracking
* File Attachments
* Multi-user/multi-company support * Multi-user/multi-company support
* Tax rates and payment terms * Tax rates and payment terms
* Reminder emails * Reminder emails
@ -45,7 +47,7 @@ We're often asked to recommend PHP developers to help setup our app and make sma
* Custom email templates * Custom email templates
* [D3.js](http://d3js.org/) visualizations * [D3.js](http://d3js.org/) visualizations
### Documentation ## Documentation
* [Ubuntu and Apache](http://blog.technerdservices.com/index.php/2015/04/techpop-how-to-install-invoice-ninja-on-ubuntu-14-04/) * [Ubuntu and Apache](http://blog.technerdservices.com/index.php/2015/04/techpop-how-to-install-invoice-ninja-on-ubuntu-14-04/)
* [Debian and Nginx](https://www.rosehosting.com/blog/install-invoice-ninja-on-a-debian-7-vps/) * [Debian and Nginx](https://www.rosehosting.com/blog/install-invoice-ninja-on-a-debian-7-vps/)
* [User Guide](https://www.invoiceninja.com/app-user-guide/) * [User Guide](https://www.invoiceninja.com/app-user-guide/)
@ -54,51 +56,22 @@ We're often asked to recommend PHP developers to help setup our app and make sma
* [Support Forum](https://www.invoiceninja.com/forums/forum/support/) * [Support Forum](https://www.invoiceninja.com/forums/forum/support/)
* [Feature Roadmap](https://trello.com/b/63BbiVVe/) * [Feature Roadmap](https://trello.com/b/63BbiVVe/)
### Pull Requests ## Contributing
We're using the [Git-Flow](http://nvie.com/posts/a-successful-git-branching-model/) model of branching and releasing, **please create pull requests against the develop branch**. All contributors are welcome!
For information on how contribute to Invoice Ninja, please see our [contributing guide](CONTRIBUTING.md).
### Contributors ## Credits
* [Hillel Coren](https://github.com/hillelcoren)
* [All contributors](https://github.com/invoiceninja/invoiceninja/graphs/contributors)
**Special thanks to:**
* [Troels Liebe Bentsen](https://github.com/tlbdk) * [Troels Liebe Bentsen](https://github.com/tlbdk)
* [Jeramy Simpson](https://github.com/JeramyMywork) - [MyWork](https://www.mywork.com.au) * [Jeramy Simpson](https://github.com/JeramyMywork) - [MyWork](https://www.mywork.com.au)
* [Sigitas Limontas](https://lt.linkedin.com/in/sigitaslimontas) * [Sigitas Limontas](https://lt.linkedin.com/in/sigitaslimontas)
* [Joshua Dwire](https://github.com/joshuadwire) - [Some Techie](https://www.sometechie.com) * [Joshua Dwire](https://github.com/joshuadwire) - [Some Techie](https://www.sometechie.com)
* [Holger Lösken](https://github.com/codedge) - [codedge](http://codedge.de/)
### Frameworks/Libraries
* [laravel/laravel](https://github.com/laravel/laravel) - A PHP Framework For Web Artisans ## License
* [twbs/bootstrap](https://github.com/twbs/bootstrap) - Sleek, intuitive, and powerful front-end framework for faster and easier web development. Invoice Ninja is released under the Attribution Assurance License.
* [jquery/jquery](https://github.com/jquery/jquery) - jQuery JavaScript Library See [LICENSE](LICENSE) for details.
* [jquery/jquery-ui](https://github.com/jquery/jquery-ui) - The official jQuery user interface library
* [patricktalmadge/bootstrapper](https://github.com/patricktalmadge/bootstrapper) - Laravel Twitter Bootstrap Bundle
* [danielfarrell/bootstrap-combobox](https://github.com/danielfarrell/bootstrap-combobox) - A combobox plugin
* [eternicode/bootstrap-datepicker](https://github.com/eternicode/bootstrap-datepicker) - A datepicker for @twitter bootstrap
* [twitter/typeahead.js](https://github.com/twitter/typeahead.js) - a fast and fully-featured autocomplete library
* [krisk/Fuse](https://github.com/krisk/Fuse) - Lightweight fuzzy-search, in JavaScript
* [knockout/knockout](https://github.com/knockout/knockout) - Knockout makes it easier to create rich, responsive UIs with JavaScript
* [rniemeyer/knockout-sortable](https://github.com/rniemeyer/knockout-sortable) - A Knockout.js binding to connect observableArrays with jQuery UI sortable functionality
* [bpampuch/pdfmake](https://github.com/bpampuch/pdfmake) - Client/server side PDF printing in pure JavaScript
* [FortAwesome/Font-Awesome](https://github.com/FortAwesome/Font-Awesome) - The iconic font designed for Bootstrap that works with twitter bootstrap
* [Anahkiasen/former](https://github.com/Anahkiasen/former) - A powerful form builder, for Laravel and other frameworks (stand-alone too)
* [barryvdh/laravel-debugbar](https://github.com/barryvdh/laravel-debugbar) - Laravel debugbar
* [DataTables/DataTables](https://github.com/DataTables/DataTables) - Tables plug-in for jQuery
* [Chumper/Datatable](https://github.com/Chumper/Datatable) - This is a laravel 4 package for the server and client side of datatables
* [omnipay/omnipay](https://github.com/omnipay/omnipay) - A framework agnostic, multi-gateway payment processing library for PHP 5.3+
* [Intervention/image](https://github.com/Intervention/image) - PHP Image Manipulation
* [webpatser/laravel-countries](https://github.com/webpatser/laravel-countries) - Almost ISO 3166_2, 3166_3, currency, Capital and more for all countries
* [briannesbitt/Carbon](https://github.com/briannesbitt/Carbon) - A simple API extension for DateTime with PHP 5.3+
* [thomaspark/bootswatch](https://github.com/thomaspark/bootswatch) - Themes for Bootstrap
* [mozilla/pdf.js](https://github.com/mozilla/pdf.js) - PDF Reader in JavaScript
* [nnnick/Chart.js](https://github.com/nnnick/Chart.js) - Simple HTML5 Charts using the canvas tag
* [josscrowcroft/accounting.js](https://github.com/josscrowcroft/accounting.js) - A lightweight JavaScript library for number, money and currency formatting
* [jashkenas/underscore](https://github.com/jashkenas/underscore) - JavaScript's utility _ belt
* [caouecs/Laravel4-long](https://github.com/caouecs/Laravel4-lang) - List of languages for Laravel4
* [bgrins/spectrum](https://github.com/bgrins/spectrum) - The No Hassle JavaScript Colorpicker
* [lokesh/lightbox2](https://github.com/lokesh/lightbox2/) - The original lightbox script
* [josdejong/jsoneditor](https://github.com/josdejong/jsoneditor/) - A web-based tool to view, edit and format JSON
* [simshaun/recurr](https://github.com/simshaun/recurr) - PHP library for working with recurrence rules
* [quilljs/quill](https://github.com/quilljs/quill/) - A cross browser rich text editor with an API
* [Maatwebsite/Laravel-Excel](https://github.com/Maatwebsite/Laravel-Excel) - An eloquent way of importing and exporting Excel and CSV files for Laravel
* [thephpleague/fractal](https://github.com/thephpleague/fractal) - Output complex, flexible, AJAX/RESTful data structures
* [ezyang/htmlpurifier](https://github.com/ezyang/htmlpurifier) - Standards compliant HTML filter written in PHP
* [cerdic/css-tidy](https://github.com/Cerdic/CSSTidy) - CSSTidy is a CSS minifier
* [asgrim/ofxparser](https://github.com/asgrim/ofxparser) - OFX File Parser
* [stacktracejs/stacktrace.js](https://github.com/stacktracejs/stacktrace.js) - Framework-agnostic, micro-library for getting stack traces in all web browsers

View File

@ -1,22 +1,47 @@
<?php namespace App\Console\Commands; <?php namespace App\Console\Commands;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use App\Ninja\Mailers\ContactMailer as Mailer; use App\Ninja\Mailers\ContactMailer as Mailer;
use App\Ninja\Repositories\AccountRepository; use App\Ninja\Repositories\AccountRepository;
use App\Services\PaymentService; use App\Services\PaymentService;
use App\Models\Invoice; use App\Models\Invoice;
/**
* Class ChargeRenewalInvoices
*/
class ChargeRenewalInvoices extends Command class ChargeRenewalInvoices extends Command
{ {
/**
* @var string
*/
protected $name = 'ninja:charge-renewals'; protected $name = 'ninja:charge-renewals';
/**
* @var string
*/
protected $description = 'Charge renewal invoices'; protected $description = 'Charge renewal invoices';
/**
* @var Mailer
*/
protected $mailer; protected $mailer;
/**
* @var AccountRepository
*/
protected $accountRepo; protected $accountRepo;
/**
* @var PaymentService
*/
protected $paymentService; protected $paymentService;
/**
* ChargeRenewalInvoices constructor.
* @param Mailer $mailer
* @param AccountRepository $repo
* @param PaymentService $paymentService
*/
public function __construct(Mailer $mailer, AccountRepository $repo, PaymentService $paymentService) public function __construct(Mailer $mailer, AccountRepository $repo, PaymentService $paymentService)
{ {
parent::__construct(); parent::__construct();
@ -47,17 +72,19 @@ class ChargeRenewalInvoices extends Command
$this->info('Done'); $this->info('Done');
} }
/**
* @return array
*/
protected function getArguments() protected function getArguments()
{ {
return array( return [];
//array('example', InputArgument::REQUIRED, 'An example argument.'),
);
} }
/**
* @return array
*/
protected function getOptions() protected function getOptions()
{ {
return array( return [];
//array('example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null),
);
} }
} }

View File

@ -1,11 +1,9 @@
<?php namespace App\Console\Commands; <?php namespace App\Console\Commands;
use DB; use DB;
use DateTime;
use Carbon; use Carbon;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
/* /*
@ -38,9 +36,19 @@ Options:
*/ */
/**
* Class CheckData
*/
class CheckData extends Command { class CheckData extends Command {
/**
* @var string
*/
protected $name = 'ninja:check-data'; protected $name = 'ninja:check-data';
/**
* @var string
*/
protected $description = 'Check/fix data'; protected $description = 'Check/fix data';
public function fire() public function fire()
@ -101,7 +109,7 @@ class CheckData extends Command {
} }
$records = $records->where("{$table}.account_id", '!=', DB::raw("{$entityType}s.account_id")) $records = $records->where("{$table}.account_id", '!=', DB::raw("{$entityType}s.account_id"))
->get(["{$table}.id", "clients.account_id", "clients.user_id"]); ->get(["{$table}.id", 'clients.account_id', 'clients.user_id']);
if (count($records)) { if (count($records)) {
$this->info(count($records) . " {$table} records with incorrect {$entityType} account id"); $this->info(count($records) . " {$table} records with incorrect {$entityType} account id");
@ -154,7 +162,7 @@ class CheckData extends Command {
$clients->where('clients.id', '=', $this->option('client_id')); $clients->where('clients.id', '=', $this->option('client_id'));
} else { } else {
$clients->where('invoices.is_deleted', '=', 0) $clients->where('invoices.is_deleted', '=', 0)
->where('invoices.is_quote', '=', 0) ->where('invoices.invoice_type_id', '=', INVOICE_TYPE_STANDARD)
->where('invoices.is_recurring', '=', 0) ->where('invoices.is_recurring', '=', 0)
->havingRaw('abs(clients.balance - sum(invoices.balance)) > .01 and clients.balance != 999999999.9999'); ->havingRaw('abs(clients.balance - sum(invoices.balance)) > .01 and clients.balance != 999999999.9999');
} }
@ -184,7 +192,7 @@ class CheckData extends Command {
if ($activity->invoice_id) { if ($activity->invoice_id) {
$invoice = DB::table('invoices') $invoice = DB::table('invoices')
->where('id', '=', $activity->invoice_id) ->where('id', '=', $activity->invoice_id)
->first(['invoices.amount', 'invoices.is_recurring', 'invoices.is_quote', 'invoices.deleted_at', 'invoices.id', 'invoices.is_deleted']); ->first(['invoices.amount', 'invoices.is_recurring', 'invoices.invoice_type_id', 'invoices.deleted_at', 'invoices.id', 'invoices.is_deleted']);
// Check if this invoice was once set as recurring invoice // Check if this invoice was once set as recurring invoice
if ($invoice && !$invoice->is_recurring && DB::table('invoices') if ($invoice && !$invoice->is_recurring && DB::table('invoices')
@ -221,14 +229,14 @@ class CheckData extends Command {
&& $invoice->amount > 0; && $invoice->amount > 0;
// **Fix for allowing converting a recurring invoice to a normal one without updating the balance** // **Fix for allowing converting a recurring invoice to a normal one without updating the balance**
if ($noAdjustment && !$invoice->is_quote && !$invoice->is_recurring) { if ($noAdjustment && $invoice->invoice_type_id == INVOICE_TYPE_STANDARD && !$invoice->is_recurring) {
$this->info("No adjustment for new invoice:{$activity->invoice_id} amount:{$invoice->amount} isQuote:{$invoice->is_quote} isRecurring:{$invoice->is_recurring}"); $this->info("No adjustment for new invoice:{$activity->invoice_id} amount:{$invoice->amount} invoiceTypeId:{$invoice->invoice_type_id} isRecurring:{$invoice->is_recurring}");
$foundProblem = true; $foundProblem = true;
$clientFix += $invoice->amount; $clientFix += $invoice->amount;
$activityFix = $invoice->amount; $activityFix = $invoice->amount;
// **Fix for updating balance when creating a quote or recurring invoice** // **Fix for updating balance when creating a quote or recurring invoice**
} elseif ($activity->adjustment != 0 && ($invoice->is_quote || $invoice->is_recurring)) { } elseif ($activity->adjustment != 0 && ($invoice->invoice_type_id == INVOICE_TYPE_QUOTE || $invoice->is_recurring)) {
$this->info("Incorrect adjustment for new invoice:{$activity->invoice_id} adjustment:{$activity->adjustment} isQuote:{$invoice->is_quote} isRecurring:{$invoice->is_recurring}"); $this->info("Incorrect adjustment for new invoice:{$activity->invoice_id} adjustment:{$activity->adjustment} invoiceTypeId:{$invoice->invoice_type_id} isRecurring:{$invoice->is_recurring}");
$foundProblem = true; $foundProblem = true;
$clientFix -= $activity->adjustment; $clientFix -= $activity->adjustment;
$activityFix = 0; $activityFix = 0;
@ -327,19 +335,23 @@ class CheckData extends Command {
} }
} }
/**
* @return array
*/
protected function getArguments() protected function getArguments()
{ {
return array( return [];
//array('example', InputArgument::REQUIRED, 'An example argument.'),
);
} }
/**
* @return array
*/
protected function getOptions() protected function getOptions()
{ {
return array( return [
array('fix', null, InputOption::VALUE_OPTIONAL, 'Fix data', null), ['fix', null, InputOption::VALUE_OPTIONAL, 'Fix data', null],
array('client_id', null, InputOption::VALUE_OPTIONAL, 'Client id', null), ['client_id', null, InputOption::VALUE_OPTIONAL, 'Client id', null],
); ];
} }
} }

View File

@ -1,28 +1,43 @@
<?php namespace App\Console\Commands; <?php namespace App\Console\Commands;
use stdClass;
use Auth; use Auth;
use DB;
use Utils; use Utils;
use Artisan;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Faker\Factory; use Faker\Factory;
use App\Models\User;
use App\Ninja\Repositories\ClientRepository; use App\Ninja\Repositories\ClientRepository;
use App\Ninja\Repositories\InvoiceRepository; use App\Ninja\Repositories\InvoiceRepository;
use App\Ninja\Repositories\PaymentRepository; use App\Ninja\Repositories\PaymentRepository;
use App\Ninja\Repositories\VendorRepository; use App\Ninja\Repositories\VendorRepository;
use App\Ninja\Repositories\ExpenseRepository; use App\Ninja\Repositories\ExpenseRepository;
/**
* Class CreateTestData
*/
class CreateTestData extends Command class CreateTestData extends Command
{ {
//protected $name = 'ninja:create-test-data'; //protected $name = 'ninja:create-test-data';
/**
* @var string
*/
protected $description = 'Create Test Data'; protected $description = 'Create Test Data';
/**
* @var string
*/
protected $signature = 'ninja:create-test-data {count=1}'; protected $signature = 'ninja:create-test-data {count=1}';
/**
* @var
*/
protected $token; protected $token;
/**
* CreateTestData constructor.
* @param ClientRepository $clientRepo
* @param InvoiceRepository $invoiceRepo
* @param PaymentRepository $paymentRepo
* @param VendorRepository $vendorRepo
* @param ExpenseRepository $expenseRepo
*/
public function __construct( public function __construct(
ClientRepository $clientRepo, ClientRepository $clientRepo,
InvoiceRepository $invoiceRepo, InvoiceRepository $invoiceRepo,
@ -41,6 +56,9 @@ class CreateTestData extends Command
$this->expenseRepo = $expenseRepo; $this->expenseRepo = $expenseRepo;
} }
/**
* @return bool
*/
public function fire() public function fire()
{ {
if (Utils::isNinjaProd()) { if (Utils::isNinjaProd()) {
@ -83,6 +101,9 @@ class CreateTestData extends Command
} }
} }
/**
* @param $client
*/
private function createInvoices($client) private function createInvoices($client)
{ {
for ($i=0; $i<$this->count; $i++) { for ($i=0; $i<$this->count; $i++) {
@ -102,7 +123,11 @@ class CreateTestData extends Command
$this->createPayment($client, $invoice); $this->createPayment($client, $invoice);
} }
} }
/**
* @param $client
* @param $invoice
*/
private function createPayment($client, $invoice) private function createPayment($client, $invoice)
{ {
$data = [ $data = [
@ -115,7 +140,7 @@ class CreateTestData extends Command
$this->info('Payment: ' . $payment->amount); $this->info('Payment: ' . $payment->amount);
} }
private function createVendors() private function createVendors()
{ {
for ($i=0; $i<$this->count; $i++) { for ($i=0; $i<$this->count; $i++) {
@ -140,7 +165,10 @@ class CreateTestData extends Command
$this->createExpense($vendor); $this->createExpense($vendor);
} }
} }
/**
* @param $vendor
*/
private function createExpense($vendor) private function createExpense($vendor)
{ {
for ($i=0; $i<$this->count; $i++) { for ($i=0; $i<$this->count; $i++) {
@ -156,17 +184,19 @@ class CreateTestData extends Command
} }
} }
/**
* @return array
*/
protected function getArguments() protected function getArguments()
{ {
return array( return [];
//array('example', InputArgument::REQUIRED, 'An example argument.'),
);
} }
/**
* @return array
*/
protected function getOptions() protected function getOptions()
{ {
return array( return [];
//array('example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null),
);
} }
} }

View File

@ -3,15 +3,22 @@
use File; use File;
use Illuminate\Console\Command; use Illuminate\Console\Command;
/**
* Class GenerateResources
*/
class GenerateResources extends Command class GenerateResources extends Command
{ {
/**
* @var string
*/
protected $name = 'ninja:generate-resources'; protected $name = 'ninja:generate-resources';
/**
* @var string
*/
protected $description = 'Generate Resouces'; protected $description = 'Generate Resouces';
/** /**
* Create a new command instance. * Create a new command instance.
*
* @return void
*/ */
public function __construct() public function __construct()
{ {
@ -25,22 +32,6 @@ class GenerateResources extends Command
*/ */
public function fire() public function fire()
{ {
$langs = [
'da',
'de',
'en',
'es',
'es_ES',
'fr',
'fr_CA',
'it',
'lt',
'nb_NO',
'nl',
'pt_BR',
'sv'
];
$texts = File::getRequire(base_path() . '/resources/lang/en/texts.php'); $texts = File::getRequire(base_path() . '/resources/lang/en/texts.php');
foreach ($texts as $key => $value) { foreach ($texts as $key => $value) {
@ -52,17 +43,19 @@ class GenerateResources extends Command
} }
} }
/**
* @return array
*/
protected function getArguments() protected function getArguments()
{ {
return array( return [];
//array('example', InputArgument::REQUIRED, 'An example argument.'),
);
} }
/**
* @return array
*/
protected function getOptions() protected function getOptions()
{ {
return array( return [];
//array('example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null),
);
} }
} }

View File

@ -3,6 +3,9 @@
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Foundation\Inspiring; use Illuminate\Foundation\Inspiring;
/**
* Class Inspire
*/
class Inspire extends Command { class Inspire extends Command {
/** /**

View File

@ -3,9 +3,19 @@
use DB; use DB;
use Illuminate\Console\Command; use Illuminate\Console\Command;
/**
* Class PruneData
*/
class PruneData extends Command class PruneData extends Command
{ {
/**
* @var string
*/
protected $name = 'ninja:prune-data'; protected $name = 'ninja:prune-data';
/**
* @var string
*/
protected $description = 'Delete inactive accounts'; protected $description = 'Delete inactive accounts';
public function fire() public function fire()
@ -41,17 +51,19 @@ class PruneData extends Command
$this->info('Done'); $this->info('Done');
} }
/**
* @return array
*/
protected function getArguments() protected function getArguments()
{ {
return array( return [];
//array('example', InputArgument::REQUIRED, 'An example argument.'),
);
} }
/**
* @return array
*/
protected function getOptions() protected function getOptions()
{ {
return array( return [];
//array('example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null),
);
} }
} }

View File

@ -4,16 +4,25 @@ use DateTime;
use App\Models\Document; use App\Models\Document;
use Illuminate\Console\Command; use Illuminate\Console\Command;
/**
* Class RemoveOrphanedDocuments
*/
class RemoveOrphanedDocuments extends Command class RemoveOrphanedDocuments extends Command
{ {
/**
* @var string
*/
protected $name = 'ninja:remove-orphaned-documents'; protected $name = 'ninja:remove-orphaned-documents';
/**
* @var string
*/
protected $description = 'Removes old documents not associated with an expense or invoice'; protected $description = 'Removes old documents not associated with an expense or invoice';
public function fire() public function fire()
{ {
$this->info(date('Y-m-d').' Running RemoveOrphanedDocuments...'); $this->info(date('Y-m-d').' Running RemoveOrphanedDocuments...');
$documents = Document::whereRaw('invoice_id IS NULL AND expense_id IS NULL AND updated_at <= ?', array(new DateTime('-1 hour'))) $documents = Document::whereRaw('invoice_id IS NULL AND expense_id IS NULL AND updated_at <= ?', [new DateTime('-1 hour')])
->get(); ->get();
$this->info(count($documents).' orphaned document(s) found'); $this->info(count($documents).' orphaned document(s) found');
@ -25,17 +34,19 @@ class RemoveOrphanedDocuments extends Command
$this->info('Done'); $this->info('Done');
} }
/**
* @return array
*/
protected function getArguments() protected function getArguments()
{ {
return array( return [];
//array('example', InputArgument::REQUIRED, 'An example argument.'),
);
} }
/**
* @return array
*/
protected function getOptions() protected function getOptions()
{ {
return array( return [];
//array('example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null),
);
} }
} }

View File

@ -1,24 +1,35 @@
<?php namespace App\Console\Commands; <?php namespace App\Console\Commands;
use Utils;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
class ResetData extends Command { /**
* Class ResetData
*/
class ResetData extends Command
{
protected $name = 'ninja:reset-data'; /**
protected $description = 'Reset data'; * @var string
*/
protected $name = 'ninja:reset-data';
/**
* @var string
*/
protected $description = 'Reset data';
public function fire() public function fire()
{ {
$this->info(date('Y-m-d') . ' Running ResetData...'); $this->info(date('Y-m-d') . ' Running ResetData...');
if (!Utils::isNinjaDev()) { if (!Utils::isNinjaDev()) {
return; return;
}
Artisan::call('migrate:reset');
Artisan::call('migrate');
Artisan::call('db:seed');
} }
Artisan::call('migrate:reset');
Artisan::call('migrate');
Artisan::call('db:seed');
}
} }

View File

@ -1,30 +1,55 @@
<?php namespace App\Console\Commands; <?php namespace App\Console\Commands;
use DateTime; use DateTime;
use Carbon;
use Utils;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use App\Ninja\Mailers\ContactMailer as Mailer; use App\Ninja\Mailers\ContactMailer as Mailer;
use App\Ninja\Repositories\InvoiceRepository; use App\Ninja\Repositories\InvoiceRepository;
use App\Services\PaymentService;
use App\Models\Invoice; use App\Models\Invoice;
use App\Models\InvoiceItem;
use App\Models\Invitation;
/**
* Class SendRecurringInvoices
*/
class SendRecurringInvoices extends Command class SendRecurringInvoices extends Command
{ {
/**
* @var string
*/
protected $name = 'ninja:send-invoices'; protected $name = 'ninja:send-invoices';
/**
* @var string
*/
protected $description = 'Send recurring invoices'; protected $description = 'Send recurring invoices';
/**
* @var Mailer
*/
protected $mailer; protected $mailer;
/**
* @var InvoiceRepository
*/
protected $invoiceRepo; protected $invoiceRepo;
public function __construct(Mailer $mailer, InvoiceRepository $invoiceRepo) /**
* @var PaymentService
*/
protected $paymentService;
/**
* SendRecurringInvoices constructor.
* @param Mailer $mailer
* @param InvoiceRepository $invoiceRepo
* @param PaymentService $paymentService
*/
public function __construct(Mailer $mailer, InvoiceRepository $invoiceRepo, PaymentService $paymentService)
{ {
parent::__construct(); parent::__construct();
$this->mailer = $mailer; $this->mailer = $mailer;
$this->invoiceRepo = $invoiceRepo; $this->invoiceRepo = $invoiceRepo;
$this->paymentService = $paymentService;
} }
public function fire() public function fire()
@ -33,18 +58,20 @@ class SendRecurringInvoices extends Command
$today = new DateTime(); $today = new DateTime();
$invoices = Invoice::with('account.timezone', 'invoice_items', 'client', 'user') $invoices = Invoice::with('account.timezone', 'invoice_items', 'client', 'user')
->whereRaw('is_deleted IS FALSE AND deleted_at IS NULL AND is_recurring IS TRUE AND frequency_id > 0 AND start_date <= ? AND (end_date IS NULL OR end_date >= ?)', array($today, $today)) ->whereRaw('is_deleted IS FALSE AND deleted_at IS NULL AND is_recurring IS TRUE AND frequency_id > 0 AND start_date <= ? AND (end_date IS NULL OR end_date >= ?)', [$today, $today])
->orderBy('id', 'asc') ->orderBy('id', 'asc')
->get(); ->get();
$this->info(count($invoices).' recurring invoice(s) found'); $this->info(count($invoices).' recurring invoice(s) found');
foreach ($invoices as $recurInvoice) { foreach ($invoices as $recurInvoice) {
if (!$recurInvoice->user->confirmed) { $shouldSendToday = $recurInvoice->shouldSendToday();
$this->info('Processing Invoice '.$recurInvoice->id.' - Should send '.($shouldSendToday ? 'YES' : 'NO'));
if ( ! $shouldSendToday) {
continue; continue;
} }
$recurInvoice->account->loadLocalizationSettings($recurInvoice->client); $recurInvoice->account->loadLocalizationSettings($recurInvoice->client);
$this->info('Processing Invoice '.$recurInvoice->id.' - Should send '.($recurInvoice->shouldSendToday() ? 'YES' : 'NO'));
$invoice = $this->invoiceRepo->createRecurringInvoice($recurInvoice); $invoice = $this->invoiceRepo->createRecurringInvoice($recurInvoice);
if ($invoice && !$invoice->isPaid()) { if ($invoice && !$invoice->isPaid()) {
@ -53,20 +80,42 @@ class SendRecurringInvoices extends Command
} }
} }
$delayedAutoBillInvoices = Invoice::with('account.timezone', 'recurring_invoice', 'invoice_items', 'client', 'user')
->whereRaw('is_deleted IS FALSE AND deleted_at IS NULL AND is_recurring IS FALSE
AND balance > 0 AND due_date = ? AND recurring_invoice_id IS NOT NULL',
[$today->format('Y-m-d')])
->orderBy('invoices.id', 'asc')
->get();
$this->info(count($delayedAutoBillInvoices).' due recurring invoice instance(s) found');
/** @var Invoice $invoice */
foreach ($delayedAutoBillInvoices as $invoice) {
if ($invoice->isPaid()) {
continue;
}
if ($invoice->getAutoBillEnabled() && $invoice->client->autoBillLater()) {
$this->info('Processing Invoice '.$invoice->id.' - Should bill '.($billNow ? 'YES' : 'NO'));
$this->paymentService->autoBillInvoice($invoice);
}
}
$this->info('Done'); $this->info('Done');
} }
/**
* @return array
*/
protected function getArguments() protected function getArguments()
{ {
return array( return [];
//array('example', InputArgument::REQUIRED, 'An example argument.'),
);
} }
/**
* @return array
*/
protected function getOptions() protected function getOptions()
{ {
return array( return [];
//array('example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null),
);
} }
} }

View File

@ -1,23 +1,47 @@
<?php namespace App\Console\Commands; <?php namespace App\Console\Commands;
use DB; use App\Models\Invoice;
use DateTime;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use App\Models\Account;
use App\Ninja\Mailers\ContactMailer as Mailer; use App\Ninja\Mailers\ContactMailer as Mailer;
use App\Ninja\Repositories\accountRepository; use App\Ninja\Repositories\AccountRepository;
use App\Ninja\Repositories\InvoiceRepository; use App\Ninja\Repositories\InvoiceRepository;
/**
* Class SendReminders
*/
class SendReminders extends Command class SendReminders extends Command
{ {
/**
* @var string
*/
protected $name = 'ninja:send-reminders'; protected $name = 'ninja:send-reminders';
/**
* @var string
*/
protected $description = 'Send reminder emails'; protected $description = 'Send reminder emails';
/**
* @var Mailer
*/
protected $mailer; protected $mailer;
/**
* @var InvoiceRepository
*/
protected $invoiceRepo; protected $invoiceRepo;
/**
* @var accountRepository
*/
protected $accountRepo; protected $accountRepo;
/**
* SendReminders constructor.
* @param Mailer $mailer
* @param InvoiceRepository $invoiceRepo
* @param accountRepository $accountRepo
*/
public function __construct(Mailer $mailer, InvoiceRepository $invoiceRepo, AccountRepository $accountRepo) public function __construct(Mailer $mailer, InvoiceRepository $invoiceRepo, AccountRepository $accountRepo)
{ {
parent::__construct(); parent::__construct();
@ -29,20 +53,21 @@ class SendReminders extends Command
public function fire() public function fire()
{ {
$this->info(date('Y-m-d').' Running SendReminders...'); $this->info(date('Y-m-d') . ' Running SendReminders...');
$today = new DateTime();
$accounts = $this->accountRepo->findWithReminders(); $accounts = $this->accountRepo->findWithReminders();
$this->info(count($accounts).' accounts found'); $this->info(count($accounts) . ' accounts found');
/** @var \App\Models\Account $account */
foreach ($accounts as $account) { foreach ($accounts as $account) {
if (!$account->hasFeature(FEATURE_EMAIL_TEMPLATES_REMINDERS)) { if (!$account->hasFeature(FEATURE_EMAIL_TEMPLATES_REMINDERS)) {
continue; continue;
} }
$invoices = $this->invoiceRepo->findNeedingReminding($account); $invoices = $this->invoiceRepo->findNeedingReminding($account);
$this->info($account->name . ': ' . count($invoices).' invoices found'); $this->info($account->name . ': ' . count($invoices) . ' invoices found');
/** @var Invoice $invoice */
foreach ($invoices as $invoice) { foreach ($invoices as $invoice) {
if ($reminder = $account->getInvoiceReminder($invoice)) { if ($reminder = $account->getInvoiceReminder($invoice)) {
$this->info('Send to ' . $invoice->id); $this->info('Send to ' . $invoice->id);
@ -54,17 +79,19 @@ class SendReminders extends Command
$this->info('Done'); $this->info('Done');
} }
/**
* @return array
*/
protected function getArguments() protected function getArguments()
{ {
return array( return [];
//array('example', InputArgument::REQUIRED, 'An example argument.'),
);
} }
/**
* @return array
*/
protected function getOptions() protected function getOptions()
{ {
return array( return [];
//array('example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null),
);
} }
} }

View File

@ -1,21 +1,42 @@
<?php namespace App\Console\Commands; <?php namespace App\Console\Commands;
use DB; use Utils;
use DateTime;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use App\Models\Company; use App\Models\Company;
use App\Ninja\Mailers\ContactMailer as Mailer; use App\Ninja\Mailers\ContactMailer as Mailer;
use App\Ninja\Repositories\AccountRepository; use App\Ninja\Repositories\AccountRepository;
/**
* Class SendRenewalInvoices
*/
class SendRenewalInvoices extends Command class SendRenewalInvoices extends Command
{ {
/**
* @var string
*/
protected $name = 'ninja:send-renewals'; protected $name = 'ninja:send-renewals';
/**
* @var string
*/
protected $description = 'Send renewal invoices'; protected $description = 'Send renewal invoices';
/**
* @var Mailer
*/
protected $mailer; protected $mailer;
/**
* @var AccountRepository
*/
protected $accountRepo; protected $accountRepo;
/**
* SendRenewalInvoices constructor.
*
* @param Mailer $mailer
* @param AccountRepository $repo
*/
public function __construct(Mailer $mailer, AccountRepository $repo) public function __construct(Mailer $mailer, AccountRepository $repo)
{ {
parent::__construct(); parent::__construct();
@ -27,8 +48,6 @@ class SendRenewalInvoices extends Command
public function fire() public function fire()
{ {
$this->info(date('Y-m-d').' Running SendRenewalInvoices...'); $this->info(date('Y-m-d').' Running SendRenewalInvoices...');
$today = new DateTime();
$sentTo = [];
// get all accounts with plans expiring in 10 days // get all accounts with plans expiring in 10 days
$companies = Company::whereRaw('datediff(plan_expires, curdate()) = 10') $companies = Company::whereRaw('datediff(plan_expires, curdate()) = 10')
@ -40,28 +59,36 @@ class SendRenewalInvoices extends Command
if (!count($company->accounts)) { if (!count($company->accounts)) {
continue; continue;
} }
$account = $company->accounts->sortBy('id')->first(); $account = $company->accounts->sortBy('id')->first();
$plan = $company->plan; $plan = [];
$term = $company->plan_term; $plan['plan'] = $company->plan;
$plan['term'] = $company->plan_term;
$plan['num_users'] = $company->num_users;
$plan['price'] = min($company->plan_price, Utils::getPlanPrice($plan));
if ($company->pending_plan) { if ($company->pending_plan) {
$plan = $company->pending_plan; $plan['plan'] = $company->pending_plan;
$term = $company->pending_term; $plan['term'] = $company->pending_term;
$plan['num_users'] = $company->pending_num_users;
$plan['price'] = min($company->pending_plan_price, Utils::getPlanPrice($plan));
} }
if ($plan == PLAN_FREE || !$plan || !$term ){ if ($plan['plan'] == PLAN_FREE || !$plan['plan'] || !$plan['term'] || !$plan['price']){
continue; continue;
} }
$client = $this->accountRepo->getNinjaClient($account); $client = $this->accountRepo->getNinjaClient($account);
$invitation = $this->accountRepo->createNinjaInvoice($client, $account, $plan, $term); $invitation = $this->accountRepo->createNinjaInvoice($client, $account, $plan, 0, false);
// set the due date to 10 days from now // set the due date to 10 days from now
$invoice = $invitation->invoice; $invoice = $invitation->invoice;
$invoice->due_date = date('Y-m-d', strtotime('+ 10 days')); $invoice->due_date = date('Y-m-d', strtotime('+ 10 days'));
$invoice->save(); $invoice->save();
$term = $plan['term'];
$plan = $plan['plan'];
if ($term == PLAN_TERM_YEARLY) { if ($term == PLAN_TERM_YEARLY) {
$this->mailer->sendInvoice($invoice); $this->mailer->sendInvoice($invoice);
$this->info("Sent {$term}ly {$plan} invoice to {$client->getDisplayName()}"); $this->info("Sent {$term}ly {$plan} invoice to {$client->getDisplayName()}");
@ -73,17 +100,19 @@ class SendRenewalInvoices extends Command
$this->info('Done'); $this->info('Done');
} }
/**
* @return array
*/
protected function getArguments() protected function getArguments()
{ {
return array( return [];
//array('example', InputArgument::REQUIRED, 'An example argument.'),
);
} }
/**
* @return array
*/
protected function getOptions() protected function getOptions()
{ {
return array( return [];
//array('example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null),
);
} }
} }

View File

@ -3,11 +3,31 @@
use Illuminate\Console\Command; use Illuminate\Console\Command;
use App\Services\BankAccountService; use App\Services\BankAccountService;
/**
* Class TestOFX
*/
class TestOFX extends Command class TestOFX extends Command
{ {
/**
* @var string
*/
protected $name = 'ninja:test-ofx'; protected $name = 'ninja:test-ofx';
/**
* @var string
*/
protected $description = 'Test OFX'; protected $description = 'Test OFX';
/**
* @var BankAccountService
*/
protected $bankAccountService;
/**
* TestOFX constructor.
*
* @param BankAccountService $bankAccountService
*/
public function __construct(BankAccountService $bankAccountService) public function __construct(BankAccountService $bankAccountService)
{ {
parent::__construct(); parent::__construct();
@ -18,15 +38,5 @@ class TestOFX extends Command
public function fire() public function fire()
{ {
$this->info(date('Y-m-d').' Running TestOFX...'); $this->info(date('Y-m-d').' Running TestOFX...');
/*
$bankId = env('TEST_BANK_ID');
$username = env('TEST_BANK_USERNAME');
$password = env('TEST_BANK_PASSWORD');
$data = $this->bankAccountService->loadBankAccounts($bankId, $username, $password, false);
echo json_encode($data);
*/
} }
} }

View File

@ -1,20 +1,26 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event; use App\Models\Client;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
/**
* Class ClientWasArchived
*/
class ClientWasArchived extends Event class ClientWasArchived extends Event
{ {
use SerializesModels; use SerializesModels;
/**
* @var Client
*/
public $client; public $client;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param Client $client
*/ */
public function __construct($client) public function __construct(Client $client)
{ {
$this->client = $client; $this->client = $client;
} }

View File

@ -1,20 +1,26 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event; use App\Models\Client;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
/**
* Class ClientWasCreated
*/
class ClientWasCreated extends Event class ClientWasCreated extends Event
{ {
use SerializesModels; use SerializesModels;
/**
* @var Client
*/
public $client; public $client;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param Client $client
*/ */
public function __construct($client) public function __construct(Client $client)
{ {
$this->client = $client; $this->client = $client;
} }

View File

@ -1,20 +1,26 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event; use App\Models\Client;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
/**
* Class ClientWasDeleted
*/
class ClientWasDeleted extends Event class ClientWasDeleted extends Event
{ {
use SerializesModels; use SerializesModels;
/**
* @var Client
*/
public $client; public $client;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param Client $client
*/ */
public function __construct($client) public function __construct(Client $client)
{ {
$this->client = $client; $this->client = $client;
} }

View File

@ -1,20 +1,26 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event; use App\Models\Client;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
/**
* Class ClientWasRestored
*/
class ClientWasRestored extends Event class ClientWasRestored extends Event
{ {
use SerializesModels; use SerializesModels;
/**
* @var Client
*/
public $client; public $client;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param Client $client
*/ */
public function __construct($client) public function __construct(Client $client)
{ {
$this->client = $client; $this->client = $client;
} }

View File

@ -1,20 +1,26 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event; use App\Models\Client;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
/**
* Class ClientWasUpdated
*/
class ClientWasUpdated extends Event class ClientWasUpdated extends Event
{ {
use SerializesModels; use SerializesModels;
/**
* @var Client
*/
public $client; public $client;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param Client $client
*/ */
public function __construct($client) public function __construct(Client $client)
{ {
$this->client = $client; $this->client = $client;
} }

View File

@ -1,23 +1,30 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event;
use App\Models\Client;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
class CreditWasArchived extends Event { /**
* Class CreditWasArchived
*/
class CreditWasArchived extends Event
{
use SerializesModels; use SerializesModels;
/**
* @var Client
*/
public $credit; public $credit;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param Client $credit
*/ */
public function __construct($credit) public function __construct(Client $credit)
{ {
$this->credit = $credit; $this->credit = $credit;
} }
} }

View File

@ -1,21 +1,24 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event; use App\Models\Credit;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
class CreditWasCreated extends Event { class CreditWasCreated extends Event
{
use SerializesModels; use SerializesModels;
/**
* @var Credit
*/
public $credit; public $credit;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param Credit $credit
*/ */
public function __construct($credit) public function __construct(Credit $credit)
{ {
$this->credit = $credit; $this->credit = $credit;
} }

View File

@ -1,21 +1,26 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event; use App\Models\Credit;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
/**
* Class CreditWasDeleted
*/
class CreditWasDeleted extends Event { class CreditWasDeleted extends Event {
use SerializesModels; use SerializesModels;
/**
* @var Credit
*/
public $credit; public $credit;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param Credit $credit
*/ */
public function __construct($credit) public function __construct(Credit $credit)
{ {
$this->credit = $credit; $this->credit = $credit;
} }

View File

@ -1,21 +1,27 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event;
use App\Models\Credit;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
/**
* Class CreditWasRestored
*/
class CreditWasRestored extends Event { class CreditWasRestored extends Event {
use SerializesModels; use SerializesModels;
/**
* @var Credit
*/
public $credit; public $credit;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param Credit $credit
*/ */
public function __construct($credit) public function __construct(Credit $credit)
{ {
$this->credit = $credit; $this->credit = $credit;
} }

View File

@ -1,7 +1,5 @@
<?php namespace App\Events; <?php namespace App\Events;
abstract class Event { abstract class Event
{
//
} }

View File

@ -1,22 +1,28 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event; use App\Models\Expense;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
/**
* Class ExpenseWasArchived
*/
class ExpenseWasArchived extends Event class ExpenseWasArchived extends Event
{ {
use SerializesModels; use SerializesModels;
/**
* @var Expense
*/
public $expense; public $expense;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param Expense $expense
*/ */
public function __construct($expense) public function __construct(Expense $expense)
{ {
$this->expense = $expense; $this->expense = $expense;
} }
} }

View File

@ -1,20 +1,26 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event; use App\Models\Expense;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
/**
* Class ExpenseWasCreated
*/
class ExpenseWasCreated extends Event class ExpenseWasCreated extends Event
{ {
use SerializesModels; use SerializesModels;
/**
* @var Expense
*/
public $expense; public $expense;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param Expense $expense
*/ */
public function __construct($expense) public function __construct(Expense $expense)
{ {
$this->expense = $expense; $this->expense = $expense;
} }

View File

@ -1,21 +1,26 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event; use App\Models\Expense;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
class ExpenseWasDeleted extends Event { /**
// Expenses * Class ExpenseWasDeleted
use SerializesModels; */
class ExpenseWasDeleted extends Event
{
use SerializesModels;
/**
* @var Expense
*/
public $expense; public $expense;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param Expense $expense
*/ */
public function __construct($expense) public function __construct(Expense $expense)
{ {
$this->expense = $expense; $this->expense = $expense;
} }

View File

@ -1,21 +1,27 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event;
use App\Models\Expense;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
class ExpenseWasRestored extends Event { /**
// Expenses * Class ExpenseWasRestored
use SerializesModels; */
class ExpenseWasRestored extends Event
{
use SerializesModels;
/**
* @var Expense
*/
public $expense; public $expense;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param Expense $expense
*/ */
public function __construct($expense) public function __construct(Expense $expense)
{ {
$this->expense = $expense; $this->expense = $expense;
} }

View File

@ -1,20 +1,26 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event; use App\Models\Expense;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
/**
* Class ExpenseWasUpdated
*/
class ExpenseWasUpdated extends Event class ExpenseWasUpdated extends Event
{ {
use SerializesModels; use SerializesModels;
/**
* @var Expense
*/
public $expense; public $expense;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param Expense $expense
*/ */
public function __construct($expense) public function __construct(Expense $expense)
{ {
$this->expense = $expense; $this->expense = $expense;
} }

View File

@ -1,21 +1,28 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event;
use App\Models\Invitation;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
class InvoiceInvitationWasEmailed extends Event { /**
* Class InvoiceInvitationWasEmailed
*/
class InvoiceInvitationWasEmailed extends Event
{
use SerializesModels; use SerializesModels;
/**
* @var Invitation
*/
public $invitation; public $invitation;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param Invitation $invitation
*/ */
public function __construct($invitation) public function __construct(Invitation $invitation)
{ {
$this->invitation = $invitation; $this->invitation = $invitation;
} }

View File

@ -1,25 +1,35 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event; use App\Models\Invitation;
use App\Models\Invoice;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
/**
* Class InvoiceInvitationWasViewed
*/
class InvoiceInvitationWasViewed extends Event { class InvoiceInvitationWasViewed extends Event {
use SerializesModels; use SerializesModels;
/**
* @var Invoice
*/
public $invoice; public $invoice;
/**
* @var Invitation
*/
public $invitation; public $invitation;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param Invoice $invoice
*/ * @param Invitation $invitation
public function __construct($invoice, $invitation) */
public function __construct(Invoice $invoice, Invitation $invitation)
{ {
$this->invoice = $invoice; $this->invoice = $invoice;
$this->invitation = $invitation; $this->invitation = $invitation;
} }
} }

View File

@ -1,20 +1,26 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event; use App\Models\Invoice;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
class InvoiceWasArchived extends Event { /**
* Class InvoiceWasArchived
*/
class InvoiceWasArchived extends Event
{
use SerializesModels;
use SerializesModels; /**
* @var Invoice
*/
public $invoice; public $invoice;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param Invoice $invoice
*/ */
public function __construct($invoice) public function __construct(Invoice $invoice)
{ {
$this->invoice = $invoice; $this->invoice = $invoice;
} }

View File

@ -1,20 +1,26 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event; use App\Models\Invoice;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
class InvoiceWasCreated extends Event { /**
* Class InvoiceWasCreated
*/
class InvoiceWasCreated extends Event
{
use SerializesModels;
use SerializesModels; /**
* @var Invoice
*/
public $invoice; public $invoice;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param Invoice $invoice
*/ */
public function __construct($invoice) public function __construct(Invoice $invoice)
{ {
$this->invoice = $invoice; $this->invoice = $invoice;
} }

View File

@ -1,22 +1,27 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event; use App\Models\Invoice;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
class InvoiceWasDeleted extends Event { /**
* Class InvoiceWasDeleted
*/
class InvoiceWasDeleted extends Event
{
use SerializesModels;
use SerializesModels; /**
* @var Invoice
*/
public $invoice; public $invoice;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param Invoice $invoice
*/ */
public function __construct($invoice) public function __construct(Invoice $invoice)
{ {
$this->invoice = $invoice; $this->invoice = $invoice;
} }
} }

View File

@ -1,22 +1,27 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event; use App\Models\Invoice;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
class InvoiceWasEmailed extends Event { /**
* Class InvoiceWasEmailed
*/
class InvoiceWasEmailed extends Event
{
use SerializesModels;
use SerializesModels; /**
* @var Invoice
*/
public $invoice; public $invoice;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param Invoice $invoice
*/ */
public function __construct($invoice) public function __construct(Invoice $invoice)
{ {
$this->invoice = $invoice; $this->invoice = $invoice;
} }
} }

View File

@ -1,22 +1,30 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event;
use App\Models\Invoice;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
class InvoiceWasRestored extends Event { /**
* Class InvoiceWasRestored
use SerializesModels; */
class InvoiceWasRestored extends Event
{
use SerializesModels;
/**
* @var Invoice
*/
public $invoice; public $invoice;
public $fromDeleted; public $fromDeleted;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param Invoice $invoice
*/ * @param $fromDeleted
public function __construct($invoice, $fromDeleted) */
public function __construct(Invoice $invoice, $fromDeleted)
{ {
$this->invoice = $invoice; $this->invoice = $invoice;
$this->fromDeleted = $fromDeleted; $this->fromDeleted = $fromDeleted;

View File

@ -1,22 +1,27 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event; use App\Models\Invoice;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
class InvoiceWasUpdated extends Event { /**
* Class InvoiceWasUpdated
*/
class InvoiceWasUpdated extends Event
{
use SerializesModels;
use SerializesModels; /**
* @var Invoice
*/
public $invoice; public $invoice;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param Invoice $invoice
*/ */
public function __construct($invoice) public function __construct(Invoice $invoice)
{ {
$this->invoice = $invoice; $this->invoice = $invoice;
} }
} }

View File

@ -0,0 +1,28 @@
<?php namespace App\Events;
use App\Models\Payment;
use Illuminate\Queue\SerializesModels;
/**
* Class PaymentCompleted
*/
class PaymentCompleted extends Event
{
use SerializesModels;
/**
* @var Payment
*/
public $payment;
/**
* Create a new event instance.
*
* @param Payment $payment
*/
public function __construct(Payment $payment)
{
$this->payment = $payment;
}
}

View File

@ -0,0 +1,27 @@
<?php namespace App\Events;
use App\Models\Payment;
use Illuminate\Queue\SerializesModels;
/**
* Class PaymentFailed
*/
class PaymentFailed extends Event
{
use SerializesModels;
/**
* @var Payment
*/
public $payment;
/**
* Create a new event instance.
*
* @param Payment $payment
*/
public function __construct(Payment $payment)
{
$this->payment = $payment;
}
}

View File

@ -1,22 +1,28 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event; use App\Models\Payment;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
class PaymentWasArchived extends Event { /**
* Class PaymentWasArchived
*/
class PaymentWasArchived extends Event
{
use SerializesModels;
use SerializesModels; /**
* @var Payment
*/
public $payment; public $payment;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param Payment $payment
*/ */
public function __construct($payment) public function __construct(Payment $payment)
{ {
$this->payment = $payment; $this->payment = $payment;
} }
} }

View File

@ -1,22 +1,27 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event; use App\Models\Payment;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
class PaymentWasCreated extends Event { /**
* Class PaymentWasCreated
*/
class PaymentWasCreated extends Event
{
use SerializesModels; use SerializesModels;
/**
* @var Payment
*/
public $payment; public $payment;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param Payment $payment
*/ */
public function __construct($payment) public function __construct(Payment $payment)
{ {
$this->payment = $payment; $this->payment = $payment;
} }
} }

View File

@ -1,22 +1,29 @@
<?php namespace App\Events; <?php
use App\Events\Event; namespace App\Events;
use App\Models\Payment;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
class PaymentWasDeleted extends Event { /**
* Class PaymentWasDeleted.
*/
class PaymentWasDeleted extends Event
{
use SerializesModels; use SerializesModels;
/**
* @var Payment
*/
public $payment; public $payment;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param Payment $payment
*/ */
public function __construct($payment) public function __construct(Payment $payment)
{ {
$this->payment = $payment; $this->payment = $payment;
} }
} }

View File

@ -0,0 +1,31 @@
<?php namespace App\Events;
use App\Models\Payment;
use Illuminate\Queue\SerializesModels;
/**
* Class PaymentWasRefunded
*/
class PaymentWasRefunded extends Event
{
use SerializesModels;
/**
* @var Payment
*/
public $payment;
public $refundAmount;
/**
* Create a new event instance.
*
* @param Payment $payment
* @param $refundAmount
*/
public function __construct(Payment $payment, $refundAmount)
{
$this->payment = $payment;
$this->refundAmount = $refundAmount;
}
}

View File

@ -1,25 +1,30 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event; use App\Models\Payment;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
class PaymentWasRestored extends Event { /**
* Class PaymentWasRestored
use SerializesModels; */
class PaymentWasRestored extends Event
{
use SerializesModels;
/**
* @var Payment
*/
public $payment; public $payment;
public $fromDeleted; public $fromDeleted;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param Payment $payment
*/ * @param $fromDeleted
public function __construct($payment, $fromDeleted) */
public function __construct(Payment $payment, $fromDeleted)
{ {
$this->payment = $payment; $this->payment = $payment;
$this->fromDeleted = $fromDeleted; $this->fromDeleted = $fromDeleted;
} }
} }

View File

@ -0,0 +1,27 @@
<?php namespace App\Events;
use App\Models\Payment;
use Illuminate\Queue\SerializesModels;
/**
* Class PaymentWasVoided
*/
class PaymentWasVoided extends Event
{
use SerializesModels;
/**
* @var Payment
*/
public $payment;
/**
* Create a new event instance.
*
* @param Payment $payment
*/
public function __construct(Payment $payment)
{
$this->payment = $payment;
}
}

View File

@ -1,27 +1,37 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event;
use App\Models\Invitation;
use App\Models\Invoice;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
class QuoteInvitationWasApproved extends Event { class QuoteInvitationWasApproved extends Event
{
use SerializesModels; use SerializesModels;
public $quote; public $quote;
/**
* @var Invoice
*/
public $invoice; public $invoice;
/**
* @var Invitation
*/
public $invitation; public $invitation;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param $quote
*/ * @param Invoice $invoice
public function __construct($quote, $invoice, $invitation) * @param Invitation $invitation
*/
public function __construct($quote, Invoice $invoice, Invitation $invitation)
{ {
$this->quote = $quote; $this->quote = $quote;
$this->invoice = $invoice; $this->invoice = $invoice;
$this->invitation = $invitation; $this->invitation = $invitation;
} }
} }

View File

@ -1,21 +1,26 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event; use App\Models\Invitation;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
class QuoteInvitationWasEmailed extends Event { /**
* Class QuoteInvitationWasEmailed
use SerializesModels; */
class QuoteInvitationWasEmailed extends Event
{
use SerializesModels;
/**
* @var Invitation
*/
public $invitation; public $invitation;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param Invitation $invitation
*/ */
public function __construct($invitation) public function __construct(Invitation $invitation)
{ {
$this->invitation = $invitation; $this->invitation = $invitation;
} }

View File

@ -1,25 +1,31 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event; use App\Models\Invitation;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
class QuoteInvitationWasViewed extends Event { /**
* Class QuoteInvitationWasViewed
*/
class QuoteInvitationWasViewed extends Event
{
use SerializesModels; use SerializesModels;
public $quote; public $quote;
/**
* @var Invitation
*/
public $invitation; public $invitation;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param $quote
*/ * @param Invitation $invitation
public function __construct($quote, $invitation) */
public function __construct($quote, Invitation $invitation)
{ {
$this->quote = $quote; $this->quote = $quote;
$this->invitation = $invitation; $this->invitation = $invitation;
} }
} }

View File

@ -1,22 +1,20 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
class QuoteWasArchived extends Event { class QuoteWasArchived extends Event
{
use SerializesModels; use SerializesModels;
public $quote; public $quote;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param $quote
*/ */
public function __construct($quote) public function __construct($quote)
{ {
$this->quote = $quote; $this->quote = $quote;
} }
} }

View File

@ -1,22 +1,22 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
class QuoteWasCreated extends Event { /**
* Class QuoteWasCreated
use SerializesModels; */
class QuoteWasCreated extends Event
{
use SerializesModels;
public $quote; public $quote;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param $quote
*/ */
public function __construct($quote) public function __construct($quote)
{ {
$this->quote = $quote; $this->quote = $quote;
} }
} }

View File

@ -1,22 +1,22 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
class QuoteWasDeleted extends Event { /**
* Class QuoteWasDeleted
use SerializesModels; */
class QuoteWasDeleted extends Event
{
use SerializesModels;
public $quote; public $quote;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param $quote
*/ */
public function __construct($quote) public function __construct($quote)
{ {
$this->quote = $quote; $this->quote = $quote;
} }
} }

View File

@ -1,22 +1,22 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
class QuoteWasEmailed extends Event { /**
* Class QuoteWasEmailed
use SerializesModels; */
class QuoteWasEmailed extends Event
{
use SerializesModels;
public $quote; public $quote;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param $quote
*/ */
public function __construct($quote) public function __construct($quote)
{ {
$this->quote = $quote; $this->quote = $quote;
} }
} }

View File

@ -1,22 +1,22 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
class QuoteWasRestored extends Event { /**
* Class QuoteWasRestored
use SerializesModels; */
class QuoteWasRestored extends Event
{
use SerializesModels;
public $quote; public $quote;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param $quote
*/ */
public function __construct($quote) public function __construct($quote)
{ {
$this->quote = $quote; $this->quote = $quote;
} }
} }

View File

@ -1,22 +1,23 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
class QuoteWasUpdated extends Event { /**
* Class QuoteWasUpdated
use SerializesModels; */
class QuoteWasUpdated extends Event
{
use SerializesModels;
public $quote; public $quote;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param $quote
*/ */
public function __construct($quote) public function __construct($quote)
{ {
$this->quote = $quote; $this->quote = $quote;
} }
} }

View File

@ -0,0 +1,28 @@
<?php namespace App\Events;
use App\Models\Task;
use Illuminate\Queue\SerializesModels;
/**
* Class TaskWasCreated
*/
class TaskWasCreated extends Event
{
use SerializesModels;
/**
* @var Task
*/
public $task;
/**
* Create a new event instance.
*
* @param Task $task
*/
public function __construct(Task $task)
{
$this->task = $task;
}
}

View File

@ -0,0 +1,28 @@
<?php namespace App\Events;
use App\Models\Task;
use Illuminate\Queue\SerializesModels;
/**
* Class TaskWasUpdated
*/
class TaskWasUpdated extends Event
{
use SerializesModels;
/**
* @var Task
*/
public $task;
/**
* Create a new event instance.
*
* @param Task $task
*/
public function __construct(Task $task)
{
$this->task = $task;
}
}

View File

@ -1,21 +1,18 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
class UserLoggedIn extends Event { /**
* Class UserLoggedIn
use SerializesModels; */
class UserLoggedIn extends Event
/** {
* Create a new event instance. use SerializesModels;
*
* @return void
*/
public function __construct()
{
//
}
/**
* UserLoggedIn constructor.
*/
public function __construct()
{
}
} }

View File

@ -1,23 +1,24 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event; use App\Models\User;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
class UserSettingsChanged extends Event { class UserSettingsChanged extends Event
{
use SerializesModels; use SerializesModels;
/**
* @var User
*/
public $user; public $user;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param User $user
*/ */
public function __construct($user = false) public function __construct(User $user = null)
{ {
$this->user = $user; $this->user = $user;
} }
} }

View File

@ -1,21 +1,18 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
class UserSignedUp extends Event { /**
* Class UserSignedUp
use SerializesModels; */
class UserSignedUp extends Event
/** {
* Create a new event instance. use SerializesModels;
*
* @return void
*/
public function __construct()
{
//
}
/**
* Create a new event instance.
*/
public function __construct()
{
}
} }

View File

@ -1,21 +1,27 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event; use App\Models\Vendor;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
/**
* Class VendorWasArchived
*/
class VendorWasArchived extends Event class VendorWasArchived extends Event
{ {
// vendor // vendor
use SerializesModels; use SerializesModels;
/**
* @var Vendor
*/
public $vendor; public $vendor;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param Vendor $vendor
*/ */
public function __construct($vendor) public function __construct(Vendor $vendor)
{ {
$this->vendor = $vendor; $this->vendor = $vendor;
} }

View File

@ -1,21 +1,26 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event; use App\Models\Vendor;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
/**
* Class VendorWasCreated
*/
class VendorWasCreated extends Event class VendorWasCreated extends Event
{ {
// vendor
use SerializesModels; use SerializesModels;
/**
* @var Vendor
*/
public $vendor; public $vendor;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param Vendor $vendor
*/ */
public function __construct($vendor) public function __construct(Vendor $vendor)
{ {
$this->vendor = $vendor; $this->vendor = $vendor;
} }

View File

@ -1,21 +1,26 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event; use App\Models\Vendor;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
/**
* Class VendorWasDeleted
*/
class VendorWasDeleted extends Event class VendorWasDeleted extends Event
{ {
// vendor
use SerializesModels; use SerializesModels;
/**
* @var Vendor
*/
public $vendor; public $vendor;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param Vendor $vendor
*/ */
public function __construct($vendor) public function __construct(Vendor $vendor)
{ {
$this->vendor = $vendor; $this->vendor = $vendor;
} }

View File

@ -1,21 +1,26 @@
<?php namespace App\Events; <?php namespace App\Events;
use App\Events\Event; use App\Models\Vendor;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
/**
* Class VendorWasRestored
*/
class VendorWasRestored extends Event class VendorWasRestored extends Event
{ {
// vendor
use SerializesModels; use SerializesModels;
/**
* @var Vendor
*/
public $vendor; public $vendor;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param Vendor $vendor
*/ */
public function __construct($vendor) public function __construct(Vendor $vendor)
{ {
$this->vendor = $vendor; $this->vendor = $vendor;
} }

View File

@ -1,20 +1,26 @@
<?php namespace App\Events; <?php namespace App\Events;
// vendor
use App\Events\Event; use App\Models\Vendor;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
/**
* Class VendorWasUpdated
*/
class VendorWasUpdated extends Event class VendorWasUpdated extends Event
{ {
use SerializesModels; use SerializesModels;
/**
* @var Vendor
*/
public $vendor; public $vendor;
/** /**
* Create a new event instance. * Create a new event instance.
* *
* @return void * @param Vendor $vendor
*/ */
public function __construct($vendor) public function __construct(Vendor $vendor)
{ {
$this->vendor = $vendor; $this->vendor = $vendor;
} }

View File

@ -4,13 +4,17 @@ use Redirect;
use Utils; use Utils;
use Exception; use Exception;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Http\Exception\HttpResponseException; use Illuminate\Http\Exception\HttpResponseException;
use Illuminate\Auth\Access\AuthorizationException; use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Database\Eloquent\ModelNotFoundException;
use Symfony\Component\HttpKernel\Exception\HttpException; use Symfony\Component\HttpKernel\Exception\HttpException;
use Illuminate\Foundation\Validation\ValidationException; use Illuminate\Validation\ValidationException;
class Handler extends ExceptionHandler { /**
* Class Handler
*/
class Handler extends ExceptionHandler
{
/** /**
* A list of the exception types that should not be reported. * A list of the exception types that should not be reported.
@ -24,14 +28,14 @@ class Handler extends ExceptionHandler {
ValidationException::class, ValidationException::class,
]; ];
/** /**
* Report or log an exception. * Report or log an exception.
* *
* This is a great spot to send exceptions to Sentry, Bugsnag, etc. * This is a great spot to send exceptions to Sentry, Bugsnag, etc.
* *
* @param \Exception $e * @param \Exception $e
* @return void * @return bool|void
*/ */
public function report(Exception $e) public function report(Exception $e)
{ {
// don't show these errors in the logs // don't show these errors in the logs

View File

@ -3,22 +3,12 @@
use Auth; use Auth;
use Utils; use Utils;
use Response; use Response;
use Input;
use Validator;
use Cache; use Cache;
use App\Models\Client;
use App\Models\Account; use App\Models\Account;
use App\Models\AccountToken;
use App\Ninja\Repositories\AccountRepository; use App\Ninja\Repositories\AccountRepository;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use League\Fractal;
use League\Fractal\Manager;
use App\Ninja\Serializers\ArraySerializer;
use App\Ninja\Transformers\AccountTransformer; use App\Ninja\Transformers\AccountTransformer;
use App\Ninja\Transformers\UserAccountTransformer; use App\Ninja\Transformers\UserAccountTransformer;
use App\Http\Controllers\BaseAPIController;
use Swagger\Annotations as SWG;
use App\Events\UserSignedUp; use App\Events\UserSignedUp;
use App\Http\Requests\RegisterRequest; use App\Http\Requests\RegisterRequest;
use App\Http\Requests\UpdateAccountRequest; use App\Http\Requests\UpdateAccountRequest;
@ -183,8 +173,6 @@ class AccountApiController extends BaseAPIController
'notify_paid' => $request->notify_paid, 'notify_paid' => $request->notify_paid,
]; ];
//unset($devices[$x]);
$devices[$x] = $newDevice; $devices[$x] = $newDevice;
$account->devices = json_encode($devices); $account->devices = json_encode($devices);
$account->save(); $account->save();

View File

@ -1,5 +1,7 @@
<?php namespace App\Http\Controllers; <?php namespace App\Http\Controllers;
use App\Models\AccountGateway;
use App\Services\TemplateService;
use Auth; use Auth;
use File; use File;
use Image; use Image;
@ -32,21 +34,55 @@ use App\Events\UserSignedUp;
use App\Events\UserSettingsChanged; use App\Events\UserSettingsChanged;
use App\Services\AuthService; use App\Services\AuthService;
use App\Services\PaymentService; use App\Services\PaymentService;
use App\Http\Requests\UpdateAccountRequest; use App\Http\Requests\UpdateAccountRequest;
/**
* Class AccountController
*/
class AccountController extends BaseController class AccountController extends BaseController
{ {
/**
* @var AccountRepository
*/
protected $accountRepo; protected $accountRepo;
/**
* @var UserMailer
*/
protected $userMailer; protected $userMailer;
/**
* @var ContactMailer
*/
protected $contactMailer; protected $contactMailer;
/**
* @var ReferralRepository
*/
protected $referralRepository; protected $referralRepository;
/**
* @var PaymentService
*/
protected $paymentService; protected $paymentService;
public function __construct(AccountRepository $accountRepo, UserMailer $userMailer, ContactMailer $contactMailer, ReferralRepository $referralRepository, PaymentService $paymentService) /**
* AccountController constructor.
*
* @param AccountRepository $accountRepo
* @param UserMailer $userMailer
* @param ContactMailer $contactMailer
* @param ReferralRepository $referralRepository
* @param PaymentService $paymentService
*/
public function __construct(
AccountRepository $accountRepo,
UserMailer $userMailer,
ContactMailer $contactMailer,
ReferralRepository $referralRepository,
PaymentService $paymentService
)
{ {
//parent::__construct();
$this->accountRepo = $accountRepo; $this->accountRepo = $accountRepo;
$this->userMailer = $userMailer; $this->userMailer = $userMailer;
$this->contactMailer = $contactMailer; $this->contactMailer = $contactMailer;
@ -54,6 +90,9 @@ class AccountController extends BaseController
$this->paymentService = $paymentService; $this->paymentService = $paymentService;
} }
/**
* @return \Illuminate\Http\RedirectResponse
*/
public function demo() public function demo()
{ {
$demoAccountId = Utils::getDemoAccountId(); $demoAccountId = Utils::getDemoAccountId();
@ -70,6 +109,9 @@ class AccountController extends BaseController
return Redirect::to('invoices/create'); return Redirect::to('invoices/create');
} }
/**
* @return \Illuminate\Http\RedirectResponse
*/
public function getStarted() public function getStarted()
{ {
$user = false; $user = false;
@ -112,17 +154,9 @@ class AccountController extends BaseController
return Redirect::to($redirectTo)->with('sign_up', Input::get('sign_up')); return Redirect::to($redirectTo)->with('sign_up', Input::get('sign_up'));
} }
public function enableProPlan() /**
{ * @return \Illuminate\Http\RedirectResponse
if (Auth::user()->isPro() && ! Auth::user()->isTrial()) { */
return false;
}
$invitation = $this->accountRepo->enablePlan();
return $invitation->invitation_key;
}
public function changePlan() { public function changePlan() {
$user = Auth::user(); $user = Auth::user();
$account = $user->account; $account = $user->account;
@ -142,22 +176,23 @@ class AccountController extends BaseController
$term = PLAN_TERM_YEARLY; $term = PLAN_TERM_YEARLY;
} }
$new_plan = array( $new_plan = [
'plan' => PLAN_ENTERPRISE, 'plan' => PLAN_ENTERPRISE,
'term' => $term, 'term' => $term,
); ];
} elseif ($planDetails['plan'] == $plan) { } elseif ($planDetails['plan'] == $plan) {
// Term switch // Term switch
if ($planDetails['term'] == PLAN_TERM_YEARLY && $term == PLAN_TERM_MONTHLY) { if ($planDetails['term'] == PLAN_TERM_YEARLY && $term == PLAN_TERM_MONTHLY) {
$pending_change = array( $pending_change = [
'plan' => $plan, 'plan' => $plan,
'term' => $term 'term' => $term
); ];
} elseif ($planDetails['term'] == PLAN_TERM_MONTHLY && $term == PLAN_TERM_YEARLY) { } elseif ($planDetails['term'] == PLAN_TERM_MONTHLY && $term == PLAN_TERM_YEARLY
$new_plan = array( || $planDetails['num_users'] != Input::get('num_users')) {
$new_plan = [
'plan' => $plan, 'plan' => $plan,
'term' => $term, 'term' => $term,
); ];
} else { } else {
// Cancel the pending change // Cancel the pending change
$account->company->pending_plan = null; $account->company->pending_plan = null;
@ -180,16 +215,10 @@ class AccountController extends BaseController
$account->company->pending_plan = null; $account->company->pending_plan = null;
$account->company->pending_term = null; $account->company->pending_term = null;
if ($account->company->payment) { if ($payment = $account->company->payment) {
$payment = $account->company->payment; $ninjaAccount = $this->accountRepo->getNinjaAccount();
$paymentDriver = $ninjaAccount->paymentDriver();
$gateway = $this->paymentService->createGateway($payment->account_gateway); $paymentDriver->refundPayment($payment);
$refund = $gateway->refund(array(
'transactionReference' => $payment->transaction_reference,
'amount' => $payment->amount
));
$refund->send();
$payment->delete();
Session::flash('message', trans('texts.plan_refunded')); Session::flash('message', trans('texts.plan_refunded'));
\Log::info("Refunded Plan Payment: {$account->name} - {$user->email}"); \Log::info("Refunded Plan Payment: {$account->name} - {$user->email}");
} else { } else {
@ -199,10 +228,10 @@ class AccountController extends BaseController
$account->company->save(); $account->company->save();
} else { } else {
$pending_change = array( $pending_change = [
'plan' => $plan, 'plan' => $plan,
'term' => $plan == PLAN_FREE ? null : $term, 'term' => $plan == PLAN_FREE ? null : $term,
); ];
} }
} }
@ -218,32 +247,44 @@ class AccountController extends BaseController
$days_total = $planDetails['paid']->diff($planDetails['expires'])->days; $days_total = $planDetails['paid']->diff($planDetails['expires'])->days;
$percent_used = $days_used / $days_total; $percent_used = $days_used / $days_total;
$old_plan_price = Account::$plan_prices[$planDetails['plan']][$planDetails['term']]; $credit = $planDetails['plan_price'] * (1 - $percent_used);
$credit = $old_plan_price * (1 - $percent_used);
} }
} else { } else {
$new_plan = array( $new_plan = [
'plan' => $plan, 'plan' => $plan,
'term' => $term, 'term' => $term,
); ];
} }
if (!empty($pending_change) && empty($new_plan)) { if (!empty($pending_change) && empty($new_plan)) {
$pending_change['num_users'] = Input::get('num_users');
$account->company->pending_plan = $pending_change['plan']; $account->company->pending_plan = $pending_change['plan'];
$account->company->pending_term = $pending_change['term']; $account->company->pending_term = $pending_change['term'];
$account->company->pending_num_users = $pending_change['num_users'];
$account->company->pending_plan_price = Utils::getPlanPrice($pending_change);
$account->company->save(); $account->company->save();
Session::flash('message', trans('texts.updated_plan')); Session::flash('message', trans('texts.updated_plan'));
} }
if (!empty($new_plan)) { if (!empty($new_plan) && $new_plan['plan'] != PLAN_FREE) {
$invitation = $this->accountRepo->enablePlan($new_plan['plan'], $new_plan['term'], $credit, !empty($pending_monthly)); $new_plan['num_users'] = 1;
if ($new_plan['plan'] == PLAN_ENTERPRISE) {
$new_plan['num_users'] = Input::get('num_users');
}
$new_plan['price'] = Utils::getPlanPrice($new_plan);
$invitation = $this->accountRepo->enablePlan($new_plan, $credit, !empty($pending_monthly));
return Redirect::to('view/'.$invitation->invitation_key); return Redirect::to('view/'.$invitation->invitation_key);
} }
return Redirect::to('/settings/'.ACCOUNT_MANAGEMENT, 301); return Redirect::to('/settings/'.ACCOUNT_MANAGEMENT, 301);
} }
/**
* @param $entityType
* @param $visible
* @return mixed
*/
public function setTrashVisible($entityType, $visible) public function setTrashVisible($entityType, $visible)
{ {
Session::put("show_trash:{$entityType}", $visible == 'true'); Session::put("show_trash:{$entityType}", $visible == 'true');
@ -251,6 +292,9 @@ class AccountController extends BaseController
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
/**
* @return \Illuminate\Http\JsonResponse
*/
public function getSearchData() public function getSearchData()
{ {
$data = $this->accountRepo->getSearchData(Auth::user()); $data = $this->accountRepo->getSearchData(Auth::user());
@ -258,6 +302,10 @@ class AccountController extends BaseController
return Response::json($data); return Response::json($data);
} }
/**
* @param bool $section
* @return \Illuminate\Contracts\View\View|\Illuminate\Http\RedirectResponse
*/
public function showSection($section = false) public function showSection($section = false)
{ {
if (!$section) { if (!$section) {
@ -303,6 +351,9 @@ class AccountController extends BaseController
} }
} }
/**
* @return \Illuminate\Contracts\View\View|\Illuminate\Http\RedirectResponse
*/
private function showSystemSettings() private function showSystemSettings()
{ {
if (Utils::isNinjaProd()) { if (Utils::isNinjaProd()) {
@ -311,13 +362,16 @@ class AccountController extends BaseController
$data = [ $data = [
'account' => Account::with('users')->findOrFail(Auth::user()->account_id), 'account' => Account::with('users')->findOrFail(Auth::user()->account_id),
'title' => trans("texts.system_settings"), 'title' => trans('texts.system_settings'),
'section' => ACCOUNT_SYSTEM_SETTINGS, 'section' => ACCOUNT_SYSTEM_SETTINGS,
]; ];
return View::make("accounts.system_settings", $data); return View::make('accounts.system_settings', $data);
} }
/**
* @return \Illuminate\Contracts\View\View
*/
private function showInvoiceSettings() private function showInvoiceSettings()
{ {
$account = Auth::user()->account; $account = Auth::user()->account;
@ -334,14 +388,17 @@ class AccountController extends BaseController
$data = [ $data = [
'account' => Account::with('users')->findOrFail(Auth::user()->account_id), 'account' => Account::with('users')->findOrFail(Auth::user()->account_id),
'title' => trans("texts.invoice_settings"), 'title' => trans('texts.invoice_settings'),
'section' => ACCOUNT_INVOICE_SETTINGS, 'section' => ACCOUNT_INVOICE_SETTINGS,
'recurringHours' => $recurringHours, 'recurringHours' => $recurringHours,
]; ];
return View::make("accounts.invoice_settings", $data); return View::make('accounts.invoice_settings', $data);
} }
/**
* @return \Illuminate\Contracts\View\View
*/
private function showCompanyDetails() private function showCompanyDetails()
{ {
// check that logo is less than the max file size // check that logo is less than the max file size
@ -352,15 +409,16 @@ class AccountController extends BaseController
$data = [ $data = [
'account' => Account::with('users')->findOrFail(Auth::user()->account_id), 'account' => Account::with('users')->findOrFail(Auth::user()->account_id),
'countries' => Cache::get('countries'),
'sizes' => Cache::get('sizes'), 'sizes' => Cache::get('sizes'),
'industries' => Cache::get('industries'),
'title' => trans('texts.company_details'), 'title' => trans('texts.company_details'),
]; ];
return View::make('accounts.details', $data); return View::make('accounts.details', $data);
} }
/**
* @return \Illuminate\Contracts\View\View
*/
private function showAccountManagement() private function showAccountManagement()
{ {
$account = Auth::user()->account; $account = Auth::user()->account;
@ -373,6 +431,9 @@ class AccountController extends BaseController
return View::make('accounts.management', $data); return View::make('accounts.management', $data);
} }
/**
* @return \Illuminate\Contracts\View\View
*/
public function showUserDetails() public function showUserDetails()
{ {
$oauthLoginUrls = []; $oauthLoginUrls = [];
@ -392,6 +453,9 @@ class AccountController extends BaseController
return View::make('accounts.user_details', $data); return View::make('accounts.user_details', $data);
} }
/**
* @return \Illuminate\Contracts\View\View
*/
private function showLocalization() private function showLocalization()
{ {
$data = [ $data = [
@ -400,33 +464,33 @@ class AccountController extends BaseController
'dateFormats' => Cache::get('dateFormats'), 'dateFormats' => Cache::get('dateFormats'),
'datetimeFormats' => Cache::get('datetimeFormats'), 'datetimeFormats' => Cache::get('datetimeFormats'),
'currencies' => Cache::get('currencies'), 'currencies' => Cache::get('currencies'),
'languages' => Cache::get('languages'),
'title' => trans('texts.localization'), 'title' => trans('texts.localization'),
'weekdays' => Utils::getTranslatedWeekdayNames(),
]; ];
return View::make('accounts.localization', $data); return View::make('accounts.localization', $data);
} }
/**
* @return \Illuminate\Contracts\View\View
*/
private function showBankAccounts() private function showBankAccounts()
{ {
$account = Auth::user()->account; return View::make('accounts.banks', [
$account->load('bank_accounts'); 'title' => trans('texts.bank_accounts'),
$count = count($account->bank_accounts); 'advanced' => ! Auth::user()->hasFeature(FEATURE_EXPENSES),
]);
if ($count == 0) {
return Redirect::to('bank_accounts/create');
} else {
return View::make('accounts.banks', [
'title' => trans('texts.bank_accounts')
]);
}
} }
/**
* @return \Illuminate\Contracts\View\View|\Illuminate\Http\RedirectResponse
*/
private function showOnlinePayments() private function showOnlinePayments()
{ {
$account = Auth::user()->account; $account = Auth::user()->account;
$account->load('account_gateways'); $account->load('account_gateways');
$count = count($account->account_gateways); $count = count($account->account_gateways);
$trashedCount = AccountGateway::scope($account->id)->withTrashed()->count();
if ($accountGateway = $account->getGatewayConfig(GATEWAY_STRIPE)) { if ($accountGateway = $account->getGatewayConfig(GATEWAY_STRIPE)) {
if (! $accountGateway->getPublishableStripeKey()) { if (! $accountGateway->getPublishableStripeKey()) {
@ -434,16 +498,26 @@ class AccountController extends BaseController
} }
} }
if ($count == 0) { if ($trashedCount == 0) {
return Redirect::to('gateways/create'); return Redirect::to('gateways/create');
} else { } else {
$tokenBillingOptions = [];
for ($i=1; $i<=4; $i++) {
$tokenBillingOptions[$i] = trans("texts.token_billing_{$i}");
}
return View::make('accounts.payments', [ return View::make('accounts.payments', [
'showAdd' => $count < count(Gateway::$paymentTypes), 'showAdd' => $count < count(Gateway::$alternate) + 1,
'title' => trans('texts.online_payments') 'title' => trans('texts.online_payments'),
'tokenBillingOptions' => $tokenBillingOptions,
'account' => $account,
]); ]);
} }
} }
/**
* @return \Illuminate\Contracts\View\View
*/
private function showProducts() private function showProducts()
{ {
$columns = ['product', 'description', 'unit_cost']; $columns = ['product', 'description', 'unit_cost'];
@ -461,6 +535,9 @@ class AccountController extends BaseController
return View::make('accounts.products', $data); return View::make('accounts.products', $data);
} }
/**
* @return \Illuminate\Contracts\View\View
*/
private function showTaxRates() private function showTaxRates()
{ {
$data = [ $data = [
@ -472,6 +549,9 @@ class AccountController extends BaseController
return View::make('accounts.tax_rates', $data); return View::make('accounts.tax_rates', $data);
} }
/**
* @return \Illuminate\Contracts\View\View
*/
private function showPaymentTerms() private function showPaymentTerms()
{ {
$data = [ $data = [
@ -483,6 +563,10 @@ class AccountController extends BaseController
return View::make('accounts.payment_terms', $data); return View::make('accounts.payment_terms', $data);
} }
/**
* @param $section
* @return \Illuminate\Contracts\View\View
*/
private function showInvoiceDesign($section) private function showInvoiceDesign($section)
{ {
$account = Auth::user()->account->load('country'); $account = Auth::user()->account->load('country');
@ -596,8 +680,8 @@ class AccountController extends BaseController
// sample invoice to help determine variables // sample invoice to help determine variables
$invoice = Invoice::scope() $invoice = Invoice::scope()
->invoiceType(INVOICE_TYPE_STANDARD)
->with('client', 'account') ->with('client', 'account')
->where('is_quote', '=', false)
->where('is_recurring', '=', false) ->where('is_recurring', '=', false)
->first(); ->first();
@ -613,6 +697,9 @@ class AccountController extends BaseController
return View::make("accounts.{$section}", $data); return View::make("accounts.{$section}", $data);
} }
/**
* @return \Illuminate\Contracts\View\View
*/
private function showClientPortal() private function showClientPortal()
{ {
$account = Auth::user()->account->load('country'); $account = Auth::user()->account->load('country');
@ -621,8 +708,8 @@ class AccountController extends BaseController
if (Utils::isNinja() && $css) { if (Utils::isNinja() && $css) {
// Unescape the CSS for display purposes // Unescape the CSS for display purposes
$css = str_replace( $css = str_replace(
array('\3C ', '\3E ', '\26 '), ['\3C ', '\3E ', '\26 '],
array('<', '>', '&'), ['<', '>', '&'],
$css $css
); );
} }
@ -631,14 +718,17 @@ class AccountController extends BaseController
'client_view_css' => $css, 'client_view_css' => $css,
'enable_portal_password' => $account->enable_portal_password, 'enable_portal_password' => $account->enable_portal_password,
'send_portal_password' => $account->send_portal_password, 'send_portal_password' => $account->send_portal_password,
'title' => trans("texts.client_portal"), 'title' => trans('texts.client_portal'),
'section' => ACCOUNT_CLIENT_PORTAL, 'section' => ACCOUNT_CLIENT_PORTAL,
'account' => $account, 'account' => $account,
]; ];
return View::make("accounts.client_portal", $data); return View::make('accounts.client_portal', $data);
} }
/**
* @return \Illuminate\Contracts\View\View
*/
private function showTemplates() private function showTemplates()
{ {
$account = Auth::user()->account->load('country'); $account = Auth::user()->account->load('country');
@ -661,12 +751,18 @@ class AccountController extends BaseController
return View::make('accounts.templates_and_reminders', $data); return View::make('accounts.templates_and_reminders', $data);
} }
/**
* @param $section
* @return \Illuminate\Http\RedirectResponse
*/
public function doSection($section = ACCOUNT_COMPANY_DETAILS) public function doSection($section = ACCOUNT_COMPANY_DETAILS)
{ {
if ($section === ACCOUNT_COMPANY_DETAILS) { if ($section === ACCOUNT_COMPANY_DETAILS) {
return AccountController::saveDetails(); return AccountController::saveDetails();
} elseif ($section === ACCOUNT_LOCALIZATION) { } elseif ($section === ACCOUNT_LOCALIZATION) {
return AccountController::saveLocalization(); return AccountController::saveLocalization();
} elseif ($section == ACCOUNT_PAYMENTS) {
return self::saveOnlinePayments();
} elseif ($section === ACCOUNT_NOTIFICATIONS) { } elseif ($section === ACCOUNT_NOTIFICATIONS) {
return AccountController::saveNotifications(); return AccountController::saveNotifications();
} elseif ($section === ACCOUNT_EXPORT) { } elseif ($section === ACCOUNT_EXPORT) {
@ -692,6 +788,9 @@ class AccountController extends BaseController
} }
} }
/**
* @return \Illuminate\Http\RedirectResponse
*/
private function saveCustomizeDesign() private function saveCustomizeDesign()
{ {
if (Auth::user()->account->hasFeature(FEATURE_CUSTOMIZE_INVOICE_DESIGN)) { if (Auth::user()->account->hasFeature(FEATURE_CUSTOMIZE_INVOICE_DESIGN)) {
@ -706,6 +805,9 @@ class AccountController extends BaseController
return Redirect::to('settings/'.ACCOUNT_CUSTOMIZE_DESIGN); return Redirect::to('settings/'.ACCOUNT_CUSTOMIZE_DESIGN);
} }
/**
* @return \Illuminate\Http\RedirectResponse
*/
private function saveClientPortal() private function saveClientPortal()
{ {
$account = Auth::user()->account; $account = Auth::user()->account;
@ -759,6 +861,9 @@ class AccountController extends BaseController
return Redirect::to('settings/'.ACCOUNT_CLIENT_PORTAL); return Redirect::to('settings/'.ACCOUNT_CLIENT_PORTAL);
} }
/**
* @return \Illuminate\Http\RedirectResponse
*/
private function saveEmailTemplates() private function saveEmailTemplates()
{ {
if (Auth::user()->account->hasFeature(FEATURE_EMAIL_TEMPLATES_REMINDERS)) { if (Auth::user()->account->hasFeature(FEATURE_EMAIL_TEMPLATES_REMINDERS)) {
@ -793,14 +898,13 @@ class AccountController extends BaseController
return Redirect::to('settings/'.ACCOUNT_TEMPLATES_AND_REMINDERS); return Redirect::to('settings/'.ACCOUNT_TEMPLATES_AND_REMINDERS);
} }
/**
* @return \Illuminate\Http\RedirectResponse
*/
private function saveTaxRates() private function saveTaxRates()
{ {
$account = Auth::user()->account; $account = Auth::user()->account;
$account->fill(Input::all());
$account->invoice_taxes = Input::get('invoice_taxes') ? true : false;
$account->invoice_item_taxes = Input::get('invoice_item_taxes') ? true : false;
$account->show_item_taxes = Input::get('show_item_taxes') ? true : false;
$account->default_tax_rate_id = Input::get('default_tax_rate_id');
$account->save(); $account->save();
Session::flash('message', trans('texts.updated_settings')); Session::flash('message', trans('texts.updated_settings'));
@ -808,6 +912,9 @@ class AccountController extends BaseController
return Redirect::to('settings/'.ACCOUNT_TAX_RATES); return Redirect::to('settings/'.ACCOUNT_TAX_RATES);
} }
/**
* @return \Illuminate\Http\RedirectResponse
*/
private function saveProducts() private function saveProducts()
{ {
$account = Auth::user()->account; $account = Auth::user()->account;
@ -821,21 +928,24 @@ class AccountController extends BaseController
return Redirect::to('settings/'.ACCOUNT_PRODUCTS); return Redirect::to('settings/'.ACCOUNT_PRODUCTS);
} }
/**
* @return $this|\Illuminate\Http\RedirectResponse
*/
private function saveEmailSettings() private function saveEmailSettings()
{ {
if (Auth::user()->account->hasFeature(FEATURE_CUSTOM_EMAILS)) { if (Auth::user()->account->hasFeature(FEATURE_CUSTOM_EMAILS)) {
$rules = [];
$user = Auth::user(); $user = Auth::user();
$iframeURL = preg_replace('/[^a-zA-Z0-9_\-\:\/\.]/', '', substr(strtolower(Input::get('iframe_url')), 0, MAX_IFRAME_URL_LENGTH)); $subdomain = null;
$iframeURL = rtrim($iframeURL, "/"); $iframeURL = null;
$rules = [];
$subdomain = preg_replace('/[^a-zA-Z0-9_\-\.]/', '', substr(strtolower(Input::get('subdomain')), 0, MAX_SUBDOMAIN_LENGTH)); if (Input::get('custom_link') == 'subdomain') {
if ($iframeURL) { $subdomain = preg_replace('/[^a-zA-Z0-9_\-\.]/', '', substr(strtolower(Input::get('subdomain')), 0, MAX_SUBDOMAIN_LENGTH));
$subdomain = null;
}
if ($subdomain) {
$exclude = ['www', 'app', 'mail', 'admin', 'blog', 'user', 'contact', 'payment', 'payments', 'billing', 'invoice', 'business', 'owner', 'info', 'ninja']; $exclude = ['www', 'app', 'mail', 'admin', 'blog', 'user', 'contact', 'payment', 'payments', 'billing', 'invoice', 'business', 'owner', 'info', 'ninja'];
$rules['subdomain'] = "unique:accounts,subdomain,{$user->account_id},id|not_in:" . implode(',', $exclude); $rules['subdomain'] = "unique:accounts,subdomain,{$user->account_id},id|not_in:" . implode(',', $exclude);
} else {
$iframeURL = preg_replace('/[^a-zA-Z0-9_\-\:\/\.]/', '', substr(strtolower(Input::get('iframe_url')), 0, MAX_IFRAME_URL_LENGTH));
$iframeURL = rtrim($iframeURL, '/');
} }
$validator = Validator::make(Input::all(), $rules); $validator = Validator::make(Input::all(), $rules);
@ -864,6 +974,9 @@ class AccountController extends BaseController
return Redirect::to('settings/'.ACCOUNT_EMAIL_SETTINGS); return Redirect::to('settings/'.ACCOUNT_EMAIL_SETTINGS);
} }
/**
* @return $this|\Illuminate\Http\RedirectResponse
*/
private function saveInvoiceSettings() private function saveInvoiceSettings()
{ {
if (Auth::user()->account->hasFeature(FEATURE_INVOICE_SETTINGS)) { if (Auth::user()->account->hasFeature(FEATURE_INVOICE_SETTINGS)) {
@ -945,6 +1058,9 @@ class AccountController extends BaseController
return Redirect::to('settings/'.ACCOUNT_INVOICE_SETTINGS); return Redirect::to('settings/'.ACCOUNT_INVOICE_SETTINGS);
} }
/**
* @return \Illuminate\Http\RedirectResponse
*/
private function saveInvoiceDesign() private function saveInvoiceDesign()
{ {
if (Auth::user()->account->hasFeature(FEATURE_CUSTOMIZE_INVOICE_DESIGN)) { if (Auth::user()->account->hasFeature(FEATURE_CUSTOMIZE_INVOICE_DESIGN)) {
@ -976,7 +1092,7 @@ class AccountController extends BaseController
} }
$labels = []; $labels = [];
foreach (['item', 'description', 'unit_cost', 'quantity', 'line_total', 'terms', 'balance_due', 'partial_due'] as $field) { foreach (['item', 'description', 'unit_cost', 'quantity', 'line_total', 'terms', 'balance_due', 'partial_due', 'subtotal', 'paid_to_date', 'discount'] as $field) {
$labels[$field] = Input::get("labels_{$field}"); $labels[$field] = Input::get("labels_{$field}");
} }
$account->invoice_labels = json_encode($labels); $account->invoice_labels = json_encode($labels);
@ -989,6 +1105,9 @@ class AccountController extends BaseController
return Redirect::to('settings/'.ACCOUNT_INVOICE_DESIGN); return Redirect::to('settings/'.ACCOUNT_INVOICE_DESIGN);
} }
/**
* @return \Illuminate\Http\RedirectResponse
*/
private function saveNotifications() private function saveNotifications()
{ {
$user = Auth::user(); $user = Auth::user();
@ -1003,6 +1122,10 @@ class AccountController extends BaseController
return Redirect::to('settings/'.ACCOUNT_NOTIFICATIONS); return Redirect::to('settings/'.ACCOUNT_NOTIFICATIONS);
} }
/**
* @param UpdateAccountRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function updateDetails(UpdateAccountRequest $request) public function updateDetails(UpdateAccountRequest $request)
{ {
$account = Auth::user()->account; $account = Auth::user()->account;
@ -1025,7 +1148,7 @@ class AccountController extends BaseController
$documentType = $extension; $documentType = $extension;
} }
if(!in_array($documentType, array('jpeg', 'png', 'gif'))){ if(!in_array($documentType, ['jpeg', 'png', 'gif'])){
Session::flash('warning', 'Unsupported file type'); Session::flash('warning', 'Unsupported file type');
} else { } else {
$documentTypeData = Document::$types[$documentType]; $documentTypeData = Document::$types[$documentType];
@ -1089,8 +1212,12 @@ class AccountController extends BaseController
return Redirect::to('settings/'.ACCOUNT_COMPANY_DETAILS); return Redirect::to('settings/'.ACCOUNT_COMPANY_DETAILS);
} }
/**
* @return $this|\Illuminate\Http\RedirectResponse
*/
public function saveUserDetails() public function saveUserDetails()
{ {
/** @var \App\Models\User $user */
$user = Auth::user(); $user = Auth::user();
$rules = ['email' => 'email|required|unique:users,email,'.$user->id.',id']; $rules = ['email' => 'email|required|unique:users,email,'.$user->id.',id'];
$validator = Validator::make(Input::all(), $rules); $validator = Validator::make(Input::all(), $rules);
@ -1124,9 +1251,14 @@ class AccountController extends BaseController
} }
} }
/**
* @return \Illuminate\Http\RedirectResponse
*/
private function saveLocalization() private function saveLocalization()
{ {
/** @var \App\Models\Account $account */
$account = Auth::user()->account; $account = Auth::user()->account;
$account->timezone_id = Input::get('timezone_id') ? Input::get('timezone_id') : null; $account->timezone_id = Input::get('timezone_id') ? Input::get('timezone_id') : null;
$account->date_format_id = Input::get('date_format_id') ? Input::get('date_format_id') : null; $account->date_format_id = Input::get('date_format_id') ? Input::get('date_format_id') : null;
$account->datetime_format_id = Input::get('datetime_format_id') ? Input::get('datetime_format_id') : null; $account->datetime_format_id = Input::get('datetime_format_id') ? Input::get('datetime_format_id') : null;
@ -1134,6 +1266,7 @@ class AccountController extends BaseController
$account->language_id = Input::get('language_id') ? Input::get('language_id') : 1; // English $account->language_id = Input::get('language_id') ? Input::get('language_id') : 1; // English
$account->military_time = Input::get('military_time') ? true : false; $account->military_time = Input::get('military_time') ? true : false;
$account->show_currency_code = Input::get('show_currency_code') ? true : false; $account->show_currency_code = Input::get('show_currency_code') ? true : false;
$account->start_of_week = Input::get('start_of_week') ? Input::get('start_of_week') : 0;
$account->save(); $account->save();
event(new UserSettingsChanged()); event(new UserSettingsChanged());
@ -1143,6 +1276,26 @@ class AccountController extends BaseController
return Redirect::to('settings/'.ACCOUNT_LOCALIZATION); return Redirect::to('settings/'.ACCOUNT_LOCALIZATION);
} }
/**
* @return \Illuminate\Http\RedirectResponse
*/
private function saveOnlinePayments()
{
$account = Auth::user()->account;
$account->token_billing_type_id = Input::get('token_billing_type_id');
$account->auto_bill_on_due_date = boolval(Input::get('auto_bill_on_due_date'));
$account->save();
event(new UserSettingsChanged());
Session::flash('message', trans('texts.updated_settings'));
return Redirect::to('settings/'.ACCOUNT_PAYMENTS);
}
/**
* @return \Illuminate\Http\RedirectResponse
*/
public function removeLogo() public function removeLogo()
{ {
$account = Auth::user()->account; $account = Auth::user()->account;
@ -1161,25 +1314,33 @@ class AccountController extends BaseController
return Redirect::to('settings/'.ACCOUNT_COMPANY_DETAILS); return Redirect::to('settings/'.ACCOUNT_COMPANY_DETAILS);
} }
/**
* @return string
*/
public function checkEmail() public function checkEmail()
{ {
$email = User::withTrashed()->where('email', '=', Input::get('email'))->where('id', '<>', Auth::user()->id)->first(); $email = User::withTrashed()->where('email', '=', Input::get('email'))
->where('id', '<>', Auth::user()->id)
->first();
if ($email) { if ($email) {
return "taken"; return 'taken';
} else { } else {
return "available"; return 'available';
} }
} }
/**
* @return string
*/
public function submitSignup() public function submitSignup()
{ {
$rules = array( $rules = [
'new_first_name' => 'required', 'new_first_name' => 'required',
'new_last_name' => 'required', 'new_last_name' => 'required',
'new_password' => 'required|min:6', 'new_password' => 'required|min:6',
'new_email' => 'email|required|unique:users,email,'.Auth::user()->id.',id', 'new_email' => 'email|required|unique:users,email,'.Auth::user()->id.',id',
); ];
$validator = Validator::make(Input::all(), $rules); $validator = Validator::make(Input::all(), $rules);
@ -1187,6 +1348,7 @@ class AccountController extends BaseController
return ''; return '';
} }
/** @var \App\Models\User $user */
$user = Auth::user(); $user = Auth::user();
$user->first_name = trim(Input::get('new_first_name')); $user->first_name = trim(Input::get('new_first_name'));
$user->last_name = trim(Input::get('new_last_name')); $user->last_name = trim(Input::get('new_last_name'));
@ -1205,6 +1367,9 @@ class AccountController extends BaseController
return "{$user->first_name} {$user->last_name}"; return "{$user->first_name} {$user->last_name}";
} }
/**
* @return mixed
*/
public function doRegister() public function doRegister()
{ {
$affiliate = Affiliate::where('affiliate_key', '=', SELF_HOST_AFFILIATE_KEY)->first(); $affiliate = Affiliate::where('affiliate_key', '=', SELF_HOST_AFFILIATE_KEY)->first();
@ -1228,6 +1393,9 @@ class AccountController extends BaseController
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
/**
* @return \Illuminate\Http\RedirectResponse
*/
public function cancelAccount() public function cancelAccount()
{ {
if ($reason = trim(Input::get('reason'))) { if ($reason = trim(Input::get('reason'))) {
@ -1268,16 +1436,25 @@ class AccountController extends BaseController
return Redirect::to('/')->with('clearGuestKey', true); return Redirect::to('/')->with('clearGuestKey', true);
} }
/**
* @return \Illuminate\Http\RedirectResponse
*/
public function resendConfirmation() public function resendConfirmation()
{ {
/** @var \App\Models\User $user */
$user = Auth::user(); $user = Auth::user();
$this->userMailer->sendConfirmation($user); $this->userMailer->sendConfirmation($user);
return Redirect::to('/settings/'.ACCOUNT_USER_DETAILS)->with('message', trans('texts.confirmation_resent')); return Redirect::to('/settings/'.ACCOUNT_USER_DETAILS)->with('message', trans('texts.confirmation_resent'));
} }
/**
* @param $plan
* @return \Illuminate\Http\RedirectResponse
*/
public function startTrial($plan) public function startTrial($plan)
{ {
/** @var \App\Models\User $user */
$user = Auth::user(); $user = Auth::user();
if ($user->isEligibleForTrial($plan)) { if ($user->isEligibleForTrial($plan)) {
@ -1287,6 +1464,11 @@ class AccountController extends BaseController
return Redirect::back()->with('message', trans('texts.trial_success')); return Redirect::back()->with('message', trans('texts.trial_success'));
} }
/**
* @param $section
* @param bool $subSection
* @return \Illuminate\Http\RedirectResponse
*/
public function redirectLegacy($section, $subSection = false) public function redirectLegacy($section, $subSection = false)
{ {
if ($section === 'details') { if ($section === 'details') {
@ -1307,7 +1489,11 @@ class AccountController extends BaseController
return Redirect::to("/settings/$section/", 301); return Redirect::to("/settings/$section/", 301);
} }
public function previewEmail(\App\Services\TemplateService $templateService) /**
* @param TemplateService $templateService
* @return \Illuminate\Http\Response
*/
public function previewEmail(TemplateService $templateService)
{ {
$template = Input::get('template'); $template = Input::get('template');
$invoice = Invoice::scope() $invoice = Invoice::scope()

View File

@ -1,8 +1,6 @@
<?php namespace App\Http\Controllers; <?php namespace App\Http\Controllers;
use Auth; use Auth;
use Datatable;
use DB;
use Input; use Input;
use Redirect; use Redirect;
use Session; use Session;
@ -11,11 +9,10 @@ use Validator;
use stdClass; use stdClass;
use URL; use URL;
use Utils; use Utils;
use WePay;
use App\Models\Gateway; use App\Models\Gateway;
use App\Models\Account; use App\Models\Account;
use App\Models\AccountGateway; use App\Models\AccountGateway;
use App\Ninja\Repositories\AccountRepository;
use App\Services\AccountGatewayService; use App\Services\AccountGatewayService;
class AccountGatewayController extends BaseController class AccountGatewayController extends BaseController
@ -61,10 +58,8 @@ class AccountGatewayController extends BaseController
$data['title'] = trans('texts.edit_gateway') . ' - ' . $accountGateway->gateway->name; $data['title'] = trans('texts.edit_gateway') . ' - ' . $accountGateway->gateway->name;
$data['config'] = $config; $data['config'] = $config;
$data['hiddenFields'] = Gateway::$hiddenFields; $data['hiddenFields'] = Gateway::$hiddenFields;
$data['paymentTypeId'] = $accountGateway->getPaymentType();
$data['selectGateways'] = Gateway::where('id', '=', $accountGateway->gateway_id)->get(); $data['selectGateways'] = Gateway::where('id', '=', $accountGateway->gateway_id)->get();
return View::make('accounts.account_gateway', $data); return View::make('accounts.account_gateway', $data);
} }
@ -84,43 +79,40 @@ class AccountGatewayController extends BaseController
*/ */
public function create() public function create()
{ {
$data = self::getViewModel();
$data['url'] = 'gateways';
$data['method'] = 'POST';
$data['title'] = trans('texts.add_gateway');
$data['selectGateways'] = Gateway::where('payment_library_id', '=', 1)
->where('id', '!=', GATEWAY_PAYPAL_EXPRESS)
->where('id', '!=', GATEWAY_BITPAY)
->where('id', '!=', GATEWAY_GOCARDLESS)
->where('id', '!=', GATEWAY_DWOLLA)
->orderBy('name')->get();
$data['hiddenFields'] = Gateway::$hiddenFields;
if ( ! \Request::secure() && ! Utils::isNinjaDev()) { if ( ! \Request::secure() && ! Utils::isNinjaDev()) {
Session::flash('warning', trans('texts.enable_https')); Session::flash('warning', trans('texts.enable_https'));
} }
return View::make('accounts.account_gateway', $data); $account = Auth::user()->account;
$accountGatewaysIds = $account->gatewayIds();
$otherProviders = Input::get('other_providers');
if ( ! Utils::isNinja() || Gateway::hasStandardGateway($accountGatewaysIds)) {
$otherProviders = true;
}
$data = self::getViewModel();
$data['url'] = 'gateways';
$data['method'] = 'POST';
$data['title'] = trans('texts.add_gateway');
if ($otherProviders) {
$availableGatewaysIds = $account->availableGatewaysIds();
$data['primaryGateways'] = Gateway::primary($availableGatewaysIds)->orderBy('name', 'desc')->get();
$data['secondaryGateways'] = Gateway::secondary($availableGatewaysIds)->orderBy('name')->get();
$data['hiddenFields'] = Gateway::$hiddenFields;
return View::make('accounts.account_gateway', $data);
} else {
return View::make('accounts.account_gateway_wepay', $data);
}
} }
private function getViewModel($accountGateway = false) private function getViewModel($accountGateway = false)
{ {
$selectedCards = $accountGateway ? $accountGateway->accepted_credit_cards : 0; $selectedCards = $accountGateway ? $accountGateway->accepted_credit_cards : 0;
$account = Auth::user()->account; $user = Auth::user();
$account =$user->account;
$paymentTypes = [];
foreach (Gateway::$paymentTypes as $type) {
if ($accountGateway || !$account->getGatewayByType($type)) {
$paymentTypes[$type] = trans('texts.'.strtolower($type));
if ($type == PAYMENT_TYPE_BITCOIN) {
$paymentTypes[$type] .= ' - BitPay';
}
if ($type == PAYMENT_TYPE_DIRECT_DEBIT) {
$paymentTypes[$type] .= ' - GoCardless';
}
}
}
$creditCardsArray = unserialize(CREDIT_CARDS); $creditCardsArray = unserialize(CREDIT_CARDS);
$creditCards = []; $creditCards = [];
@ -139,25 +131,19 @@ class AccountGatewayController extends BaseController
foreach ($gateways as $gateway) { foreach ($gateways as $gateway) {
$fields = $gateway->getFields(); $fields = $gateway->getFields();
asort($fields); asort($fields);
$gateway->fields = $fields; $gateway->fields = $gateway->id == GATEWAY_WEPAY ? [] : $fields;
if ($accountGateway && $accountGateway->gateway_id == $gateway->id) { if ($accountGateway && $accountGateway->gateway_id == $gateway->id) {
$accountGateway->fields = $gateway->fields; $accountGateway->fields = $gateway->fields;
} }
} }
$tokenBillingOptions = [];
for ($i=1; $i<=4; $i++) {
$tokenBillingOptions[$i] = trans("texts.token_billing_{$i}");
}
return [ return [
'paymentTypes' => $paymentTypes,
'account' => $account, 'account' => $account,
'user' => $user,
'accountGateway' => $accountGateway, 'accountGateway' => $accountGateway,
'config' => false, 'config' => false,
'gateways' => $gateways, 'gateways' => $gateways,
'creditCardTypes' => $creditCards, 'creditCardTypes' => $creditCards,
'tokenBillingOptions' => $tokenBillingOptions,
'countGateways' => count($currentGateways) 'countGateways' => count($currentGateways)
]; ];
} }
@ -169,7 +155,7 @@ class AccountGatewayController extends BaseController
$ids = Input::get('bulk_public_id'); $ids = Input::get('bulk_public_id');
$count = $this->accountGatewayService->bulk($ids, $action); $count = $this->accountGatewayService->bulk($ids, $action);
Session::flash('message', trans('texts.archived_account_gateway')); Session::flash('message', trans("texts.{$action}d_account_gateway"));
return Redirect::to('settings/' . ACCOUNT_PAYMENTS); return Redirect::to('settings/' . ACCOUNT_PAYMENTS);
} }
@ -180,27 +166,10 @@ class AccountGatewayController extends BaseController
*/ */
public function save($accountGatewayPublicId = false) public function save($accountGatewayPublicId = false)
{ {
$rules = array(); $gatewayId = Input::get('primary_gateway_id') ?: Input::get('secondary_gateway_id');
$paymentType = Input::get('payment_type_id');
$gatewayId = Input::get('gateway_id');
if ($paymentType == PAYMENT_TYPE_PAYPAL) {
$gatewayId = GATEWAY_PAYPAL_EXPRESS;
} elseif ($paymentType == PAYMENT_TYPE_BITCOIN) {
$gatewayId = GATEWAY_BITPAY;
} elseif ($paymentType == PAYMENT_TYPE_DIRECT_DEBIT) {
$gatewayId = GATEWAY_GOCARDLESS;
} elseif ($paymentType == PAYMENT_TYPE_DWOLLA) {
$gatewayId = GATEWAY_DWOLLA;
}
if (!$gatewayId) {
Session::flash('error', trans('validation.required', ['attribute' => 'gateway']));
return Redirect::to('gateways/create')
->withInput();
}
$gateway = Gateway::findOrFail($gatewayId); $gateway = Gateway::findOrFail($gatewayId);
$rules = [];
$fields = $gateway->getFields(); $fields = $gateway->getFields();
$optional = array_merge(Gateway::$hiddenFields, Gateway::$optionalFields); $optional = array_merge(Gateway::$hiddenFields, Gateway::$optionalFields);
@ -211,17 +180,20 @@ class AccountGatewayController extends BaseController
// do nothing - we're unable to acceptance test with StripeJS // do nothing - we're unable to acceptance test with StripeJS
} else { } else {
$rules['publishable_key'] = 'required'; $rules['publishable_key'] = 'required';
$rules['enable_ach'] = 'boolean';
} }
} }
foreach ($fields as $field => $details) { if ($gatewayId != GATEWAY_WEPAY) {
if (!in_array($field, $optional)) { foreach ($fields as $field => $details) {
if (strtolower($gateway->name) == 'beanstream') { if (!in_array($field, $optional)) {
if (in_array($field, ['merchant_id', 'passCode'])) { if (strtolower($gateway->name) == 'beanstream') {
$rules[$gateway->id.'_'.$field] = 'required'; if (in_array($field, ['merchant_id', 'passCode'])) {
$rules[$gateway->id . '_' . $field] = 'required';
}
} else {
$rules[$gateway->id . '_' . $field] = 'required';
} }
} else {
$rules[$gateway->id.'_'.$field] = 'required';
} }
} }
} }
@ -241,22 +213,44 @@ class AccountGatewayController extends BaseController
$accountGateway = AccountGateway::scope($accountGatewayPublicId)->firstOrFail(); $accountGateway = AccountGateway::scope($accountGatewayPublicId)->firstOrFail();
$oldConfig = $accountGateway->getConfig(); $oldConfig = $accountGateway->getConfig();
} else { } else {
// check they don't already have an active gateway for this provider
// TODO complete this
$accountGateway = AccountGateway::scope()
->whereGatewayId($gatewayId)
->first();
if ($accountGateway) {
Session::flash('error', trans('texts.gateway_exists'));
return Redirect::to("gateways/{$accountGateway->public_id}/edit");
}
$accountGateway = AccountGateway::createNew(); $accountGateway = AccountGateway::createNew();
$accountGateway->gateway_id = $gatewayId; $accountGateway->gateway_id = $gatewayId;
if ($gatewayId == GATEWAY_WEPAY) {
if(!$this->setupWePay($accountGateway, $wepayResponse)) {
return $wepayResponse;
}
$oldConfig = $accountGateway->getConfig();
}
} }
$config = new stdClass(); $config = new stdClass();
foreach ($fields as $field => $details) {
$value = trim(Input::get($gateway->id.'_'.$field)); if ($gatewayId != GATEWAY_WEPAY) {
// if the new value is masked use the original value foreach ($fields as $field => $details) {
if ($oldConfig && $value && $value === str_repeat('*', strlen($value))) { $value = trim(Input::get($gateway->id . '_' . $field));
$value = $oldConfig->$field; // if the new value is masked use the original value
} if ($oldConfig && $value && $value === str_repeat('*', strlen($value))) {
if (!$value && ($field == 'testMode' || $field == 'developerMode')) { $value = $oldConfig->$field;
// do nothing }
} else { if (!$value && ($field == 'testMode' || $field == 'developerMode')) {
$config->$field = $value; // do nothing
} else {
$config->$field = $value;
}
} }
} elseif($oldConfig) {
$config = clone $oldConfig;
} }
$publishableKey = Input::get('publishable_key'); $publishableKey = Input::get('publishable_key');
@ -266,6 +260,35 @@ class AccountGatewayController extends BaseController
$config->publishableKey = $oldConfig->publishableKey; $config->publishableKey = $oldConfig->publishableKey;
} }
$plaidClientId = Input::get('plaid_client_id');
if ($plaidClientId = str_replace('*', '', $plaidClientId)) {
$config->plaidClientId = $plaidClientId;
} elseif ($oldConfig && property_exists($oldConfig, 'plaidClientId')) {
$config->plaidClientId = $oldConfig->plaidClientId;
}
$plaidSecret = Input::get('plaid_secret');
if ($plaidSecret = str_replace('*', '', $plaidSecret)) {
$config->plaidSecret = $plaidSecret;
} elseif ($oldConfig && property_exists($oldConfig, 'plaidSecret')) {
$config->plaidSecret = $oldConfig->plaidSecret;
}
$plaidPublicKey = Input::get('plaid_public_key');
if ($plaidPublicKey = str_replace('*', '', $plaidPublicKey)) {
$config->plaidPublicKey = $plaidPublicKey;
} elseif ($oldConfig && property_exists($oldConfig, 'plaidPublicKey')) {
$config->plaidPublicKey = $oldConfig->plaidPublicKey;
}
if ($gatewayId == GATEWAY_STRIPE || $gatewayId == GATEWAY_WEPAY) {
$config->enableAch = boolval(Input::get('enable_ach'));
}
if ($gatewayId == GATEWAY_BRAINTREE) {
$config->enablePayPal = boolval(Input::get('enable_paypal'));
}
$cardCount = 0; $cardCount = 0;
if ($creditcards) { if ($creditcards) {
foreach ($creditcards as $card => $value) { foreach ($creditcards as $card => $value) {
@ -284,21 +307,167 @@ class AccountGatewayController extends BaseController
$account->account_gateways()->save($accountGateway); $account->account_gateways()->save($accountGateway);
} }
if (Input::get('token_billing_type_id')) { if(isset($wepayResponse)) {
$account->token_billing_type_id = Input::get('token_billing_type_id'); return $wepayResponse;
$account->save();
}
if ($accountGatewayPublicId) {
$message = trans('texts.updated_gateway');
} else { } else {
$message = trans('texts.created_gateway'); if ($accountGatewayPublicId) {
$message = trans('texts.updated_gateway');
} else {
$message = trans('texts.created_gateway');
}
Session::flash('message', $message);
return Redirect::to("gateways/{$accountGateway->public_id}/edit");
} }
Session::flash('message', $message);
return Redirect::to("gateways/{$accountGateway->public_id}/edit");
} }
} }
protected function getWePayUpdateUri($accountGateway)
{
if ($accountGateway->gateway_id != GATEWAY_WEPAY) {
return null;
}
$wepay = Utils::setupWePay($accountGateway);
$update_uri_data = $wepay->request('account/get_update_uri', [
'account_id' => $accountGateway->getConfig()->accountId,
'mode' => 'iframe',
'redirect_uri' => URL::to('/gateways'),
]);
return $update_uri_data->uri;
}
protected function setupWePay($accountGateway, &$response)
{
$user = Auth::user();
$account = $user->account;
$rules = [
'company_name' => 'required',
'description' => 'required',
'tos_agree' => 'required',
'first_name' => 'required',
'last_name' => 'required',
'email' => 'required',
];
if (WEPAY_ENABLE_CANADA) {
$rules['country'] = 'required|in:US,CA';
}
$validator = Validator::make(Input::all(), $rules);
if ($validator->fails()) {
return Redirect::to('gateways/create')
->withErrors($validator)
->withInput();
}
try{
$wepay = Utils::setupWePay();
$userDetails = [
'client_id' => WEPAY_CLIENT_ID,
'client_secret' => WEPAY_CLIENT_SECRET,
'email' => Input::get('email'),
'first_name' => Input::get('first_name'),
'last_name' => Input::get('last_name'),
'original_ip' => \Request::getClientIp(true),
'original_device' => \Request::server('HTTP_USER_AGENT'),
'tos_acceptance_time' => time(),
'redirect_uri' => URL::to('gateways'),
'scope' => 'manage_accounts,collect_payments,view_user,preapprove_payments,send_money',
];
$wepayUser = $wepay->request('user/register/', $userDetails);
$accessToken = $wepayUser->access_token;
$accessTokenExpires = $wepayUser->expires_in ? (time() + $wepayUser->expires_in) : null;
$wepay = new WePay($accessToken);
$accountDetails = [
'name' => Input::get('company_name'),
'description' => Input::get('description'),
'theme_object' => json_decode(WEPAY_THEME),
'callback_uri' => $accountGateway->getWebhookUrl(),
];
if (WEPAY_ENABLE_CANADA) {
$accountDetails['country'] = Input::get('country');
if (Input::get('country') == 'CA') {
$accountDetails['currencies'] = ['CAD'];
$accountDetails['country_options'] = ['debit_opt_in' => boolval(Input::get('debit_cards'))];
}
}
$wepayAccount = $wepay->request('account/create/', $accountDetails);
try {
$wepay->request('user/send_confirmation/', []);
$confirmationRequired = true;
} catch(\WePayException $ex){
if ($ex->getMessage() == 'This access_token is already approved.') {
$confirmationRequired = false;
} else {
throw $ex;
}
}
$accountGateway->gateway_id = GATEWAY_WEPAY;
$accountGateway->setConfig([
'userId' => $wepayUser->user_id,
'accessToken' => $accessToken,
'tokenType' => $wepayUser->token_type,
'tokenExpires' => $accessTokenExpires,
'accountId' => $wepayAccount->account_id,
'state' => $wepayAccount->state,
'testMode' => WEPAY_ENVIRONMENT == WEPAY_STAGE,
'country' => WEPAY_ENABLE_CANADA ? Input::get('country') : 'US',
]);
if ($confirmationRequired) {
Session::flash('message', trans('texts.created_wepay_confirmation_required'));
} else {
$updateUri = $wepay->request('/account/get_update_uri', [
'account_id' => $wepayAccount->account_id,
'redirect_uri' => URL::to('gateways'),
]);
$response = Redirect::to($updateUri->uri);
return true;
}
$response = Redirect::to("gateways/{$accountGateway->public_id}/edit");
return true;
} catch (\WePayException $e) {
Session::flash('error', $e->getMessage());
$response = Redirect::to('gateways/create')
->withInput();
return false;
}
}
public function resendConfirmation($publicId = false)
{
$accountGateway = AccountGateway::scope($publicId)->firstOrFail();
if ($accountGateway->gateway_id == GATEWAY_WEPAY) {
try {
$wepay = Utils::setupWePay($accountGateway);
$wepay->request('user/send_confirmation', []);
Session::flash('message', trans('texts.resent_confirmation_email'));
} catch (\WePayException $e) {
Session::flash('error', $e->getMessage());
}
}
return Redirect::to("gateways/{$accountGateway->public_id}/edit");
}
} }

View File

@ -1,12 +1,5 @@
<?php namespace App\Http\Controllers; <?php namespace App\Http\Controllers;
use Auth;
use DB;
use Datatable;
use Utils;
use View;
use App\Models\Client;
use App\Models\Activity;
use App\Services\ActivityService; use App\Services\ActivityService;
class ActivityController extends BaseController class ActivityController extends BaseController

View File

@ -11,10 +11,8 @@ use Utils;
use View; use View;
use Event; use Event;
use Session; use Session;
use Cookie;
use Response; use Response;
use Redirect; use Redirect;
use App\Models\User;
use App\Models\Account; use App\Models\Account;
use App\Models\Industry; use App\Models\Industry;
use App\Ninja\Mailers\Mailer; use App\Ninja\Mailers\Mailer;
@ -100,6 +98,8 @@ class AppController extends BaseController
$_ENV['MAIL_FROM_NAME'] = $mail['from']['name']; $_ENV['MAIL_FROM_NAME'] = $mail['from']['name'];
$_ENV['MAIL_PASSWORD'] = $mail['password']; $_ENV['MAIL_PASSWORD'] = $mail['password'];
$_ENV['PHANTOMJS_CLOUD_KEY'] = 'a-demo-key-with-low-quota-per-ip-address'; $_ENV['PHANTOMJS_CLOUD_KEY'] = 'a-demo-key-with-low-quota-per-ip-address';
$_ENV['MAILGUN_DOMAIN'] = $mail['mailgun_domain'];
$_ENV['MAILGUN_SECRET'] = $mail['mailgun_secret'];
$config = ''; $config = '';
foreach ($_ENV as $key => $val) { foreach ($_ENV as $key => $val) {
@ -114,18 +114,18 @@ class AppController extends BaseController
// Write Config Settings // Write Config Settings
$fp = fopen(base_path()."/.env", 'w'); $fp = fopen(base_path().'/.env', 'w');
fwrite($fp, $config); fwrite($fp, $config);
fclose($fp); fclose($fp);
// == DB Migrate & Seed == // // == DB Migrate & Seed == //
// Artisan::call('migrate:rollback', array('--force' => true)); // Debug Purposes // Artisan::call('migrate:rollback', array('--force' => true)); // Debug Purposes
Artisan::call('migrate', array('--force' => true)); Artisan::call('migrate', ['--force' => true]);
if (Industry::count() == 0) { if (Industry::count() == 0) {
Artisan::call('db:seed', array('--force' => true)); Artisan::call('db:seed', ['--force' => true]);
} }
Cache::flush(); Cache::flush();
Artisan::call('optimize', array('--force' => true)); Artisan::call('optimize', ['--force' => true]);
$firstName = trim(Input::get('first_name')); $firstName = trim(Input::get('first_name'));
$lastName = trim(Input::get('last_name')); $lastName = trim(Input::get('last_name'));
@ -147,7 +147,7 @@ class AppController extends BaseController
return Redirect::to('/'); return Redirect::to('/');
} }
if ( ! $canUpdateEnv = @fopen(base_path()."/.env", 'w')) { if ( ! $canUpdateEnv = @fopen(base_path().'/.env', 'w')) {
Session::flash('error', 'Warning: Permission denied to write to .env config file, try running <code>sudo chown www-data:www-data /path/to/ninja/.env</code>'); Session::flash('error', 'Warning: Permission denied to write to .env config file, try running <code>sudo chown www-data:www-data /path/to/ninja/.env</code>');
return Redirect::to('/settings/system_settings'); return Redirect::to('/settings/system_settings');
} }
@ -174,6 +174,8 @@ class AppController extends BaseController
$_ENV['MAIL_FROM_NAME'] = $mail['from']['name']; $_ENV['MAIL_FROM_NAME'] = $mail['from']['name'];
$_ENV['MAIL_PASSWORD'] = $mail['password']; $_ENV['MAIL_PASSWORD'] = $mail['password'];
$_ENV['MAIL_FROM_ADDRESS'] = $mail['username']; $_ENV['MAIL_FROM_ADDRESS'] = $mail['username'];
$_ENV['MAILGUN_DOMAIN'] = $mail['mailgun_domain'];
$_ENV['MAILGUN_SECRET'] = $mail['mailgun_secret'];
} }
$config = ''; $config = '';
@ -187,7 +189,7 @@ class AppController extends BaseController
$config .= "{$key}={$val}\n"; $config .= "{$key}={$val}\n";
} }
$fp = fopen(base_path()."/.env", 'w'); $fp = fopen(base_path().'/.env', 'w');
fwrite($fp, $config); fwrite($fp, $config);
fclose($fp); fclose($fp);
@ -243,11 +245,11 @@ class AppController extends BaseController
if (!Utils::isNinjaProd() && !Utils::isDatabaseSetup()) { if (!Utils::isNinjaProd() && !Utils::isDatabaseSetup()) {
try { try {
set_time_limit(60 * 5); // shouldn't take this long but just in case set_time_limit(60 * 5); // shouldn't take this long but just in case
Artisan::call('migrate', array('--force' => true)); Artisan::call('migrate', ['--force' => true]);
if (Industry::count() == 0) { if (Industry::count() == 0) {
Artisan::call('db:seed', array('--force' => true)); Artisan::call('db:seed', ['--force' => true]);
} }
Artisan::call('optimize', array('--force' => true)); Artisan::call('optimize', ['--force' => true]);
} catch (Exception $e) { } catch (Exception $e) {
Utils::logError($e); Utils::logError($e);
return Response::make($e->getMessage(), 500); return Response::make($e->getMessage(), 500);
@ -268,13 +270,18 @@ class AppController extends BaseController
Artisan::call('route:clear'); Artisan::call('route:clear');
Artisan::call('view:clear'); Artisan::call('view:clear');
Artisan::call('config:clear'); Artisan::call('config:clear');
Artisan::call('optimize', array('--force' => true)); Artisan::call('optimize', ['--force' => true]);
Cache::flush(); Cache::flush();
Session::flush(); Session::flush();
Artisan::call('migrate', array('--force' => true)); Artisan::call('migrate', ['--force' => true]);
Artisan::call('db:seed', array('--force' => true, '--class' => "UpdateSeeder")); Artisan::call('db:seed', ['--force' => true, '--class' => 'UpdateSeeder']);
Event::fire(new UserSettingsChanged()); Event::fire(new UserSettingsChanged());
Session::flash('message', trans('texts.processed_updates'));
// show message with link to Trello board
$message = trans('texts.see_whats_new', ['version' => NINJA_VERSION]);
$message = link_to(RELEASES_URL, $message, ['target' => '_blank']);
$message = sprintf('%s - %s', trans('texts.processed_updates'), $message);
Session::flash('warning', $message);
} catch (Exception $e) { } catch (Exception $e) {
Utils::logError($e); Utils::logError($e);
return Response::make($e->getMessage(), 500); return Response::make($e->getMessage(), 500);

View File

@ -12,40 +12,55 @@ use App\Ninja\Repositories\AccountRepository;
use App\Services\AuthService; use App\Services\AuthService;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers; use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
class AuthController extends Controller { class AuthController extends Controller
{
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Registration & Login Controller | Registration & Login Controller
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| This controller handles the registration of new users, as well as the | This controller handles the registration of new users, as well as the
| authentication of existing users. By default, this controller uses | authentication of existing users. By default, this controller uses
| a simple trait to add these behaviors. Why don't you explore it? | a simple trait to add these behaviors. Why don't you explore it?
| |
*/ */
use AuthenticatesAndRegistersUsers; use AuthenticatesAndRegistersUsers;
/**
* @var string
*/
protected $redirectTo = '/dashboard'; protected $redirectTo = '/dashboard';
/**
* @var AuthService
*/
protected $authService; protected $authService;
/**
* @var AccountRepository
*/
protected $accountRepo; protected $accountRepo;
/** /**
* Create a new authentication controller instance. * Create a new authentication controller instance.
* *
* @param \Illuminate\Contracts\Auth\Guard $auth * @param AccountRepository $repo
* @param \Illuminate\Contracts\Auth\Registrar $registrar * @param AuthService $authService
* @return void * @internal param \Illuminate\Contracts\Auth\Guard $auth
*/ * @internal param \Illuminate\Contracts\Auth\Registrar $registrar
public function __construct(AccountRepository $repo, AuthService $authService) */
{ public function __construct(AccountRepository $repo, AuthService $authService)
{
$this->accountRepo = $repo; $this->accountRepo = $repo;
$this->authService = $authService; $this->authService = $authService;
}
//$this->middleware('guest', ['except' => 'getLogout']); /**
} * @param array $data
* @return mixed
*/
public function validator(array $data) public function validator(array $data)
{ {
return Validator::make($data, [ return Validator::make($data, [
@ -58,7 +73,8 @@ class AuthController extends Controller {
/** /**
* Create a new user instance after a valid registration. * Create a new user instance after a valid registration.
* *
* @param array $data * @param array $data
*
* @return User * @return User
*/ */
public function create(array $data) public function create(array $data)
@ -70,11 +86,20 @@ class AuthController extends Controller {
]); ]);
} }
/**
* @param $provider
* @param Request $request
*
* @return \Illuminate\Http\RedirectResponse
*/
public function authLogin($provider, Request $request) public function authLogin($provider, Request $request)
{ {
return $this->authService->execute($provider, $request->has('code')); return $this->authService->execute($provider, $request->has('code'));
} }
/**
* @return \Illuminate\Http\RedirectResponse
*/
public function authUnlink() public function authUnlink()
{ {
$this->accountRepo->unlinkUserFromOauth(Auth::user()); $this->accountRepo->unlinkUserFromOauth(Auth::user());
@ -83,6 +108,9 @@ class AuthController extends Controller {
return redirect()->to('/settings/' . ACCOUNT_USER_DETAILS); return redirect()->to('/settings/' . ACCOUNT_USER_DETAILS);
} }
/**
* @return \Illuminate\Http\Response
*/
public function getLoginWrapper() public function getLoginWrapper()
{ {
if (!Utils::isNinja() && !User::count()) { if (!Utils::isNinja() && !User::count()) {
@ -92,6 +120,11 @@ class AuthController extends Controller {
return self::getLogin(); return self::getLogin();
} }
/**
* @param Request $request
*
* @return \Illuminate\Http\Response
*/
public function postLoginWrapper(Request $request) public function postLoginWrapper(Request $request)
{ {
@ -113,7 +146,7 @@ class AuthController extends Controller {
if ($request->link_accounts && $userId && Auth::user()->id != $userId) { if ($request->link_accounts && $userId && Auth::user()->id != $userId) {
$users = $this->accountRepo->associateAccounts($userId, Auth::user()->id); $users = $this->accountRepo->associateAccounts($userId, Auth::user()->id);
Session::flash('message', trans('texts.associated_accounts')); Session::flash('message', trans('texts.associated_accounts'));
// check if other accounts are linked // check if other accounts are linked
} else { } else {
$users = $this->accountRepo->loadAccounts(Auth::user()->id); $users = $this->accountRepo->loadAccounts(Auth::user()->id);
} }
@ -127,14 +160,16 @@ class AuthController extends Controller {
return $response; return $response;
} }
/**
* @return \Illuminate\Http\Response
*/
public function getLogoutWrapper() public function getLogoutWrapper()
{ {
if (Auth::check() && !Auth::user()->registered) { if (Auth::check() && !Auth::user()->registered) {
$account = Auth::user()->account; $account = Auth::user()->account;
$this->accountRepo->unlinkAccount($account); $this->accountRepo->unlinkAccount($account);
if ($account->company->accounts->count() == 1) { if ($account->company->accounts->count() == 1) {
$account->company->forceDelete(); $account->company->forceDelete();
} }
$account->forceDelete(); $account->forceDelete();
} }

View File

@ -3,33 +3,36 @@
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ResetsPasswords; use Illuminate\Foundation\Auth\ResetsPasswords;
class PasswordController extends Controller { class PasswordController extends Controller
{
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Password Reset Controller | Password Reset Controller
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| This controller is responsible for handling password reset requests | This controller is responsible for handling password reset requests
| and uses a simple trait to include this behavior. You're free to | and uses a simple trait to include this behavior. You're free to
| explore this trait and override any methods you wish to tweak. | explore this trait and override any methods you wish to tweak.
| |
*/ */
use ResetsPasswords; use ResetsPasswords;
/**
* @var string
*/
protected $redirectTo = '/dashboard'; protected $redirectTo = '/dashboard';
/** /**
* Create a new password controller instance. * Create a new password controller instance.
* *
* @param \Illuminate\Contracts\Auth\Guard $auth * @internal param \Illuminate\Contracts\Auth\Guard $auth
* @param \Illuminate\Contracts\Auth\PasswordBroker $passwords * @internal param \Illuminate\Contracts\Auth\PasswordBroker $passwords
* @return void */
*/ public function __construct()
public function __construct() {
{ $this->middleware('guest');
$this->middleware('guest'); }
}
} }

View File

@ -2,23 +2,18 @@
use Cache; use Cache;
use Auth; use Auth;
use Datatable;
use DB;
use Input; use Input;
use Redirect; use Redirect;
use Session; use Session;
use View; use View;
use Validator;
use stdClass;
use Crypt; use Crypt;
use URL; use File;
use Utils;
use App\Models\Gateway;
use App\Models\Account; use App\Models\Account;
use App\Models\BankAccount; use App\Models\BankAccount;
use App\Ninja\Repositories\BankAccountRepository; use App\Ninja\Repositories\BankAccountRepository;
use App\Services\BankAccountService; use App\Services\BankAccountService;
use App\Http\Requests\CreateBankAccountRequest; use App\Http\Requests\CreateBankAccountRequest;
use Illuminate\Http\Request;
class BankAccountController extends BaseController class BankAccountController extends BaseController
{ {
@ -122,4 +117,28 @@ class BankAccountController extends BaseController
return $this->bankAccountService->importExpenses($bankId, Input::all()); return $this->bankAccountService->importExpenses($bankId, Input::all());
} }
public function showImportOFX()
{
return view('accounts.import_ofx');
}
public function doImportOFX(Request $request)
{
$file = File::get($request->file('ofx_file'));
try {
$data = $this->bankAccountService->parseOFX($file);
} catch (\Exception $e) {
Session::flash('error', trans('texts.ofx_parse_failed'));
return view('accounts.import_ofx');
}
$data = [
'banks' => null,
'bankAccount' => null,
'transactions' => json_encode([$data])
];
return View::make('accounts.bank_account', $data);
}
} }

View File

@ -1,13 +1,10 @@
<?php namespace App\Http\Controllers; <?php namespace App\Http\Controllers;
use Session;
use Utils; use Utils;
use Auth; use Auth;
use Log;
use Input; use Input;
use Response; use Response;
use Request; use Request;
use League\Fractal;
use League\Fractal\Manager; use League\Fractal\Manager;
use League\Fractal\Resource\Item; use League\Fractal\Resource\Item;
use League\Fractal\Resource\Collection; use League\Fractal\Resource\Collection;
@ -15,7 +12,6 @@ use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use App\Models\EntityModel; use App\Models\EntityModel;
use App\Ninja\Serializers\ArraySerializer; use App\Ninja\Serializers\ArraySerializer;
use League\Fractal\Serializer\JsonApiSerializer; use League\Fractal\Serializer\JsonApiSerializer;
use Illuminate\Pagination\LengthAwarePaginator;
/** /**
* @SWG\Swagger( * @SWG\Swagger(
@ -169,7 +165,7 @@ class BaseAPIController extends Controller
if (Utils::isNinjaDev()) { if (Utils::isNinjaDev()) {
$count = count(\DB::getQueryLog()); $count = count(\DB::getQueryLog());
Log::info(Request::method() . ' - ' . Request::url() . ": $count queries"); Log::info(Request::method() . ' - ' . Request::url() . ": $count queries");
Log::info(json_encode(\DB::getQueryLog())); //Log::info(json_encode(\DB::getQueryLog()));
} }
$index = Request::get('index') ?: 'data'; $index = Request::get('index') ?: 'data';

View File

@ -1,16 +1,12 @@
<?php namespace App\Http\Controllers; <?php namespace App\Http\Controllers;
use App\Http\Middleware\PermissionsRequired;
use Illuminate\Foundation\Bus\DispatchesJobs; use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Input;
use Auth;
use Utils;
class BaseController extends Controller class BaseController extends Controller
{ {
use DispatchesJobs, AuthorizesRequests; use DispatchesJobs, AuthorizesRequests;
protected $entityType; protected $entityType;
/** /**

View File

@ -1,15 +1,10 @@
<?php namespace App\Http\Controllers; <?php namespace App\Http\Controllers;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Utils;
use Response; use Response;
use Input; use Input;
use Auth;
use App\Models\Client; use App\Models\Client;
use App\Ninja\Repositories\ClientRepository; use App\Ninja\Repositories\ClientRepository;
use App\Http\Requests\CreateClientRequest; use App\Http\Requests\CreateClientRequest;
use App\Http\Controllers\BaseAPIController;
use App\Ninja\Transformers\ClientTransformer;
use App\Http\Requests\UpdateClientRequest; use App\Http\Requests\UpdateClientRequest;
class ClientApiController extends BaseAPIController class ClientApiController extends BaseAPIController

View File

@ -1,73 +1,75 @@
<?php namespace App\Http\Controllers\ClientAuth; <?php namespace App\Http\Controllers\ClientAuth;
use Auth;
use Event;
use Utils;
use Session; use Session;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use App\Models\User; use App\Models\User;
use App\Events\UserLoggedIn;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Ninja\Repositories\AccountRepository; use App\Models\Contact;
use App\Services\AuthService;
use App\Models\Invitation;
use Illuminate\Foundation\Auth\AuthenticatesUsers; use Illuminate\Foundation\Auth\AuthenticatesUsers;
class AuthController extends Controller { class AuthController extends Controller
{
use AuthenticatesUsers;
protected $guard = 'client'; /**
* @var string
*/
protected $guard = 'client';
/**
* @var string
*/
protected $redirectTo = '/client/dashboard'; protected $redirectTo = '/client/dashboard';
use AuthenticatesUsers; /**
* @return mixed
*/
public function showLoginForm()
{
$data = [];
public function showLoginForm() $contactKey = session('contact_key');
{ if ($contactKey) {
$data = array( $contact = Contact::where('contact_key', '=', $contactKey)->first();
); if ($contact && !$contact->is_deleted) {
$account = $contact->account;
$invitation_key = session('invitation_key');
if($invitation_key){ $data['account'] = $account;
$invitation = Invitation::where('invitation_key', '=', $invitation_key)->first();
if ($invitation && !$invitation->is_deleted) {
$invoice = $invitation->invoice;
$client = $invoice->client;
$account = $client->account;
$data['hideLogo'] = $account->hasFeature(FEATURE_WHITE_LABEL);
$data['clientViewCSS'] = $account->clientViewCSS();
$data['clientFontUrl'] = $account->getFontsUrl(); $data['clientFontUrl'] = $account->getFontsUrl();
} }
} }
return view('clientauth.login')->with($data);
}
/** return view('clientauth.login')->with($data);
}
/**
* Get the needed authorization credentials from the request. * Get the needed authorization credentials from the request.
* *
* @param \Illuminate\Http\Request $request * @param \Illuminate\Http\Request $request
*
* @return array * @return array
*/ */
protected function getCredentials(Request $request) protected function getCredentials(Request $request)
{ {
$credentials = $request->only('password'); $credentials = $request->only('password');
$credentials['id'] = null; $credentials['id'] = null;
$invitation_key = session('invitation_key'); $contactKey = session('contact_key');
if($invitation_key){ if ($contactKey) {
$invitation = Invitation::where('invitation_key', '=', $invitation_key)->first(); $contact = Contact::where('contact_key', '=', $contactKey)->first();
if ($invitation && !$invitation->is_deleted) { if ($contact && !$contact->is_deleted) {
$credentials['id'] = $invitation->contact_id; $credentials['id'] = $contact->id;
} }
} }
return $credentials; return $credentials;
} }
/** /**
* Validate the user login request. * Validate the user login request.
* *
* @param \Illuminate\Http\Request $request * @param \Illuminate\Http\Request $request
*
* @return void * @return void
*/ */
protected function validateLogin(Request $request) protected function validateLogin(Request $request)
@ -76,4 +78,12 @@ class AuthController extends Controller {
'password' => 'required', 'password' => 'required',
]); ]);
} }
/**
* @return mixed
*/
public function getSessionExpired()
{
return view('clientauth.sessionexpired');
}
} }

View File

@ -6,79 +6,84 @@ use Illuminate\Foundation\Auth\ResetsPasswords;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Mail\Message; use Illuminate\Mail\Message;
use Illuminate\Support\Facades\Password; use Illuminate\Support\Facades\Password;
use App\Models\Contact;
use App\Models\Invitation; use App\Models\Invitation;
class PasswordController extends Controller
{
class PasswordController extends Controller { /*
|--------------------------------------------------------------------------
| Password Reset Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling password reset requests
| and uses a simple trait to include this behavior. You're free to
| explore this trait and override any methods you wish to tweak.
|
*/
/* use ResetsPasswords;
|--------------------------------------------------------------------------
| Password Reset Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling password reset requests
| and uses a simple trait to include this behavior. You're free to
| explore this trait and override any methods you wish to tweak.
|
*/
use ResetsPasswords;
/**
* @var string
*/
protected $redirectTo = '/client/dashboard'; protected $redirectTo = '/client/dashboard';
/**
* Create a new password controller instance.
*
* @param \Illuminate\Contracts\Auth\Guard $auth
* @param \Illuminate\Contracts\Auth\PasswordBroker $passwords
* @return void
*/
public function __construct()
{
$this->middleware('guest');
Config::set("auth.defaults.passwords","client");
}
public function showLinkRequestForm() /**
{ * Create a new password controller instance.
$data = array(); *
$invitation_key = session('invitation_key'); * @internal param \Illuminate\Contracts\Auth\Guard $auth
if($invitation_key){ * @internal param \Illuminate\Contracts\Auth\PasswordBroker $passwords
$invitation = Invitation::where('invitation_key', '=', $invitation_key)->first(); */
if ($invitation && !$invitation->is_deleted) { public function __construct()
$invoice = $invitation->invoice; {
$client = $invoice->client; $this->middleware('guest');
$account = $client->account; Config::set('auth.defaults.passwords', 'client');
}
$data['hideLogo'] = $account->hasFeature(FEATURE_WHITE_LABEL);
$data['clientViewCSS'] = $account->clientViewCSS(); /**
* @return \Illuminate\Http\RedirectResponse
*/
public function showLinkRequestForm()
{
$data = [];
$contactKey = session('contact_key');
if ($contactKey) {
$contact = Contact::where('contact_key', '=', $contactKey)->first();
if ($contact && !$contact->is_deleted) {
$account = $contact->account;
$data['account'] = $account;
$data['clientFontUrl'] = $account->getFontsUrl(); $data['clientFontUrl'] = $account->getFontsUrl();
} }
} else {
return \Redirect::to('/client/sessionexpired');
} }
return view('clientauth.password')->with($data); return view('clientauth.password')->with($data);
} }
/** /**
* Send a reset link to the given user. * Send a reset link to the given user.
* *
* @param \Illuminate\Http\Request $request * @param \Illuminate\Http\Request $request
*
* @return \Illuminate\Http\Response * @return \Illuminate\Http\Response
*/ */
public function sendResetLinkEmail(Request $request) public function sendResetLinkEmail(Request $request)
{ {
$broker = $this->getBroker(); $broker = $this->getBroker();
$contact_id = null; $contactId = null;
$invitation_key = session('invitation_key'); $contactKey = session('contact_key');
if($invitation_key){ if ($contactKey) {
$invitation = Invitation::where('invitation_key', '=', $invitation_key)->first(); $contact = Contact::where('contact_key', '=', $contactKey)->first();
if ($invitation && !$invitation->is_deleted) { if ($contact && !$contact->is_deleted) {
$contact_id = $invitation->contact_id; $contactId = $contact->id;
} }
} }
$response = Password::broker($broker)->sendResetLink(array('id'=>$contact_id), function (Message $message) { $response = Password::broker($broker)->sendResetLink(['id' => $contactId], function (Message $message) {
$message->subject($this->getEmailSubject()); $message->subject($this->getEmailSubject());
}); });
@ -91,62 +96,69 @@ class PasswordController extends Controller {
return $this->getSendResetLinkEmailFailureResponse($response); return $this->getSendResetLinkEmailFailureResponse($response);
} }
} }
/** /**
* Display the password reset view for the given token. * Display the password reset view for the given token.
* *
* If no token is present, display the link request form. * If no token is present, display the link request form.
* *
* @param \Illuminate\Http\Request $request * @param \Illuminate\Http\Request $request
* @param string|null $invitation_key * @param string|null $key
* @param string|null $token * @param string|null $token
* @return \Illuminate\Http\Response * @return \Illuminate\Http\Response
*/ */
public function showResetForm(Request $request, $invitation_key = null, $token = null) public function showResetForm(Request $request, $key = null, $token = null)
{ {
if (is_null($token)) { if (is_null($token)) {
return $this->getEmail(); return $this->getEmail();
} }
$data = compact('token', 'invitation_key'); $data = compact('token');
$invitation_key = session('invitation_key'); if ($key) {
if($invitation_key){ $contact = Contact::where('contact_key', '=', $key)->first();
$invitation = Invitation::where('invitation_key', '=', $invitation_key)->first(); if ($contact && !$contact->is_deleted) {
if ($invitation && !$invitation->is_deleted) { $account = $contact->account;
$invoice = $invitation->invoice; $data['contact_key'] = $contact->contact_key;
$client = $invoice->client; } else {
$account = $client->account; // Maybe it's an invitation key
$invitation = Invitation::where('invitation_key', '=', $key)->first();
$data['hideLogo'] = $account->hasFeature(FEATURE_WHITE_LABEL); if ($invitation && !$invitation->is_deleted) {
$data['clientViewCSS'] = $account->clientViewCSS(); $account = $invitation->account;
$data['contact_key'] = $invitation->contact->contact_key;
}
}
if (!empty($account)) {
$data['account'] = $account;
$data['clientFontUrl'] = $account->getFontsUrl(); $data['clientFontUrl'] = $account->getFontsUrl();
} else {
return \Redirect::to('/client/sessionexpired');
} }
} }
return view('clientauth.reset')->with($data); return view('clientauth.reset')->with($data);
} }
/** /**
* Display the password reset view for the given token. * Display the password reset view for the given token.
* *
* If no token is present, display the link request form. * If no token is present, display the link request form.
* *
* @param \Illuminate\Http\Request $request * @param \Illuminate\Http\Request $request
* @param string|null $invitation_key * @param string|null $key
* @param string|null $token * @param string|null $token
* @return \Illuminate\Http\Response * @return \Illuminate\Http\Response
*/ */
public function getReset(Request $request, $invitation_key = null, $token = null) public function getReset(Request $request, $key = null, $token = null)
{ {
return $this->showResetForm($request, $invitation_key, $token); return $this->showResetForm($request, $key, $token);
} }
/** /**
* Reset the given user's password. * Reset the given user's password.
* *
* @param \Illuminate\Http\Request $request * @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response * @return \Illuminate\Http\Response
*/ */
public function reset(Request $request) public function reset(Request $request)
@ -156,14 +168,14 @@ class PasswordController extends Controller {
$credentials = $request->only( $credentials = $request->only(
'password', 'password_confirmation', 'token' 'password', 'password_confirmation', 'token'
); );
$credentials['id'] = null; $credentials['id'] = null;
$invitation_key = $request->input('invitation_key'); $contactKey = session('contact_key');
if($invitation_key){ if ($contactKey) {
$invitation = Invitation::where('invitation_key', '=', $invitation_key)->first(); $contact = Contact::where('contact_key', '=', $contactKey)->first();
if ($invitation && !$invitation->is_deleted) { if ($contact && !$contact->is_deleted) {
$credentials['id'] = $invitation->contact_id; $credentials['id'] = $contact->id;
} }
} }
@ -181,7 +193,7 @@ class PasswordController extends Controller {
return $this->getResetFailureResponse($request, $response); return $this->getResetFailureResponse($request, $response);
} }
} }
/** /**
* Get the password reset validation rules. * Get the password reset validation rules.
* *

View File

@ -1,33 +1,21 @@
<?php namespace App\Http\Controllers; <?php namespace App\Http\Controllers;
use Auth; use Auth;
use Datatable;
use Utils; use Utils;
use View; use View;
use URL; use URL;
use Validator;
use Input; use Input;
use Session; use Session;
use Redirect; use Redirect;
use Cache; use Cache;
use App\Models\Activity;
use App\Models\Client; use App\Models\Client;
use App\Models\Account; use App\Models\Account;
use App\Models\Contact; use App\Models\Contact;
use App\Models\Invoice; use App\Models\Invoice;
use App\Models\Size;
use App\Models\PaymentTerm;
use App\Models\Industry;
use App\Models\Currency;
use App\Models\Payment;
use App\Models\Credit; use App\Models\Credit;
use App\Models\Expense;
use App\Models\Country;
use App\Models\Task; use App\Models\Task;
use App\Ninja\Repositories\ClientRepository; use App\Ninja\Repositories\ClientRepository;
use App\Services\ClientService; use App\Services\ClientService;
use App\Http\Requests\ClientRequest; use App\Http\Requests\ClientRequest;
use App\Http\Requests\CreateClientRequest; use App\Http\Requests\CreateClientRequest;
use App\Http\Requests\UpdateClientRequest; use App\Http\Requests\UpdateClientRequest;
@ -53,7 +41,7 @@ class ClientController extends BaseController
*/ */
public function index() public function index()
{ {
return View::make('list', array( return View::make('list', [
'entityType' => ENTITY_CLIENT, 'entityType' => ENTITY_CLIENT,
'title' => trans('texts.clients'), 'title' => trans('texts.clients'),
'sortCol' => '4', 'sortCol' => '4',
@ -67,12 +55,15 @@ class ClientController extends BaseController
'balance', 'balance',
'' ''
]), ]),
)); ]);
} }
public function getDatatable() public function getDatatable()
{ {
return $this->clientService->getDatatable(Input::get('sSearch')); $search = Input::get('sSearch');
$userId = Auth::user()->filterId();
return $this->clientService->getDatatable($search, $userId);
} }
/** /**
@ -97,8 +88,8 @@ class ClientController extends BaseController
*/ */
public function show(ClientRequest $request) public function show(ClientRequest $request)
{ {
$client = $request->entity(); $client = $request->entity();
$user = Auth::user(); $user = Auth::user();
Utils::trackViewed($client->getDisplayName(), ENTITY_CLIENT); Utils::trackViewed($client->getDisplayName(), ENTITY_CLIENT);
@ -109,34 +100,37 @@ class ClientController extends BaseController
if (Utils::hasFeature(FEATURE_QUOTES) && $user->can('create', ENTITY_INVOICE)) { if (Utils::hasFeature(FEATURE_QUOTES) && $user->can('create', ENTITY_INVOICE)) {
$actionLinks[] = ['label' => trans('texts.new_quote'), 'url' => URL::to('/quotes/create/'.$client->public_id)]; $actionLinks[] = ['label' => trans('texts.new_quote'), 'url' => URL::to('/quotes/create/'.$client->public_id)];
} }
if(!empty($actionLinks)){ if(!empty($actionLinks)){
$actionLinks[] = \DropdownButton::DIVIDER; $actionLinks[] = \DropdownButton::DIVIDER;
} }
if($user->can('create', ENTITY_PAYMENT)){ if($user->can('create', ENTITY_PAYMENT)){
$actionLinks[] = ['label' => trans('texts.enter_payment'), 'url' => URL::to('/payments/create/'.$client->public_id)]; $actionLinks[] = ['label' => trans('texts.enter_payment'), 'url' => URL::to('/payments/create/'.$client->public_id)];
} }
if($user->can('create', ENTITY_CREDIT)){ if($user->can('create', ENTITY_CREDIT)){
$actionLinks[] = ['label' => trans('texts.enter_credit'), 'url' => URL::to('/credits/create/'.$client->public_id)]; $actionLinks[] = ['label' => trans('texts.enter_credit'), 'url' => URL::to('/credits/create/'.$client->public_id)];
} }
if($user->can('create', ENTITY_EXPENSE)){ if($user->can('create', ENTITY_EXPENSE)){
$actionLinks[] = ['label' => trans('texts.enter_expense'), 'url' => URL::to('/expenses/create/0/'.$client->public_id)]; $actionLinks[] = ['label' => trans('texts.enter_expense'), 'url' => URL::to('/expenses/create/0/'.$client->public_id)];
} }
$data = array( $token = $client->getGatewayToken();
$data = [
'actionLinks' => $actionLinks, 'actionLinks' => $actionLinks,
'showBreadcrumbs' => false, 'showBreadcrumbs' => false,
'client' => $client, 'client' => $client,
'credit' => $client->getTotalCredit(), 'credit' => $client->getTotalCredit(),
'title' => trans('texts.view_client'), 'title' => trans('texts.view_client'),
'hasRecurringInvoices' => Invoice::scope()->where('is_recurring', '=', true)->whereClientId($client->id)->count() > 0, 'hasRecurringInvoices' => Invoice::scope()->where('is_recurring', '=', true)->whereClientId($client->id)->count() > 0,
'hasQuotes' => Invoice::scope()->where('is_quote', '=', true)->whereClientId($client->id)->count() > 0, 'hasQuotes' => Invoice::scope()->invoiceType(INVOICE_TYPE_QUOTE)->whereClientId($client->id)->count() > 0,
'hasTasks' => Task::scope()->whereClientId($client->id)->count() > 0, 'hasTasks' => Task::scope()->whereClientId($client->id)->count() > 0,
'gatewayLink' => $client->getGatewayLink(), 'gatewayLink' => $token ? $token->gatewayLink() : false,
); 'gatewayName' => $token ? $token->gatewayName() : false,
];
return View::make('clients.show', $data); return View::make('clients.show', $data);
} }
@ -149,7 +143,7 @@ class ClientController extends BaseController
public function create(ClientRequest $request) public function create(ClientRequest $request)
{ {
if (Client::scope()->withTrashed()->count() > Auth::user()->getMaxNumClients()) { if (Client::scope()->withTrashed()->count() > Auth::user()->getMaxNumClients()) {
return View::make('error', ['hideHeader' => true, 'error' => "Sorry, you've exceeded the limit of ".Auth::user()->getMaxNumClients()." clients"]); return View::make('error', ['hideHeader' => true, 'error' => "Sorry, you've exceeded the limit of ".Auth::user()->getMaxNumClients().' clients']);
} }
$data = [ $data = [
@ -173,7 +167,7 @@ class ClientController extends BaseController
public function edit(ClientRequest $request) public function edit(ClientRequest $request)
{ {
$client = $request->entity(); $client = $request->entity();
$data = [ $data = [
'client' => $client, 'client' => $client,
'method' => 'PUT', 'method' => 'PUT',
@ -199,10 +193,7 @@ class ClientController extends BaseController
'account' => Auth::user()->account, 'account' => Auth::user()->account,
'sizes' => Cache::get('sizes'), 'sizes' => Cache::get('sizes'),
'paymentTerms' => Cache::get('paymentTerms'), 'paymentTerms' => Cache::get('paymentTerms'),
'industries' => Cache::get('industries'),
'currencies' => Cache::get('currencies'), 'currencies' => Cache::get('currencies'),
'languages' => Cache::get('languages'),
'countries' => Cache::get('countries'),
'customLabel1' => Auth::user()->account->custom_client_label1, 'customLabel1' => Auth::user()->account->custom_client_label1,
'customLabel2' => Auth::user()->account->custom_client_label2, 'customLabel2' => Auth::user()->account->custom_client_label2,
]; ];

View File

@ -2,7 +2,6 @@
use Auth; use Auth;
use View; use View;
use DB;
use URL; use URL;
use Input; use Input;
use Utils; use Utils;
@ -10,9 +9,15 @@ use Request;
use Response; use Response;
use Session; use Session;
use Datatable; use Datatable;
use Validator;
use Cache;
use Redirect;
use Exception;
use App\Models\Gateway; use App\Models\Gateway;
use App\Models\Invitation; use App\Models\Invitation;
use App\Models\Document; use App\Models\Document;
use App\Models\PaymentMethod;
use App\Models\Contact;
use App\Ninja\Repositories\InvoiceRepository; use App\Ninja\Repositories\InvoiceRepository;
use App\Ninja\Repositories\PaymentRepository; use App\Ninja\Repositories\PaymentRepository;
use App\Ninja\Repositories\ActivityRepository; use App\Ninja\Repositories\ActivityRepository;
@ -22,7 +27,7 @@ use App\Events\QuoteInvitationWasViewed;
use App\Services\PaymentService; use App\Services\PaymentService;
use Barracuda\ArchiveStream\ZipArchive; use Barracuda\ArchiveStream\ZipArchive;
class PublicClientController extends BaseController class ClientPortalController extends BaseController
{ {
private $invoiceRepo; private $invoiceRepo;
private $paymentRepo; private $paymentRepo;
@ -56,9 +61,9 @@ class PublicClientController extends BaseController
]); ]);
} }
if (!Input::has('phantomjs') && !Input::has('silent') && !Session::has($invitationKey) if (!Input::has('phantomjs') && !Input::has('silent') && !Session::has($invitationKey)
&& (!Auth::check() || Auth::user()->account_id != $invoice->account_id)) { && (!Auth::check() || Auth::user()->account_id != $invoice->account_id)) {
if ($invoice->is_quote) { if ($invoice->isType(INVOICE_TYPE_QUOTE)) {
event(new QuoteInvitationWasViewed($invoice, $invitation)); event(new QuoteInvitationWasViewed($invoice, $invitation));
} else { } else {
event(new InvoiceInvitationWasViewed($invoice, $invitation)); event(new InvoiceInvitationWasViewed($invoice, $invitation));
@ -66,10 +71,10 @@ class PublicClientController extends BaseController
} }
Session::put($invitationKey, true); // track this invitation has been seen Session::put($invitationKey, true); // track this invitation has been seen
Session::put('invitation_key', $invitationKey); // track current invitation Session::put('contact_key', $invitation->contact->contact_key);// track current contact
$account->loadLocalizationSettings($client); $account->loadLocalizationSettings($client);
$invoice->invoice_date = Utils::fromSqlDate($invoice->invoice_date); $invoice->invoice_date = Utils::fromSqlDate($invoice->invoice_date);
$invoice->due_date = Utils::fromSqlDate($invoice->due_date); $invoice->due_date = Utils::fromSqlDate($invoice->due_date);
$invoice->features = [ $invoice->features = [
@ -78,7 +83,7 @@ class PublicClientController extends BaseController
'invoice_settings' => $account->hasFeature(FEATURE_INVOICE_SETTINGS), 'invoice_settings' => $account->hasFeature(FEATURE_INVOICE_SETTINGS),
]; ];
$invoice->invoice_fonts = $account->getFontsData(); $invoice->invoice_fonts = $account->getFontsData();
if ($invoice->invoice_design_id == CUSTOM_DESIGN) { if ($invoice->invoice_design_id == CUSTOM_DESIGN) {
$invoice->invoice_design->javascript = $account->custom_design; $invoice->invoice_design->javascript = $account->custom_design;
} else { } else {
@ -92,15 +97,20 @@ class PublicClientController extends BaseController
'phone', 'phone',
]); ]);
$paymentTypes = $this->getPaymentTypes($client, $invitation); $data = [];
$paymentTypes = $this->getPaymentTypes($account, $client, $invitation);
$paymentURL = ''; $paymentURL = '';
if (count($paymentTypes)) { if (count($paymentTypes) == 1) {
$paymentURL = $paymentTypes[0]['url']; $paymentURL = $paymentTypes[0]['url'];
if (!$account->isGatewayConfigured(GATEWAY_PAYPAL_EXPRESS)) { if (!$account->isGatewayConfigured(GATEWAY_PAYPAL_EXPRESS)) {
$paymentURL = URL::to($paymentURL); $paymentURL = URL::to($paymentURL);
} }
} }
if ($wepayGateway = $account->getGatewayConfig(GATEWAY_WEPAY)){
$data['enableWePayACH'] = $wepayGateway->getAchEnabled();
}
$showApprove = $invoice->quote_invoice_id ? false : true; $showApprove = $invoice->quote_invoice_id ? false : true;
if ($invoice->due_date) { if ($invoice->due_date) {
$showApprove = time() < strtotime($invoice->due_date); $showApprove = time() < strtotime($invoice->due_date);
@ -109,28 +119,10 @@ class PublicClientController extends BaseController
$showApprove = false; $showApprove = false;
} }
// Checkout.com requires first getting a payment token $data += [
$checkoutComToken = false;
$checkoutComKey = false;
$checkoutComDebug = false;
if ($accountGateway = $account->getGatewayConfig(GATEWAY_CHECKOUT_COM)) {
$checkoutComDebug = $accountGateway->getConfigField('testMode');
if ($checkoutComToken = $this->paymentService->getCheckoutComToken($invitation)) {
$checkoutComKey = $accountGateway->getConfigField('publicApiKey');
$invitation->transaction_reference = $checkoutComToken;
$invitation->save();
}
}
$data = array(
'account' => $account, 'account' => $account,
'showApprove' => $showApprove, 'showApprove' => $showApprove,
'showBreadcrumbs' => false, 'showBreadcrumbs' => false,
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL),
'hideHeader' => $account->isNinjaAccount() || !$account->enable_client_portal,
'hideDashboard' => !$account->enable_client_portal_dashboard,
'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS),
'clientViewCSS' => $account->clientViewCSS(),
'clientFontUrl' => $account->getFontsUrl(), 'clientFontUrl' => $account->getFontsUrl(),
'invoice' => $invoice->hidePrivateFields(), 'invoice' => $invoice->hidePrivateFields(),
'invitation' => $invitation, 'invitation' => $invitation,
@ -138,15 +130,22 @@ class PublicClientController extends BaseController
'contact' => $contact, 'contact' => $contact,
'paymentTypes' => $paymentTypes, 'paymentTypes' => $paymentTypes,
'paymentURL' => $paymentURL, 'paymentURL' => $paymentURL,
'checkoutComToken' => $checkoutComToken,
'checkoutComKey' => $checkoutComKey,
'checkoutComDebug' => $checkoutComDebug,
'phantomjs' => Input::has('phantomjs'), 'phantomjs' => Input::has('phantomjs'),
); ];
if ($paymentDriver = $account->paymentDriver($invitation, GATEWAY_TYPE_CREDIT_CARD)) {
$data += [
'transactionToken' => $paymentDriver->createTransactionToken(),
'partialView' => $paymentDriver->partialView(),
'accountGateway' => $paymentDriver->accountGateway,
];
}
if($account->hasFeature(FEATURE_DOCUMENTS) && $this->canCreateZip()){ if($account->hasFeature(FEATURE_DOCUMENTS) && $this->canCreateZip()){
$zipDocs = $this->getInvoiceZipDocuments($invoice, $size); $zipDocs = $this->getInvoiceZipDocuments($invoice, $size);
if(count($zipDocs) > 1){ if(count($zipDocs) > 1){
$data['documentsZipURL'] = URL::to("client/documents/{$invitation->invitation_key}"); $data['documentsZipURL'] = URL::to("client/documents/{$invitation->invitation_key}");
$data['documentsZipSize'] = $size; $data['documentsZipSize'] = $size;
@ -156,32 +155,29 @@ class PublicClientController extends BaseController
return View::make('invoices.view', $data); return View::make('invoices.view', $data);
} }
private function getPaymentTypes($client, $invitation) public function contactIndex($contactKey) {
if (!$contact = Contact::where('contact_key', '=', $contactKey)->first()) {
return $this->returnError();
}
$client = $contact->client;
Session::put('contact_key', $contactKey);// track current contact
return redirect()->to($client->account->enable_client_portal_dashboard?'/client/dashboard':'/client/invoices/');
}
private function getPaymentTypes($account, $client, $invitation)
{ {
$paymentTypes = []; $links = [];
$account = $client->account;
if ($client->getGatewayToken()) { foreach ($account->account_gateways as $accountGateway) {
$paymentTypes[] = [ $paymentDriver = $accountGateway->paymentDriver($invitation);
'url' => URL::to("payment/{$invitation->invitation_key}/token"), 'label' => trans('texts.use_card_on_file') $links = array_merge($links, $paymentDriver->tokenLinks());
]; $links = array_merge($links, $paymentDriver->paymentLinks());
}
foreach(Gateway::$paymentTypes as $type) {
if ($account->getGatewayByType($type)) {
$typeLink = strtolower(str_replace('PAYMENT_TYPE_', '', $type));
$url = URL::to("/payment/{$invitation->invitation_key}/{$typeLink}");
// PayPal doesn't allow being run in an iframe so we need to open in new tab
if ($type === PAYMENT_TYPE_PAYPAL && $account->iframe_url) {
$url = 'javascript:window.open("'.$url.'", "_blank")';
}
$paymentTypes[] = [
'url' => $url, 'label' => trans('texts.'.strtolower($type))
];
}
} }
return $paymentTypes; return $links;
} }
public function download($invitationKey) public function download($invitationKey)
@ -207,40 +203,46 @@ class PublicClientController extends BaseController
public function dashboard() public function dashboard()
{ {
if (!$invitation = $this->getInvitation()) { if (!$contact = $this->getContact()) {
return $this->returnError(); return $this->returnError();
} }
$account = $invitation->account; $client = $contact->client;
$invoice = $invitation->invoice; $account = $client->account;
$client = $invoice->client;
$color = $account->primary_color ? $account->primary_color : '#0b4d78'; $color = $account->primary_color ? $account->primary_color : '#0b4d78';
$customer = false;
if (!$account->enable_client_portal || !$account->enable_client_portal_dashboard) { if (!$account->enable_client_portal || !$account->enable_client_portal_dashboard) {
return $this->returnError(); return $this->returnError();
} }
if ($paymentDriver = $account->paymentDriver(false, GATEWAY_TYPE_TOKEN)) {
$customer = $paymentDriver->customer($client->id);
}
$data = [ $data = [
'color' => $color, 'color' => $color,
'contact' => $contact,
'account' => $account, 'account' => $account,
'client' => $client, 'client' => $client,
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL),
'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS),
'clientViewCSS' => $account->clientViewCSS(),
'clientFontUrl' => $account->getFontsUrl(), 'clientFontUrl' => $account->getFontsUrl(),
'gateway' => $account->getTokenGateway(),
'paymentMethods' => $customer ? $customer->payment_methods : false,
'transactionToken' => $paymentDriver ? $paymentDriver->createTransactionToken() : false,
]; ];
return response()->view('invited.dashboard', $data); return response()->view('invited.dashboard', $data);
} }
public function activityDatatable() public function activityDatatable()
{ {
if (!$invitation = $this->getInvitation()) { if (!$contact = $this->getContact()) {
return false; return $this->returnError();
} }
$invoice = $invitation->invoice;
$query = $this->activityRepo->findByClientId($invoice->client_id); $client = $contact->client;
$query = $this->activityRepo->findByClientId($client->id);
$query->where('activities.adjustment', '!=', 0); $query->where('activities.adjustment', '!=', 0);
return Datatable::query($query) return Datatable::query($query)
@ -248,10 +250,13 @@ class PublicClientController extends BaseController
->addColumn('activity_type_id', function ($model) { ->addColumn('activity_type_id', function ($model) {
$data = [ $data = [
'client' => Utils::getClientDisplayName($model), 'client' => Utils::getClientDisplayName($model),
'user' => $model->is_system ? ('<i>' . trans('texts.system') . '</i>') : ($model->user_first_name . ' ' . $model->user_last_name), 'user' => $model->is_system ? ('<i>' . trans('texts.system') . '</i>') : ($model->account_name),
'invoice' => trans('texts.invoice') . ' ' . $model->invoice, 'invoice' => $model->invoice,
'contact' => Utils::getClientDisplayName($model), 'contact' => Utils::getClientDisplayName($model),
'payment' => trans('texts.payment') . ($model->payment ? ' ' . $model->payment : ''), 'payment' => $model->payment ? ' ' . $model->payment : '',
'credit' => $model->payment_amount ? Utils::formatMoney($model->credit, $model->currency_id, $model->country_id) : '',
'payment_amount' => $model->payment_amount ? Utils::formatMoney($model->payment_amount, $model->currency_id, $model->country_id) : null,
'adjustment' => $model->adjustment ? Utils::formatMoney($model->adjustment, $model->currency_id, $model->country_id) : null,
]; ];
return trans("texts.activity_{$model->activity_type_id}", $data); return trans("texts.activity_{$model->activity_type_id}", $data);
@ -261,26 +266,51 @@ class PublicClientController extends BaseController
->make(); ->make();
} }
public function invoiceIndex() public function recurringInvoiceIndex()
{ {
if (!$invitation = $this->getInvitation()) { if (!$contact = $this->getContact()) {
return $this->returnError(); return $this->returnError();
} }
$account = $invitation->account; $account = $contact->account;
if (!$account->enable_client_portal) { if (!$account->enable_client_portal) {
return $this->returnError(); return $this->returnError();
} }
$color = $account->primary_color ? $account->primary_color : '#0b4d78'; $color = $account->primary_color ? $account->primary_color : '#0b4d78';
$data = [ $data = [
'color' => $color, 'color' => $color,
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL), 'account' => $account,
'hideDashboard' => !$account->enable_client_portal_dashboard, 'client' => $contact->client,
'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS), 'clientFontUrl' => $account->getFontsUrl(),
'clientViewCSS' => $account->clientViewCSS(), 'title' => trans('texts.recurring_invoices'),
'entityType' => ENTITY_RECURRING_INVOICE,
'columns' => Utils::trans(['frequency', 'start_date', 'end_date', 'invoice_total', 'auto_bill']),
];
return response()->view('public_list', $data);
}
public function invoiceIndex()
{
if (!$contact = $this->getContact()) {
return $this->returnError();
}
$account = $contact->account;
if (!$account->enable_client_portal) {
return $this->returnError();
}
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
$data = [
'color' => $color,
'account' => $account,
'client' => $contact->client,
'clientFontUrl' => $account->getFontsUrl(), 'clientFontUrl' => $account->getFontsUrl(),
'title' => trans('texts.invoices'), 'title' => trans('texts.invoices'),
'entityType' => ENTITY_INVOICE, 'entityType' => ENTITY_INVOICE,
@ -292,36 +322,43 @@ class PublicClientController extends BaseController
public function invoiceDatatable() public function invoiceDatatable()
{ {
if (!$invitation = $this->getInvitation()) { if (!$contact = $this->getContact()) {
return ''; return '';
} }
return $this->invoiceRepo->getClientDatatable($invitation->contact_id, ENTITY_INVOICE, Input::get('sSearch')); return $this->invoiceRepo->getClientDatatable($contact->id, ENTITY_INVOICE, Input::get('sSearch'));
}
public function recurringInvoiceDatatable()
{
if (!$contact = $this->getContact()) {
return '';
}
return $this->invoiceRepo->getClientRecurringDatatable($contact->id);
} }
public function paymentIndex() public function paymentIndex()
{ {
if (!$invitation = $this->getInvitation()) { if (!$contact = $this->getContact()) {
return $this->returnError(); return $this->returnError();
} }
$account = $invitation->account;
$account = $contact->account;
if (!$account->enable_client_portal) { if (!$account->enable_client_portal) {
return $this->returnError(); return $this->returnError();
} }
$color = $account->primary_color ? $account->primary_color : '#0b4d78'; $color = $account->primary_color ? $account->primary_color : '#0b4d78';
$data = [ $data = [
'color' => $color, 'color' => $color,
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL), 'account' => $account,
'hideDashboard' => !$account->enable_client_portal_dashboard,
'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS),
'clientViewCSS' => $account->clientViewCSS(),
'clientFontUrl' => $account->getFontsUrl(), 'clientFontUrl' => $account->getFontsUrl(),
'entityType' => ENTITY_PAYMENT, 'entityType' => ENTITY_PAYMENT,
'title' => trans('texts.payments'), 'title' => trans('texts.payments'),
'columns' => Utils::trans(['invoice', 'transaction_reference', 'method', 'payment_amount', 'payment_date']) 'columns' => Utils::trans(['invoice', 'transaction_reference', 'method', 'payment_amount', 'payment_date', 'status'])
]; ];
return response()->view('public_list', $data); return response()->view('public_list', $data);
@ -329,27 +366,56 @@ class PublicClientController extends BaseController
public function paymentDatatable() public function paymentDatatable()
{ {
if (!$invitation = $this->getInvitation()) { if (!$contact = $this->getContact()) {
return false; return $this->returnError();
} }
$payments = $this->paymentRepo->findForContact($invitation->contact->id, Input::get('sSearch')); $payments = $this->paymentRepo->findForContact($contact->id, Input::get('sSearch'));
return Datatable::query($payments) return Datatable::query($payments)
->addColumn('invoice_number', function ($model) { return $model->invitation_key ? link_to('/view/'.$model->invitation_key, $model->invoice_number)->toHtml() : $model->invoice_number; }) ->addColumn('invoice_number', function ($model) { return $model->invitation_key ? link_to('/view/'.$model->invitation_key, $model->invoice_number)->toHtml() : $model->invoice_number; })
->addColumn('transaction_reference', function ($model) { return $model->transaction_reference ? $model->transaction_reference : '<i>Manual entry</i>'; }) ->addColumn('transaction_reference', function ($model) { return $model->transaction_reference ? $model->transaction_reference : '<i>'.trans('texts.manual_entry').'</i>'; })
->addColumn('payment_type', function ($model) { return $model->payment_type ? $model->payment_type : ($model->account_gateway_id ? '<i>Online payment</i>' : ''); }) ->addColumn('payment_type', function ($model) { return ($model->payment_type && !$model->last4) ? $model->payment_type : ($model->account_gateway_id ? '<i>Online payment</i>' : ''); })
->addColumn('amount', function ($model) { return Utils::formatMoney($model->amount, $model->currency_id, $model->country_id); }) ->addColumn('amount', function ($model) { return Utils::formatMoney($model->amount, $model->currency_id, $model->country_id); })
->addColumn('payment_date', function ($model) { return Utils::dateToString($model->payment_date); }) ->addColumn('payment_date', function ($model) { return Utils::dateToString($model->payment_date); })
->addColumn('status', function ($model) { return $this->getPaymentStatusLabel($model); })
->orderColumns( 'invoice_number', 'transaction_reference', 'payment_type', 'amount', 'payment_date')
->make(); ->make();
} }
private function getPaymentStatusLabel($model)
{
$label = trans('texts.status_' . strtolower($model->payment_status_name));
$class = 'default';
switch ($model->payment_status_id) {
case PAYMENT_STATUS_PENDING:
$class = 'info';
break;
case PAYMENT_STATUS_COMPLETED:
$class = 'success';
break;
case PAYMENT_STATUS_FAILED:
$class = 'danger';
break;
case PAYMENT_STATUS_PARTIALLY_REFUNDED:
$label = trans('texts.status_partially_refunded_amount', [
'amount' => Utils::formatMoney($model->refunded, $model->currency_id, $model->country_id),
]);
$class = 'primary';
break;
case PAYMENT_STATUS_REFUNDED:
$class = 'default';
break;
}
return "<h4><div class=\"label label-{$class}\">$label</div></h4>";
}
public function quoteIndex() public function quoteIndex()
{ {
if (!$invitation = $this->getInvitation()) { if (!$contact = $this->getContact()) {
return $this->returnError(); return $this->returnError();
} }
$account = $invitation->account; $account = $contact->account;
if (!$account->enable_client_portal) { if (!$account->enable_client_portal) {
return $this->returnError(); return $this->returnError();
@ -358,10 +424,7 @@ class PublicClientController extends BaseController
$color = $account->primary_color ? $account->primary_color : '#0b4d78'; $color = $account->primary_color ? $account->primary_color : '#0b4d78';
$data = [ $data = [
'color' => $color, 'color' => $color,
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL), 'account' => $account,
'hideDashboard' => !$account->enable_client_portal_dashboard,
'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS),
'clientViewCSS' => $account->clientViewCSS(),
'clientFontUrl' => $account->getFontsUrl(), 'clientFontUrl' => $account->getFontsUrl(),
'title' => trans('texts.quotes'), 'title' => trans('texts.quotes'),
'entityType' => ENTITY_QUOTE, 'entityType' => ENTITY_QUOTE,
@ -374,32 +437,29 @@ class PublicClientController extends BaseController
public function quoteDatatable() public function quoteDatatable()
{ {
if (!$invitation = $this->getInvitation()) { if (!$contact = $this->getContact()) {
return false; return false;
} }
return $this->invoiceRepo->getClientDatatable($invitation->contact_id, ENTITY_QUOTE, Input::get('sSearch')); return $this->invoiceRepo->getClientDatatable($contact->id, ENTITY_QUOTE, Input::get('sSearch'));
} }
public function documentIndex() public function documentIndex()
{ {
if (!$invitation = $this->getInvitation()) { if (!$contact = $this->getContact()) {
return $this->returnError(); return $this->returnError();
} }
$account = $invitation->account; $account = $contact->account;
if (!$account->enable_client_portal) { if (!$account->enable_client_portal) {
return $this->returnError(); return $this->returnError();
} }
$color = $account->primary_color ? $account->primary_color : '#0b4d78'; $color = $account->primary_color ? $account->primary_color : '#0b4d78';
$data = [ $data = [
'color' => $color, 'color' => $color,
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL), 'account' => $account,
'hideDashboard' => !$account->enable_client_portal_dashboard,
'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS),
'clientViewCSS' => $account->clientViewCSS(),
'clientFontUrl' => $account->getFontsUrl(), 'clientFontUrl' => $account->getFontsUrl(),
'title' => trans('texts.documents'), 'title' => trans('texts.documents'),
'entityType' => ENTITY_DOCUMENT, 'entityType' => ENTITY_DOCUMENT,
@ -412,11 +472,11 @@ class PublicClientController extends BaseController
public function documentDatatable() public function documentDatatable()
{ {
if (!$invitation = $this->getInvitation()) { if (!$contact = $this->getContact()) {
return false; return false;
} }
return $this->documentRepo->getClientDatatable($invitation->contact_id, ENTITY_DOCUMENT, Input::get('sSearch')); return $this->documentRepo->getClientDatatable($contact->id, ENTITY_DOCUMENT, Input::get('sSearch'));
} }
private function returnError($error = false) private function returnError($error = false)
@ -424,97 +484,90 @@ class PublicClientController extends BaseController
return response()->view('error', [ return response()->view('error', [
'error' => $error ?: trans('texts.invoice_not_found'), 'error' => $error ?: trans('texts.invoice_not_found'),
'hideHeader' => true, 'hideHeader' => true,
'account' => $this->getContact()->account,
]); ]);
} }
private function getInvitation() private function getContact() {
{ $contactKey = session('contact_key');
$invitationKey = session('invitation_key');
if (!$invitationKey) { if (!$contactKey) {
return false; return false;
} }
$invitation = Invitation::where('invitation_key', '=', $invitationKey)->first(); $contact = Contact::where('contact_key', '=', $contactKey)->first();
if (!$invitation || $invitation->is_deleted) { if (!$contact || $contact->is_deleted) {
return false; return false;
} }
$invoice = $invitation->invoice; return $contact;
if (!$invoice || $invoice->is_deleted) {
return false;
}
return $invitation;
} }
public function getDocumentVFSJS($publicId, $name){ public function getDocumentVFSJS($publicId, $name){
if (!$invitation = $this->getInvitation()) { if (!$contact = $this->getContact()) {
return $this->returnError(); return $this->returnError();
} }
$clientId = $invitation->invoice->client_id; $document = Document::scope($publicId, $contact->account_id)->first();
$document = Document::scope($publicId, $invitation->account_id)->first();
if(!$document->isPDFEmbeddable()){ if(!$document->isPDFEmbeddable()){
return Response::view('error', array('error'=>'Image does not exist!'), 404); return Response::view('error', ['error'=>'Image does not exist!'], 404);
} }
$authorized = false; $authorized = false;
if($document->expense && $document->expense->client_id == $invitation->invoice->client_id){ if($document->expense && $document->expense->client_id == $contact->client_id){
$authorized = true; $authorized = true;
} else if($document->invoice && $document->invoice->client_id == $invitation->invoice->client_id){ } else if($document->invoice && $document->invoice->client_id ==$contact->client_id){
$authorized = true; $authorized = true;
} }
if(!$authorized){ if(!$authorized){
return Response::view('error', array('error'=>'Not authorized'), 403); return Response::view('error', ['error'=>'Not authorized'], 403);
} }
if(substr($name, -3)=='.js'){ if(substr($name, -3)=='.js'){
$name = substr($name, 0, -3); $name = substr($name, 0, -3);
} }
$content = $document->preview?$document->getRawPreview():$document->getRaw(); $content = $document->preview?$document->getRawPreview():$document->getRaw();
$content = 'ninjaAddVFSDoc('.json_encode(intval($publicId).'/'.strval($name)).',"'.base64_encode($content).'")'; $content = 'ninjaAddVFSDoc('.json_encode(intval($publicId).'/'.strval($name)).',"'.base64_encode($content).'")';
$response = Response::make($content, 200); $response = Response::make($content, 200);
$response->header('content-type', 'text/javascript'); $response->header('content-type', 'text/javascript');
$response->header('cache-control', 'max-age=31536000'); $response->header('cache-control', 'max-age=31536000');
return $response; return $response;
} }
protected function canCreateZip(){ protected function canCreateZip(){
return function_exists('gmp_init'); return function_exists('gmp_init');
} }
protected function getInvoiceZipDocuments($invoice, &$size=0){ protected function getInvoiceZipDocuments($invoice, &$size=0){
$documents = $invoice->documents; $documents = $invoice->documents;
foreach($invoice->expenses as $expense){ foreach($invoice->expenses as $expense){
$documents = $documents->merge($expense->documents); $documents = $documents->merge($expense->documents);
} }
$documents = $documents->sortBy('size'); $documents = $documents->sortBy('size');
$size = 0; $size = 0;
$maxSize = MAX_ZIP_DOCUMENTS_SIZE * 1000; $maxSize = MAX_ZIP_DOCUMENTS_SIZE * 1000;
$toZip = array(); $toZip = [];
foreach($documents as $document){ foreach($documents as $document){
if($size + $document->size > $maxSize)break; if($size + $document->size > $maxSize)break;
if(!empty($toZip[$document->name])){ if(!empty($toZip[$document->name])){
// This name is taken // This name is taken
if($toZip[$document->name]->hash != $document->hash){ if($toZip[$document->name]->hash != $document->hash){
// 2 different files with the same name // 2 different files with the same name
$nameInfo = pathinfo($document->name); $nameInfo = pathinfo($document->name);
for($i = 1;; $i++){ for($i = 1;; $i++){
$name = $nameInfo['filename'].' ('.$i.').'.$nameInfo['extension']; $name = $nameInfo['filename'].' ('.$i.').'.$nameInfo['extension'];
if(empty($toZip[$name])){ if(empty($toZip[$name])){
$toZip[$name] = $document; $toZip[$name] = $document;
$size += $document->size; $size += $document->size;
@ -524,7 +577,7 @@ class PublicClientController extends BaseController
break; break;
} }
} }
} }
} }
else{ else{
@ -532,31 +585,31 @@ class PublicClientController extends BaseController
$size += $document->size; $size += $document->size;
} }
} }
return $toZip; return $toZip;
} }
public function getInvoiceDocumentsZip($invitationKey){ public function getInvoiceDocumentsZip($invitationKey){
if (!$invitation = $this->invoiceRepo->findInvoiceByInvitation($invitationKey)) { if (!$invitation = $this->invoiceRepo->findInvoiceByInvitation($invitationKey)) {
return $this->returnError(); return $this->returnError();
} }
Session::put('invitation_key', $invitationKey); // track current invitation Session::put('contact_key', $invitation->contact->contact_key);// track current contact
$invoice = $invitation->invoice; $invoice = $invitation->invoice;
$toZip = $this->getInvoiceZipDocuments($invoice); $toZip = $this->getInvoiceZipDocuments($invoice);
if(!count($toZip)){ if(!count($toZip)){
return Response::view('error', array('error'=>'No documents small enough'), 404); return Response::view('error', ['error'=>'No documents small enough'], 404);
} }
$zip = new ZipArchive($invitation->account->name.' Invoice '.$invoice->invoice_number.'.zip'); $zip = new ZipArchive($invitation->account->name.' Invoice '.$invoice->invoice_number.'.zip');
return Response::stream(function() use ($toZip, $zip) { return Response::stream(function() use ($toZip, $zip) {
foreach($toZip as $name=>$document){ foreach($toZip as $name=>$document){
$fileStream = $document->getStream(); $fileStream = $document->getStream();
if($fileStream){ if($fileStream){
$zip->init_file_stream_transfer($name, $document->size, array('time'=>$document->created_at->timestamp)); $zip->init_file_stream_transfer($name, $document->size, ['time'=>$document->created_at->timestamp]);
while ($buffer = fread($fileStream, 256000))$zip->stream_file_part($buffer); while ($buffer = fread($fileStream, 256000))$zip->stream_file_part($buffer);
fclose($fileStream); fclose($fileStream);
$zip->complete_file_stream(); $zip->complete_file_stream();
@ -568,29 +621,169 @@ class PublicClientController extends BaseController
$zip->finish(); $zip->finish();
}, 200); }, 200);
} }
public function getDocument($invitationKey, $publicId){ public function getDocument($invitationKey, $publicId){
if (!$invitation = $this->invoiceRepo->findInvoiceByInvitation($invitationKey)) { if (!$invitation = $this->invoiceRepo->findInvoiceByInvitation($invitationKey)) {
return $this->returnError(); return $this->returnError();
} }
Session::put('invitation_key', $invitationKey); // track current invitation Session::put('contact_key', $invitation->contact->contact_key);// track current contact
$clientId = $invitation->invoice->client_id; $clientId = $invitation->invoice->client_id;
$document = Document::scope($publicId, $invitation->account_id)->firstOrFail(); $document = Document::scope($publicId, $invitation->account_id)->firstOrFail();
$authorized = false; $authorized = false;
if($document->expense && $document->expense->client_id == $invitation->invoice->client_id){ if($document->expense && $document->expense->client_id == $invitation->invoice->client_id){
$authorized = true; $authorized = true;
} else if($document->invoice && $document->invoice->client_id == $invitation->invoice->client_id){ } else if($document->invoice && $document->invoice->client_id == $invitation->invoice->client_id){
$authorized = true; $authorized = true;
} }
if(!$authorized){ if(!$authorized){
return Response::view('error', array('error'=>'Not authorized'), 403); return Response::view('error', ['error'=>'Not authorized'], 403);
} }
return DocumentController::getDownloadResponse($document); return DocumentController::getDownloadResponse($document);
} }
public function paymentMethods()
{
if (!$contact = $this->getContact()) {
return $this->returnError();
}
$client = $contact->client;
$account = $client->account;
$paymentDriver = $account->paymentDriver(false, GATEWAY_TYPE_TOKEN);
$customer = $paymentDriver->customer($client->id);
$data = [
'account' => $account,
'contact' => $contact,
'color' => $account->primary_color ? $account->primary_color : '#0b4d78',
'client' => $client,
'clientViewCSS' => $account->clientViewCSS(),
'clientFontUrl' => $account->getFontsUrl(),
'paymentMethods' => $customer ? $customer->payment_methods : false,
'gateway' => $account->getTokenGateway(),
'title' => trans('texts.payment_methods'),
'transactionToken' => $paymentDriver->createTransactionToken(),
];
return response()->view('payments.paymentmethods', $data);
}
public function verifyPaymentMethod()
{
$publicId = Input::get('source_id');
$amount1 = Input::get('verification1');
$amount2 = Input::get('verification2');
if (!$contact = $this->getContact()) {
return $this->returnError();
}
$client = $contact->client;
$account = $client->account;
$paymentDriver = $account->paymentDriver(null, GATEWAY_TYPE_BANK_TRANSFER);
$result = $paymentDriver->verifyBankAccount($client, $publicId, $amount1, $amount2);
if (is_string($result)) {
Session::flash('error', $result);
} else {
Session::flash('message', trans('texts.payment_method_verified'));
}
return redirect()->to($account->enable_client_portal_dashboard?'/client/dashboard':'/client/payment_methods/');
}
public function removePaymentMethod($publicId)
{
if (!$contact = $this->getContact()) {
return $this->returnError();
}
$client = $contact->client;
$account = $contact->account;
$paymentDriver = $account->paymentDriver(false, GATEWAY_TYPE_TOKEN);
$paymentMethod = PaymentMethod::clientId($client->id)
->wherePublicId($publicId)
->firstOrFail();
try {
$paymentDriver->removePaymentMethod($paymentMethod);
Session::flash('message', trans('texts.payment_method_removed'));
} catch (Exception $exception) {
Session::flash('error', $exception->getMessage());
}
return redirect()->to($client->account->enable_client_portal_dashboard?'/client/dashboard':'/client/payment_methods/');
}
public function setDefaultPaymentMethod(){
if (!$contact = $this->getContact()) {
return $this->returnError();
}
$client = $contact->client;
$account = $client->account;
$validator = Validator::make(Input::all(), ['source' => 'required']);
if ($validator->fails()) {
return Redirect::to($client->account->enable_client_portal_dashboard?'/client/dashboard':'/client/payment_methods/');
}
$paymentDriver = $account->paymentDriver(false, GATEWAY_TYPE_TOKEN);
$paymentMethod = PaymentMethod::clientId($client->id)
->wherePublicId(Input::get('source'))
->firstOrFail();
$customer = $paymentDriver->customer($client->id);
$customer->default_payment_method_id = $paymentMethod->id;
$customer->save();
Session::flash('message', trans('texts.payment_method_set_as_default'));
return redirect()->to($client->account->enable_client_portal_dashboard?'/client/dashboard':'/client/payment_methods/');
}
private function paymentMethodError($type, $error, $accountGateway = false, $exception = false)
{
$message = '';
if ($accountGateway && $accountGateway->gateway) {
$message = $accountGateway->gateway->name . ': ';
}
$message .= $error ?: trans('texts.payment_method_error');
Session::flash('error', $message);
Utils::logError("Payment Method Error [{$type}]: " . ($exception ? Utils::getErrorString($exception) : $message), 'PHP', true);
}
public function setAutoBill(){
if (!$contact = $this->getContact()) {
return $this->returnError();
}
$client = $contact->client;
$validator = Validator::make(Input::all(), ['public_id' => 'required']);
if ($validator->fails()) {
return Redirect::to('client/invoices/recurring');
}
$publicId = Input::get('public_id');
$enable = Input::get('enable');
$invoice = $client->invoices()->where('public_id', intval($publicId))->first();
if ($invoice && $invoice->is_recurring && ($invoice->auto_bill == AUTO_BILL_OPT_IN || $invoice->auto_bill == AUTO_BILL_OPT_OUT)) {
$invoice->client_enable_auto_bill = $enable ? true : false;
$invoice->save();
}
return Redirect::to('client/invoices/recurring');
}
} }

View File

@ -4,8 +4,10 @@ use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController; use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests; use Illuminate\Foundation\Validation\ValidatesRequests;
abstract class Controller extends BaseController { /**
* Class Controller
use DispatchesJobs, ValidatesRequests; */
abstract class Controller extends BaseController
{
use DispatchesJobs, ValidatesRequests;
} }

View File

@ -1,13 +1,11 @@
<?php namespace App\Http\Controllers; <?php namespace App\Http\Controllers;
use Datatable;
use Input; use Input;
use Redirect; use Redirect;
use Session; use Session;
use URL; use URL;
use Utils; use Utils;
use View; use View;
use Validator;
use App\Models\Client; use App\Models\Client;
use App\Services\CreditService; use App\Services\CreditService;
use App\Ninja\Repositories\CreditRepository; use App\Ninja\Repositories\CreditRepository;
@ -35,7 +33,7 @@ class CreditController extends BaseController
*/ */
public function index() public function index()
{ {
return View::make('list', array( return View::make('list', [
'entityType' => ENTITY_CREDIT, 'entityType' => ENTITY_CREDIT,
'title' => trans('texts.credits'), 'title' => trans('texts.credits'),
'sortCol' => '4', 'sortCol' => '4',
@ -48,7 +46,7 @@ class CreditController extends BaseController
'private_notes', 'private_notes',
'' ''
]), ]),
)); ]);
} }
public function getDatatable($clientPublicId = null) public function getDatatable($clientPublicId = null)
@ -58,14 +56,14 @@ class CreditController extends BaseController
public function create(CreditRequest $request) public function create(CreditRequest $request)
{ {
$data = array( $data = [
'clientPublicId' => Input::old('client') ? Input::old('client') : ($request->client_id ?: 0), 'clientPublicId' => Input::old('client') ? Input::old('client') : ($request->client_id ?: 0),
'credit' => null, 'credit' => null,
'method' => 'POST', 'method' => 'POST',
'url' => 'credits', 'url' => 'credits',
'title' => trans('texts.new_credit'), 'title' => trans('texts.new_credit'),
'clients' => Client::scope()->viewable()->with('contacts')->orderBy('name')->get(), 'clients' => Client::scope()->with('contacts')->orderBy('name')->get(),
); ];
return View::make('credits.edit', $data); return View::make('credits.edit', $data);
} }

View File

@ -2,14 +2,12 @@
use Auth; use Auth;
use DB; use DB;
use View;
use App\Models\Activity;
class DashboardApiController extends BaseAPIController class DashboardApiController extends BaseAPIController
{ {
public function index() public function index()
{ {
$view_all = !Auth::user()->hasPermission('view_all'); $view_all = Auth::user()->hasPermission('view_all');
$user_id = Auth::user()->id; $user_id = Auth::user()->id;
// total_income, billed_clients, invoice_sent and active_clients // total_income, billed_clients, invoice_sent and active_clients
@ -24,7 +22,7 @@ class DashboardApiController extends BaseAPIController
->where('clients.is_deleted', '=', false) ->where('clients.is_deleted', '=', false)
->where('invoices.is_deleted', '=', false) ->where('invoices.is_deleted', '=', false)
->where('invoices.is_recurring', '=', false) ->where('invoices.is_recurring', '=', false)
->where('invoices.is_quote', '=', false); ->where('invoices.invoice_type_id', '=', false);
if(!$view_all){ if(!$view_all){
$metrics = $metrics->where(function($query) use($user_id){ $metrics = $metrics->where(function($query) use($user_id){
@ -62,7 +60,7 @@ class DashboardApiController extends BaseAPIController
->where('accounts.id', '=', Auth::user()->account_id) ->where('accounts.id', '=', Auth::user()->account_id)
->where('clients.is_deleted', '=', false) ->where('clients.is_deleted', '=', false)
->where('invoices.is_deleted', '=', false) ->where('invoices.is_deleted', '=', false)
->where('invoices.is_quote', '=', false) ->where('invoices.invoice_type_id', '=', INVOICE_TYPE_STANDARD)
->where('invoices.is_recurring', '=', false); ->where('invoices.is_recurring', '=', false);
if(!$view_all){ if(!$view_all){
@ -80,8 +78,13 @@ class DashboardApiController extends BaseAPIController
->where('accounts.id', '=', Auth::user()->account_id) ->where('accounts.id', '=', Auth::user()->account_id)
->where('clients.is_deleted', '=', false) ->where('clients.is_deleted', '=', false)
->groupBy('accounts.id') ->groupBy('accounts.id')
->groupBy(DB::raw('CASE WHEN clients.currency_id IS NULL THEN CASE WHEN accounts.currency_id IS NULL THEN 1 ELSE accounts.currency_id END ELSE clients.currency_id END')) ->groupBy(DB::raw('CASE WHEN clients.currency_id IS NULL THEN CASE WHEN accounts.currency_id IS NULL THEN 1 ELSE accounts.currency_id END ELSE clients.currency_id END'));
->get();
if (!$view_all) {
$balances->where('clients.user_id', '=', $user_id);
}
$balances = $balances->get();
$pastDue = DB::table('invoices') $pastDue = DB::table('invoices')
->leftJoin('clients', 'clients.id', '=', 'invoices.client_id') ->leftJoin('clients', 'clients.id', '=', 'invoices.client_id')
@ -101,7 +104,7 @@ class DashboardApiController extends BaseAPIController
$pastDue = $pastDue->where('invoices.user_id', '=', $user_id); $pastDue = $pastDue->where('invoices.user_id', '=', $user_id);
} }
$pastDue = $pastDue->select(['invoices.due_date', 'invoices.balance', 'invoices.public_id', 'invoices.invoice_number', 'clients.name as client_name', 'contacts.email', 'contacts.first_name', 'contacts.last_name', 'clients.currency_id', 'clients.public_id as client_public_id', 'clients.user_id as client_user_id', 'is_quote']) $pastDue = $pastDue->select(['invoices.due_date', 'invoices.balance', 'invoices.public_id', 'invoices.invoice_number', 'clients.name as client_name', 'contacts.email', 'contacts.first_name', 'contacts.last_name', 'clients.currency_id', 'clients.public_id as client_public_id', 'clients.user_id as client_user_id', 'invoice_type_id'])
->orderBy('invoices.due_date', 'asc') ->orderBy('invoices.due_date', 'asc')
->take(50) ->take(50)
->get(); ->get();
@ -126,7 +129,7 @@ class DashboardApiController extends BaseAPIController
} }
$upcoming = $upcoming->take(50) $upcoming = $upcoming->take(50)
->select(['invoices.due_date', 'invoices.balance', 'invoices.public_id', 'invoices.invoice_number', 'clients.name as client_name', 'contacts.email', 'contacts.first_name', 'contacts.last_name', 'clients.currency_id', 'clients.public_id as client_public_id', 'clients.user_id as client_user_id', 'is_quote']) ->select(['invoices.due_date', 'invoices.balance', 'invoices.public_id', 'invoices.invoice_number', 'clients.name as client_name', 'contacts.email', 'contacts.first_name', 'contacts.last_name', 'clients.currency_id', 'clients.public_id as client_public_id', 'clients.user_id as client_user_id', 'invoice_type_id'])
->get(); ->get();
$payments = DB::table('payments') $payments = DB::table('payments')
@ -152,21 +155,20 @@ class DashboardApiController extends BaseAPIController
$hasQuotes = false; $hasQuotes = false;
foreach ([$upcoming, $pastDue] as $data) { foreach ([$upcoming, $pastDue] as $data) {
foreach ($data as $invoice) { foreach ($data as $invoice) {
if ($invoice->is_quote) { if ($invoice->invoice_type_id == INVOICE_TYPE_QUOTE) {
$hasQuotes = true; $hasQuotes = true;
} }
} }
} }
$data = [ $data = [
'id' => 1, 'id' => 1,
'paidToDate' => $paidToDate[0]->value, 'paidToDate' => $paidToDate[0]->value ? $paidToDate[0]->value : 0,
'paidToDateCurrency' => $paidToDate[0]->currency_id, 'paidToDateCurrency' => $paidToDate[0]->currency_id ? $paidToDate[0]->currency_id : 0,
'balances' => $balances[0]->value, 'balances' => $balances[0]->value ? $balances[0]->value : 0,
'balancesCurrency' => $balances[0]->currency_id, 'balancesCurrency' => $balances[0]->currency_id ? $balances[0]->currency_id : 0,
'averageInvoice' => $averageInvoice[0]->invoice_avg, 'averageInvoice' => $averageInvoice[0]->invoice_avg ? $averageInvoice[0]->invoice_avg : 0,
'averageInvoiceCurrency' => $averageInvoice[0]->currency_id, 'averageInvoiceCurrency' => $averageInvoice[0]->currency_id ? $averageInvoice[0]->currency_id : 0,
'invoicesSent' => $metrics ? $metrics->invoices_sent : 0, 'invoicesSent' => $metrics ? $metrics->invoices_sent : 0,
'activeClients' => $metrics ? $metrics->active_clients : 0, 'activeClients' => $metrics ? $metrics->active_clients : 0,
]; ];

View File

@ -7,17 +7,25 @@ use App\Models\Activity;
use App\Models\Invoice; use App\Models\Invoice;
use App\Models\Payment; use App\Models\Payment;
/**
* Class DashboardController
*/
class DashboardController extends BaseController class DashboardController extends BaseController
{ {
/**
* @return \Illuminate\Contracts\View\View
*/
public function index() public function index()
{ {
$view_all = Auth::user()->hasPermission('view_all'); $view_all = Auth::user()->hasPermission('view_all');
$user_id = Auth::user()->id; $user_id = Auth::user()->id;
// total_income, billed_clients, invoice_sent and active_clients // total_income, billed_clients, invoice_sent and active_clients
$select = DB::raw('COUNT(DISTINCT CASE WHEN invoices.id IS NOT NULL THEN clients.id ELSE null END) billed_clients, $select = DB::raw(
SUM(CASE WHEN invoices.invoice_status_id >= '.INVOICE_STATUS_SENT.' THEN 1 ELSE 0 END) invoices_sent, 'COUNT(DISTINCT CASE WHEN '.DB::getQueryGrammar()->wrap('invoices.id', true).' IS NOT NULL THEN '.DB::getQueryGrammar()->wrap('clients.id', true).' ELSE null END) billed_clients,
COUNT(DISTINCT clients.id) active_clients'); SUM(CASE WHEN '.DB::getQueryGrammar()->wrap('invoices.invoice_status_id', true).' >= '.INVOICE_STATUS_SENT.' THEN 1 ELSE 0 END) invoices_sent,
COUNT(DISTINCT '.DB::getQueryGrammar()->wrap('clients.id', true).') active_clients'
);
$metrics = DB::table('accounts') $metrics = DB::table('accounts')
->select($select) ->select($select)
->leftJoin('clients', 'accounts.id', '=', 'clients.account_id') ->leftJoin('clients', 'accounts.id', '=', 'clients.account_id')
@ -26,7 +34,7 @@ class DashboardController extends BaseController
->where('clients.is_deleted', '=', false) ->where('clients.is_deleted', '=', false)
->where('invoices.is_deleted', '=', false) ->where('invoices.is_deleted', '=', false)
->where('invoices.is_recurring', '=', false) ->where('invoices.is_recurring', '=', false)
->where('invoices.is_quote', '=', false); ->where('invoices.invoice_type_id', '=', INVOICE_TYPE_STANDARD);
if(!$view_all){ if(!$view_all){
$metrics = $metrics->where(function($query) use($user_id){ $metrics = $metrics->where(function($query) use($user_id){
@ -41,7 +49,10 @@ class DashboardController extends BaseController
$metrics = $metrics->groupBy('accounts.id') $metrics = $metrics->groupBy('accounts.id')
->first(); ->first();
$select = DB::raw('SUM(clients.paid_to_date) as value, clients.currency_id as currency_id'); $select = DB::raw(
'SUM('.DB::getQueryGrammar()->wrap('clients.paid_to_date', true).') as value,'
.DB::getQueryGrammar()->wrap('clients.currency_id', true).' as currency_id'
);
$paidToDate = DB::table('accounts') $paidToDate = DB::table('accounts')
->select($select) ->select($select)
->leftJoin('clients', 'accounts.id', '=', 'clients.account_id') ->leftJoin('clients', 'accounts.id', '=', 'clients.account_id')
@ -53,10 +64,13 @@ class DashboardController extends BaseController
} }
$paidToDate = $paidToDate->groupBy('accounts.id') $paidToDate = $paidToDate->groupBy('accounts.id')
->groupBy(DB::raw('CASE WHEN clients.currency_id IS NULL THEN CASE WHEN accounts.currency_id IS NULL THEN 1 ELSE accounts.currency_id END ELSE clients.currency_id END')) ->groupBy(DB::raw('CASE WHEN '.DB::getQueryGrammar()->wrap('clients.currency_id', true).' IS NULL THEN CASE WHEN '.DB::getQueryGrammar()->wrap('accounts.currency_id', true).' IS NULL THEN 1 ELSE '.DB::getQueryGrammar()->wrap('accounts.currency_id', true).' END ELSE '.DB::getQueryGrammar()->wrap('clients.currency_id', true).' END'))
->get(); ->get();
$select = DB::raw('AVG(invoices.amount) as invoice_avg, clients.currency_id as currency_id'); $select = DB::raw(
'AVG('.DB::getQueryGrammar()->wrap('invoices.amount', true).') as invoice_avg, '
.DB::getQueryGrammar()->wrap('clients.currency_id', true).' as currency_id'
);
$averageInvoice = DB::table('accounts') $averageInvoice = DB::table('accounts')
->select($select) ->select($select)
->leftJoin('clients', 'accounts.id', '=', 'clients.account_id') ->leftJoin('clients', 'accounts.id', '=', 'clients.account_id')
@ -64,7 +78,7 @@ class DashboardController extends BaseController
->where('accounts.id', '=', Auth::user()->account_id) ->where('accounts.id', '=', Auth::user()->account_id)
->where('clients.is_deleted', '=', false) ->where('clients.is_deleted', '=', false)
->where('invoices.is_deleted', '=', false) ->where('invoices.is_deleted', '=', false)
->where('invoices.is_quote', '=', false) ->where('invoices.invoice_type_id', '=', INVOICE_TYPE_STANDARD)
->where('invoices.is_recurring', '=', false); ->where('invoices.is_recurring', '=', false);
if(!$view_all){ if(!$view_all){
@ -72,17 +86,20 @@ class DashboardController extends BaseController
} }
$averageInvoice = $averageInvoice->groupBy('accounts.id') $averageInvoice = $averageInvoice->groupBy('accounts.id')
->groupBy(DB::raw('CASE WHEN clients.currency_id IS NULL THEN CASE WHEN accounts.currency_id IS NULL THEN 1 ELSE accounts.currency_id END ELSE clients.currency_id END')) ->groupBy(DB::raw('CASE WHEN '.DB::getQueryGrammar()->wrap('clients.currency_id', true).' IS NULL THEN CASE WHEN '.DB::getQueryGrammar()->wrap('accounts.currency_id', true).' IS NULL THEN 1 ELSE '.DB::getQueryGrammar()->wrap('accounts.currency_id', true).' END ELSE '.DB::getQueryGrammar()->wrap('clients.currency_id', true).' END'))
->get(); ->get();
$select = DB::raw('SUM(clients.balance) as value, clients.currency_id as currency_id'); $select = DB::raw(
'SUM('.DB::getQueryGrammar()->wrap('clients.balance', true).') as value, '
.DB::getQueryGrammar()->wrap('clients.currency_id', true).' as currency_id'
);
$balances = DB::table('accounts') $balances = DB::table('accounts')
->select($select) ->select($select)
->leftJoin('clients', 'accounts.id', '=', 'clients.account_id') ->leftJoin('clients', 'accounts.id', '=', 'clients.account_id')
->where('accounts.id', '=', Auth::user()->account_id) ->where('accounts.id', '=', Auth::user()->account_id)
->where('clients.is_deleted', '=', false) ->where('clients.is_deleted', '=', false)
->groupBy('accounts.id') ->groupBy('accounts.id')
->groupBy(DB::raw('CASE WHEN clients.currency_id IS NULL THEN CASE WHEN accounts.currency_id IS NULL THEN 1 ELSE accounts.currency_id END ELSE clients.currency_id END')); ->groupBy(DB::raw('CASE WHEN '.DB::getQueryGrammar()->wrap('clients.currency_id', true).' IS NULL THEN CASE WHEN '.DB::getQueryGrammar()->wrap('accounts.currency_id', true).' IS NULL THEN 1 ELSE '.DB::getQueryGrammar()->wrap('accounts.currency_id', true).' END ELSE '.DB::getQueryGrammar()->wrap('clients.currency_id', true).' END'));
if (!$view_all) { if (!$view_all) {
$balances->where('clients.user_id', '=', $user_id); $balances->where('clients.user_id', '=', $user_id);
@ -121,7 +138,7 @@ class DashboardController extends BaseController
$pastDue = $pastDue->where('invoices.user_id', '=', $user_id); $pastDue = $pastDue->where('invoices.user_id', '=', $user_id);
} }
$pastDue = $pastDue->select(['invoices.due_date', 'invoices.balance', 'invoices.public_id', 'invoices.invoice_number', 'clients.name as client_name', 'contacts.email', 'contacts.first_name', 'contacts.last_name', 'clients.currency_id', 'clients.public_id as client_public_id', 'clients.user_id as client_user_id', 'is_quote']) $pastDue = $pastDue->select(['invoices.due_date', 'invoices.balance', 'invoices.public_id', 'invoices.invoice_number', 'clients.name as client_name', 'contacts.email', 'contacts.first_name', 'contacts.last_name', 'clients.currency_id', 'clients.public_id as client_public_id', 'clients.user_id as client_user_id', 'invoice_type_id'])
->orderBy('invoices.due_date', 'asc') ->orderBy('invoices.due_date', 'asc')
->take(50) ->take(50)
->get(); ->get();
@ -147,7 +164,7 @@ class DashboardController extends BaseController
} }
$upcoming = $upcoming->take(50) $upcoming = $upcoming->take(50)
->select(['invoices.due_date', 'invoices.balance', 'invoices.public_id', 'invoices.invoice_number', 'clients.name as client_name', 'contacts.email', 'contacts.first_name', 'contacts.last_name', 'clients.currency_id', 'clients.public_id as client_public_id', 'clients.user_id as client_user_id', 'is_quote']) ->select(['invoices.due_date', 'invoices.balance', 'invoices.public_id', 'invoices.invoice_number', 'clients.name as client_name', 'contacts.email', 'contacts.first_name', 'contacts.last_name', 'clients.currency_id', 'clients.public_id as client_public_id', 'clients.user_id as client_user_id', 'invoice_type_id'])
->get(); ->get();
$payments = DB::table('payments') $payments = DB::table('payments')
@ -173,7 +190,7 @@ class DashboardController extends BaseController
$hasQuotes = false; $hasQuotes = false;
foreach ([$upcoming, $pastDue] as $data) { foreach ([$upcoming, $pastDue] as $data) {
foreach ($data as $invoice) { foreach ($data as $invoice) {
if ($invoice->is_quote) { if ($invoice->invoice_type_id == INVOICE_TYPE_QUOTE) {
$hasQuotes = true; $hasQuotes = true;
} }
} }

View File

@ -0,0 +1,70 @@
<?php namespace App\Http\Controllers;
use App\Models\Document;
use App\Ninja\Repositories\DocumentRepository;
use App\Http\Requests\DocumentRequest;
use App\Http\Requests\CreateDocumentRequest;
/**
* Class DocumentAPIController
*/
class DocumentAPIController extends BaseAPIController
{
/**
* @var DocumentRepository
*/
protected $documentRepo;
/**
* @var string
*/
protected $entityType = ENTITY_DOCUMENT;
/**
* DocumentAPIController constructor.
*
* @param DocumentRepository $documentRepo
*/
public function __construct(DocumentRepository $documentRepo)
{
parent::__construct();
$this->documentRepo = $documentRepo;
}
/**
* @return \Illuminate\Http\Response
*/
public function index()
{
$documents = Document::scope();
return $this->listResponse($documents);
}
/**
* @param DocumentRequest $request
*
* @return \Illuminate\Http\Response|\Redirect|\Symfony\Component\HttpFoundation\StreamedResponse
*/
public function show(DocumentRequest $request)
{
$document = $request->entity();
return DocumentController::getDownloadResponse($document);
}
/**
* @param CreateDocumentRequest $request
*
* @return \Illuminate\Http\Response
*/
public function store(CreateDocumentRequest $request)
{
$document = $this->documentRepo->upload($request->all());
return $this->itemResponse($document);
}
}

View File

@ -1,17 +1,10 @@
<?php namespace App\Http\Controllers; <?php namespace App\Http\Controllers;
use Datatable;
use Input;
use Redirect; use Redirect;
use Session;
use URL;
use Utils;
use View; use View;
use Validator;
use Response; use Response;
use App\Models\Document; use App\Models\Document;
use App\Ninja\Repositories\DocumentRepository; use App\Ninja\Repositories\DocumentRepository;
use App\Http\Requests\DocumentRequest; use App\Http\Requests\DocumentRequest;
use App\Http\Requests\CreateDocumentRequest; use App\Http\Requests\CreateDocumentRequest;
use App\Http\Requests\UpdateDocumentRequest; use App\Http\Requests\UpdateDocumentRequest;
@ -64,7 +57,7 @@ class DocumentController extends BaseController
$document = $request->entity(); $document = $request->entity();
if(empty($document->preview)){ if(empty($document->preview)){
return Response::view('error', array('error'=>'Preview does not exist!'), 404); return Response::view('error', ['error'=>'Preview does not exist!'], 404);
} }
$direct_url = $document->getDirectPreviewUrl(); $direct_url = $document->getDirectPreviewUrl();
@ -88,7 +81,7 @@ class DocumentController extends BaseController
} }
if(!$document->isPDFEmbeddable()){ if(!$document->isPDFEmbeddable()){
return Response::view('error', array('error'=>'Image does not exist!'), 404); return Response::view('error', ['error'=>'Image does not exist!'], 404);
} }
$content = $document->preview?$document->getRawPreview():$document->getRaw(); $content = $document->preview?$document->getRawPreview():$document->getRaw();
@ -106,7 +99,7 @@ class DocumentController extends BaseController
return; return;
} }
$result = $this->documentRepo->upload(Input::all()['file'], $doc_array); $result = $this->documentRepo->upload($request->all(), $doc_array);
if(is_string($result)){ if(is_string($result)){
return Response::json([ return Response::json([

View File

@ -1,14 +1,8 @@
<?php namespace App\Http\Controllers; <?php namespace App\Http\Controllers;
use App\Models\Expense; use App\Models\Expense;
use app\Ninja\Repositories\ExpenseRepository; use App\Ninja\Repositories\ExpenseRepository;
use App\Ninja\Transformers\ExpenseTransformer;
use App\Services\ExpenseService; use App\Services\ExpenseService;
use Utils;
use Response;
use Input;
use Auth;
class ExpenseApiController extends BaseAPIController class ExpenseApiController extends BaseAPIController
{ {

View File

@ -0,0 +1,108 @@
<?php namespace App\Http\Controllers;
use View;
use Utils;
use Input;
use Session;
use App\Services\ExpenseCategoryService;
use App\Ninja\Repositories\ExpenseCategoryRepository;
use App\Http\Requests\ExpenseCategoryRequest;
use App\Http\Requests\CreateExpenseCategoryRequest;
use App\Http\Requests\UpdateExpenseCategoryRequest;
class ExpenseCategoryController extends BaseController
{
protected $categoryRepo;
protected $categoryService;
protected $entityType = ENTITY_EXPENSE_CATEGORY;
public function __construct(ExpenseCategoryRepository $categoryRepo, ExpenseCategoryService $categoryService)
{
$this->categoryRepo = $categoryRepo;
$this->categoryService = $categoryService;
}
/**
* Display a listing of the resource.
*
* @return Response
*/
public function index()
{
return View::make('list', [
'entityType' => ENTITY_EXPENSE_CATEGORY,
'title' => trans('texts.expense_categories'),
'sortCol' => '1',
'columns' => Utils::trans([
'checkbox',
'name',
''
]),
]);
}
public function getDatatable($expensePublicId = null)
{
return $this->categoryService->getDatatable(Input::get('sSearch'));
}
public function create(ExpenseCategoryRequest $request)
{
$data = [
'category' => null,
'method' => 'POST',
'url' => 'expense_categories',
'title' => trans('texts.new_category'),
];
return View::make('expense_categories.edit', $data);
}
public function edit(ExpenseCategoryRequest $request)
{
$category = $request->entity();
$data = [
'category' => $category,
'method' => 'PUT',
'url' => 'expense_categories/' . $category->public_id,
'title' => trans('texts.edit_category'),
];
return View::make('expense_categories.edit', $data);
}
public function store(CreateExpenseCategoryRequest $request)
{
$category = $this->categoryRepo->save($request->input());
Session::flash('message', trans('texts.created_expense_category'));
return redirect()->to($category->getRoute());
}
public function update(UpdateExpenseCategoryRequest $request)
{
$category = $this->categoryRepo->save($request->input(), $request->entity());
Session::flash('message', trans('texts.updated_expense_category'));
return redirect()->to($category->getRoute());
}
public function bulk()
{
$action = Input::get('action');
$ids = Input::get('public_id') ? Input::get('public_id') : Input::get('ids');
$count = $this->categoryService->bulk($ids, $action);
if ($count > 0) {
$field = $count == 1 ? "{$action}d_expense_category" : "{$action}d_expense_categories";
$message = trans("texts.$field", ['count' => $count]);
Session::flash('message', $message);
}
return redirect()->to('/expense_categories');
}
}

View File

@ -1,23 +1,20 @@
<?php namespace App\Http\Controllers; <?php namespace App\Http\Controllers;
use Debugbar;
use DB;
use Auth; use Auth;
use Datatable;
use Utils; use Utils;
use View; use View;
use URL; use URL;
use Validator;
use Input; use Input;
use Session; use Session;
use Redirect; use Redirect;
use Cache; use Cache;
use App\Models\Vendor; use App\Models\Vendor;
use App\Models\Expense; use App\Models\Expense;
use App\Models\ExpenseCategory;
use App\Models\Client; use App\Models\Client;
use App\Models\TaxRate;
use App\Services\ExpenseService; use App\Services\ExpenseService;
use App\Ninja\Repositories\ExpenseRepository; use App\Ninja\Repositories\ExpenseRepository;
use App\Http\Requests\ExpenseRequest; use App\Http\Requests\ExpenseRequest;
use App\Http\Requests\CreateExpenseRequest; use App\Http\Requests\CreateExpenseRequest;
use App\Http\Requests\UpdateExpenseRequest; use App\Http\Requests\UpdateExpenseRequest;
@ -44,7 +41,7 @@ class ExpenseController extends BaseController
*/ */
public function index() public function index()
{ {
return View::make('list', array( return View::make('list', [
'entityType' => ENTITY_EXPENSE, 'entityType' => ENTITY_EXPENSE,
'title' => trans('texts.expenses'), 'title' => trans('texts.expenses'),
'sortCol' => '3', 'sortCol' => '3',
@ -54,11 +51,12 @@ class ExpenseController extends BaseController
'client', 'client',
'expense_date', 'expense_date',
'amount', 'amount',
'category',
'public_notes', 'public_notes',
'status', 'status',
'' ''
]), ]),
)); ]);
} }
public function getDatatable($expensePublicId = null) public function getDatatable($expensePublicId = null)
@ -78,8 +76,8 @@ class ExpenseController extends BaseController
} else { } else {
$vendor = null; $vendor = null;
} }
$data = array( $data = [
'vendorPublicId' => Input::old('vendor') ? Input::old('vendor') : $request->vendor_id, 'vendorPublicId' => Input::old('vendor') ? Input::old('vendor') : $request->vendor_id,
'expense' => null, 'expense' => null,
'method' => 'POST', 'method' => 'POST',
@ -89,7 +87,8 @@ class ExpenseController extends BaseController
'vendor' => $vendor, 'vendor' => $vendor,
'clients' => Client::scope()->with('contacts')->orderBy('name')->get(), 'clients' => Client::scope()->with('contacts')->orderBy('name')->get(),
'clientPublicId' => $request->client_id, 'clientPublicId' => $request->client_id,
); 'categoryPublicId' => $request->category_id,
];
$data = array_merge($data, self::getViewModel()); $data = array_merge($data, self::getViewModel());
@ -99,14 +98,14 @@ class ExpenseController extends BaseController
public function edit(ExpenseRequest $request) public function edit(ExpenseRequest $request)
{ {
$expense = $request->entity(); $expense = $request->entity();
$expense->expense_date = Utils::fromSqlDate($expense->expense_date); $expense->expense_date = Utils::fromSqlDate($expense->expense_date);
$actions = []; $actions = [];
if ($expense->invoice) { if ($expense->invoice) {
$actions[] = ['url' => URL::to("invoices/{$expense->invoice->public_id}/edit"), 'label' => trans("texts.view_invoice")]; $actions[] = ['url' => URL::to("invoices/{$expense->invoice->public_id}/edit"), 'label' => trans('texts.view_invoice')];
} else { } else {
$actions[] = ['url' => 'javascript:submitAction("invoice")', 'label' => trans("texts.invoice_expense")]; $actions[] = ['url' => 'javascript:submitAction("invoice")', 'label' => trans('texts.invoice_expense')];
} }
$actions[] = \DropdownButton::DIVIDER; $actions[] = \DropdownButton::DIVIDER;
@ -117,7 +116,7 @@ class ExpenseController extends BaseController
$actions[] = ['url' => 'javascript:submitAction("restore")', 'label' => trans('texts.restore_expense')]; $actions[] = ['url' => 'javascript:submitAction("restore")', 'label' => trans('texts.restore_expense')];
} }
$data = array( $data = [
'vendor' => null, 'vendor' => null,
'expense' => $expense, 'expense' => $expense,
'method' => 'PUT', 'method' => 'PUT',
@ -128,7 +127,8 @@ class ExpenseController extends BaseController
'vendorPublicId' => $expense->vendor ? $expense->vendor->public_id : null, 'vendorPublicId' => $expense->vendor ? $expense->vendor->public_id : null,
'clients' => Client::scope()->with('contacts')->orderBy('name')->get(), 'clients' => Client::scope()->with('contacts')->orderBy('name')->get(),
'clientPublicId' => $expense->client ? $expense->client->public_id : null, 'clientPublicId' => $expense->client ? $expense->client->public_id : null,
); 'categoryPublicId' => $expense->expense_category ? $expense->expense_category->public_id : null,
];
$data = array_merge($data, self::getViewModel()); $data = array_merge($data, self::getViewModel());
@ -145,7 +145,7 @@ class ExpenseController extends BaseController
{ {
$data = $request->input(); $data = $request->input();
$data['documents'] = $request->file('documents'); $data['documents'] = $request->file('documents');
$expense = $this->expenseService->save($data, $request->entity()); $expense = $this->expenseService->save($data, $request->entity());
Session::flash('message', trans('texts.updated_expense')); Session::flash('message', trans('texts.updated_expense'));
@ -162,7 +162,7 @@ class ExpenseController extends BaseController
{ {
$data = $request->input(); $data = $request->input();
$data['documents'] = $request->file('documents'); $data['documents'] = $request->file('documents');
$expense = $this->expenseService->save($data); $expense = $this->expenseService->save($data);
Session::flash('message', trans('texts.created_expense')); Session::flash('message', trans('texts.created_expense'));
@ -181,7 +181,7 @@ class ExpenseController extends BaseController
$expenses = Expense::scope($ids)->with('client')->get(); $expenses = Expense::scope($ids)->with('client')->get();
$clientPublicId = null; $clientPublicId = null;
$currencyId = null; $currencyId = null;
// Validate that either all expenses do not have a client or if there is a client, it is the same client // Validate that either all expenses do not have a client or if there is a client, it is the same client
foreach ($expenses as $expense) foreach ($expenses as $expense)
{ {
@ -237,6 +237,8 @@ class ExpenseController extends BaseController
'countries' => Cache::get('countries'), 'countries' => Cache::get('countries'),
'customLabel1' => Auth::user()->account->custom_vendor_label1, 'customLabel1' => Auth::user()->account->custom_vendor_label1,
'customLabel2' => Auth::user()->account->custom_vendor_label2, 'customLabel2' => Auth::user()->account->custom_vendor_label2,
'categories' => ExpenseCategory::whereAccountId(Auth::user()->account_id)->orderBy('name')->get(),
'taxRates' => TaxRate::scope()->orderBy('name')->get(),
]; ];
} }

View File

@ -16,8 +16,16 @@ use App\Models\Payment;
use App\Models\Vendor; use App\Models\Vendor;
use App\Models\VendorContact; use App\Models\VendorContact;
/**
* Class ExportController
*/
class ExportController extends BaseController class ExportController extends BaseController
{ {
/**
* @param Request $request
*
* @return \Illuminate\Http\JsonResponse
*/
public function doExport(Request $request) public function doExport(Request $request)
{ {
$format = $request->input('format'); $format = $request->input('format');
@ -33,6 +41,12 @@ class ExportController extends BaseController
} }
} }
/**
* @param $request
* @param $fileName
*
* @return \Illuminate\Http\JsonResponse
*/
private function returnJSON($request, $fileName) private function returnJSON($request, $fileName)
{ {
$output = fopen('php://output', 'w') or Utils::fatalError(); $output = fopen('php://output', 'w') or Utils::fatalError();
@ -42,16 +56,32 @@ class ExportController extends BaseController
$manager = new Manager(); $manager = new Manager();
$manager->setSerializer(new ArraySerializer()); $manager->setSerializer(new ArraySerializer());
// eager load data, include archived but exclude deleted
$account = Auth::user()->account; $account = Auth::user()->account;
$account->loadAllData(); $account->load(['clients' => function($query) {
$query->withArchived()
->with(['contacts', 'invoices' => function($query) {
$query->withArchived()
->with(['invoice_items', 'payments' => function($query) {
$query->withArchived();
}]);
}]);
}]);
$resource = new Item($account, new AccountTransformer); $resource = new Item($account, new AccountTransformer);
$data = $manager->createData($resource)->toArray(); $data = $manager->parseIncludes('clients.invoices.payments')
->createData($resource)
->toArray();
return response()->json($data); return response()->json($data);
} }
/**
* @param $request
* @param $fileName
*
* @return mixed
*/
private function returnCSV($request, $fileName) private function returnCSV($request, $fileName)
{ {
$data = $this->getData($request); $data = $this->getData($request);
@ -63,6 +93,12 @@ class ExportController extends BaseController
})->download('csv'); })->download('csv');
} }
/**
* @param $request
* @param $fileName
*
* @return mixed
*/
private function returnXLS($request, $fileName) private function returnXLS($request, $fileName)
{ {
$user = Auth::user(); $user = Auth::user();
@ -84,13 +120,14 @@ class ExportController extends BaseController
if ($key === 'account' || $key === 'title' || $key === 'multiUser') { if ($key === 'account' || $key === 'title' || $key === 'multiUser') {
continue; continue;
} }
if ($key === 'recurringInvoices') {
$key = 'recurring_invoices';
}
$label = trans("texts.{$key}"); $label = trans("texts.{$key}");
$excel->sheet($label, function($sheet) use ($key, $data) { $excel->sheet($label, function($sheet) use ($key, $data) {
if ($key === 'quotes') { if ($key === 'quotes') {
$key = 'invoices'; $key = 'invoices';
$data['entityType'] = ENTITY_QUOTE; $data['entityType'] = ENTITY_QUOTE;
} elseif ($key === 'recurringInvoices') {
$key = 'recurring_invoices';
} }
$sheet->loadView("export.{$key}", $data); $sheet->loadView("export.{$key}", $data);
}); });
@ -98,6 +135,11 @@ class ExportController extends BaseController
})->download('xls'); })->download('xls');
} }
/**
* @param $request
*
* @return array
*/
private function getData($request) private function getData($request)
{ {
$account = Auth::user()->account; $account = Auth::user()->account;
@ -107,79 +149,82 @@ class ExportController extends BaseController
'title' => 'Invoice Ninja v' . NINJA_VERSION . ' - ' . $account->formatDateTime($account->getDateTime()), 'title' => 'Invoice Ninja v' . NINJA_VERSION . ' - ' . $account->formatDateTime($account->getDateTime()),
'multiUser' => $account->users->count() > 1 'multiUser' => $account->users->count() > 1
]; ];
if ($request->input(ENTITY_CLIENT)) { if ($request->input('include') === 'all' || $request->input('clients')) {
$data['clients'] = Client::scope() $data['clients'] = Client::scope()
->with('user', 'contacts', 'country') ->with('user', 'contacts', 'country')
->withArchived() ->withArchived()
->get(); ->get();
}
if ($request->input('include') === 'all' || $request->input('contacts')) {
$data['contacts'] = Contact::scope() $data['contacts'] = Contact::scope()
->with('user', 'client.contacts') ->with('user', 'client.contacts')
->withTrashed() ->withTrashed()
->get(); ->get();
}
if ($request->input('include') === 'all' || $request->input('credits')) {
$data['credits'] = Credit::scope() $data['credits'] = Credit::scope()
->with('user', 'client.contacts') ->with('user', 'client.contacts')
->get(); ->get();
} }
if ($request->input(ENTITY_TASK)) { if ($request->input('include') === 'all' || $request->input('tasks')) {
$data['tasks'] = Task::scope() $data['tasks'] = Task::scope()
->with('user', 'client.contacts') ->with('user', 'client.contacts')
->withArchived() ->withArchived()
->get(); ->get();
} }
if ($request->input(ENTITY_INVOICE)) {
$data['invoices'] = Invoice::scope()
->with('user', 'client.contacts', 'invoice_status')
->withArchived()
->where('is_quote', '=', false)
->where('is_recurring', '=', false)
->get();
$data['quotes'] = Invoice::scope()
->with('user', 'client.contacts', 'invoice_status')
->withArchived()
->where('is_quote', '=', true)
->where('is_recurring', '=', false)
->get();
if ($request->input('include') === 'all' || $request->input('invoices')) {
$data['invoices'] = Invoice::scope()
->invoiceType(INVOICE_TYPE_STANDARD)
->with('user', 'client.contacts', 'invoice_status')
->withArchived()
->where('is_recurring', '=', false)
->get();
}
if ($request->input('include') === 'all' || $request->input('quotes')) {
$data['quotes'] = Invoice::scope()
->invoiceType(INVOICE_TYPE_QUOTE)
->with('user', 'client.contacts', 'invoice_status')
->withArchived()
->where('is_recurring', '=', false)
->get();
}
if ($request->input('include') === 'all' || $request->input('recurring')) {
$data['recurringInvoices'] = Invoice::scope() $data['recurringInvoices'] = Invoice::scope()
->invoiceType(INVOICE_TYPE_STANDARD)
->with('user', 'client.contacts', 'invoice_status', 'frequency') ->with('user', 'client.contacts', 'invoice_status', 'frequency')
->withArchived() ->withArchived()
->where('is_quote', '=', false)
->where('is_recurring', '=', true) ->where('is_recurring', '=', true)
->get(); ->get();
} }
if ($request->input(ENTITY_PAYMENT)) { if ($request->input('include') === 'all' || $request->input('payments')) {
$data['payments'] = Payment::scope() $data['payments'] = Payment::scope()
->withArchived() ->withArchived()
->with('user', 'client.contacts', 'payment_type', 'invoice', 'account_gateway.gateway') ->with('user', 'client.contacts', 'payment_type', 'invoice', 'account_gateway.gateway')
->get(); ->get();
} }
if ($request->input('include') === 'all' || $request->input('vendors')) {
if ($request->input(ENTITY_VENDOR)) { $data['vendors'] = Vendor::scope()
$data['clients'] = Vendor::scope()
->with('user', 'vendor_contacts', 'country') ->with('user', 'vendor_contacts', 'country')
->withArchived() ->withArchived()
->get(); ->get();
}
if ($request->input('include') === 'all' || $request->input('vendor_contacts')) {
$data['vendor_contacts'] = VendorContact::scope() $data['vendor_contacts'] = VendorContact::scope()
->with('user', 'vendor.vendor_contacts') ->with('user', 'vendor.vendor_contacts')
->withTrashed() ->withTrashed()
->get(); ->get();
/*
$data['expenses'] = Credit::scope()
->with('user', 'client.contacts')
->get();
*/
} }
return $data; return $data;
} }
} }

View File

@ -9,12 +9,22 @@ use Session;
use App\Models\Account; use App\Models\Account;
use App\Libraries\Utils; use App\Libraries\Utils;
use App\Ninja\Mailers\Mailer; use App\Ninja\Mailers\Mailer;
use Symfony\Component\Security\Core\Util\StringUtils;
/**
* Class HomeController
*/
class HomeController extends BaseController class HomeController extends BaseController
{ {
/**
* @var Mailer
*/
protected $mailer; protected $mailer;
/**
* HomeController constructor.
*
* @param Mailer $mailer
*/
public function __construct(Mailer $mailer) public function __construct(Mailer $mailer)
{ {
//parent::__construct(); //parent::__construct();
@ -22,6 +32,9 @@ class HomeController extends BaseController
$this->mailer = $mailer; $this->mailer = $mailer;
} }
/**
* @return \Illuminate\Http\RedirectResponse
*/
public function showIndex() public function showIndex()
{ {
Session::reflash(); Session::reflash();
@ -35,16 +48,25 @@ class HomeController extends BaseController
} }
} }
/**
* @return \Illuminate\Contracts\View\View
*/
public function showTerms() public function showTerms()
{ {
return View::make('public.terms', ['hideHeader' => true]); return View::make('public.terms', ['hideHeader' => true]);
} }
/**
* @return \Illuminate\Contracts\View\View
*/
public function viewLogo() public function viewLogo()
{ {
return View::make('public.logo'); return View::make('public.logo');
} }
/**
* @return \Illuminate\Contracts\View\View|\Illuminate\Http\RedirectResponse
*/
public function invoiceNow() public function invoiceNow()
{ {
if (Auth::check() && Input::get('new_company')) { if (Auth::check() && Input::get('new_company')) {
@ -68,6 +90,11 @@ class HomeController extends BaseController
} }
} }
/**
* @param $userType
* @param $version
* @return \Illuminate\Http\JsonResponse
*/
public function newsFeed($userType, $version) public function newsFeed($userType, $version)
{ {
$response = Utils::getNewsFeedResponse($userType); $response = Utils::getNewsFeedResponse($userType);
@ -75,6 +102,9 @@ class HomeController extends BaseController
return Response::json($response); return Response::json($response);
} }
/**
* @return string
*/
public function hideMessage() public function hideMessage()
{ {
if (Auth::check() && Session::has('news_feed_id')) { if (Auth::check() && Session::has('news_feed_id')) {
@ -91,11 +121,17 @@ class HomeController extends BaseController
return 'success'; return 'success';
} }
/**
* @return string
*/
public function logError() public function logError()
{ {
return Utils::logError(Input::get('error'), 'JavaScript'); return Utils::logError(Input::get('error'), 'JavaScript');
} }
/**
* @return mixed
*/
public function keepAlive() public function keepAlive()
{ {
return RESULT_SUCCESS; return RESULT_SUCCESS;

View File

@ -7,7 +7,6 @@ use Input;
use Session; use Session;
use Redirect; use Redirect;
use App\Services\ImportService; use App\Services\ImportService;
use App\Http\Controllers\BaseController;
class ImportController extends BaseController class ImportController extends BaseController
{ {
@ -36,8 +35,11 @@ class ImportController extends BaseController
if ($source === IMPORT_CSV) { if ($source === IMPORT_CSV) {
$data = $this->importService->mapCSV($files); $data = $this->importService->mapCSV($files);
return View::make('accounts.import_map', ['data' => $data]); return View::make('accounts.import_map', ['data' => $data]);
} elseif ($source === IMPORT_JSON) {
$results = $this->importService->importJSON($files[IMPORT_JSON]);
return $this->showResult($results);
} else { } else {
$results = $this->importService->import($source, $files); $results = $this->importService->importFiles($source, $files);
return $this->showResult($results); return $this->showResult($results);
} }
} catch (Exception $exception) { } catch (Exception $exception) {

View File

@ -6,8 +6,14 @@ use Auth;
use Input; use Input;
use App\Models\Subscription; use App\Models\Subscription;
/**
* Class IntegrationController
*/
class IntegrationController extends Controller class IntegrationController extends Controller
{ {
/**
* @return \Illuminate\Http\JsonResponse
*/
public function subscribe() public function subscribe()
{ {
$eventId = Utils::lookupEventId(trim(Input::get('event'))); $eventId = Utils::lookupEventId(trim(Input::get('event')));

View File

@ -1,8 +1,6 @@
<?php namespace App\Http\Controllers; <?php namespace App\Http\Controllers;
use Auth; use Auth;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Request;
use Utils; use Utils;
use Response; use Response;
use Input; use Input;
@ -11,13 +9,10 @@ use App\Models\Invoice;
use App\Models\Client; use App\Models\Client;
use App\Models\Contact; use App\Models\Contact;
use App\Models\Product; use App\Models\Product;
use App\Models\Invitation;
use App\Ninja\Repositories\ClientRepository; use App\Ninja\Repositories\ClientRepository;
use App\Ninja\Repositories\PaymentRepository; use App\Ninja\Repositories\PaymentRepository;
use App\Ninja\Repositories\InvoiceRepository; use App\Ninja\Repositories\InvoiceRepository;
use App\Ninja\Mailers\ContactMailer as Mailer; use App\Ninja\Mailers\ContactMailer as Mailer;
use App\Http\Controllers\BaseAPIController;
use App\Ninja\Transformers\InvoiceTransformer;
use App\Http\Requests\InvoiceRequest; use App\Http\Requests\InvoiceRequest;
use App\Http\Requests\CreateInvoiceAPIRequest; use App\Http\Requests\CreateInvoiceAPIRequest;
use App\Http\Requests\UpdateInvoiceAPIRequest; use App\Http\Requests\UpdateInvoiceAPIRequest;
@ -137,6 +132,7 @@ class InvoiceApiController extends BaseAPIController
'city', 'city',
'state', 'state',
'postal_code', 'postal_code',
'country_id',
'private_notes', 'private_notes',
'currency_code', 'currency_code',
] as $field) { ] as $field) {

View File

@ -8,10 +8,7 @@ use Input;
use Cache; use Cache;
use Redirect; use Redirect;
use DB; use DB;
use Event;
use URL; use URL;
use Datatable;
use Request;
use DropdownButton; use DropdownButton;
use App\Models\Invoice; use App\Models\Invoice;
use App\Models\Client; use App\Models\Client;
@ -26,8 +23,8 @@ use App\Ninja\Repositories\InvoiceRepository;
use App\Ninja\Repositories\ClientRepository; use App\Ninja\Repositories\ClientRepository;
use App\Ninja\Repositories\DocumentRepository; use App\Ninja\Repositories\DocumentRepository;
use App\Services\InvoiceService; use App\Services\InvoiceService;
use App\Services\PaymentService;
use App\Services\RecurringInvoiceService; use App\Services\RecurringInvoiceService;
use App\Http\Requests\InvoiceRequest; use App\Http\Requests\InvoiceRequest;
use App\Http\Requests\CreateInvoiceRequest; use App\Http\Requests\CreateInvoiceRequest;
use App\Http\Requests\UpdateInvoiceRequest; use App\Http\Requests\UpdateInvoiceRequest;
@ -39,10 +36,11 @@ class InvoiceController extends BaseController
protected $clientRepo; protected $clientRepo;
protected $documentRepo; protected $documentRepo;
protected $invoiceService; protected $invoiceService;
protected $paymentService;
protected $recurringInvoiceService; protected $recurringInvoiceService;
protected $entityType = ENTITY_INVOICE; protected $entityType = ENTITY_INVOICE;
public function __construct(Mailer $mailer, InvoiceRepository $invoiceRepo, ClientRepository $clientRepo, InvoiceService $invoiceService, DocumentRepository $documentRepo, RecurringInvoiceService $recurringInvoiceService) public function __construct(Mailer $mailer, InvoiceRepository $invoiceRepo, ClientRepository $clientRepo, InvoiceService $invoiceService, DocumentRepository $documentRepo, RecurringInvoiceService $recurringInvoiceService, PaymentService $paymentService)
{ {
// parent::__construct(); // parent::__construct();
@ -51,6 +49,7 @@ class InvoiceController extends BaseController
$this->clientRepo = $clientRepo; $this->clientRepo = $clientRepo;
$this->invoiceService = $invoiceService; $this->invoiceService = $invoiceService;
$this->recurringInvoiceService = $recurringInvoiceService; $this->recurringInvoiceService = $recurringInvoiceService;
$this->paymentService = $paymentService;
} }
public function index() public function index()
@ -95,9 +94,9 @@ class InvoiceController extends BaseController
{ {
$account = Auth::user()->account; $account = Auth::user()->account;
$invoice = $request->entity()->load('invitations', 'account.country', 'client.contacts', 'client.country', 'invoice_items', 'documents', 'expenses', 'expenses.documents', 'payments'); $invoice = $request->entity()->load('invitations', 'account.country', 'client.contacts', 'client.country', 'invoice_items', 'documents', 'expenses', 'expenses.documents', 'payments');
$entityType = $invoice->getEntityType(); $entityType = $invoice->getEntityType();
$contactIds = DB::table('invitations') $contactIds = DB::table('invitations')
->join('contacts', 'contacts.id', '=', 'invitations.contact_id') ->join('contacts', 'contacts.id', '=', 'invitations.contact_id')
->where('invitations.invoice_id', '=', $invoice->id) ->where('invitations.invoice_id', '=', $invoice->id)
@ -136,34 +135,34 @@ class InvoiceController extends BaseController
$actions = [ $actions = [
['url' => 'javascript:onCloneClick()', 'label' => trans("texts.clone_{$entityType}")], ['url' => 'javascript:onCloneClick()', 'label' => trans("texts.clone_{$entityType}")],
['url' => URL::to("{$entityType}s/{$entityType}_history/{$invoice->public_id}"), 'label' => trans("texts.view_history")], ['url' => URL::to("{$entityType}s/{$entityType}_history/{$invoice->public_id}"), 'label' => trans('texts.view_history')],
DropdownButton::DIVIDER DropdownButton::DIVIDER
]; ];
if ($invoice->invoice_status_id < INVOICE_STATUS_SENT && !$invoice->is_recurring) { if ($invoice->invoice_status_id < INVOICE_STATUS_SENT && !$invoice->is_recurring) {
$actions[] = ['url' => 'javascript:onMarkClick()', 'label' => trans("texts.mark_sent")]; $actions[] = ['url' => 'javascript:onMarkClick()', 'label' => trans('texts.mark_sent')];
} }
if ($entityType == ENTITY_QUOTE) { if ($entityType == ENTITY_QUOTE) {
if ($invoice->quote_invoice_id) { if ($invoice->quote_invoice_id) {
$actions[] = ['url' => URL::to("invoices/{$invoice->quote_invoice_id}/edit"), 'label' => trans("texts.view_invoice")]; $actions[] = ['url' => URL::to("invoices/{$invoice->quote_invoice_id}/edit"), 'label' => trans('texts.view_invoice')];
} else { } else {
$actions[] = ['url' => 'javascript:onConvertClick()', 'label' => trans("texts.convert_to_invoice")]; $actions[] = ['url' => 'javascript:onConvertClick()', 'label' => trans('texts.convert_to_invoice')];
} }
} elseif ($entityType == ENTITY_INVOICE) { } elseif ($entityType == ENTITY_INVOICE) {
if ($invoice->quote_id) { if ($invoice->quote_id) {
$actions[] = ['url' => URL::to("quotes/{$invoice->quote_id}/edit"), 'label' => trans("texts.view_quote")]; $actions[] = ['url' => URL::to("quotes/{$invoice->quote_id}/edit"), 'label' => trans('texts.view_quote')];
} }
if (!$invoice->is_recurring && $invoice->balance > 0) { if (!$invoice->is_recurring && $invoice->balance > 0) {
$actions[] = ['url' => 'javascript:onPaymentClick()', 'label' => trans('texts.enter_payment')]; $actions[] = ['url' => 'javascript:onPaymentClick()', 'label' => trans('texts.enter_payment')];
} }
foreach ($invoice->payments as $payment) { foreach ($invoice->payments as $payment) {
$label = trans("texts.view_payment"); $label = trans('texts.view_payment');
if (count($invoice->payments) > 1) { if (count($invoice->payments) > 1) {
$label .= ' - ' . $account->formatMoney($payment->amount, $invoice->client); $label .= ' - ' . $account->formatMoney($payment->amount, $invoice->client);
} }
$actions[] = ['url' => $payment->present()->url, 'label' => $label]; $actions[] = ['url' => $payment->present()->url, 'label' => $label];
} }
} }
@ -180,8 +179,8 @@ class InvoiceController extends BaseController
if(!Auth::user()->hasPermission('view_all')){ if(!Auth::user()->hasPermission('view_all')){
$clients = $clients->where('clients.user_id', '=', Auth::user()->id); $clients = $clients->where('clients.user_id', '=', Auth::user()->id);
} }
$data = array( $data = [
'clients' => $clients->get(), 'clients' => $clients->get(),
'entityType' => $entityType, 'entityType' => $entityType,
'showBreadcrumbs' => $clone, 'showBreadcrumbs' => $clone,
@ -193,9 +192,13 @@ class InvoiceController extends BaseController
'client' => $invoice->client, 'client' => $invoice->client,
'isRecurring' => $invoice->is_recurring, 'isRecurring' => $invoice->is_recurring,
'actions' => $actions, 'actions' => $actions,
'lastSent' => $lastSent); 'lastSent' => $lastSent];
$data = array_merge($data, self::getViewModel($invoice)); $data = array_merge($data, self::getViewModel($invoice));
if ($invoice->isSent() && $invoice->getAutoBillEnabled() && !$invoice->isPaid()) {
$data['autoBillChangeWarning'] = $invoice->client->autoBillLater();
}
if ($clone) { if ($clone) {
$data['formIsChanged'] = true; $data['formIsChanged'] = true;
} }
@ -230,7 +233,7 @@ class InvoiceController extends BaseController
public function create(InvoiceRequest $request, $clientPublicId = 0, $isRecurring = false) public function create(InvoiceRequest $request, $clientPublicId = 0, $isRecurring = false)
{ {
$account = Auth::user()->account; $account = Auth::user()->account;
$entityType = $isRecurring ? ENTITY_RECURRING_INVOICE : ENTITY_INVOICE; $entityType = $isRecurring ? ENTITY_RECURRING_INVOICE : ENTITY_INVOICE;
$clientId = null; $clientId = null;
@ -240,17 +243,17 @@ class InvoiceController extends BaseController
$invoice = $account->createInvoice($entityType, $clientId); $invoice = $account->createInvoice($entityType, $clientId);
$invoice->public_id = 0; $invoice->public_id = 0;
if (Session::get('expenses')) { if (Session::get('expenses')) {
$invoice->expenses = Expense::scope(Session::get('expenses'))->with('documents')->get(); $invoice->expenses = Expense::scope(Session::get('expenses'))->with('documents', 'expense_category')->get();
} }
$clients = Client::scope()->with('contacts', 'country')->orderBy('name'); $clients = Client::scope()->with('contacts', 'country')->orderBy('name');
if (!Auth::user()->hasPermission('view_all')) { if (!Auth::user()->hasPermission('view_all')) {
$clients = $clients->where('clients.user_id', '=', Auth::user()->id); $clients = $clients->where('clients.user_id', '=', Auth::user()->id);
} }
$data = [ $data = [
'clients' => $clients->get(), 'clients' => $clients->get(),
'entityType' => $invoice->getEntityType(), 'entityType' => $invoice->getEntityType(),
@ -273,7 +276,7 @@ class InvoiceController extends BaseController
{ {
$recurringHelp = ''; $recurringHelp = '';
foreach (preg_split("/((\r?\n)|(\r\n?))/", trans('texts.recurring_help')) as $line) { foreach (preg_split("/((\r?\n)|(\r\n?))/", trans('texts.recurring_help')) as $line) {
$parts = explode("=>", $line); $parts = explode('=>', $line);
if (count($parts) > 1) { if (count($parts) > 1) {
$line = $parts[0].' => '.Utils::processVariables($parts[0]); $line = $parts[0].' => '.Utils::processVariables($parts[0]);
$recurringHelp .= '<li>'.strip_tags($line).'</li>'; $recurringHelp .= '<li>'.strip_tags($line).'</li>';
@ -284,7 +287,7 @@ class InvoiceController extends BaseController
$recurringDueDateHelp = ''; $recurringDueDateHelp = '';
foreach (preg_split("/((\r?\n)|(\r\n?))/", trans('texts.recurring_due_date_help')) as $line) { foreach (preg_split("/((\r?\n)|(\r\n?))/", trans('texts.recurring_due_date_help')) as $line) {
$parts = explode("=>", $line); $parts = explode('=>', $line);
if (count($parts) > 1) { if (count($parts) > 1) {
$line = $parts[0].' => '.Utils::processVariables($parts[0]); $line = $parts[0].' => '.Utils::processVariables($parts[0]);
$recurringDueDateHelp .= '<li>'.strip_tags($line).'</li>'; $recurringDueDateHelp .= '<li>'.strip_tags($line).'</li>';
@ -294,24 +297,24 @@ class InvoiceController extends BaseController
} }
// Create due date options // Create due date options
$recurringDueDates = array( $recurringDueDates = [
trans('texts.use_client_terms') => array('value' => '', 'class' => 'monthly weekly'), trans('texts.use_client_terms') => ['value' => '', 'class' => 'monthly weekly'],
); ];
$ends = array('th','st','nd','rd','th','th','th','th','th','th'); $ends = ['th','st','nd','rd','th','th','th','th','th','th'];
for($i = 1; $i < 31; $i++){ for($i = 1; $i < 31; $i++){
if ($i >= 11 && $i <= 13) $ordinal = $i. 'th'; if ($i >= 11 && $i <= 13) $ordinal = $i. 'th';
else $ordinal = $i . $ends[$i % 10]; else $ordinal = $i . $ends[$i % 10];
$dayStr = str_pad($i, 2, '0', STR_PAD_LEFT); $dayStr = str_pad($i, 2, '0', STR_PAD_LEFT);
$str = trans('texts.day_of_month', array('ordinal'=>$ordinal)); $str = trans('texts.day_of_month', ['ordinal'=>$ordinal]);
$recurringDueDates[$str] = array('value' => "1998-01-$dayStr", 'data-num' => $i, 'class' => 'monthly'); $recurringDueDates[$str] = ['value' => "1998-01-$dayStr", 'data-num' => $i, 'class' => 'monthly'];
} }
$recurringDueDates[trans('texts.last_day_of_month')] = array('value' => "1998-01-31", 'data-num' => 31, 'class' => 'monthly'); $recurringDueDates[trans('texts.last_day_of_month')] = ['value' => '1998-01-31', 'data-num' => 31, 'class' => 'monthly'];
$daysOfWeek = array( $daysOfWeek = [
trans('texts.sunday'), trans('texts.sunday'),
trans('texts.monday'), trans('texts.monday'),
trans('texts.tuesday'), trans('texts.tuesday'),
@ -319,14 +322,14 @@ class InvoiceController extends BaseController
trans('texts.thursday'), trans('texts.thursday'),
trans('texts.friday'), trans('texts.friday'),
trans('texts.saturday'), trans('texts.saturday'),
); ];
foreach(array('1st','2nd','3rd','4th') as $i=>$ordinal){ foreach(['1st','2nd','3rd','4th'] as $i=>$ordinal){
foreach($daysOfWeek as $j=>$dayOfWeek){ foreach($daysOfWeek as $j=>$dayOfWeek){
$str = trans('texts.day_of_week_after', array('ordinal' => $ordinal, 'day' => $dayOfWeek)); $str = trans('texts.day_of_week_after', ['ordinal' => $ordinal, 'day' => $dayOfWeek]);
$day = $i * 7 + $j + 1; $day = $i * 7 + $j + 1;
$dayStr = str_pad($day, 2, '0', STR_PAD_LEFT); $dayStr = str_pad($day, 2, '0', STR_PAD_LEFT);
$recurringDueDates[$str] = array('value' => "1998-02-$dayStr", 'data-num' => $day, 'class' => 'weekly'); $recurringDueDates[$str] = ['value' => "1998-02-$dayStr", 'data-num' => $day, 'class' => 'weekly'];
} }
} }
@ -335,26 +338,26 @@ class InvoiceController extends BaseController
$rates = TaxRate::scope()->orderBy('name')->get(); $rates = TaxRate::scope()->orderBy('name')->get();
$options = []; $options = [];
$defaultTax = false; $defaultTax = false;
foreach ($rates as $rate) { foreach ($rates as $rate) {
$options[$rate->rate . ' ' . $rate->name] = $rate->name . ' ' . ($rate->rate+0) . '%'; $options[$rate->rate . ' ' . $rate->name] = $rate->name . ' ' . ($rate->rate+0) . '%';
// load default invoice tax // load default invoice tax
if ($rate->id == $account->default_tax_rate_id) { if ($rate->id == $account->default_tax_rate_id) {
$defaultTax = $rate; $defaultTax = $rate;
} }
} }
// Check for any taxes which have been deleted // Check for any taxes which have been deleted
if ($invoice->exists) { if ($invoice->exists) {
foreach ($invoice->getTaxes() as $key => $rate) { foreach ($invoice->getTaxes() as $key => $rate) {
if (isset($options[$key])) { if (isset($options[$key])) {
continue; continue;
} }
$options[$key] = $rate['name'] . ' ' . $rate['rate'] . '%'; $options[$key] = $rate['name'] . ' ' . $rate['rate'] . '%';
} }
} }
return [ return [
'data' => Input::old('data'), 'data' => Input::old('data'),
'account' => Auth::user()->account->load('country'), 'account' => Auth::user()->account->load('country'),
@ -362,21 +365,19 @@ class InvoiceController extends BaseController
'taxRateOptions' => $options, 'taxRateOptions' => $options,
'defaultTax' => $defaultTax, 'defaultTax' => $defaultTax,
'currencies' => Cache::get('currencies'), 'currencies' => Cache::get('currencies'),
'languages' => Cache::get('languages'),
'sizes' => Cache::get('sizes'), 'sizes' => Cache::get('sizes'),
'paymentTerms' => Cache::get('paymentTerms'), 'paymentTerms' => Cache::get('paymentTerms'),
'industries' => Cache::get('industries'),
'invoiceDesigns' => InvoiceDesign::getDesigns(), 'invoiceDesigns' => InvoiceDesign::getDesigns(),
'invoiceFonts' => Cache::get('fonts'), 'invoiceFonts' => Cache::get('fonts'),
'frequencies' => array( 'frequencies' => [
1 => 'Weekly', 1 => trans('texts.freq_weekly'),
2 => 'Two weeks', 2 => trans('texts.freq_two_weeks'),
3 => 'Four weeks', 3 => trans('texts.freq_four_weeks'),
4 => 'Monthly', 4 => trans('texts.freq_monthly'),
5 => 'Three months', 5 => trans('texts.freq_three_months'),
6 => 'Six months', 6 => trans('texts.freq_six_months'),
7 => 'Annually', 7 => trans('texts.freq_annually'),
), ],
'recurringDueDates' => $recurringDueDates, 'recurringDueDates' => $recurringDueDates,
'recurringHelp' => $recurringHelp, 'recurringHelp' => $recurringHelp,
'recurringDueDateHelp' => $recurringDueDateHelp, 'recurringDueDateHelp' => $recurringDueDateHelp,
@ -396,10 +397,10 @@ class InvoiceController extends BaseController
{ {
$data = $request->input(); $data = $request->input();
$data['documents'] = $request->file('documents'); $data['documents'] = $request->file('documents');
$action = Input::get('action'); $action = Input::get('action');
$entityType = Input::get('entityType'); $entityType = Input::get('entityType');
$invoice = $this->invoiceService->save($data); $invoice = $this->invoiceService->save($data);
$entityType = $invoice->getEntityType(); $entityType = $invoice->getEntityType();
$message = trans("texts.created_{$entityType}"); $message = trans("texts.created_{$entityType}");
@ -433,7 +434,7 @@ class InvoiceController extends BaseController
{ {
$data = $request->input(); $data = $request->input();
$data['documents'] = $request->file('documents'); $data['documents'] = $request->file('documents');
$action = Input::get('action'); $action = Input::get('action');
$entityType = Input::get('entityType'); $entityType = Input::get('entityType');
@ -547,7 +548,7 @@ class InvoiceController extends BaseController
$clone = $this->invoiceService->convertQuote($request->entity()); $clone = $this->invoiceService->convertQuote($request->entity());
Session::flash('message', trans('texts.converted_to_invoice')); Session::flash('message', trans('texts.converted_to_invoice'));
return Redirect::to('invoices/' . $clone->public_id); return Redirect::to('invoices/' . $clone->public_id);
} }
@ -567,9 +568,9 @@ class InvoiceController extends BaseController
'remove_created_by' => Auth::user()->hasFeature(FEATURE_REMOVE_CREATED_BY), 'remove_created_by' => Auth::user()->hasFeature(FEATURE_REMOVE_CREATED_BY),
'invoice_settings' => Auth::user()->hasFeature(FEATURE_INVOICE_SETTINGS), 'invoice_settings' => Auth::user()->hasFeature(FEATURE_INVOICE_SETTINGS),
]; ];
$invoice->is_quote = intval($invoice->is_quote); $invoice->invoice_type_id = intval($invoice->invoice_type_id);
$activityTypeId = $invoice->is_quote ? ACTIVITY_TYPE_UPDATE_QUOTE : ACTIVITY_TYPE_UPDATE_INVOICE; $activityTypeId = $invoice->isType(INVOICE_TYPE_QUOTE) ? ACTIVITY_TYPE_UPDATE_QUOTE : ACTIVITY_TYPE_UPDATE_INVOICE;
$activities = Activity::scope(false, $invoice->account_id) $activities = Activity::scope(false, $invoice->account_id)
->where('activity_type_id', '=', $activityTypeId) ->where('activity_type_id', '=', $activityTypeId)
->where('invoice_id', '=', $invoice->id) ->where('invoice_id', '=', $invoice->id)
@ -589,7 +590,7 @@ class InvoiceController extends BaseController
'remove_created_by' => Auth::user()->hasFeature(FEATURE_REMOVE_CREATED_BY), 'remove_created_by' => Auth::user()->hasFeature(FEATURE_REMOVE_CREATED_BY),
'invoice_settings' => Auth::user()->hasFeature(FEATURE_INVOICE_SETTINGS), 'invoice_settings' => Auth::user()->hasFeature(FEATURE_INVOICE_SETTINGS),
]; ];
$backup->is_quote = isset($backup->is_quote) && intval($backup->is_quote); $backup->invoice_type_id = isset($backup->invoice_type_id) && intval($backup->invoice_type_id) == INVOICE_TYPE_QUOTE;
$backup->account = $invoice->account->toArray(); $backup->account = $invoice->account->toArray();
$versionsJson[$activity->id] = $backup; $versionsJson[$activity->id] = $backup;

Some files were not shown because too many files have changed in this diff Show More