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_DEBUG=false
APP_URL=http://ninja.dev
APP_CIPHER=rijndael-128
APP_KEY=SomeRandomString
DB_TYPE=mysql
@ -20,6 +19,9 @@ MAIL_FROM_ADDRESS
MAIL_FROM_NAME
MAIL_PASSWORD
MAILGUN_DOMAIN=
MAILGUN_SECRET=
#POSTMARK_API_TOKEN=
PHANTOMJS_CLOUD_KEY='a-demo-key-with-low-quota-per-ip-address'
@ -68,3 +70,13 @@ API_SECRET=password
#MAX_EMAIL_DOCUMENTS_SIZE # Total KB
#MAX_ZIP_DOCUMENTS_SIZE # Total KB (uncompressed)
#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

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
php:
- 5.5.9
# - 5.5.9
# - 5.6
# - 7.0
# - 5.6
- 7.0
# - hhvm
addons:
@ -27,13 +28,14 @@ before_install:
# set GitHub token and update composer
- if [ -n "$GH_TOKEN" ]; then composer config github-oauth.github.com ${GH_TOKEN}; fi;
- composer self-update && composer -V
# - export USE_ZEND_ALLOC=0
install:
# install Composer dependencies
- rm composer.lock
# - rm composer.lock
# these providers require referencing git commit's which cause Travis to fail
- sed -i '/mollie/d' composer.json
- sed -i '/2checkout/d' composer.json
# - sed -i '/mollie/d' composer.json
# - sed -i '/2checkout/d' composer.json
- travis_retry composer install --prefer-dist;
before_script:
@ -66,17 +68,17 @@ before_script:
script:
- 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 CheckBalanceCest.php
#- php ./vendor/codeception/codeception/codecept run --debug acceptance ClientCest.php
#- php ./vendor/codeception/codeception/codecept run --debug acceptance ExpenseCest.php
#- php ./vendor/codeception/codeception/codecept run --debug acceptance CreditCest.php
#- php ./vendor/codeception/codeception/codecept run --debug acceptance InvoiceCest.php
#- php ./vendor/codeception/codeception/codecept run --debug acceptance QuoteCest.php
#- php ./vendor/codeception/codeception/codecept run --debug acceptance InvoiceDesignCest.php
#- php ./vendor/codeception/codeception/codecept run acceptance OnlinePaymentCest.php
#- php ./vendor/codeception/codeception/codecept run --debug acceptance PaymentCest.php
#- php ./vendor/codeception/codeception/codecept run --debug acceptance TaskCest.php
#- php ./vendor/codeception/codeception/codecept run --debug acceptance TaxRatesCest.php
- php ./vendor/codeception/codeception/codecept run --debug acceptance TaxRatesCest.php
- php ./vendor/codeception/codeception/codecept run --debug acceptance CheckBalanceCest.php
- php ./vendor/codeception/codeception/codecept run --debug acceptance ClientCest.php
- php ./vendor/codeception/codeception/codecept run --debug acceptance ExpenseCest.php
- php ./vendor/codeception/codeception/codecept run --debug acceptance CreditCest.php
- php ./vendor/codeception/codeception/codecept run --debug acceptance InvoiceCest.php
- php ./vendor/codeception/codeception/codecept run --debug acceptance QuoteCest.php
- php ./vendor/codeception/codeception/codecept run --debug acceptance InvoiceDesignCest.php
- php ./vendor/codeception/codeception/codecept run --debug acceptance OnlinePaymentCest.php
- php ./vendor/codeception/codeception/codecept run --debug acceptance PaymentCest.php
- php ./vendor/codeception/codeception/codecept run --debug acceptance TaskCest.php
#- sed -i 's/NINJA_DEV=true/NINJA_PROD=true/g' .env
#- 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 payments;' 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-info.log
- 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
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
- Please try to follow [PSR-2 guidlines](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)
- Add translations in our [Transifex](https://www.transifex.com/invoice-ninja/) project
### Submit pull requests
* [Fork](https://github.com/invoiceninja/invoiceninja#fork-destination-box) the [Invoice Ninja repository](https://github.com/invoiceninja/invoiceninja)
* 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>
# 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)
[![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/)
* 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
* [Softaculous](https://www.softaculous.com/apps/ecommerce/Invoice_Ninja) - $30
### Requirements
## Requirements
* PHP >= 5.5.9
* MCrypt PHP Extension
* MySQL
### Recommended Providers
## Recommended Providers
* [Stripe](https://stripe.com/)
* [Postmark](https://postmarkapp.com/)
### Features
## Features
* Built using Laravel 5.2
* 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
* Expenses and vendors
* Tasks with time-tracking
* File Attachments
* Multi-user/multi-company support
* Tax rates and payment terms
* 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
* [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/)
* [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/)
@ -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/)
* [Feature Roadmap](https://trello.com/b/63BbiVVe/)
### Pull Requests
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**.
## Contributing
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)
* [Jeramy Simpson](https://github.com/JeramyMywork) - [MyWork](https://www.mywork.com.au)
* [Sigitas Limontas](https://lt.linkedin.com/in/sigitaslimontas)
* [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
* [twbs/bootstrap](https://github.com/twbs/bootstrap) - Sleek, intuitive, and powerful front-end framework for faster and easier web development.
* [jquery/jquery](https://github.com/jquery/jquery) - jQuery JavaScript Library
* [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
## License
Invoice Ninja is released under the Attribution Assurance License.
See [LICENSE](LICENSE) for details.

View File

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

View File

@ -1,11 +1,9 @@
<?php namespace App\Console\Commands;
use DB;
use DateTime;
use Carbon;
use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
/*
@ -38,9 +36,19 @@ Options:
*/
/**
* Class CheckData
*/
class CheckData extends Command {
/**
* @var string
*/
protected $name = 'ninja:check-data';
/**
* @var string
*/
protected $description = 'Check/fix data';
public function fire()
@ -101,7 +109,7 @@ class CheckData extends Command {
}
$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)) {
$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'));
} else {
$clients->where('invoices.is_deleted', '=', 0)
->where('invoices.is_quote', '=', 0)
->where('invoices.invoice_type_id', '=', INVOICE_TYPE_STANDARD)
->where('invoices.is_recurring', '=', 0)
->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) {
$invoice = DB::table('invoices')
->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
if ($invoice && !$invoice->is_recurring && DB::table('invoices')
@ -221,14 +229,14 @@ class CheckData extends Command {
&& $invoice->amount > 0;
// **Fix for allowing converting a recurring invoice to a normal one without updating the balance**
if ($noAdjustment && !$invoice->is_quote && !$invoice->is_recurring) {
$this->info("No adjustment for new invoice:{$activity->invoice_id} amount:{$invoice->amount} isQuote:{$invoice->is_quote} isRecurring:{$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} invoiceTypeId:{$invoice->invoice_type_id} isRecurring:{$invoice->is_recurring}");
$foundProblem = true;
$clientFix += $invoice->amount;
$activityFix = $invoice->amount;
// **Fix for updating balance when creating a quote or recurring invoice**
} elseif ($activity->adjustment != 0 && ($invoice->is_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}");
} 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} invoiceTypeId:{$invoice->invoice_type_id} isRecurring:{$invoice->is_recurring}");
$foundProblem = true;
$clientFix -= $activity->adjustment;
$activityFix = 0;
@ -327,19 +335,23 @@ class CheckData extends Command {
}
}
/**
* @return array
*/
protected function getArguments()
{
return array(
//array('example', InputArgument::REQUIRED, 'An example argument.'),
);
return [];
}
/**
* @return array
*/
protected function getOptions()
{
return array(
array('fix', null, InputOption::VALUE_OPTIONAL, 'Fix data', null),
array('client_id', null, InputOption::VALUE_OPTIONAL, 'Client id', null),
);
return [
['fix', null, InputOption::VALUE_OPTIONAL, 'Fix data', null],
['client_id', null, InputOption::VALUE_OPTIONAL, 'Client id', null],
];
}
}

View File

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

View File

@ -3,15 +3,22 @@
use File;
use Illuminate\Console\Command;
/**
* Class GenerateResources
*/
class GenerateResources extends Command
{
/**
* @var string
*/
protected $name = 'ninja:generate-resources';
/**
* @var string
*/
protected $description = 'Generate Resouces';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
@ -25,22 +32,6 @@ class GenerateResources extends Command
*/
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');
foreach ($texts as $key => $value) {
@ -52,17 +43,19 @@ class GenerateResources extends Command
}
}
/**
* @return array
*/
protected function getArguments()
{
return array(
//array('example', InputArgument::REQUIRED, 'An example argument.'),
);
return [];
}
/**
* @return array
*/
protected function getOptions()
{
return array(
//array('example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null),
);
return [];
}
}

View File

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

View File

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

View File

@ -4,16 +4,25 @@ use DateTime;
use App\Models\Document;
use Illuminate\Console\Command;
/**
* Class RemoveOrphanedDocuments
*/
class RemoveOrphanedDocuments extends Command
{
/**
* @var string
*/
protected $name = 'ninja:remove-orphaned-documents';
/**
* @var string
*/
protected $description = 'Removes old documents not associated with an expense or invoice';
public function fire()
{
$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();
$this->info(count($documents).' orphaned document(s) found');
@ -25,17 +34,19 @@ class RemoveOrphanedDocuments extends Command
$this->info('Done');
}
/**
* @return array
*/
protected function getArguments()
{
return array(
//array('example', InputArgument::REQUIRED, 'An example argument.'),
);
return [];
}
/**
* @return array
*/
protected function getOptions()
{
return array(
//array('example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null),
);
return [];
}
}

View File

@ -1,24 +1,35 @@
<?php namespace App\Console\Commands;
use Utils;
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';
public function fire()
{
$this->info(date('Y-m-d') . ' Running ResetData...');
/**
* @var string
*/
protected $description = 'Reset data';
if (!Utils::isNinjaDev()) {
return;
public function fire()
{
$this->info(date('Y-m-d') . ' Running ResetData...');
if (!Utils::isNinjaDev()) {
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;
use DateTime;
use Carbon;
use Utils;
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\Repositories\InvoiceRepository;
use App\Services\PaymentService;
use App\Models\Invoice;
use App\Models\InvoiceItem;
use App\Models\Invitation;
/**
* Class SendRecurringInvoices
*/
class SendRecurringInvoices extends Command
{
/**
* @var string
*/
protected $name = 'ninja:send-invoices';
/**
* @var string
*/
protected $description = 'Send recurring invoices';
/**
* @var Mailer
*/
protected $mailer;
/**
* @var InvoiceRepository
*/
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();
$this->mailer = $mailer;
$this->invoiceRepo = $invoiceRepo;
$this->paymentService = $paymentService;
}
public function fire()
@ -33,18 +58,20 @@ class SendRecurringInvoices extends Command
$today = new DateTime();
$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')
->get();
$this->info(count($invoices).' recurring invoice(s) found');
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;
}
$recurInvoice->account->loadLocalizationSettings($recurInvoice->client);
$this->info('Processing Invoice '.$recurInvoice->id.' - Should send '.($recurInvoice->shouldSendToday() ? 'YES' : 'NO'));
$invoice = $this->invoiceRepo->createRecurringInvoice($recurInvoice);
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');
}
/**
* @return array
*/
protected function getArguments()
{
return array(
//array('example', InputArgument::REQUIRED, 'An example argument.'),
);
return [];
}
/**
* @return array
*/
protected function getOptions()
{
return array(
//array('example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null),
);
return [];
}
}

View File

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

View File

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

View File

@ -3,11 +3,31 @@
use Illuminate\Console\Command;
use App\Services\BankAccountService;
/**
* Class TestOFX
*/
class TestOFX extends Command
{
/**
* @var string
*/
protected $name = 'ninja:test-ofx';
/**
* @var string
*/
protected $description = 'Test OFX';
/**
* @var BankAccountService
*/
protected $bankAccountService;
/**
* TestOFX constructor.
*
* @param BankAccountService $bankAccountService
*/
public function __construct(BankAccountService $bankAccountService)
{
parent::__construct();
@ -18,15 +38,5 @@ class TestOFX extends Command
public function fire()
{
$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;
use App\Events\Event;
use App\Models\Client;
use Illuminate\Queue\SerializesModels;
/**
* Class ClientWasArchived
*/
class ClientWasArchived extends Event
{
use SerializesModels;
/**
* @var Client
*/
public $client;
/**
* Create a new event instance.
*
* @return void
* @param Client $client
*/
public function __construct($client)
public function __construct(Client $client)
{
$this->client = $client;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,22 +1,27 @@
<?php namespace App\Events;
use App\Events\Event;
use App\Models\Payment;
use Illuminate\Queue\SerializesModels;
class PaymentWasCreated extends Event {
/**
* Class PaymentWasCreated
*/
class PaymentWasCreated extends Event
{
use SerializesModels;
/**
* @var Payment
*/
public $payment;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct($payment)
/**
* Create a new event instance.
*
* @param Payment $payment
*/
public function __construct(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;
class PaymentWasDeleted extends Event {
/**
* Class PaymentWasDeleted.
*/
class PaymentWasDeleted extends Event
{
use SerializesModels;
/**
* @var Payment
*/
public $payment;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct($payment)
/**
* Create a new event instance.
*
* @param Payment $payment
*/
public function __construct(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;
use App\Events\Event;
use App\Models\Payment;
use Illuminate\Queue\SerializesModels;
class PaymentWasRestored extends Event {
use SerializesModels;
/**
* Class PaymentWasRestored
*/
class PaymentWasRestored extends Event
{
use SerializesModels;
/**
* @var Payment
*/
public $payment;
public $fromDeleted;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct($payment, $fromDeleted)
/**
* Create a new event instance.
*
* @param Payment $payment
* @param $fromDeleted
*/
public function __construct(Payment $payment, $fromDeleted)
{
$this->payment = $payment;
$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;
use App\Events\Event;
use App\Models\Invitation;
use App\Models\Invoice;
use Illuminate\Queue\SerializesModels;
class QuoteInvitationWasApproved extends Event {
use SerializesModels;
class QuoteInvitationWasApproved extends Event
{
use SerializesModels;
public $quote;
/**
* @var Invoice
*/
public $invoice;
/**
* @var Invitation
*/
public $invitation;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct($quote, $invoice, $invitation)
/**
* Create a new event instance.
*
* @param $quote
* @param Invoice $invoice
* @param Invitation $invitation
*/
public function __construct($quote, Invoice $invoice, Invitation $invitation)
{
$this->quote = $quote;
$this->invoice = $invoice;
$this->invitation = $invitation;
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,9 +8,13 @@ use Illuminate\Http\Exception\HttpResponseException;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
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.
@ -24,14 +28,14 @@ class Handler extends ExceptionHandler {
ValidationException::class,
];
/**
* Report or log an exception.
*
* This is a great spot to send exceptions to Sentry, Bugsnag, etc.
*
* @param \Exception $e
* @return void
*/
/**
* Report or log an exception.
*
* This is a great spot to send exceptions to Sentry, Bugsnag, etc.
*
* @param \Exception $e
* @return bool|void
*/
public function report(Exception $e)
{
// don't show these errors in the logs

View File

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

View File

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

View File

@ -1,8 +1,6 @@
<?php namespace App\Http\Controllers;
use Auth;
use Datatable;
use DB;
use Input;
use Redirect;
use Session;
@ -11,11 +9,10 @@ use Validator;
use stdClass;
use URL;
use Utils;
use WePay;
use App\Models\Gateway;
use App\Models\Account;
use App\Models\AccountGateway;
use App\Ninja\Repositories\AccountRepository;
use App\Services\AccountGatewayService;
class AccountGatewayController extends BaseController
@ -61,10 +58,8 @@ class AccountGatewayController extends BaseController
$data['title'] = trans('texts.edit_gateway') . ' - ' . $accountGateway->gateway->name;
$data['config'] = $config;
$data['hiddenFields'] = Gateway::$hiddenFields;
$data['paymentTypeId'] = $accountGateway->getPaymentType();
$data['selectGateways'] = Gateway::where('id', '=', $accountGateway->gateway_id)->get();
return View::make('accounts.account_gateway', $data);
}
@ -84,43 +79,40 @@ class AccountGatewayController extends BaseController
*/
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()) {
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)
{
$selectedCards = $accountGateway ? $accountGateway->accepted_credit_cards : 0;
$account = Auth::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';
}
}
}
$user = Auth::user();
$account =$user->account;
$creditCardsArray = unserialize(CREDIT_CARDS);
$creditCards = [];
@ -139,25 +131,19 @@ class AccountGatewayController extends BaseController
foreach ($gateways as $gateway) {
$fields = $gateway->getFields();
asort($fields);
$gateway->fields = $fields;
$gateway->fields = $gateway->id == GATEWAY_WEPAY ? [] : $fields;
if ($accountGateway && $accountGateway->gateway_id == $gateway->id) {
$accountGateway->fields = $gateway->fields;
}
}
$tokenBillingOptions = [];
for ($i=1; $i<=4; $i++) {
$tokenBillingOptions[$i] = trans("texts.token_billing_{$i}");
}
return [
'paymentTypes' => $paymentTypes,
'account' => $account,
'user' => $user,
'accountGateway' => $accountGateway,
'config' => false,
'gateways' => $gateways,
'creditCardTypes' => $creditCards,
'tokenBillingOptions' => $tokenBillingOptions,
'countGateways' => count($currentGateways)
];
}
@ -169,7 +155,7 @@ class AccountGatewayController extends BaseController
$ids = Input::get('bulk_public_id');
$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);
}
@ -180,27 +166,10 @@ class AccountGatewayController extends BaseController
*/
public function save($accountGatewayPublicId = false)
{
$rules = array();
$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();
}
$gatewayId = Input::get('primary_gateway_id') ?: Input::get('secondary_gateway_id');
$gateway = Gateway::findOrFail($gatewayId);
$rules = [];
$fields = $gateway->getFields();
$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
} else {
$rules['publishable_key'] = 'required';
$rules['enable_ach'] = 'boolean';
}
}
foreach ($fields as $field => $details) {
if (!in_array($field, $optional)) {
if (strtolower($gateway->name) == 'beanstream') {
if (in_array($field, ['merchant_id', 'passCode'])) {
$rules[$gateway->id.'_'.$field] = 'required';
if ($gatewayId != GATEWAY_WEPAY) {
foreach ($fields as $field => $details) {
if (!in_array($field, $optional)) {
if (strtolower($gateway->name) == 'beanstream') {
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();
$oldConfig = $accountGateway->getConfig();
} 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->gateway_id = $gatewayId;
if ($gatewayId == GATEWAY_WEPAY) {
if(!$this->setupWePay($accountGateway, $wepayResponse)) {
return $wepayResponse;
}
$oldConfig = $accountGateway->getConfig();
}
}
$config = new stdClass();
foreach ($fields as $field => $details) {
$value = trim(Input::get($gateway->id.'_'.$field));
// if the new value is masked use the original value
if ($oldConfig && $value && $value === str_repeat('*', strlen($value))) {
$value = $oldConfig->$field;
}
if (!$value && ($field == 'testMode' || $field == 'developerMode')) {
// do nothing
} else {
$config->$field = $value;
if ($gatewayId != GATEWAY_WEPAY) {
foreach ($fields as $field => $details) {
$value = trim(Input::get($gateway->id . '_' . $field));
// if the new value is masked use the original value
if ($oldConfig && $value && $value === str_repeat('*', strlen($value))) {
$value = $oldConfig->$field;
}
if (!$value && ($field == 'testMode' || $field == 'developerMode')) {
// do nothing
} else {
$config->$field = $value;
}
}
} elseif($oldConfig) {
$config = clone $oldConfig;
}
$publishableKey = Input::get('publishable_key');
@ -266,6 +260,35 @@ class AccountGatewayController extends BaseController
$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;
if ($creditcards) {
foreach ($creditcards as $card => $value) {
@ -284,21 +307,167 @@ class AccountGatewayController extends BaseController
$account->account_gateways()->save($accountGateway);
}
if (Input::get('token_billing_type_id')) {
$account->token_billing_type_id = Input::get('token_billing_type_id');
$account->save();
}
if ($accountGatewayPublicId) {
$message = trans('texts.updated_gateway');
if(isset($wepayResponse)) {
return $wepayResponse;
} 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;
use Auth;
use DB;
use Datatable;
use Utils;
use View;
use App\Models\Client;
use App\Models\Activity;
use App\Services\ActivityService;
class ActivityController extends BaseController

View File

@ -11,10 +11,8 @@ use Utils;
use View;
use Event;
use Session;
use Cookie;
use Response;
use Redirect;
use App\Models\User;
use App\Models\Account;
use App\Models\Industry;
use App\Ninja\Mailers\Mailer;
@ -100,6 +98,8 @@ class AppController extends BaseController
$_ENV['MAIL_FROM_NAME'] = $mail['from']['name'];
$_ENV['MAIL_PASSWORD'] = $mail['password'];
$_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 = '';
foreach ($_ENV as $key => $val) {
@ -114,18 +114,18 @@ class AppController extends BaseController
// Write Config Settings
$fp = fopen(base_path()."/.env", 'w');
$fp = fopen(base_path().'/.env', 'w');
fwrite($fp, $config);
fclose($fp);
// == DB Migrate & Seed == //
// Artisan::call('migrate:rollback', array('--force' => true)); // Debug Purposes
Artisan::call('migrate', array('--force' => true));
Artisan::call('migrate', ['--force' => true]);
if (Industry::count() == 0) {
Artisan::call('db:seed', array('--force' => true));
Artisan::call('db:seed', ['--force' => true]);
}
Cache::flush();
Artisan::call('optimize', array('--force' => true));
Artisan::call('optimize', ['--force' => true]);
$firstName = trim(Input::get('first_name'));
$lastName = trim(Input::get('last_name'));
@ -147,7 +147,7 @@ class AppController extends BaseController
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>');
return Redirect::to('/settings/system_settings');
}
@ -174,6 +174,8 @@ class AppController extends BaseController
$_ENV['MAIL_FROM_NAME'] = $mail['from']['name'];
$_ENV['MAIL_PASSWORD'] = $mail['password'];
$_ENV['MAIL_FROM_ADDRESS'] = $mail['username'];
$_ENV['MAILGUN_DOMAIN'] = $mail['mailgun_domain'];
$_ENV['MAILGUN_SECRET'] = $mail['mailgun_secret'];
}
$config = '';
@ -187,7 +189,7 @@ class AppController extends BaseController
$config .= "{$key}={$val}\n";
}
$fp = fopen(base_path()."/.env", 'w');
$fp = fopen(base_path().'/.env', 'w');
fwrite($fp, $config);
fclose($fp);
@ -243,11 +245,11 @@ class AppController extends BaseController
if (!Utils::isNinjaProd() && !Utils::isDatabaseSetup()) {
try {
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) {
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) {
Utils::logError($e);
return Response::make($e->getMessage(), 500);
@ -268,13 +270,18 @@ class AppController extends BaseController
Artisan::call('route:clear');
Artisan::call('view:clear');
Artisan::call('config:clear');
Artisan::call('optimize', array('--force' => true));
Artisan::call('optimize', ['--force' => true]);
Cache::flush();
Session::flush();
Artisan::call('migrate', array('--force' => true));
Artisan::call('db:seed', array('--force' => true, '--class' => "UpdateSeeder"));
Artisan::call('migrate', ['--force' => true]);
Artisan::call('db:seed', ['--force' => true, '--class' => 'UpdateSeeder']);
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) {
Utils::logError($e);
return Response::make($e->getMessage(), 500);

View File

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

View File

@ -3,33 +3,36 @@
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ResetsPasswords;
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.
|
*/
/*
|--------------------------------------------------------------------------
| 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;
use ResetsPasswords;
/**
* @var string
*/
protected $redirectTo = '/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');
}
/**
* Create a new password controller instance.
*
* @internal param \Illuminate\Contracts\Auth\Guard $auth
* @internal param \Illuminate\Contracts\Auth\PasswordBroker $passwords
*/
public function __construct()
{
$this->middleware('guest');
}
}

View File

@ -2,23 +2,18 @@
use Cache;
use Auth;
use Datatable;
use DB;
use Input;
use Redirect;
use Session;
use View;
use Validator;
use stdClass;
use Crypt;
use URL;
use Utils;
use App\Models\Gateway;
use File;
use App\Models\Account;
use App\Models\BankAccount;
use App\Ninja\Repositories\BankAccountRepository;
use App\Services\BankAccountService;
use App\Http\Requests\CreateBankAccountRequest;
use Illuminate\Http\Request;
class BankAccountController extends BaseController
{
@ -122,4 +117,28 @@ class BankAccountController extends BaseController
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;
use Session;
use Utils;
use Auth;
use Log;
use Input;
use Response;
use Request;
use League\Fractal;
use League\Fractal\Manager;
use League\Fractal\Resource\Item;
use League\Fractal\Resource\Collection;
@ -15,7 +12,6 @@ use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use App\Models\EntityModel;
use App\Ninja\Serializers\ArraySerializer;
use League\Fractal\Serializer\JsonApiSerializer;
use Illuminate\Pagination\LengthAwarePaginator;
/**
* @SWG\Swagger(
@ -169,7 +165,7 @@ class BaseAPIController extends Controller
if (Utils::isNinjaDev()) {
$count = count(\DB::getQueryLog());
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';

View File

@ -1,11 +1,7 @@
<?php namespace App\Http\Controllers;
use App\Http\Middleware\PermissionsRequired;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Input;
use Auth;
use Utils;
class BaseController extends Controller
{

View File

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

View File

@ -1,51 +1,52 @@
<?php namespace App\Http\Controllers\ClientAuth;
use Auth;
use Event;
use Utils;
use Session;
use Illuminate\Http\Request;
use App\Models\User;
use App\Events\UserLoggedIn;
use App\Http\Controllers\Controller;
use App\Ninja\Repositories\AccountRepository;
use App\Services\AuthService;
use App\Models\Invitation;
use App\Models\Contact;
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';
use AuthenticatesUsers;
/**
* @return mixed
*/
public function showLoginForm()
{
$data = [];
public function showLoginForm()
{
$data = array(
);
$contactKey = session('contact_key');
if ($contactKey) {
$contact = Contact::where('contact_key', '=', $contactKey)->first();
if ($contact && !$contact->is_deleted) {
$account = $contact->account;
$invitation_key = session('invitation_key');
if($invitation_key){
$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['account'] = $account;
$data['clientFontUrl'] = $account->getFontsUrl();
}
}
return view('clientauth.login')->with($data);
}
return view('clientauth.login')->with($data);
}
/**
/**
* Get the needed authorization credentials from the request.
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Http\Request $request
*
* @return array
*/
protected function getCredentials(Request $request)
@ -53,21 +54,22 @@ class AuthController extends Controller {
$credentials = $request->only('password');
$credentials['id'] = null;
$invitation_key = session('invitation_key');
if($invitation_key){
$invitation = Invitation::where('invitation_key', '=', $invitation_key)->first();
if ($invitation && !$invitation->is_deleted) {
$credentials['id'] = $invitation->contact_id;
$contactKey = session('contact_key');
if ($contactKey) {
$contact = Contact::where('contact_key', '=', $contactKey)->first();
if ($contact && !$contact->is_deleted) {
$credentials['id'] = $contact->id;
}
}
return $credentials;
}
/**
/**
* Validate the user login request.
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Http\Request $request
*
* @return void
*/
protected function validateLogin(Request $request)
@ -76,4 +78,12 @@ class AuthController extends Controller {
'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\Mail\Message;
use Illuminate\Support\Facades\Password;
use App\Models\Contact;
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.
|
*/
/*
|--------------------------------------------------------------------------
| 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;
use ResetsPasswords;
/**
* @var string
*/
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");
}
/**
* Create a new password controller instance.
*
* @internal param \Illuminate\Contracts\Auth\Guard $auth
* @internal param \Illuminate\Contracts\Auth\PasswordBroker $passwords
*/
public function __construct()
{
$this->middleware('guest');
Config::set('auth.defaults.passwords', 'client');
}
public function showLinkRequestForm()
{
$data = array();
$invitation_key = session('invitation_key');
if($invitation_key){
$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();
/**
* @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();
}
} 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.
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Http\Request $request
*
* @return \Illuminate\Http\Response
*/
public function sendResetLinkEmail(Request $request)
{
$broker = $this->getBroker();
$contact_id = null;
$invitation_key = session('invitation_key');
if($invitation_key){
$invitation = Invitation::where('invitation_key', '=', $invitation_key)->first();
if ($invitation && !$invitation->is_deleted) {
$contact_id = $invitation->contact_id;
$contactId = null;
$contactKey = session('contact_key');
if ($contactKey) {
$contact = Contact::where('contact_key', '=', $contactKey)->first();
if ($contact && !$contact->is_deleted) {
$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());
});
@ -97,29 +102,37 @@ class PasswordController extends Controller {
*
* If no token is present, display the link request form.
*
* @param \Illuminate\Http\Request $request
* @param string|null $invitation_key
* @param string|null $token
* @param \Illuminate\Http\Request $request
* @param string|null $key
* @param string|null $token
* @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)) {
return $this->getEmail();
}
$data = compact('token', 'invitation_key');
$invitation_key = session('invitation_key');
if($invitation_key){
$invitation = Invitation::where('invitation_key', '=', $invitation_key)->first();
if ($invitation && !$invitation->is_deleted) {
$invoice = $invitation->invoice;
$client = $invoice->client;
$account = $client->account;
$data = compact('token');
if ($key) {
$contact = Contact::where('contact_key', '=', $key)->first();
if ($contact && !$contact->is_deleted) {
$account = $contact->account;
$data['contact_key'] = $contact->contact_key;
} else {
// Maybe it's an invitation key
$invitation = Invitation::where('invitation_key', '=', $key)->first();
if ($invitation && !$invitation->is_deleted) {
$account = $invitation->account;
$data['contact_key'] = $invitation->contact->contact_key;
}
}
$data['hideLogo'] = $account->hasFeature(FEATURE_WHITE_LABEL);
$data['clientViewCSS'] = $account->clientViewCSS();
if (!empty($account)) {
$data['account'] = $account;
$data['clientFontUrl'] = $account->getFontsUrl();
} else {
return \Redirect::to('/client/sessionexpired');
}
}
@ -127,26 +140,25 @@ class PasswordController extends Controller {
}
/**
* Display the password reset view for the given token.
*
* If no token is present, display the link request form.
*
* @param \Illuminate\Http\Request $request
* @param string|null $invitation_key
* @param string|null $token
* @param \Illuminate\Http\Request $request
* @param string|null $key
* @param string|null $token
* @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.
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function reset(Request $request)
@ -159,11 +171,11 @@ class PasswordController extends Controller {
$credentials['id'] = null;
$invitation_key = $request->input('invitation_key');
if($invitation_key){
$invitation = Invitation::where('invitation_key', '=', $invitation_key)->first();
if ($invitation && !$invitation->is_deleted) {
$credentials['id'] = $invitation->contact_id;
$contactKey = session('contact_key');
if ($contactKey) {
$contact = Contact::where('contact_key', '=', $contactKey)->first();
if ($contact && !$contact->is_deleted) {
$credentials['id'] = $contact->id;
}
}

View File

@ -1,33 +1,21 @@
<?php namespace App\Http\Controllers;
use Auth;
use Datatable;
use Utils;
use View;
use URL;
use Validator;
use Input;
use Session;
use Redirect;
use Cache;
use App\Models\Activity;
use App\Models\Client;
use App\Models\Account;
use App\Models\Contact;
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\Expense;
use App\Models\Country;
use App\Models\Task;
use App\Ninja\Repositories\ClientRepository;
use App\Services\ClientService;
use App\Http\Requests\ClientRequest;
use App\Http\Requests\CreateClientRequest;
use App\Http\Requests\UpdateClientRequest;
@ -53,7 +41,7 @@ class ClientController extends BaseController
*/
public function index()
{
return View::make('list', array(
return View::make('list', [
'entityType' => ENTITY_CLIENT,
'title' => trans('texts.clients'),
'sortCol' => '4',
@ -67,12 +55,15 @@ class ClientController extends BaseController
'balance',
''
]),
));
]);
}
public function getDatatable()
{
return $this->clientService->getDatatable(Input::get('sSearch'));
$search = Input::get('sSearch');
$userId = Auth::user()->filterId();
return $this->clientService->getDatatable($search, $userId);
}
/**
@ -126,17 +117,20 @@ class ClientController extends BaseController
$actionLinks[] = ['label' => trans('texts.enter_expense'), 'url' => URL::to('/expenses/create/0/'.$client->public_id)];
}
$data = array(
$token = $client->getGatewayToken();
$data = [
'actionLinks' => $actionLinks,
'showBreadcrumbs' => false,
'client' => $client,
'credit' => $client->getTotalCredit(),
'title' => trans('texts.view_client'),
'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,
'gatewayLink' => $client->getGatewayLink(),
);
'gatewayLink' => $token ? $token->gatewayLink() : false,
'gatewayName' => $token ? $token->gatewayName() : false,
];
return View::make('clients.show', $data);
}
@ -149,7 +143,7 @@ class ClientController extends BaseController
public function create(ClientRequest $request)
{
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 = [
@ -199,10 +193,7 @@ class ClientController extends BaseController
'account' => Auth::user()->account,
'sizes' => Cache::get('sizes'),
'paymentTerms' => Cache::get('paymentTerms'),
'industries' => Cache::get('industries'),
'currencies' => Cache::get('currencies'),
'languages' => Cache::get('languages'),
'countries' => Cache::get('countries'),
'customLabel1' => Auth::user()->account->custom_client_label1,
'customLabel2' => Auth::user()->account->custom_client_label2,
];

View File

@ -2,7 +2,6 @@
use Auth;
use View;
use DB;
use URL;
use Input;
use Utils;
@ -10,9 +9,15 @@ use Request;
use Response;
use Session;
use Datatable;
use Validator;
use Cache;
use Redirect;
use Exception;
use App\Models\Gateway;
use App\Models\Invitation;
use App\Models\Document;
use App\Models\PaymentMethod;
use App\Models\Contact;
use App\Ninja\Repositories\InvoiceRepository;
use App\Ninja\Repositories\PaymentRepository;
use App\Ninja\Repositories\ActivityRepository;
@ -22,7 +27,7 @@ use App\Events\QuoteInvitationWasViewed;
use App\Services\PaymentService;
use Barracuda\ArchiveStream\ZipArchive;
class PublicClientController extends BaseController
class ClientPortalController extends BaseController
{
private $invoiceRepo;
private $paymentRepo;
@ -58,7 +63,7 @@ class PublicClientController extends BaseController
if (!Input::has('phantomjs') && !Input::has('silent') && !Session::has($invitationKey)
&& (!Auth::check() || Auth::user()->account_id != $invoice->account_id)) {
if ($invoice->is_quote) {
if ($invoice->isType(INVOICE_TYPE_QUOTE)) {
event(new QuoteInvitationWasViewed($invoice, $invitation));
} else {
event(new InvoiceInvitationWasViewed($invoice, $invitation));
@ -66,7 +71,7 @@ class PublicClientController extends BaseController
}
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);
@ -92,15 +97,20 @@ class PublicClientController extends BaseController
'phone',
]);
$paymentTypes = $this->getPaymentTypes($client, $invitation);
$data = [];
$paymentTypes = $this->getPaymentTypes($account, $client, $invitation);
$paymentURL = '';
if (count($paymentTypes)) {
if (count($paymentTypes) == 1) {
$paymentURL = $paymentTypes[0]['url'];
if (!$account->isGatewayConfigured(GATEWAY_PAYPAL_EXPRESS)) {
$paymentURL = URL::to($paymentURL);
}
}
if ($wepayGateway = $account->getGatewayConfig(GATEWAY_WEPAY)){
$data['enableWePayACH'] = $wepayGateway->getAchEnabled();
}
$showApprove = $invoice->quote_invoice_id ? false : true;
if ($invoice->due_date) {
$showApprove = time() < strtotime($invoice->due_date);
@ -109,28 +119,10 @@ class PublicClientController extends BaseController
$showApprove = false;
}
// Checkout.com requires first getting a payment token
$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(
$data += [
'account' => $account,
'showApprove' => $showApprove,
'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(),
'invoice' => $invoice->hidePrivateFields(),
'invitation' => $invitation,
@ -138,11 +130,18 @@ class PublicClientController extends BaseController
'contact' => $contact,
'paymentTypes' => $paymentTypes,
'paymentURL' => $paymentURL,
'checkoutComToken' => $checkoutComToken,
'checkoutComKey' => $checkoutComKey,
'checkoutComDebug' => $checkoutComDebug,
'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()){
$zipDocs = $this->getInvoiceZipDocuments($invoice, $size);
@ -156,32 +155,29 @@ class PublicClientController extends BaseController
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 = [];
$account = $client->account;
$links = [];
if ($client->getGatewayToken()) {
$paymentTypes[] = [
'url' => URL::to("payment/{$invitation->invitation_key}/token"), 'label' => trans('texts.use_card_on_file')
];
}
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))
];
}
foreach ($account->account_gateways as $accountGateway) {
$paymentDriver = $accountGateway->paymentDriver($invitation);
$links = array_merge($links, $paymentDriver->tokenLinks());
$links = array_merge($links, $paymentDriver->paymentLinks());
}
return $paymentTypes;
return $links;
}
public function download($invitationKey)
@ -207,27 +203,32 @@ class PublicClientController extends BaseController
public function dashboard()
{
if (!$invitation = $this->getInvitation()) {
if (!$contact = $this->getContact()) {
return $this->returnError();
}
$account = $invitation->account;
$invoice = $invitation->invoice;
$client = $invoice->client;
$client = $contact->client;
$account = $client->account;
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
$customer = false;
if (!$account->enable_client_portal || !$account->enable_client_portal_dashboard) {
return $this->returnError();
}
if ($paymentDriver = $account->paymentDriver(false, GATEWAY_TYPE_TOKEN)) {
$customer = $paymentDriver->customer($client->id);
}
$data = [
'color' => $color,
'contact' => $contact,
'account' => $account,
'client' => $client,
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL),
'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS),
'clientViewCSS' => $account->clientViewCSS(),
'clientFontUrl' => $account->getFontsUrl(),
'gateway' => $account->getTokenGateway(),
'paymentMethods' => $customer ? $customer->payment_methods : false,
'transactionToken' => $paymentDriver ? $paymentDriver->createTransactionToken() : false,
];
return response()->view('invited.dashboard', $data);
@ -235,12 +236,13 @@ class PublicClientController extends BaseController
public function activityDatatable()
{
if (!$invitation = $this->getInvitation()) {
return false;
if (!$contact = $this->getContact()) {
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);
return Datatable::query($query)
@ -248,10 +250,13 @@ class PublicClientController extends BaseController
->addColumn('activity_type_id', function ($model) {
$data = [
'client' => Utils::getClientDisplayName($model),
'user' => $model->is_system ? ('<i>' . trans('texts.system') . '</i>') : ($model->user_first_name . ' ' . $model->user_last_name),
'invoice' => trans('texts.invoice') . ' ' . $model->invoice,
'user' => $model->is_system ? ('<i>' . trans('texts.system') . '</i>') : ($model->account_name),
'invoice' => $model->invoice,
'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);
@ -261,13 +266,13 @@ class PublicClientController extends BaseController
->make();
}
public function invoiceIndex()
public function recurringInvoiceIndex()
{
if (!$invitation = $this->getInvitation()) {
if (!$contact = $this->getContact()) {
return $this->returnError();
}
$account = $invitation->account;
$account = $contact->account;
if (!$account->enable_client_portal) {
return $this->returnError();
@ -277,10 +282,35 @@ class PublicClientController extends BaseController
$data = [
'color' => $color,
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL),
'hideDashboard' => !$account->enable_client_portal_dashboard,
'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS),
'clientViewCSS' => $account->clientViewCSS(),
'account' => $account,
'client' => $contact->client,
'clientFontUrl' => $account->getFontsUrl(),
'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(),
'title' => trans('texts.invoices'),
'entityType' => ENTITY_INVOICE,
@ -292,20 +322,30 @@ class PublicClientController extends BaseController
public function invoiceDatatable()
{
if (!$invitation = $this->getInvitation()) {
if (!$contact = $this->getContact()) {
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()
{
if (!$invitation = $this->getInvitation()) {
if (!$contact = $this->getContact()) {
return $this->returnError();
}
$account = $invitation->account;
$account = $contact->account;
if (!$account->enable_client_portal) {
return $this->returnError();
@ -314,14 +354,11 @@ class PublicClientController extends BaseController
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
$data = [
'color' => $color,
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL),
'hideDashboard' => !$account->enable_client_portal_dashboard,
'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS),
'clientViewCSS' => $account->clientViewCSS(),
'account' => $account,
'clientFontUrl' => $account->getFontsUrl(),
'entityType' => ENTITY_PAYMENT,
'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);
@ -329,27 +366,56 @@ class PublicClientController extends BaseController
public function paymentDatatable()
{
if (!$invitation = $this->getInvitation()) {
return false;
if (!$contact = $this->getContact()) {
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)
->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('payment_type', function ($model) { return $model->payment_type ? $model->payment_type : ($model->account_gateway_id ? '<i>Online payment</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->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('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();
}
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()
{
if (!$invitation = $this->getInvitation()) {
if (!$contact = $this->getContact()) {
return $this->returnError();
}
$account = $invitation->account;
$account = $contact->account;
if (!$account->enable_client_portal) {
return $this->returnError();
@ -358,10 +424,7 @@ class PublicClientController extends BaseController
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
$data = [
'color' => $color,
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL),
'hideDashboard' => !$account->enable_client_portal_dashboard,
'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS),
'clientViewCSS' => $account->clientViewCSS(),
'account' => $account,
'clientFontUrl' => $account->getFontsUrl(),
'title' => trans('texts.quotes'),
'entityType' => ENTITY_QUOTE,
@ -374,20 +437,20 @@ class PublicClientController extends BaseController
public function quoteDatatable()
{
if (!$invitation = $this->getInvitation()) {
if (!$contact = $this->getContact()) {
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()
{
if (!$invitation = $this->getInvitation()) {
if (!$contact = $this->getContact()) {
return $this->returnError();
}
$account = $invitation->account;
$account = $contact->account;
if (!$account->enable_client_portal) {
return $this->returnError();
@ -396,10 +459,7 @@ class PublicClientController extends BaseController
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
$data = [
'color' => $color,
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL),
'hideDashboard' => !$account->enable_client_portal_dashboard,
'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS),
'clientViewCSS' => $account->clientViewCSS(),
'account' => $account,
'clientFontUrl' => $account->getFontsUrl(),
'title' => trans('texts.documents'),
'entityType' => ENTITY_DOCUMENT,
@ -412,11 +472,11 @@ class PublicClientController extends BaseController
public function documentDatatable()
{
if (!$invitation = $this->getInvitation()) {
if (!$contact = $this->getContact()) {
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)
@ -424,54 +484,47 @@ class PublicClientController extends BaseController
return response()->view('error', [
'error' => $error ?: trans('texts.invoice_not_found'),
'hideHeader' => true,
'account' => $this->getContact()->account,
]);
}
private function getInvitation()
{
$invitationKey = session('invitation_key');
private function getContact() {
$contactKey = session('contact_key');
if (!$invitationKey) {
if (!$contactKey) {
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;
}
$invoice = $invitation->invoice;
if (!$invoice || $invoice->is_deleted) {
return false;
}
return $invitation;
return $contact;
}
public function getDocumentVFSJS($publicId, $name){
if (!$invitation = $this->getInvitation()) {
if (!$contact = $this->getContact()) {
return $this->returnError();
}
$clientId = $invitation->invoice->client_id;
$document = Document::scope($publicId, $invitation->account_id)->first();
$document = Document::scope($publicId, $contact->account_id)->first();
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;
if($document->expense && $document->expense->client_id == $invitation->invoice->client_id){
if($document->expense && $document->expense->client_id == $contact->client_id){
$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;
}
if(!$authorized){
return Response::view('error', array('error'=>'Not authorized'), 403);
return Response::view('error', ['error'=>'Not authorized'], 403);
}
if(substr($name, -3)=='.js'){
@ -502,7 +555,7 @@ class PublicClientController extends BaseController
$size = 0;
$maxSize = MAX_ZIP_DOCUMENTS_SIZE * 1000;
$toZip = array();
$toZip = [];
foreach($documents as $document){
if($size + $document->size > $maxSize)break;
@ -541,14 +594,14 @@ class PublicClientController extends BaseController
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;
$toZip = $this->getInvoiceZipDocuments($invoice);
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');
@ -556,7 +609,7 @@ class PublicClientController extends BaseController
foreach($toZip as $name=>$document){
$fileStream = $document->getStream();
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);
fclose($fileStream);
$zip->complete_file_stream();
@ -574,7 +627,7 @@ class PublicClientController extends BaseController
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;
$document = Document::scope($publicId, $invitation->account_id)->firstOrFail();
@ -587,10 +640,150 @@ class PublicClientController extends BaseController
}
if(!$authorized){
return Response::view('error', array('error'=>'Not authorized'), 403);
return Response::view('error', ['error'=>'Not authorized'], 403);
}
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\Foundation\Validation\ValidatesRequests;
abstract class Controller extends BaseController {
use DispatchesJobs, ValidatesRequests;
/**
* Class Controller
*/
abstract class Controller extends BaseController
{
use DispatchesJobs, ValidatesRequests;
}

View File

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

View File

@ -2,14 +2,12 @@
use Auth;
use DB;
use View;
use App\Models\Activity;
class DashboardApiController extends BaseAPIController
{
public function index()
{
$view_all = !Auth::user()->hasPermission('view_all');
$view_all = Auth::user()->hasPermission('view_all');
$user_id = Auth::user()->id;
// total_income, billed_clients, invoice_sent and active_clients
@ -24,7 +22,7 @@ class DashboardApiController extends BaseAPIController
->where('clients.is_deleted', '=', false)
->where('invoices.is_deleted', '=', false)
->where('invoices.is_recurring', '=', false)
->where('invoices.is_quote', '=', false);
->where('invoices.invoice_type_id', '=', false);
if(!$view_all){
$metrics = $metrics->where(function($query) use($user_id){
@ -62,7 +60,7 @@ class DashboardApiController extends BaseAPIController
->where('accounts.id', '=', Auth::user()->account_id)
->where('clients.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);
if(!$view_all){
@ -80,8 +78,13 @@ class DashboardApiController extends BaseAPIController
->where('accounts.id', '=', Auth::user()->account_id)
->where('clients.is_deleted', '=', false)
->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'))
->get();
->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'));
if (!$view_all) {
$balances->where('clients.user_id', '=', $user_id);
}
$balances = $balances->get();
$pastDue = DB::table('invoices')
->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->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')
->take(50)
->get();
@ -126,7 +129,7 @@ class DashboardApiController extends BaseAPIController
}
$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();
$payments = DB::table('payments')
@ -152,21 +155,20 @@ class DashboardApiController extends BaseAPIController
$hasQuotes = false;
foreach ([$upcoming, $pastDue] as $data) {
foreach ($data as $invoice) {
if ($invoice->is_quote) {
if ($invoice->invoice_type_id == INVOICE_TYPE_QUOTE) {
$hasQuotes = true;
}
}
}
$data = [
'id' => 1,
'paidToDate' => $paidToDate[0]->value,
'paidToDateCurrency' => $paidToDate[0]->currency_id,
'balances' => $balances[0]->value,
'balancesCurrency' => $balances[0]->currency_id,
'averageInvoice' => $averageInvoice[0]->invoice_avg,
'averageInvoiceCurrency' => $averageInvoice[0]->currency_id,
'paidToDate' => $paidToDate[0]->value ? $paidToDate[0]->value : 0,
'paidToDateCurrency' => $paidToDate[0]->currency_id ? $paidToDate[0]->currency_id : 0,
'balances' => $balances[0]->value ? $balances[0]->value : 0,
'balancesCurrency' => $balances[0]->currency_id ? $balances[0]->currency_id : 0,
'averageInvoice' => $averageInvoice[0]->invoice_avg ? $averageInvoice[0]->invoice_avg : 0,
'averageInvoiceCurrency' => $averageInvoice[0]->currency_id ? $averageInvoice[0]->currency_id : 0,
'invoicesSent' => $metrics ? $metrics->invoices_sent : 0,
'activeClients' => $metrics ? $metrics->active_clients : 0,
];

View File

@ -7,17 +7,25 @@ use App\Models\Activity;
use App\Models\Invoice;
use App\Models\Payment;
/**
* Class DashboardController
*/
class DashboardController extends BaseController
{
/**
* @return \Illuminate\Contracts\View\View
*/
public function index()
{
$view_all = Auth::user()->hasPermission('view_all');
$user_id = Auth::user()->id;
// 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,
SUM(CASE WHEN invoices.invoice_status_id >= '.INVOICE_STATUS_SENT.' THEN 1 ELSE 0 END) invoices_sent,
COUNT(DISTINCT clients.id) active_clients');
$select = DB::raw(
'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,
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')
->select($select)
->leftJoin('clients', 'accounts.id', '=', 'clients.account_id')
@ -26,7 +34,7 @@ class DashboardController extends BaseController
->where('clients.is_deleted', '=', false)
->where('invoices.is_deleted', '=', false)
->where('invoices.is_recurring', '=', false)
->where('invoices.is_quote', '=', false);
->where('invoices.invoice_type_id', '=', INVOICE_TYPE_STANDARD);
if(!$view_all){
$metrics = $metrics->where(function($query) use($user_id){
@ -41,7 +49,10 @@ class DashboardController extends BaseController
$metrics = $metrics->groupBy('accounts.id')
->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')
->select($select)
->leftJoin('clients', 'accounts.id', '=', 'clients.account_id')
@ -53,10 +64,13 @@ class DashboardController extends BaseController
}
$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();
$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')
->select($select)
->leftJoin('clients', 'accounts.id', '=', 'clients.account_id')
@ -64,7 +78,7 @@ class DashboardController extends BaseController
->where('accounts.id', '=', Auth::user()->account_id)
->where('clients.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);
if(!$view_all){
@ -72,17 +86,20 @@ class DashboardController extends BaseController
}
$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();
$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')
->select($select)
->leftJoin('clients', 'accounts.id', '=', 'clients.account_id')
->where('accounts.id', '=', Auth::user()->account_id)
->where('clients.is_deleted', '=', false)
->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) {
$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->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')
->take(50)
->get();
@ -147,7 +164,7 @@ class DashboardController extends BaseController
}
$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();
$payments = DB::table('payments')
@ -173,7 +190,7 @@ class DashboardController extends BaseController
$hasQuotes = false;
foreach ([$upcoming, $pastDue] as $data) {
foreach ($data as $invoice) {
if ($invoice->is_quote) {
if ($invoice->invoice_type_id == INVOICE_TYPE_QUOTE) {
$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;
use Datatable;
use Input;
use Redirect;
use Session;
use URL;
use Utils;
use View;
use Validator;
use Response;
use App\Models\Document;
use App\Ninja\Repositories\DocumentRepository;
use App\Http\Requests\DocumentRequest;
use App\Http\Requests\CreateDocumentRequest;
use App\Http\Requests\UpdateDocumentRequest;
@ -64,7 +57,7 @@ class DocumentController extends BaseController
$document = $request->entity();
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();
@ -88,7 +81,7 @@ class DocumentController extends BaseController
}
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();
@ -106,7 +99,7 @@ class DocumentController extends BaseController
return;
}
$result = $this->documentRepo->upload(Input::all()['file'], $doc_array);
$result = $this->documentRepo->upload($request->all(), $doc_array);
if(is_string($result)){
return Response::json([

View File

@ -1,14 +1,8 @@
<?php namespace App\Http\Controllers;
use App\Models\Expense;
use app\Ninja\Repositories\ExpenseRepository;
use App\Ninja\Transformers\ExpenseTransformer;
use App\Ninja\Repositories\ExpenseRepository;
use App\Services\ExpenseService;
use Utils;
use Response;
use Input;
use Auth;
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;
use Debugbar;
use DB;
use Auth;
use Datatable;
use Utils;
use View;
use URL;
use Validator;
use Input;
use Session;
use Redirect;
use Cache;
use App\Models\Vendor;
use App\Models\Expense;
use App\Models\ExpenseCategory;
use App\Models\Client;
use App\Models\TaxRate;
use App\Services\ExpenseService;
use App\Ninja\Repositories\ExpenseRepository;
use App\Http\Requests\ExpenseRequest;
use App\Http\Requests\CreateExpenseRequest;
use App\Http\Requests\UpdateExpenseRequest;
@ -44,7 +41,7 @@ class ExpenseController extends BaseController
*/
public function index()
{
return View::make('list', array(
return View::make('list', [
'entityType' => ENTITY_EXPENSE,
'title' => trans('texts.expenses'),
'sortCol' => '3',
@ -54,11 +51,12 @@ class ExpenseController extends BaseController
'client',
'expense_date',
'amount',
'category',
'public_notes',
'status',
''
]),
));
]);
}
public function getDatatable($expensePublicId = null)
@ -79,7 +77,7 @@ class ExpenseController extends BaseController
$vendor = null;
}
$data = array(
$data = [
'vendorPublicId' => Input::old('vendor') ? Input::old('vendor') : $request->vendor_id,
'expense' => null,
'method' => 'POST',
@ -89,7 +87,8 @@ class ExpenseController extends BaseController
'vendor' => $vendor,
'clients' => Client::scope()->with('contacts')->orderBy('name')->get(),
'clientPublicId' => $request->client_id,
);
'categoryPublicId' => $request->category_id,
];
$data = array_merge($data, self::getViewModel());
@ -104,9 +103,9 @@ class ExpenseController extends BaseController
$actions = [];
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 {
$actions[] = ['url' => 'javascript:submitAction("invoice")', 'label' => trans("texts.invoice_expense")];
$actions[] = ['url' => 'javascript:submitAction("invoice")', 'label' => trans('texts.invoice_expense')];
}
$actions[] = \DropdownButton::DIVIDER;
@ -117,7 +116,7 @@ class ExpenseController extends BaseController
$actions[] = ['url' => 'javascript:submitAction("restore")', 'label' => trans('texts.restore_expense')];
}
$data = array(
$data = [
'vendor' => null,
'expense' => $expense,
'method' => 'PUT',
@ -128,7 +127,8 @@ class ExpenseController extends BaseController
'vendorPublicId' => $expense->vendor ? $expense->vendor->public_id : null,
'clients' => Client::scope()->with('contacts')->orderBy('name')->get(),
'clientPublicId' => $expense->client ? $expense->client->public_id : null,
);
'categoryPublicId' => $expense->expense_category ? $expense->expense_category->public_id : null,
];
$data = array_merge($data, self::getViewModel());
@ -237,6 +237,8 @@ class ExpenseController extends BaseController
'countries' => Cache::get('countries'),
'customLabel1' => Auth::user()->account->custom_vendor_label1,
'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\VendorContact;
/**
* Class ExportController
*/
class ExportController extends BaseController
{
/**
* @param Request $request
*
* @return \Illuminate\Http\JsonResponse
*/
public function doExport(Request $request)
{
$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)
{
$output = fopen('php://output', 'w') or Utils::fatalError();
@ -42,16 +56,32 @@ class ExportController extends BaseController
$manager = new Manager();
$manager->setSerializer(new ArraySerializer());
// eager load data, include archived but exclude deleted
$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);
$data = $manager->createData($resource)->toArray();
$data = $manager->parseIncludes('clients.invoices.payments')
->createData($resource)
->toArray();
return response()->json($data);
}
/**
* @param $request
* @param $fileName
*
* @return mixed
*/
private function returnCSV($request, $fileName)
{
$data = $this->getData($request);
@ -63,6 +93,12 @@ class ExportController extends BaseController
})->download('csv');
}
/**
* @param $request
* @param $fileName
*
* @return mixed
*/
private function returnXLS($request, $fileName)
{
$user = Auth::user();
@ -84,13 +120,14 @@ class ExportController extends BaseController
if ($key === 'account' || $key === 'title' || $key === 'multiUser') {
continue;
}
if ($key === 'recurringInvoices') {
$key = 'recurring_invoices';
}
$label = trans("texts.{$key}");
$excel->sheet($label, function($sheet) use ($key, $data) {
if ($key === 'quotes') {
$key = 'invoices';
$data['entityType'] = ENTITY_QUOTE;
} elseif ($key === 'recurringInvoices') {
$key = 'recurring_invoices';
}
$sheet->loadView("export.{$key}", $data);
});
@ -98,6 +135,11 @@ class ExportController extends BaseController
})->download('xls');
}
/**
* @param $request
*
* @return array
*/
private function getData($request)
{
$account = Auth::user()->account;
@ -108,76 +150,79 @@ class ExportController extends BaseController
'multiUser' => $account->users->count() > 1
];
if ($request->input(ENTITY_CLIENT)) {
if ($request->input('include') === 'all' || $request->input('clients')) {
$data['clients'] = Client::scope()
->with('user', 'contacts', 'country')
->withArchived()
->get();
}
if ($request->input('include') === 'all' || $request->input('contacts')) {
$data['contacts'] = Contact::scope()
->with('user', 'client.contacts')
->withTrashed()
->get();
}
if ($request->input('include') === 'all' || $request->input('credits')) {
$data['credits'] = Credit::scope()
->with('user', 'client.contacts')
->get();
}
if ($request->input(ENTITY_TASK)) {
if ($request->input('include') === 'all' || $request->input('tasks')) {
$data['tasks'] = Task::scope()
->with('user', 'client.contacts')
->withArchived()
->get();
}
if ($request->input(ENTITY_INVOICE)) {
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_quote', '=', false)
->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_quote', '=', true)
->where('is_recurring', '=', false)
->get();
}
if ($request->input('include') === 'all' || $request->input('recurring')) {
$data['recurringInvoices'] = Invoice::scope()
->invoiceType(INVOICE_TYPE_STANDARD)
->with('user', 'client.contacts', 'invoice_status', 'frequency')
->withArchived()
->where('is_quote', '=', false)
->where('is_recurring', '=', true)
->get();
}
if ($request->input(ENTITY_PAYMENT)) {
if ($request->input('include') === 'all' || $request->input('payments')) {
$data['payments'] = Payment::scope()
->withArchived()
->with('user', 'client.contacts', 'payment_type', 'invoice', 'account_gateway.gateway')
->get();
}
if ($request->input(ENTITY_VENDOR)) {
$data['clients'] = Vendor::scope()
if ($request->input('include') === 'all' || $request->input('vendors')) {
$data['vendors'] = Vendor::scope()
->with('user', 'vendor_contacts', 'country')
->withArchived()
->get();
}
if ($request->input('include') === 'all' || $request->input('vendor_contacts')) {
$data['vendor_contacts'] = VendorContact::scope()
->with('user', 'vendor.vendor_contacts')
->withTrashed()
->get();
/*
$data['expenses'] = Credit::scope()
->with('user', 'client.contacts')
->get();
*/
}
return $data;

View File

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

View File

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

View File

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

View File

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

View File

@ -8,10 +8,7 @@ use Input;
use Cache;
use Redirect;
use DB;
use Event;
use URL;
use Datatable;
use Request;
use DropdownButton;
use App\Models\Invoice;
use App\Models\Client;
@ -26,8 +23,8 @@ use App\Ninja\Repositories\InvoiceRepository;
use App\Ninja\Repositories\ClientRepository;
use App\Ninja\Repositories\DocumentRepository;
use App\Services\InvoiceService;
use App\Services\PaymentService;
use App\Services\RecurringInvoiceService;
use App\Http\Requests\InvoiceRequest;
use App\Http\Requests\CreateInvoiceRequest;
use App\Http\Requests\UpdateInvoiceRequest;
@ -39,10 +36,11 @@ class InvoiceController extends BaseController
protected $clientRepo;
protected $documentRepo;
protected $invoiceService;
protected $paymentService;
protected $recurringInvoiceService;
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();
@ -51,6 +49,7 @@ class InvoiceController extends BaseController
$this->clientRepo = $clientRepo;
$this->invoiceService = $invoiceService;
$this->recurringInvoiceService = $recurringInvoiceService;
$this->paymentService = $paymentService;
}
public function index()
@ -136,23 +135,23 @@ class InvoiceController extends BaseController
$actions = [
['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
];
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 ($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 {
$actions[] = ['url' => 'javascript:onConvertClick()', 'label' => trans("texts.convert_to_invoice")];
$actions[] = ['url' => 'javascript:onConvertClick()', 'label' => trans('texts.convert_to_invoice')];
}
} elseif ($entityType == ENTITY_INVOICE) {
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) {
@ -160,7 +159,7 @@ class InvoiceController extends BaseController
}
foreach ($invoice->payments as $payment) {
$label = trans("texts.view_payment");
$label = trans('texts.view_payment');
if (count($invoice->payments) > 1) {
$label .= ' - ' . $account->formatMoney($payment->amount, $invoice->client);
}
@ -181,7 +180,7 @@ class InvoiceController extends BaseController
$clients = $clients->where('clients.user_id', '=', Auth::user()->id);
}
$data = array(
$data = [
'clients' => $clients->get(),
'entityType' => $entityType,
'showBreadcrumbs' => $clone,
@ -193,9 +192,13 @@ class InvoiceController extends BaseController
'client' => $invoice->client,
'isRecurring' => $invoice->is_recurring,
'actions' => $actions,
'lastSent' => $lastSent);
'lastSent' => $lastSent];
$data = array_merge($data, self::getViewModel($invoice));
if ($invoice->isSent() && $invoice->getAutoBillEnabled() && !$invoice->isPaid()) {
$data['autoBillChangeWarning'] = $invoice->client->autoBillLater();
}
if ($clone) {
$data['formIsChanged'] = true;
}
@ -242,7 +245,7 @@ class InvoiceController extends BaseController
$invoice->public_id = 0;
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();
}
@ -273,7 +276,7 @@ class InvoiceController extends BaseController
{
$recurringHelp = '';
foreach (preg_split("/((\r?\n)|(\r\n?))/", trans('texts.recurring_help')) as $line) {
$parts = explode("=>", $line);
$parts = explode('=>', $line);
if (count($parts) > 1) {
$line = $parts[0].' => '.Utils::processVariables($parts[0]);
$recurringHelp .= '<li>'.strip_tags($line).'</li>';
@ -284,7 +287,7 @@ class InvoiceController extends BaseController
$recurringDueDateHelp = '';
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) {
$line = $parts[0].' => '.Utils::processVariables($parts[0]);
$recurringDueDateHelp .= '<li>'.strip_tags($line).'</li>';
@ -294,24 +297,24 @@ class InvoiceController extends BaseController
}
// Create due date options
$recurringDueDates = array(
trans('texts.use_client_terms') => array('value' => '', 'class' => 'monthly weekly'),
);
$recurringDueDates = [
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++){
if ($i >= 11 && $i <= 13) $ordinal = $i. 'th';
else $ordinal = $i . $ends[$i % 10];
$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.monday'),
trans('texts.tuesday'),
@ -319,14 +322,14 @@ class InvoiceController extends BaseController
trans('texts.thursday'),
trans('texts.friday'),
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){
$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;
$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'];
}
}
@ -362,21 +365,19 @@ class InvoiceController extends BaseController
'taxRateOptions' => $options,
'defaultTax' => $defaultTax,
'currencies' => Cache::get('currencies'),
'languages' => Cache::get('languages'),
'sizes' => Cache::get('sizes'),
'paymentTerms' => Cache::get('paymentTerms'),
'industries' => Cache::get('industries'),
'invoiceDesigns' => InvoiceDesign::getDesigns(),
'invoiceFonts' => Cache::get('fonts'),
'frequencies' => array(
1 => 'Weekly',
2 => 'Two weeks',
3 => 'Four weeks',
4 => 'Monthly',
5 => 'Three months',
6 => 'Six months',
7 => 'Annually',
),
'frequencies' => [
1 => trans('texts.freq_weekly'),
2 => trans('texts.freq_two_weeks'),
3 => trans('texts.freq_four_weeks'),
4 => trans('texts.freq_monthly'),
5 => trans('texts.freq_three_months'),
6 => trans('texts.freq_six_months'),
7 => trans('texts.freq_annually'),
],
'recurringDueDates' => $recurringDueDates,
'recurringHelp' => $recurringHelp,
'recurringDueDateHelp' => $recurringDueDateHelp,
@ -567,9 +568,9 @@ class InvoiceController extends BaseController
'remove_created_by' => Auth::user()->hasFeature(FEATURE_REMOVE_CREATED_BY),
'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)
->where('activity_type_id', '=', $activityTypeId)
->where('invoice_id', '=', $invoice->id)
@ -589,7 +590,7 @@ class InvoiceController extends BaseController
'remove_created_by' => Auth::user()->hasFeature(FEATURE_REMOVE_CREATED_BY),
'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();
$versionsJson[$activity->id] = $backup;

View File

@ -0,0 +1,267 @@
<?php namespace App\Http\Controllers;
use CreditCard;
use Session;
use Input;
use Utils;
use View;
use Validator;
use URL;
use Cache;
use Omnipay;
use App\Models\Country;
use App\Models\License;
use App\Models\Affiliate;
use App\Ninja\Repositories\AccountRepository;
use App\Ninja\Mailers\ContactMailer;
class NinjaController extends BaseController
{
/**
* @var AccountRepository
*/
protected $accountRepo;
/**
* @var ContactMailer
*/
protected $contactMailer;
/**
* NinjaController constructor.
*
* @param AccountRepository $accountRepo
* @param ContactMailer $contactMailer
*/
public function __construct(AccountRepository $accountRepo, ContactMailer $contactMailer)
{
$this->accountRepo = $accountRepo;
$this->contactMailer = $contactMailer;
}
/**
* @param array $input
* @param Affiliate $affiliate
*
* @return array
*/
private function getLicensePaymentDetails(array $input, Affiliate $affiliate)
{
$country = Country::find($input['country_id']);
$data = [
'firstName' => $input['first_name'],
'lastName' => $input['last_name'],
'email' => $input['email'],
'number' => $input['card_number'],
'expiryMonth' => $input['expiration_month'],
'expiryYear' => $input['expiration_year'],
'cvv' => $input['cvv'],
'billingAddress1' => $input['address1'],
'billingAddress2' => $input['address2'],
'billingCity' => $input['city'],
'billingState' => $input['state'],
'billingPostcode' => $input['postal_code'],
'billingCountry' => $country->iso_3166_2,
'shippingAddress1' => $input['address1'],
'shippingAddress2' => $input['address2'],
'shippingCity' => $input['city'],
'shippingState' => $input['state'],
'shippingPostcode' => $input['postal_code'],
'shippingCountry' => $country->iso_3166_2
];
$card = new CreditCard($data);
return [
'amount' => $affiliate->price,
'card' => $card,
'currency' => 'USD',
'returnUrl' => URL::to('license_complete'),
'cancelUrl' => URL::to('/')
];
}
/**
* @return $this|\Illuminate\Contracts\View\View
*/
public function show_license_payment()
{
if (Input::has('return_url')) {
Session::set('return_url', Input::get('return_url'));
}
if (Input::has('affiliate_key')) {
if ($affiliate = Affiliate::where('affiliate_key', '=', Input::get('affiliate_key'))->first()) {
Session::set('affiliate_id', $affiliate->id);
}
}
if (Input::has('product_id')) {
Session::set('product_id', Input::get('product_id'));
} else if (!Session::has('product_id')) {
Session::set('product_id', PRODUCT_ONE_CLICK_INSTALL);
}
if (!Session::get('affiliate_id')) {
return Utils::fatalError();
}
if (Utils::isNinjaDev() && Input::has('test_mode')) {
Session::set('test_mode', Input::get('test_mode'));
}
$account = $this->accountRepo->getNinjaAccount();
$account->load('account_gateways.gateway');
$accountGateway = $account->getGatewayByType(GATEWAY_TYPE_CREDIT_CARD);
$gateway = $accountGateway->gateway;
$acceptedCreditCardTypes = $accountGateway->getCreditcardTypes();
$affiliate = Affiliate::find(Session::get('affiliate_id'));
$data = [
'showBreadcrumbs' => false,
'hideHeader' => true,
'url' => 'license',
'amount' => $affiliate->price,
'client' => false,
'contact' => false,
'gateway' => $gateway,
'account' => $account,
'accountGateway' => $accountGateway,
'acceptedCreditCardTypes' => $acceptedCreditCardTypes,
'countries' => Cache::get('countries'),
'currencyId' => 1,
'currencyCode' => 'USD',
'paymentTitle' => $affiliate->payment_title,
'paymentSubtitle' => $affiliate->payment_subtitle,
'showAddress' => true,
];
return View::make('payments.stripe.credit_card', $data);
}
/**
* @return \Illuminate\Contracts\View\View
*/
public function do_license_payment()
{
$testMode = Session::get('test_mode') === 'true';
$rules = [
'first_name' => 'required',
'last_name' => 'required',
'email' => 'required',
'card_number' => 'required',
'expiration_month' => 'required',
'expiration_year' => 'required',
'cvv' => 'required',
'address1' => 'required',
'city' => 'required',
'state' => 'required',
'postal_code' => 'required',
'country_id' => 'required',
];
$validator = Validator::make(Input::all(), $rules);
if ($validator->fails()) {
return redirect()->to('license')
->withErrors($validator)
->withInput();
}
$account = $this->accountRepo->getNinjaAccount();
$account->load('account_gateways.gateway');
$accountGateway = $account->getGatewayByType(GATEWAY_TYPE_CREDIT_CARD);
try {
$affiliate = Affiliate::find(Session::get('affiliate_id'));
if ($testMode) {
$ref = 'TEST_MODE';
} else {
$details = self::getLicensePaymentDetails(Input::all(), $affiliate);
$gateway = Omnipay::create($accountGateway->gateway->provider);
$gateway->initialize((array) $accountGateway->getConfig());
$response = $gateway->purchase($details)->send();
$ref = $response->getTransactionReference();
if (!$response->isSuccessful() || !$ref) {
$this->error('License', $response->getMessage(), $accountGateway);
return redirect()->to('license')->withInput();
}
}
$licenseKey = Utils::generateLicense();
$license = new License();
$license->first_name = Input::get('first_name');
$license->last_name = Input::get('last_name');
$license->email = Input::get('email');
$license->transaction_reference = $ref;
$license->license_key = $licenseKey;
$license->affiliate_id = Session::get('affiliate_id');
$license->product_id = Session::get('product_id');
$license->save();
$data = [
'message' => $affiliate->payment_subtitle,
'license' => $licenseKey,
'hideHeader' => true,
'productId' => $license->product_id,
'price' => $affiliate->price,
];
$name = "{$license->first_name} {$license->last_name}";
$this->contactMailer->sendLicensePaymentConfirmation($name, $license->email, $affiliate->price, $license->license_key, $license->product_id);
if (Session::has('return_url')) {
$data['redirectTo'] = Session::get('return_url')."?license_key={$license->license_key}&product_id=".Session::get('product_id');
$data['message'] = 'Redirecting to ' . Session::get('return_url');
}
return View::make('public.license', $data);
} catch (\Exception $e) {
$this->error('License-Uncaught', false, $accountGateway, $e);
return redirect()->to('license')->withInput();
}
}
/**
* @return string
*/
public function claim_license()
{
$licenseKey = Input::get('license_key');
$productId = Input::get('product_id', PRODUCT_ONE_CLICK_INSTALL);
$license = License::where('license_key', '=', $licenseKey)
->where('is_claimed', '<', 10)
->where('product_id', '=', $productId)
->first();
if ($license) {
if ($license->transaction_reference != 'TEST_MODE') {
$license->is_claimed = $license->is_claimed + 1;
$license->save();
}
if ($productId == PRODUCT_INVOICE_DESIGNS) {
return file_get_contents(storage_path() . '/invoice_designs.txt');
} else {
// temporary fix to enable previous version to work
if (Input::get('get_date')) {
return $license->created_at->format('Y-m-d');
} else {
return 'valid';
}
}
} else {
return RESULT_FAILURE;
}
}
}

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