mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-06-23 20:00:33 -04:00
Merge branch 'release-3.2.0'
This commit is contained in:
commit
9fff9fb2af
@ -3,6 +3,7 @@ APP_DEBUG=false
|
|||||||
APP_URL=http://ninja.dev
|
APP_URL=http://ninja.dev
|
||||||
APP_KEY=SomeRandomStringSomeRandomString
|
APP_KEY=SomeRandomStringSomeRandomString
|
||||||
APP_CIPHER=AES-256-CBC
|
APP_CIPHER=AES-256-CBC
|
||||||
|
APP_LOCALE=en
|
||||||
|
|
||||||
DB_TYPE=mysql
|
DB_TYPE=mysql
|
||||||
DB_STRICT=false
|
DB_STRICT=false
|
||||||
@ -90,7 +91,8 @@ WEPAY_ENVIRONMENT=production # production or stage
|
|||||||
WEPAY_AUTO_UPDATE=true # Requires permission from WePay
|
WEPAY_AUTO_UPDATE=true # Requires permission from WePay
|
||||||
WEPAY_ENABLE_CANADA=true
|
WEPAY_ENABLE_CANADA=true
|
||||||
WEPAY_FEE_PAYER=payee
|
WEPAY_FEE_PAYER=payee
|
||||||
WEPAY_APP_FEE_MULTIPLIER=0.002
|
WEPAY_APP_FEE_CC_MULTIPLIER=0
|
||||||
|
WEPAY_APP_FEE_ACH_MULTIPLIER=0
|
||||||
WEPAY_APP_FEE_FIXED=0
|
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
|
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
|
||||||
|
|
||||||
|
14
.travis.yml
14
.travis.yml
@ -50,6 +50,7 @@ before_script:
|
|||||||
- sed -i 's/APP_ENV=production/APP_ENV=development/g' .env
|
- sed -i 's/APP_ENV=production/APP_ENV=development/g' .env
|
||||||
- sed -i 's/APP_DEBUG=false/APP_DEBUG=true/g' .env
|
- sed -i 's/APP_DEBUG=false/APP_DEBUG=true/g' .env
|
||||||
- sed -i 's/MAIL_DRIVER=smtp/MAIL_DRIVER=log/g' .env
|
- sed -i 's/MAIL_DRIVER=smtp/MAIL_DRIVER=log/g' .env
|
||||||
|
- sed -i 's/PHANTOMJS_CLOUD_KEY/#PHANTOMJS_CLOUD_KEY/g' .env
|
||||||
- sed -i '$a NINJA_DEV=true' .env
|
- sed -i '$a NINJA_DEV=true' .env
|
||||||
- sed -i '$a TRAVIS=true' .env
|
- sed -i '$a TRAVIS=true' .env
|
||||||
# create the database and user
|
# create the database and user
|
||||||
@ -58,7 +59,6 @@ before_script:
|
|||||||
# migrate and seed the database
|
# migrate and seed the database
|
||||||
- php artisan migrate --no-interaction
|
- php artisan migrate --no-interaction
|
||||||
- php artisan db:seed --no-interaction # default seed
|
- php artisan db:seed --no-interaction # default seed
|
||||||
- php artisan db:seed --no-interaction --class=UserTableSeeder # development seed
|
|
||||||
# Start webserver on ninja.dev:8000
|
# Start webserver on ninja.dev:8000
|
||||||
- php artisan serve --host=ninja.dev --port=8000 & # '&' allows to run in background
|
- php artisan serve --host=ninja.dev --port=8000 & # '&' allows to run in background
|
||||||
# Start PhantomJS
|
# Start PhantomJS
|
||||||
@ -67,10 +67,10 @@ before_script:
|
|||||||
- sleep 5
|
- sleep 5
|
||||||
# Make sure the app is up-to-date
|
# Make sure the app is up-to-date
|
||||||
- curl -L http://ninja.dev:8000/update
|
- curl -L http://ninja.dev:8000/update
|
||||||
#- php artisan ninja:create-test-data 25
|
- php artisan ninja:create-test-data 4 true
|
||||||
|
- php artisan db:seed --no-interaction --class=UserTableSeeder # development seed
|
||||||
|
|
||||||
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 APICest.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 CheckBalanceCest.php
|
||||||
@ -83,23 +83,29 @@ script:
|
|||||||
- php ./vendor/codeception/codeception/codecept run --debug acceptance OnlinePaymentCest.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 PaymentCest.php
|
||||||
- php ./vendor/codeception/codeception/codecept run --debug acceptance TaskCest.php
|
- php ./vendor/codeception/codeception/codecept run --debug acceptance TaskCest.php
|
||||||
|
- php ./vendor/codeception/codeception/codecept run --debug acceptance GatewayFeesCest.php
|
||||||
|
- php ./vendor/codeception/codeception/codecept run --debug acceptance AllPagesCept.php
|
||||||
|
|
||||||
#- sed -i 's/NINJA_DEV=true/NINJA_PROD=true/g' .env
|
#- sed -i 's/NINJA_DEV=true/NINJA_PROD=true/g' .env
|
||||||
#- php ./vendor/codeception/codeception/codecept run acceptance GoProCest.php
|
#- php ./vendor/codeception/codeception/codecept run acceptance GoProCest.php
|
||||||
|
|
||||||
after_script:
|
after_script:
|
||||||
|
- php artisan ninja:check-data --no-interaction
|
||||||
- cat .env
|
- cat .env
|
||||||
- mysql -u root -e 'select * from accounts;' ninja
|
- mysql -u root -e 'select * from accounts;' ninja
|
||||||
|
- mysql -u root -e 'select * from users;' ninja
|
||||||
- mysql -u root -e 'select * from account_gateways;' ninja
|
- mysql -u root -e 'select * from account_gateways;' ninja
|
||||||
- mysql -u root -e 'select * from clients;' ninja
|
- mysql -u root -e 'select * from clients;' ninja
|
||||||
|
- mysql -u root -e 'select * from contacts;' ninja
|
||||||
- mysql -u root -e 'select * from invoices;' ninja
|
- mysql -u root -e 'select * from invoices;' ninja
|
||||||
- mysql -u root -e 'select * from invoice_items;' ninja
|
- mysql -u root -e 'select * from invoice_items;' ninja
|
||||||
|
- mysql -u root -e 'select * from invitations;' ninja
|
||||||
- mysql -u root -e 'select * from payments;' ninja
|
- mysql -u root -e 'select * from payments;' ninja
|
||||||
- mysql -u root -e 'select * from credits;' ninja
|
- mysql -u root -e 'select * from credits;' ninja
|
||||||
- mysql -u root -e 'select * from expenses;' ninja
|
- mysql -u root -e 'select * from expenses;' ninja
|
||||||
- cat storage/logs/laravel-error.log
|
- cat storage/logs/laravel-error.log
|
||||||
- cat storage/logs/laravel-info.log
|
- cat storage/logs/laravel-info.log
|
||||||
- FILES=$(find tests/_output -type f -name '*.png')
|
- FILES=$(find tests/_output -type f -name '*.png' | sort -nr)
|
||||||
- for i in $FILES; do echo $i; base64 "$i"; break; done
|
- for i in $FILES; do echo $i; base64 "$i"; break; done
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
|
@ -4,6 +4,8 @@ Thanks for your contributions!
|
|||||||
|
|
||||||
## Submit bug reports or feature requests
|
## Submit bug reports or feature requests
|
||||||
|
|
||||||
|
Please discuss the changes with us ahead of time to ensure they will be merged.
|
||||||
|
|
||||||
### Submit pull requests
|
### Submit pull requests
|
||||||
* [Fork](https://github.com/invoiceninja/invoiceninja#fork-destination-box) the [Invoice Ninja repository](https://github.com/invoiceninja/invoiceninja)
|
* [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`
|
* Create a new branch with the name `#issue_number-Short-description`
|
||||||
@ -11,7 +13,7 @@ Thanks for your contributions!
|
|||||||
* Make your changes and commit
|
* Make your changes and commit
|
||||||
* Check if your branch is still in sync with the repositorys **`develop`** branch
|
* 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/)
|
* _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)
|
* _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
|
* Push your branch and create a PR against the Invoice Ninja **`develop`** branch
|
||||||
* Update the [Changelog](CHANGELOG.md)
|
* Update the [Changelog](CHANGELOG.md)
|
||||||
|
|
||||||
@ -21,7 +23,7 @@ To make the contribution process nice and easy for anyone, please follow some ru
|
|||||||
to give a more detailed explanation.
|
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 issue. If you want to submit more, create multiple issues.
|
||||||
* Only one feature/bugfix per PR(pull request). Split more changes into multiple PRs.
|
* Only one feature/bugfix per PR(pull request). Split more changes into multiple PRs.
|
||||||
|
|
||||||
#### Coding Style
|
#### 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)
|
Try to follow the [PSR-2 guidlines](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)
|
||||||
|
|
||||||
@ -29,7 +31,7 @@ _Example styling:_
|
|||||||
```php
|
```php
|
||||||
/**
|
/**
|
||||||
* Gets a preview of the email
|
* Gets a preview of the email
|
||||||
*
|
*
|
||||||
* @param TemplateService $templateService
|
* @param TemplateService $templateService
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\Response
|
||||||
|
@ -4,6 +4,7 @@ namespace App\Console\Commands;
|
|||||||
|
|
||||||
use Carbon;
|
use Carbon;
|
||||||
use DB;
|
use DB;
|
||||||
|
use Exception;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use Mail;
|
use Mail;
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
@ -83,6 +84,8 @@ class CheckData extends Command
|
|||||||
->from(CONTACT_EMAIL)
|
->from(CONTACT_EMAIL)
|
||||||
->subject('Check-Data: ' . strtoupper($this->isValid ? RESULT_SUCCESS : RESULT_FAILURE));
|
->subject('Check-Data: ' . strtoupper($this->isValid ? RESULT_SUCCESS : RESULT_FAILURE));
|
||||||
});
|
});
|
||||||
|
} elseif (! $this->isValid) {
|
||||||
|
throw new Exception('Check data failed!!');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,9 +160,15 @@ class CheckData extends Command
|
|||||||
'products' => [
|
'products' => [
|
||||||
ENTITY_USER,
|
ENTITY_USER,
|
||||||
],
|
],
|
||||||
|
'vendors' => [
|
||||||
|
ENTITY_USER,
|
||||||
|
],
|
||||||
'expense_categories' => [
|
'expense_categories' => [
|
||||||
ENTITY_USER,
|
ENTITY_USER,
|
||||||
],
|
],
|
||||||
|
'payment_terms' => [
|
||||||
|
ENTITY_USER,
|
||||||
|
],
|
||||||
'projects' => [
|
'projects' => [
|
||||||
ENTITY_USER,
|
ENTITY_USER,
|
||||||
ENTITY_CLIENT,
|
ENTITY_CLIENT,
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Ninja\Repositories\AccountRepository;
|
||||||
use App\Ninja\Repositories\ClientRepository;
|
use App\Ninja\Repositories\ClientRepository;
|
||||||
use App\Ninja\Repositories\ExpenseRepository;
|
use App\Ninja\Repositories\ExpenseRepository;
|
||||||
use App\Ninja\Repositories\InvoiceRepository;
|
use App\Ninja\Repositories\InvoiceRepository;
|
||||||
@ -25,7 +26,7 @@ class CreateTestData extends Command
|
|||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $signature = 'ninja:create-test-data {count=1}';
|
protected $signature = 'ninja:create-test-data {count=1} {create_account=false}';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var
|
* @var
|
||||||
@ -40,13 +41,15 @@ class CreateTestData extends Command
|
|||||||
* @param PaymentRepository $paymentRepo
|
* @param PaymentRepository $paymentRepo
|
||||||
* @param VendorRepository $vendorRepo
|
* @param VendorRepository $vendorRepo
|
||||||
* @param ExpenseRepository $expenseRepo
|
* @param ExpenseRepository $expenseRepo
|
||||||
|
* @param AccountRepository $accountRepo
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
ClientRepository $clientRepo,
|
ClientRepository $clientRepo,
|
||||||
InvoiceRepository $invoiceRepo,
|
InvoiceRepository $invoiceRepo,
|
||||||
PaymentRepository $paymentRepo,
|
PaymentRepository $paymentRepo,
|
||||||
VendorRepository $vendorRepo,
|
VendorRepository $vendorRepo,
|
||||||
ExpenseRepository $expenseRepo)
|
ExpenseRepository $expenseRepo,
|
||||||
|
AccountRepository $accountRepo)
|
||||||
{
|
{
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
|
|
||||||
@ -57,6 +60,7 @@ class CreateTestData extends Command
|
|||||||
$this->paymentRepo = $paymentRepo;
|
$this->paymentRepo = $paymentRepo;
|
||||||
$this->vendorRepo = $vendorRepo;
|
$this->vendorRepo = $vendorRepo;
|
||||||
$this->expenseRepo = $expenseRepo;
|
$this->expenseRepo = $expenseRepo;
|
||||||
|
$this->accountRepo = $accountRepo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -69,10 +73,21 @@ class CreateTestData extends Command
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->info(date('Y-m-d').' Running CreateTestData...');
|
$this->info(date('Y-m-d').' Running CreateTestData...');
|
||||||
|
|
||||||
Auth::loginUsingId(1);
|
|
||||||
$this->count = $this->argument('count');
|
$this->count = $this->argument('count');
|
||||||
|
|
||||||
|
if (filter_var($this->argument('create_account'), FILTER_VALIDATE_BOOLEAN)) {
|
||||||
|
$this->info('Creating new account...');
|
||||||
|
$account = $this->accountRepo->create(
|
||||||
|
$this->faker->firstName,
|
||||||
|
$this->faker->lastName,
|
||||||
|
$this->faker->safeEmail
|
||||||
|
);
|
||||||
|
Auth::login($account->users[0]);
|
||||||
|
} else {
|
||||||
|
$this->info('Using first account...');
|
||||||
|
Auth::loginUsingId(1);
|
||||||
|
}
|
||||||
|
|
||||||
$this->createClients();
|
$this->createClients();
|
||||||
$this->createVendors();
|
$this->createVendors();
|
||||||
|
|
||||||
@ -182,7 +197,7 @@ class CreateTestData extends Command
|
|||||||
'vendor_id' => $vendor->id,
|
'vendor_id' => $vendor->id,
|
||||||
'amount' => $this->faker->randomFloat(2, 1, 10),
|
'amount' => $this->faker->randomFloat(2, 1, 10),
|
||||||
'expense_date' => null,
|
'expense_date' => null,
|
||||||
'public_notes' => null,
|
'public_notes' => '',
|
||||||
];
|
];
|
||||||
|
|
||||||
$expense = $this->expenseRepo->save($data);
|
$expense = $this->expenseRepo->save($data);
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Models\Account;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
use App\Ninja\Mailers\ContactMailer as Mailer;
|
use App\Ninja\Mailers\ContactMailer as Mailer;
|
||||||
use App\Ninja\Repositories\InvoiceRepository;
|
use App\Ninja\Repositories\InvoiceRepository;
|
||||||
@ -57,9 +58,18 @@ class SendRecurringInvoices extends Command
|
|||||||
|
|
||||||
public function fire()
|
public function fire()
|
||||||
{
|
{
|
||||||
$this->info(date('Y-m-d').' Running SendRecurringInvoices...');
|
$this->info(date('Y-m-d H:i:s') . ' Running SendRecurringInvoices...');
|
||||||
$today = new DateTime();
|
$today = new DateTime();
|
||||||
|
|
||||||
|
// check for counter resets
|
||||||
|
$accounts = Account::where('reset_counter_frequency_id', '>', 0)
|
||||||
|
->orderBy('id', 'asc')
|
||||||
|
->get();
|
||||||
|
|
||||||
|
foreach ($accounts as $account) {
|
||||||
|
$account->checkCounterReset();
|
||||||
|
}
|
||||||
|
|
||||||
$invoices = Invoice::with('account.timezone', 'invoice_items', 'client', 'user')
|
$invoices = Invoice::with('account.timezone', 'invoice_items', 'client', 'user')
|
||||||
->whereRaw('is_deleted IS FALSE AND deleted_at IS NULL AND is_recurring IS TRUE AND is_public IS TRUE AND frequency_id > 0 AND start_date <= ? AND (end_date IS NULL OR end_date >= ?)', [$today, $today])
|
->whereRaw('is_deleted IS FALSE AND deleted_at IS NULL AND is_recurring IS TRUE AND is_public IS TRUE AND frequency_id > 0 AND start_date <= ? AND (end_date IS NULL OR end_date >= ?)', [$today, $today])
|
||||||
->orderBy('id', 'asc')
|
->orderBy('id', 'asc')
|
||||||
@ -74,7 +84,8 @@ class SendRecurringInvoices extends Command
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$recurInvoice->account->loadLocalizationSettings($recurInvoice->client);
|
$account = $recurInvoice->account;
|
||||||
|
$account->loadLocalizationSettings($recurInvoice->client);
|
||||||
$invoice = $this->invoiceRepo->createRecurringInvoice($recurInvoice);
|
$invoice = $this->invoiceRepo->createRecurringInvoice($recurInvoice);
|
||||||
|
|
||||||
if ($invoice && ! $invoice->isPaid()) {
|
if ($invoice && ! $invoice->isPaid()) {
|
||||||
@ -103,7 +114,7 @@ class SendRecurringInvoices extends Command
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->info('Done');
|
$this->info(date('Y-m-d H:i:s') . ' Done');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,11 +23,12 @@ class $STUDLY_NAME$ApiController extends BaseAPIController
|
|||||||
/**
|
/**
|
||||||
* @SWG\Get(
|
* @SWG\Get(
|
||||||
* path="/$LOWER_NAME$",
|
* path="/$LOWER_NAME$",
|
||||||
* summary="List of $LOWER_NAME$",
|
* summary="List $LOWER_NAME$",
|
||||||
|
* operationId="list$STUDLY_NAME$s",
|
||||||
* tags={"$LOWER_NAME$"},
|
* tags={"$LOWER_NAME$"},
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
* response=200,
|
* response=200,
|
||||||
* description="A list with $LOWER_NAME$",
|
* description="A list of $LOWER_NAME$",
|
||||||
* @SWG\Schema(type="array", @SWG\Items(ref="#/definitions/$STUDLY_NAME$"))
|
* @SWG\Schema(type="array", @SWG\Items(ref="#/definitions/$STUDLY_NAME$"))
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
@ -47,7 +48,14 @@ class $STUDLY_NAME$ApiController extends BaseAPIController
|
|||||||
* @SWG\Get(
|
* @SWG\Get(
|
||||||
* path="/$LOWER_NAME$/{$LOWER_NAME$_id}",
|
* path="/$LOWER_NAME$/{$LOWER_NAME$_id}",
|
||||||
* summary="Individual $STUDLY_NAME$",
|
* summary="Individual $STUDLY_NAME$",
|
||||||
|
* operationId="get$STUDLY_NAME$",
|
||||||
* tags={"$LOWER_NAME$"},
|
* tags={"$LOWER_NAME$"},
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="path",
|
||||||
|
* name="$LOWER_NAME$_id",
|
||||||
|
* type="integer",
|
||||||
|
* required=true
|
||||||
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
* response=200,
|
* response=200,
|
||||||
* description="A single $LOWER_NAME$",
|
* description="A single $LOWER_NAME$",
|
||||||
@ -59,7 +67,6 @@ class $STUDLY_NAME$ApiController extends BaseAPIController
|
|||||||
* )
|
* )
|
||||||
* )
|
* )
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public function show($STUDLY_NAME$Request $request)
|
public function show($STUDLY_NAME$Request $request)
|
||||||
{
|
{
|
||||||
return $this->itemResponse($request->entity());
|
return $this->itemResponse($request->entity());
|
||||||
@ -71,11 +78,12 @@ class $STUDLY_NAME$ApiController extends BaseAPIController
|
|||||||
/**
|
/**
|
||||||
* @SWG\Post(
|
* @SWG\Post(
|
||||||
* path="/$LOWER_NAME$",
|
* path="/$LOWER_NAME$",
|
||||||
* tags={"$LOWER_NAME$"},
|
|
||||||
* summary="Create a $LOWER_NAME$",
|
* summary="Create a $LOWER_NAME$",
|
||||||
|
* operationId="create$STUDLY_NAME$",
|
||||||
|
* tags={"$LOWER_NAME$"},
|
||||||
* @SWG\Parameter(
|
* @SWG\Parameter(
|
||||||
* in="body",
|
* in="body",
|
||||||
* name="body",
|
* name="$LOWER_NAME$",
|
||||||
* @SWG\Schema(ref="#/definitions/$STUDLY_NAME$")
|
* @SWG\Schema(ref="#/definitions/$STUDLY_NAME$")
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
@ -99,16 +107,23 @@ class $STUDLY_NAME$ApiController extends BaseAPIController
|
|||||||
/**
|
/**
|
||||||
* @SWG\Put(
|
* @SWG\Put(
|
||||||
* path="/$LOWER_NAME$/{$LOWER_NAME$_id}",
|
* path="/$LOWER_NAME$/{$LOWER_NAME$_id}",
|
||||||
* tags={"$LOWER_NAME$"},
|
|
||||||
* summary="Update a $LOWER_NAME$",
|
* summary="Update a $LOWER_NAME$",
|
||||||
|
* operationId="update$STUDLY_NAME$",
|
||||||
|
* tags={"$LOWER_NAME$"},
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="path",
|
||||||
|
* name="$LOWER_NAME$_id",
|
||||||
|
* type="integer",
|
||||||
|
* required=true
|
||||||
|
* ),
|
||||||
* @SWG\Parameter(
|
* @SWG\Parameter(
|
||||||
* in="body",
|
* in="body",
|
||||||
* name="body",
|
* name="$LOWER_NAME$",
|
||||||
* @SWG\Schema(ref="#/definitions/$STUDLY_NAME$")
|
* @SWG\Schema(ref="#/definitions/$STUDLY_NAME$")
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
* response=200,
|
* response=200,
|
||||||
* description="Update $LOWER_NAME$",
|
* description="Updated $LOWER_NAME$",
|
||||||
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/$STUDLY_NAME$"))
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/$STUDLY_NAME$"))
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
@ -117,7 +132,6 @@ class $STUDLY_NAME$ApiController extends BaseAPIController
|
|||||||
* )
|
* )
|
||||||
* )
|
* )
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public function update(Update$STUDLY_NAME$Request $request, $publicId)
|
public function update(Update$STUDLY_NAME$Request $request, $publicId)
|
||||||
{
|
{
|
||||||
if ($request->action) {
|
if ($request->action) {
|
||||||
@ -133,16 +147,18 @@ class $STUDLY_NAME$ApiController extends BaseAPIController
|
|||||||
/**
|
/**
|
||||||
* @SWG\Delete(
|
* @SWG\Delete(
|
||||||
* path="/$LOWER_NAME$/{$LOWER_NAME$_id}",
|
* path="/$LOWER_NAME$/{$LOWER_NAME$_id}",
|
||||||
* tags={"$LOWER_NAME$"},
|
|
||||||
* summary="Delete a $LOWER_NAME$",
|
* summary="Delete a $LOWER_NAME$",
|
||||||
|
* operationId="delete$STUDLY_NAME$",
|
||||||
|
* tags={"$LOWER_NAME$"},
|
||||||
* @SWG\Parameter(
|
* @SWG\Parameter(
|
||||||
* in="body",
|
* in="path",
|
||||||
* name="body",
|
* name="$LOWER_NAME$_id",
|
||||||
* @SWG\Schema(ref="#/definitions/$STUDLY_NAME$")
|
* type="integer",
|
||||||
|
* required=true
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
* response=200,
|
* response=200,
|
||||||
* description="Delete $LOWER_NAME$",
|
* description="Deleted $LOWER_NAME$",
|
||||||
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/$STUDLY_NAME$"))
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/$STUDLY_NAME$"))
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
@ -151,7 +167,6 @@ class $STUDLY_NAME$ApiController extends BaseAPIController
|
|||||||
* )
|
* )
|
||||||
* )
|
* )
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public function destroy(Update$STUDLY_NAME$Request $request)
|
public function destroy(Update$STUDLY_NAME$Request $request)
|
||||||
{
|
{
|
||||||
$$LOWER_NAME$ = $request->entity();
|
$$LOWER_NAME$ = $request->entity();
|
||||||
|
@ -15,8 +15,8 @@ class $STUDLY_NAME$Transformer extends EntityTransformer
|
|||||||
* @SWG\Property(property="id", type="integer", example=1, readOnly=true)
|
* @SWG\Property(property="id", type="integer", example=1, readOnly=true)
|
||||||
* @SWG\Property(property="user_id", type="integer", example=1)
|
* @SWG\Property(property="user_id", type="integer", example=1)
|
||||||
* @SWG\Property(property="account_key", type="string", example="123456")
|
* @SWG\Property(property="account_key", type="string", example="123456")
|
||||||
* @SWG\Property(property="updated_at", type="timestamp", example="")
|
* @SWG\Property(property="updated_at", type="integer", example=1451160233, readOnly=true)
|
||||||
* @SWG\Property(property="archived_at", type="timestamp", example="1451160233")
|
* @SWG\Property(property="archived_at", type="integer", example=1451160233, readOnly=true)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -41,6 +41,11 @@ if (! defined('APP_NAME')) {
|
|||||||
define('INVOICE_TYPE_STANDARD', 1);
|
define('INVOICE_TYPE_STANDARD', 1);
|
||||||
define('INVOICE_TYPE_QUOTE', 2);
|
define('INVOICE_TYPE_QUOTE', 2);
|
||||||
|
|
||||||
|
define('INVOICE_ITEM_TYPE_STANDARD', 1);
|
||||||
|
define('INVOICE_ITEM_TYPE_TASK', 2);
|
||||||
|
define('INVOICE_ITEM_TYPE_PENDING_GATEWAY_FEE', 3);
|
||||||
|
define('INVOICE_ITEM_TYPE_PAID_GATEWAY_FEE', 4);
|
||||||
|
|
||||||
define('PERSON_CONTACT', 'contact');
|
define('PERSON_CONTACT', 'contact');
|
||||||
define('PERSON_USER', 'user');
|
define('PERSON_USER', 'user');
|
||||||
define('PERSON_VENDOR_CONTACT', 'vendorcontact');
|
define('PERSON_VENDOR_CONTACT', 'vendorcontact');
|
||||||
@ -283,7 +288,6 @@ if (! defined('APP_NAME')) {
|
|||||||
|
|
||||||
define('REQUESTED_PRO_PLAN', 'REQUESTED_PRO_PLAN');
|
define('REQUESTED_PRO_PLAN', 'REQUESTED_PRO_PLAN');
|
||||||
define('DEMO_ACCOUNT_ID', 'DEMO_ACCOUNT_ID');
|
define('DEMO_ACCOUNT_ID', 'DEMO_ACCOUNT_ID');
|
||||||
define('PREV_USER_ID', 'PREV_USER_ID');
|
|
||||||
define('NINJA_ACCOUNT_KEY', 'zg4ylmzDkdkPOT8yoKQw9LTWaoZJx79h');
|
define('NINJA_ACCOUNT_KEY', 'zg4ylmzDkdkPOT8yoKQw9LTWaoZJx79h');
|
||||||
define('NINJA_LICENSE_ACCOUNT_KEY', 'AsFmBAeLXF0IKf7tmi0eiyZfmWW9hxMT');
|
define('NINJA_LICENSE_ACCOUNT_KEY', 'AsFmBAeLXF0IKf7tmi0eiyZfmWW9hxMT');
|
||||||
define('NINJA_GATEWAY_ID', GATEWAY_STRIPE);
|
define('NINJA_GATEWAY_ID', GATEWAY_STRIPE);
|
||||||
@ -292,7 +296,7 @@ if (! defined('APP_NAME')) {
|
|||||||
define('NINJA_APP_URL', env('NINJA_APP_URL', 'https://app.invoiceninja.com'));
|
define('NINJA_APP_URL', env('NINJA_APP_URL', 'https://app.invoiceninja.com'));
|
||||||
define('NINJA_DOCS_URL', env('NINJA_DOCS_URL', 'http://docs.invoiceninja.com/en/latest'));
|
define('NINJA_DOCS_URL', env('NINJA_DOCS_URL', 'http://docs.invoiceninja.com/en/latest'));
|
||||||
define('NINJA_DATE', '2000-01-01');
|
define('NINJA_DATE', '2000-01-01');
|
||||||
define('NINJA_VERSION', '3.1.3' . env('NINJA_VERSION_SUFFIX'));
|
define('NINJA_VERSION', '3.2.0' . env('NINJA_VERSION_SUFFIX'));
|
||||||
|
|
||||||
define('SOCIAL_LINK_FACEBOOK', env('SOCIAL_LINK_FACEBOOK', 'https://www.facebook.com/invoiceninja'));
|
define('SOCIAL_LINK_FACEBOOK', env('SOCIAL_LINK_FACEBOOK', 'https://www.facebook.com/invoiceninja'));
|
||||||
define('SOCIAL_LINK_TWITTER', env('SOCIAL_LINK_TWITTER', 'https://twitter.com/invoiceninja'));
|
define('SOCIAL_LINK_TWITTER', env('SOCIAL_LINK_TWITTER', 'https://twitter.com/invoiceninja'));
|
||||||
|
@ -10,6 +10,7 @@ use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
|||||||
use Illuminate\Foundation\Validation\ValidationException;
|
use Illuminate\Foundation\Validation\ValidationException;
|
||||||
use Illuminate\Http\Exception\HttpResponseException;
|
use Illuminate\Http\Exception\HttpResponseException;
|
||||||
use Illuminate\Support\Facades\Response;
|
use Illuminate\Support\Facades\Response;
|
||||||
|
use Illuminate\Session\TokenMismatchException;
|
||||||
use Redirect;
|
use Redirect;
|
||||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||||
@ -26,10 +27,11 @@ class Handler extends ExceptionHandler
|
|||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $dontReport = [
|
protected $dontReport = [
|
||||||
AuthorizationException::class,
|
TokenMismatchException::class,
|
||||||
HttpException::class,
|
|
||||||
ModelNotFoundException::class,
|
ModelNotFoundException::class,
|
||||||
ValidationException::class,
|
//AuthorizationException::class,
|
||||||
|
//HttpException::class,
|
||||||
|
//ValidationException::class,
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -43,11 +45,20 @@ class Handler extends ExceptionHandler
|
|||||||
*/
|
*/
|
||||||
public function report(Exception $e)
|
public function report(Exception $e)
|
||||||
{
|
{
|
||||||
|
if (! $this->shouldReport($e)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// don't show these errors in the logs
|
// don't show these errors in the logs
|
||||||
if ($e instanceof NotFoundHttpException) {
|
if ($e instanceof NotFoundHttpException) {
|
||||||
if (Crawler::isCrawler()) {
|
if (Crawler::isCrawler()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
// The logo can take a few seconds to get synced between servers
|
||||||
|
// TODO: remove once we're using cloud storage for logos
|
||||||
|
if (Utils::isNinja() && strpos(request()->url(), '/logo/') !== false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} elseif ($e instanceof HttpResponseException) {
|
} elseif ($e instanceof HttpResponseException) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -74,9 +85,9 @@ class Handler extends ExceptionHandler
|
|||||||
if ($e instanceof ModelNotFoundException) {
|
if ($e instanceof ModelNotFoundException) {
|
||||||
return Redirect::to('/');
|
return Redirect::to('/');
|
||||||
}
|
}
|
||||||
if ($e instanceof \Illuminate\Session\TokenMismatchException) {
|
|
||||||
// prevent loop since the page auto-submits
|
if ($e instanceof TokenMismatchException) {
|
||||||
if ($request->path() != 'get_started') {
|
if (! in_array($request->path(), ['get_started', 'save_sidebar_state'])) {
|
||||||
// https://gist.github.com/jrmadsen67/bd0f9ad0ef1ed6bb594e
|
// https://gist.github.com/jrmadsen67/bd0f9ad0ef1ed6bb594e
|
||||||
return redirect()
|
return redirect()
|
||||||
->back()
|
->back()
|
||||||
|
@ -6,6 +6,7 @@ use App\Events\UserSignedUp;
|
|||||||
use App\Http\Requests\RegisterRequest;
|
use App\Http\Requests\RegisterRequest;
|
||||||
use App\Http\Requests\UpdateAccountRequest;
|
use App\Http\Requests\UpdateAccountRequest;
|
||||||
use App\Models\Account;
|
use App\Models\Account;
|
||||||
|
use App\Ninja\OAuth\OAuth;
|
||||||
use App\Ninja\Repositories\AccountRepository;
|
use App\Ninja\Repositories\AccountRepository;
|
||||||
use App\Ninja\Transformers\AccountTransformer;
|
use App\Ninja\Transformers\AccountTransformer;
|
||||||
use App\Ninja\Transformers\UserAccountTransformer;
|
use App\Ninja\Transformers\UserAccountTransformer;
|
||||||
@ -121,6 +122,7 @@ class AccountApiController extends BaseAPIController
|
|||||||
for ($x = 0; $x < count($devices); $x++) {
|
for ($x = 0; $x < count($devices); $x++) {
|
||||||
if ($devices[$x]['email'] == Auth::user()->username) {
|
if ($devices[$x]['email'] == Auth::user()->username) {
|
||||||
$devices[$x]['token'] = $request->token; //update
|
$devices[$x]['token'] = $request->token; //update
|
||||||
|
$devices[$x]['device'] = $request->device;
|
||||||
$account->devices = json_encode($devices);
|
$account->devices = json_encode($devices);
|
||||||
$account->save();
|
$account->save();
|
||||||
$devices[$x]['account_key'] = $account->account_key;
|
$devices[$x]['account_key'] = $account->account_key;
|
||||||
@ -187,25 +189,15 @@ class AccountApiController extends BaseAPIController
|
|||||||
$token = $request->input('token');
|
$token = $request->input('token');
|
||||||
$provider = $request->input('provider');
|
$provider = $request->input('provider');
|
||||||
|
|
||||||
try {
|
$oAuth = new OAuth();
|
||||||
$user = Socialite::driver($provider)->stateless()->userFromToken($token);
|
$user = $oAuth->getProvider($provider)->getTokenResponse($token);
|
||||||
} catch (Exception $exception) {
|
|
||||||
return $this->errorResponse(['message' => $exception->getMessage()], 401);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($user) {
|
if($user) {
|
||||||
$providerId = AuthService::getProviderId($provider);
|
|
||||||
$user = $this->accountRepo->findUserByOauth($providerId, $user->id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($user) {
|
|
||||||
Auth::login($user);
|
Auth::login($user);
|
||||||
|
|
||||||
return $this->processLogin($request);
|
return $this->processLogin($request);
|
||||||
} else {
|
|
||||||
sleep(ERROR_DELAY);
|
|
||||||
|
|
||||||
return $this->errorResponse(['message' => 'Invalid credentials'], 401);
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
return $this->errorResponse(['message' => 'Invalid credentials'], 401);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,6 @@ use App\Http\Requests\SaveEmailSettings;
|
|||||||
use App\Http\Requests\UpdateAccountRequest;
|
use App\Http\Requests\UpdateAccountRequest;
|
||||||
use App\Models\Account;
|
use App\Models\Account;
|
||||||
use App\Models\AccountGateway;
|
use App\Models\AccountGateway;
|
||||||
use App\Models\AccountGatewaySettings;
|
|
||||||
use App\Models\Affiliate;
|
use App\Models\Affiliate;
|
||||||
use App\Models\Document;
|
use App\Models\Document;
|
||||||
use App\Models\Gateway;
|
use App\Models\Gateway;
|
||||||
@ -38,6 +37,7 @@ use Request;
|
|||||||
use Response;
|
use Response;
|
||||||
use Session;
|
use Session;
|
||||||
use stdClass;
|
use stdClass;
|
||||||
|
use Exception;
|
||||||
use URL;
|
use URL;
|
||||||
use Utils;
|
use Utils;
|
||||||
|
|
||||||
@ -123,17 +123,16 @@ class AccountController extends BaseController
|
|||||||
{
|
{
|
||||||
$user = false;
|
$user = false;
|
||||||
$guestKey = Input::get('guest_key'); // local storage key to login until registered
|
$guestKey = Input::get('guest_key'); // local storage key to login until registered
|
||||||
$prevUserId = Session::pull(PREV_USER_ID); // last user id used to link to new account
|
|
||||||
|
|
||||||
if (Auth::check()) {
|
if (Auth::check()) {
|
||||||
return Redirect::to('invoices/create');
|
return Redirect::to('invoices/create');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! Utils::isNinja() && (Account::count() > 0 && ! $prevUserId)) {
|
if (! Utils::isNinja() && Account::count() > 0) {
|
||||||
return Redirect::to('/login');
|
return Redirect::to('/login');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($guestKey && ! $prevUserId) {
|
if ($guestKey) {
|
||||||
$user = User::where('password', '=', $guestKey)->first();
|
$user = User::where('password', '=', $guestKey)->first();
|
||||||
|
|
||||||
if ($user && $user->registered) {
|
if ($user && $user->registered) {
|
||||||
@ -144,11 +143,6 @@ class AccountController extends BaseController
|
|||||||
if (! $user) {
|
if (! $user) {
|
||||||
$account = $this->accountRepo->create();
|
$account = $this->accountRepo->create();
|
||||||
$user = $account->users()->first();
|
$user = $account->users()->first();
|
||||||
|
|
||||||
if ($prevUserId) {
|
|
||||||
$users = $this->accountRepo->associateAccounts($user->id, $prevUserId);
|
|
||||||
Session::put(SESSION_USER_ACCOUNTS, $users);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Auth::login($user, true);
|
Auth::login($user, true);
|
||||||
@ -186,22 +180,8 @@ class AccountController extends BaseController
|
|||||||
$newPlan['price'] = Utils::getPlanPrice($newPlan);
|
$newPlan['price'] = Utils::getPlanPrice($newPlan);
|
||||||
$credit = 0;
|
$credit = 0;
|
||||||
|
|
||||||
if (! empty($planDetails['started']) && $plan == PLAN_FREE) {
|
if ($plan == PLAN_FREE && $company->processRefund(Auth::user())) {
|
||||||
// Downgrade
|
Session::flash('warning', trans('texts.plan_refunded'));
|
||||||
$refund_deadline = clone $planDetails['started'];
|
|
||||||
$refund_deadline->modify('+30 days');
|
|
||||||
|
|
||||||
if ($plan == PLAN_FREE && $refund_deadline >= date_create()) {
|
|
||||||
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} - Deadline: {$refund_deadline->format('Y-m-d')}");
|
|
||||||
} else {
|
|
||||||
Session::flash('message', trans('texts.updated_plan'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$hasPaid = false;
|
$hasPaid = false;
|
||||||
@ -241,6 +221,8 @@ class AccountController extends BaseController
|
|||||||
$company->plan = $plan;
|
$company->plan = $plan;
|
||||||
$company->save();
|
$company->save();
|
||||||
|
|
||||||
|
Session::flash('message', trans('texts.updated_plan'));
|
||||||
|
|
||||||
return Redirect::to('settings/account_management');
|
return Redirect::to('settings/account_management');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -488,23 +470,19 @@ class AccountController extends BaseController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($trashedCount == 0) {
|
$tokenBillingOptions = [];
|
||||||
return Redirect::to('gateways/create');
|
for ($i = 1; $i <= 4; $i++) {
|
||||||
} else {
|
$tokenBillingOptions[$i] = trans("texts.token_billing_{$i}");
|
||||||
$tokenBillingOptions = [];
|
|
||||||
for ($i = 1; $i <= 4; $i++) {
|
|
||||||
$tokenBillingOptions[$i] = trans("texts.token_billing_{$i}");
|
|
||||||
}
|
|
||||||
|
|
||||||
return View::make('accounts.payments', [
|
|
||||||
'showAdd' => $count < count(Gateway::$alternate) + 1,
|
|
||||||
'title' => trans('texts.online_payments'),
|
|
||||||
'tokenBillingOptions' => $tokenBillingOptions,
|
|
||||||
'currency' => Utils::getFromCache(Session::get(SESSION_CURRENCY, DEFAULT_CURRENCY),
|
|
||||||
'currencies'),
|
|
||||||
'account' => $account,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return View::make('accounts.payments', [
|
||||||
|
'showAdd' => $count < count(Gateway::$alternate) + 1,
|
||||||
|
'title' => trans('texts.online_payments'),
|
||||||
|
'tokenBillingOptions' => $tokenBillingOptions,
|
||||||
|
'currency' => Utils::getFromCache(Session::get(SESSION_CURRENCY, DEFAULT_CURRENCY), 'currencies'),
|
||||||
|
'taxRates' => TaxRate::scope()->whereIsInclusive(false)->orderBy('rate')->get(['public_id', 'name', 'rate']),
|
||||||
|
'account' => $account,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -812,9 +790,12 @@ class AccountController extends BaseController
|
|||||||
{
|
{
|
||||||
$account = $request->user()->account;
|
$account = $request->user()->account;
|
||||||
$account->fill($request->all());
|
$account->fill($request->all());
|
||||||
$account->bcc_email = $request->bcc_email;
|
|
||||||
$account->save();
|
$account->save();
|
||||||
|
|
||||||
|
$settings = $account->account_email_settings;
|
||||||
|
$settings->fill($request->all());
|
||||||
|
$settings->save();
|
||||||
|
|
||||||
return redirect('settings/' . ACCOUNT_EMAIL_SETTINGS)
|
return redirect('settings/' . ACCOUNT_EMAIL_SETTINGS)
|
||||||
->with('message', trans('texts.updated_settings'));
|
->with('message', trans('texts.updated_settings'));
|
||||||
}
|
}
|
||||||
@ -830,11 +811,11 @@ class AccountController extends BaseController
|
|||||||
foreach ([ENTITY_INVOICE, ENTITY_QUOTE, ENTITY_PAYMENT, REMINDER1, REMINDER2, REMINDER3] as $type) {
|
foreach ([ENTITY_INVOICE, ENTITY_QUOTE, ENTITY_PAYMENT, REMINDER1, REMINDER2, REMINDER3] as $type) {
|
||||||
$subjectField = "email_subject_{$type}";
|
$subjectField = "email_subject_{$type}";
|
||||||
$subject = Input::get($subjectField, $account->getEmailSubject($type));
|
$subject = Input::get($subjectField, $account->getEmailSubject($type));
|
||||||
$account->$subjectField = ($subject == $account->getDefaultEmailSubject($type) ? null : $subject);
|
$account->account_email_settings->$subjectField = ($subject == $account->getDefaultEmailSubject($type) ? null : $subject);
|
||||||
|
|
||||||
$bodyField = "email_template_{$type}";
|
$bodyField = "email_template_{$type}";
|
||||||
$body = Input::get($bodyField, $account->getEmailTemplate($type));
|
$body = Input::get($bodyField, $account->getEmailTemplate($type));
|
||||||
$account->$bodyField = ($body == $account->getDefaultEmailTemplate($type) ? null : $body);
|
$account->account_email_settings->$bodyField = ($body == $account->getDefaultEmailTemplate($type) ? null : $body);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ([REMINDER1, REMINDER2, REMINDER3] as $type) {
|
foreach ([REMINDER1, REMINDER2, REMINDER3] as $type) {
|
||||||
@ -846,6 +827,7 @@ class AccountController extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
$account->save();
|
$account->save();
|
||||||
|
$account->account_email_settings->save();
|
||||||
|
|
||||||
Session::flash('message', trans('texts.updated_settings'));
|
Session::flash('message', trans('texts.updated_settings'));
|
||||||
}
|
}
|
||||||
@ -932,6 +914,8 @@ class AccountController extends BaseController
|
|||||||
$account->client_number_prefix = trim(Input::get('client_number_prefix'));
|
$account->client_number_prefix = trim(Input::get('client_number_prefix'));
|
||||||
$account->client_number_pattern = trim(Input::get('client_number_pattern'));
|
$account->client_number_pattern = trim(Input::get('client_number_pattern'));
|
||||||
$account->client_number_counter = Input::get('client_number_counter');
|
$account->client_number_counter = Input::get('client_number_counter');
|
||||||
|
$account->reset_counter_frequency_id = Input::get('reset_counter_frequency_id');
|
||||||
|
$account->reset_counter_date = $account->reset_counter_frequency_id ? Utils::toSqlDate(Input::get('reset_counter_date')) : null;
|
||||||
|
|
||||||
if (Input::has('recurring_hour')) {
|
if (Input::has('recurring_hour')) {
|
||||||
$account->recurring_hour = Input::get('recurring_hour');
|
$account->recurring_hour = Input::get('recurring_hour');
|
||||||
@ -1054,28 +1038,32 @@ class AccountController extends BaseController
|
|||||||
$size = filesize($filePath);
|
$size = filesize($filePath);
|
||||||
|
|
||||||
if ($size / 1000 > MAX_DOCUMENT_SIZE) {
|
if ($size / 1000 > MAX_DOCUMENT_SIZE) {
|
||||||
Session::flash('warning', 'File too large');
|
Session::flash('warning', trans('texts.logo_warning_too_large'));
|
||||||
} else {
|
} else {
|
||||||
if ($documentType != 'gif') {
|
if ($documentType != 'gif') {
|
||||||
$account->logo = $account->account_key.'.'.$documentType;
|
$account->logo = $account->account_key.'.'.$documentType;
|
||||||
|
|
||||||
$imageSize = getimagesize($filePath);
|
try {
|
||||||
$account->logo_width = $imageSize[0];
|
$imageSize = getimagesize($filePath);
|
||||||
$account->logo_height = $imageSize[1];
|
$account->logo_width = $imageSize[0];
|
||||||
$account->logo_size = $size;
|
$account->logo_height = $imageSize[1];
|
||||||
|
$account->logo_size = $size;
|
||||||
|
|
||||||
// make sure image isn't interlaced
|
// make sure image isn't interlaced
|
||||||
if (extension_loaded('fileinfo')) {
|
if (extension_loaded('fileinfo')) {
|
||||||
$image = Image::make($path);
|
$image = Image::make($path);
|
||||||
$image->interlace(false);
|
$image->interlace(false);
|
||||||
$imageStr = (string) $image->encode($documentType);
|
$imageStr = (string) $image->encode($documentType);
|
||||||
$disk->put($account->logo, $imageStr);
|
$disk->put($account->logo, $imageStr);
|
||||||
|
|
||||||
$account->logo_size = strlen($imageStr);
|
$account->logo_size = strlen($imageStr);
|
||||||
} else {
|
} else {
|
||||||
$stream = fopen($filePath, 'r');
|
$stream = fopen($filePath, 'r');
|
||||||
$disk->getDriver()->putStream($account->logo, $stream, ['mimetype' => $documentTypeData['mime']]);
|
$disk->getDriver()->putStream($account->logo, $stream, ['mimetype' => $documentTypeData['mime']]);
|
||||||
fclose($stream);
|
fclose($stream);
|
||||||
|
}
|
||||||
|
} catch (Exception $exception) {
|
||||||
|
Session::flash('warning', trans('texts.logo_warning_invalid'));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (extension_loaded('fileinfo')) {
|
if (extension_loaded('fileinfo')) {
|
||||||
@ -1093,7 +1081,7 @@ class AccountController extends BaseController
|
|||||||
$account->logo_width = $image->width();
|
$account->logo_width = $image->width();
|
||||||
$account->logo_height = $image->height();
|
$account->logo_height = $image->height();
|
||||||
} else {
|
} else {
|
||||||
Session::flash('warning', 'Warning: To support gifs the fileinfo PHP extension needs to be enabled.');
|
Session::flash('warning', trans('texts.logo_warning_fileinfo'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1142,9 +1130,6 @@ class AccountController extends BaseController
|
|||||||
$user->referral_code = $this->accountRepo->getReferralCode();
|
$user->referral_code = $this->accountRepo->getReferralCode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Utils::isNinjaDev()) {
|
|
||||||
$user->dark_mode = Input::get('dark_mode') ? true : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$user->save();
|
$user->save();
|
||||||
|
|
||||||
@ -1189,6 +1174,8 @@ class AccountController extends BaseController
|
|||||||
$account = Auth::user()->account;
|
$account = Auth::user()->account;
|
||||||
$account->token_billing_type_id = Input::get('token_billing_type_id');
|
$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->auto_bill_on_due_date = boolval(Input::get('auto_bill_on_due_date'));
|
||||||
|
$account->gateway_fee_enabled = boolval(Input::get('gateway_fee_enabled'));
|
||||||
|
|
||||||
$account->save();
|
$account->save();
|
||||||
|
|
||||||
event(new UserSettingsChanged());
|
event(new UserSettingsChanged());
|
||||||
@ -1198,35 +1185,6 @@ class AccountController extends BaseController
|
|||||||
return Redirect::to('settings/'.ACCOUNT_PAYMENTS);
|
return Redirect::to('settings/'.ACCOUNT_PAYMENTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function savePaymentGatewayLimits()
|
|
||||||
{
|
|
||||||
$gateway_type_id = intval(Input::get('gateway_type_id'));
|
|
||||||
$gateway_settings = AccountGatewaySettings::scope()->where('gateway_type_id', '=', $gateway_type_id)->first();
|
|
||||||
|
|
||||||
if (! $gateway_settings) {
|
|
||||||
$gateway_settings = AccountGatewaySettings::createNew();
|
|
||||||
$gateway_settings->gateway_type_id = $gateway_type_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
$gateway_settings->min_limit = Input::get('limit_min_enable') ? intval(Input::get('limit_min')) : null;
|
|
||||||
$gateway_settings->max_limit = Input::get('limit_max_enable') ? intval(Input::get('limit_max')) : null;
|
|
||||||
|
|
||||||
if ($gateway_settings->max_limit !== null && $gateway_settings->min_limit > $gateway_settings->max_limit) {
|
|
||||||
$gateway_settings->max_limit = $gateway_settings->min_limit;
|
|
||||||
}
|
|
||||||
|
|
||||||
$gateway_settings->save();
|
|
||||||
|
|
||||||
event(new UserSettingsChanged());
|
|
||||||
|
|
||||||
Session::flash('message', trans('texts.updated_settings'));
|
|
||||||
|
|
||||||
return Redirect::to('settings/' . ACCOUNT_PAYMENTS);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
@ -1255,7 +1213,7 @@ class AccountController extends BaseController
|
|||||||
public function checkEmail()
|
public function checkEmail()
|
||||||
{
|
{
|
||||||
$email = User::withTrashed()->where('email', '=', Input::get('email'))
|
$email = User::withTrashed()->where('email', '=', Input::get('email'))
|
||||||
->where('id', '<>', Auth::user()->id)
|
->where('id', '<>', Auth::user()->registered ? 0 : Auth::user()->id)
|
||||||
->first();
|
->first();
|
||||||
|
|
||||||
if ($email) {
|
if ($email) {
|
||||||
@ -1270,36 +1228,58 @@ class AccountController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function submitSignup()
|
public function submitSignup()
|
||||||
{
|
{
|
||||||
|
$user = Auth::user();
|
||||||
|
$account = $user->account;
|
||||||
|
|
||||||
$rules = [
|
$rules = [
|
||||||
'new_first_name' => 'required',
|
'new_first_name' => 'required',
|
||||||
'new_last_name' => 'required',
|
'new_last_name' => 'required',
|
||||||
'new_password' => 'required|min:6',
|
'new_password' => 'required|min:6',
|
||||||
'new_email' => 'email|required|unique:users,email,'.Auth::user()->id.',id',
|
'new_email' => 'email|required|unique:users,email',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if (! $user->registered) {
|
||||||
|
$rules['new_email'] .= ',' . Auth::user()->id . ',id';
|
||||||
|
}
|
||||||
|
|
||||||
$validator = Validator::make(Input::all(), $rules);
|
$validator = Validator::make(Input::all(), $rules);
|
||||||
|
|
||||||
if ($validator->fails()) {
|
if ($validator->fails()) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var \App\Models\User $user */
|
$firstName = trim(Input::get('new_first_name'));
|
||||||
$user = Auth::user();
|
$lastName = trim(Input::get('new_last_name'));
|
||||||
$user->first_name = trim(Input::get('new_first_name'));
|
$email = trim(strtolower(Input::get('new_email')));
|
||||||
$user->last_name = trim(Input::get('new_last_name'));
|
$password = trim(Input::get('new_password'));
|
||||||
$user->email = trim(strtolower(Input::get('new_email')));
|
|
||||||
$user->username = $user->email;
|
|
||||||
$user->password = bcrypt(trim(Input::get('new_password')));
|
|
||||||
$user->registered = true;
|
|
||||||
$user->save();
|
|
||||||
|
|
||||||
$user->account->startTrial(PLAN_PRO);
|
if ($user->registered) {
|
||||||
|
$newAccount = $this->accountRepo->create($firstName, $lastName, $email, $password, $account->company);
|
||||||
|
$newUser = $newAccount->users()->first();
|
||||||
|
$users = $this->accountRepo->associateAccounts($user->id, $newUser->id);
|
||||||
|
|
||||||
if (Input::get('go_pro') == 'true') {
|
Session::flash('message', trans('texts.created_new_company'));
|
||||||
Session::set(REQUESTED_PRO_PLAN, true);
|
Session::put(SESSION_USER_ACCOUNTS, $users);
|
||||||
|
Auth::loginUsingId($newUser->id);
|
||||||
|
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
} else {
|
||||||
|
$user->first_name = $firstName;
|
||||||
|
$user->last_name = $lastName;
|
||||||
|
$user->email = $email;
|
||||||
|
$user->username = $user->email;
|
||||||
|
$user->password = bcrypt($password);
|
||||||
|
$user->registered = true;
|
||||||
|
$user->save();
|
||||||
|
|
||||||
|
$user->account->startTrial(PLAN_PRO);
|
||||||
|
|
||||||
|
if (Input::get('go_pro') == 'true') {
|
||||||
|
Session::set(REQUESTED_PRO_PLAN, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return "{$user->first_name} {$user->last_name}";
|
||||||
}
|
}
|
||||||
|
|
||||||
return "{$user->first_name} {$user->last_name}";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1328,6 +1308,16 @@ class AccountController extends BaseController
|
|||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
|
*/
|
||||||
|
public function purgeData()
|
||||||
|
{
|
||||||
|
$this->dispatch(new \App\Jobs\PurgeAccountData());
|
||||||
|
|
||||||
|
return redirect('/settings/account_management')->withMessage(trans('texts.purge_successful'));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
@ -1350,6 +1340,9 @@ class AccountController extends BaseController
|
|||||||
$account = Auth::user()->account;
|
$account = Auth::user()->account;
|
||||||
\Log::info("Canceled Account: {$account->name} - {$user->email}");
|
\Log::info("Canceled Account: {$account->name} - {$user->email}");
|
||||||
|
|
||||||
|
$company = $account->company;
|
||||||
|
$refunded = $company->processRefund(Auth::user());
|
||||||
|
|
||||||
Document::scope()->each(function ($item, $key) {
|
Document::scope()->each(function ($item, $key) {
|
||||||
$item->delete();
|
$item->delete();
|
||||||
});
|
});
|
||||||
@ -1365,6 +1358,10 @@ class AccountController extends BaseController
|
|||||||
Auth::logout();
|
Auth::logout();
|
||||||
Session::flush();
|
Session::flush();
|
||||||
|
|
||||||
|
if ($refunded) {
|
||||||
|
Session::flash('warning', trans('texts.plan_refunded'));
|
||||||
|
}
|
||||||
|
|
||||||
return Redirect::to('/')->with('clearGuestKey', true);
|
return Redirect::to('/')->with('clearGuestKey', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1414,18 +1411,17 @@ class AccountController extends BaseController
|
|||||||
public function previewEmail(TemplateService $templateService)
|
public function previewEmail(TemplateService $templateService)
|
||||||
{
|
{
|
||||||
$template = Input::get('template');
|
$template = Input::get('template');
|
||||||
$invoice = Invoice::scope()
|
$invitation = \App\Models\Invitation::scope()
|
||||||
->invoices()
|
->with('invoice.client.contacts')
|
||||||
->withTrashed()
|
->first();
|
||||||
->first();
|
|
||||||
|
|
||||||
if (! $invoice) {
|
if (! $invitation) {
|
||||||
return trans('texts.create_invoice_for_sample');
|
return trans('texts.create_invoice_for_sample');
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var \App\Models\Account $account */
|
/** @var \App\Models\Account $account */
|
||||||
$account = Auth::user()->account;
|
$account = Auth::user()->account;
|
||||||
$invitation = $invoice->invitations->first();
|
$invoice = $invitation->invoice;
|
||||||
|
|
||||||
// replace the variables with sample data
|
// replace the variables with sample data
|
||||||
$data = [
|
$data = [
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Models\Account;
|
use App\Models\Account;
|
||||||
|
use App\Models\AccountGatewaySettings;
|
||||||
use App\Models\AccountGateway;
|
use App\Models\AccountGateway;
|
||||||
use App\Models\Gateway;
|
use App\Models\Gateway;
|
||||||
use App\Services\AccountGatewayService;
|
use App\Services\AccountGatewayService;
|
||||||
@ -131,6 +132,10 @@ class AccountGatewayController extends BaseController
|
|||||||
$currentGateways = $account->account_gateways;
|
$currentGateways = $account->account_gateways;
|
||||||
$gateways = Gateway::where('payment_library_id', '=', 1)->orderBy('name')->get();
|
$gateways = Gateway::where('payment_library_id', '=', 1)->orderBy('name')->get();
|
||||||
|
|
||||||
|
if ($accountGateway) {
|
||||||
|
$accountGateway->fields = [];
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($gateways as $gateway) {
|
foreach ($gateways as $gateway) {
|
||||||
$fields = $gateway->getFields();
|
$fields = $gateway->getFields();
|
||||||
if (! $gateway->isCustom()) {
|
if (! $gateway->isCustom()) {
|
||||||
@ -372,7 +377,7 @@ class AccountGatewayController extends BaseController
|
|||||||
'tos_agree' => 'required',
|
'tos_agree' => 'required',
|
||||||
'first_name' => 'required',
|
'first_name' => 'required',
|
||||||
'last_name' => 'required',
|
'last_name' => 'required',
|
||||||
'email' => 'required',
|
'email' => 'required|email',
|
||||||
];
|
];
|
||||||
|
|
||||||
if (WEPAY_ENABLE_CANADA) {
|
if (WEPAY_ENABLE_CANADA) {
|
||||||
@ -387,6 +392,13 @@ class AccountGatewayController extends BaseController
|
|||||||
->withInput();
|
->withInput();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (! $user->email) {
|
||||||
|
$user->email = trim(Input::get('email'));
|
||||||
|
$user->first_name = trim(Input::get('first_name'));
|
||||||
|
$user->last_name = trim(Input::get('last_name'));
|
||||||
|
$user->save();
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$wepay = Utils::setupWePay();
|
$wepay = Utils::setupWePay();
|
||||||
|
|
||||||
@ -494,4 +506,33 @@ class AccountGatewayController extends BaseController
|
|||||||
|
|
||||||
return Redirect::to("gateways/{$accountGateway->public_id}/edit");
|
return Redirect::to("gateways/{$accountGateway->public_id}/edit");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
|
*/
|
||||||
|
public function savePaymentGatewayLimits()
|
||||||
|
{
|
||||||
|
$gateway_type_id = intval(Input::get('gateway_type_id'));
|
||||||
|
$gateway_settings = AccountGatewaySettings::scope()->where('gateway_type_id', '=', $gateway_type_id)->first();
|
||||||
|
|
||||||
|
if (! $gateway_settings) {
|
||||||
|
$gateway_settings = AccountGatewaySettings::createNew();
|
||||||
|
$gateway_settings->gateway_type_id = $gateway_type_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
$gateway_settings->min_limit = Input::get('limit_min_enable') ? intval(Input::get('limit_min')) : null;
|
||||||
|
$gateway_settings->max_limit = Input::get('limit_max_enable') ? intval(Input::get('limit_max')) : null;
|
||||||
|
|
||||||
|
if ($gateway_settings->max_limit !== null && $gateway_settings->min_limit > $gateway_settings->max_limit) {
|
||||||
|
$gateway_settings->max_limit = $gateway_settings->min_limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$gateway_settings->fill(Input::all());
|
||||||
|
$gateway_settings->save();
|
||||||
|
|
||||||
|
Session::flash('message', trans('texts.updated_settings'));
|
||||||
|
|
||||||
|
return Redirect::to('settings/' . ACCOUNT_PAYMENTS);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ class AppController extends BaseController
|
|||||||
$test = Input::get('test');
|
$test = Input::get('test');
|
||||||
|
|
||||||
$app = Input::get('app');
|
$app = Input::get('app');
|
||||||
$app['key'] = env('APP_KEY') ?: str_random(RANDOM_KEY_LENGTH);
|
$app['key'] = env('APP_KEY') ?: strtolower(str_random(RANDOM_KEY_LENGTH));
|
||||||
$app['debug'] = Input::get('debug') ? 'true' : 'false';
|
$app['debug'] = Input::get('debug') ? 'true' : 'false';
|
||||||
$app['https'] = Input::get('https') ? 'true' : 'false';
|
$app['https'] = Input::get('https') ? 'true' : 'false';
|
||||||
|
|
||||||
@ -101,7 +101,7 @@ class AppController extends BaseController
|
|||||||
$_ENV['MAIL_FROM_ADDRESS'] = $mail['from']['address'];
|
$_ENV['MAIL_FROM_ADDRESS'] = $mail['from']['address'];
|
||||||
$_ENV['MAIL_PASSWORD'] = $mail['password'];
|
$_ENV['MAIL_PASSWORD'] = $mail['password'];
|
||||||
$_ENV['PHANTOMJS_CLOUD_KEY'] = 'a-demo-key-with-low-quota-per-ip-address';
|
$_ENV['PHANTOMJS_CLOUD_KEY'] = 'a-demo-key-with-low-quota-per-ip-address';
|
||||||
$_ENV['PHANTOMJS_SECRET'] = str_random(RANDOM_KEY_LENGTH);
|
$_ENV['PHANTOMJS_SECRET'] = strtolower(str_random(RANDOM_KEY_LENGTH));
|
||||||
$_ENV['MAILGUN_DOMAIN'] = $mail['mailgun_domain'];
|
$_ENV['MAILGUN_DOMAIN'] = $mail['mailgun_domain'];
|
||||||
$_ENV['MAILGUN_SECRET'] = $mail['mailgun_secret'];
|
$_ENV['MAILGUN_SECRET'] = $mail['mailgun_secret'];
|
||||||
|
|
||||||
@ -191,7 +191,8 @@ class AppController extends BaseController
|
|||||||
$config .= "{$key}={$val}\n";
|
$config .= "{$key}={$val}\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
$fp = fopen(base_path().'/.env', 'w');
|
$filePath = base_path().'/.env';
|
||||||
|
$fp = fopen($filePath, 'w');
|
||||||
fwrite($fp, $config);
|
fwrite($fp, $config);
|
||||||
fclose($fp);
|
fclose($fp);
|
||||||
|
|
||||||
@ -345,6 +346,16 @@ class AppController extends BaseController
|
|||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function checkData()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Artisan::call('ninja:check-data');
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
} catch (Exception $exception) {
|
||||||
|
return RESULT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function stats()
|
public function stats()
|
||||||
{
|
{
|
||||||
if (! hash_equals(Input::get('password'), env('RESELLER_PASSWORD'))) {
|
if (! hash_equals(Input::get('password'), env('RESELLER_PASSWORD'))) {
|
||||||
|
@ -173,13 +173,17 @@ class AuthController extends Controller
|
|||||||
public function getLogoutWrapper()
|
public function getLogoutWrapper()
|
||||||
{
|
{
|
||||||
if (Auth::check() && ! Auth::user()->registered) {
|
if (Auth::check() && ! Auth::user()->registered) {
|
||||||
$account = Auth::user()->account;
|
if (request()->force_logout) {
|
||||||
$this->accountRepo->unlinkAccount($account);
|
$account = Auth::user()->account;
|
||||||
|
$this->accountRepo->unlinkAccount($account);
|
||||||
|
|
||||||
if (! $account->hasMultipleAccounts()) {
|
if (! $account->hasMultipleAccounts()) {
|
||||||
$account->company->forceDelete();
|
$account->company->forceDelete();
|
||||||
|
}
|
||||||
|
$account->forceDelete();
|
||||||
|
} else {
|
||||||
|
return redirect('/');
|
||||||
}
|
}
|
||||||
$account->forceDelete();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$response = self::getLogout();
|
$response = self::getLogout();
|
||||||
|
@ -20,6 +20,7 @@ use Utils;
|
|||||||
* schemes={"http","https"},
|
* schemes={"http","https"},
|
||||||
* host="ninja.dev",
|
* host="ninja.dev",
|
||||||
* basePath="/api/v1",
|
* basePath="/api/v1",
|
||||||
|
* produces={"application/json"},
|
||||||
* @SWG\Info(
|
* @SWG\Info(
|
||||||
* version="1.0.0",
|
* version="1.0.0",
|
||||||
* title="Invoice Ninja API",
|
* title="Invoice Ninja API",
|
||||||
@ -37,11 +38,12 @@ use Utils;
|
|||||||
* description="Find out more about Invoice Ninja",
|
* description="Find out more about Invoice Ninja",
|
||||||
* url="https://www.invoiceninja.com"
|
* url="https://www.invoiceninja.com"
|
||||||
* ),
|
* ),
|
||||||
|
* security={"api_key": {}},
|
||||||
* @SWG\SecurityScheme(
|
* @SWG\SecurityScheme(
|
||||||
* securityDefinition="api_key",
|
* securityDefinition="api_key",
|
||||||
* type="apiKey",
|
* type="apiKey",
|
||||||
* in="header",
|
* in="header",
|
||||||
* name="TOKEN"
|
* name="X-Ninja-Token"
|
||||||
* )
|
* )
|
||||||
* )
|
* )
|
||||||
*/
|
*/
|
||||||
|
@ -37,7 +37,7 @@ class BaseController extends Controller
|
|||||||
|
|
||||||
// when restoring redirect to entity
|
// when restoring redirect to entity
|
||||||
if ($action == 'restore' && count($ids) == 1) {
|
if ($action == 'restore' && count($ids) == 1) {
|
||||||
return redirect("{$entityTypes}/" . $ids[0]);
|
return redirect("{$entityTypes}/" . $ids[0] . '/edit');
|
||||||
// when viewing from a datatable list
|
// when viewing from a datatable list
|
||||||
} elseif (strpos($referer, '/clients/')) {
|
} elseif (strpos($referer, '/clients/')) {
|
||||||
return redirect($referer);
|
return redirect($referer);
|
||||||
@ -45,7 +45,7 @@ class BaseController extends Controller
|
|||||||
return redirect("{$entityTypes}");
|
return redirect("{$entityTypes}");
|
||||||
// when viewing individual entity
|
// when viewing individual entity
|
||||||
} elseif (count($ids)) {
|
} elseif (count($ids)) {
|
||||||
return redirect("{$entityTypes}/" . $ids[0]);
|
return redirect("{$entityTypes}/" . $ids[0] . '/edit');
|
||||||
} else {
|
} else {
|
||||||
return redirect("{$entityTypes}");
|
return redirect("{$entityTypes}");
|
||||||
}
|
}
|
||||||
|
@ -26,11 +26,12 @@ class ClientApiController extends BaseAPIController
|
|||||||
/**
|
/**
|
||||||
* @SWG\Get(
|
* @SWG\Get(
|
||||||
* path="/clients",
|
* path="/clients",
|
||||||
* summary="List of clients",
|
* summary="List clients",
|
||||||
|
* operationId="listClients",
|
||||||
* tags={"client"},
|
* tags={"client"},
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
* response=200,
|
* response=200,
|
||||||
* description="A list with clients",
|
* description="A list of clients",
|
||||||
* @SWG\Schema(type="array", @SWG\Items(ref="#/definitions/Client"))
|
* @SWG\Schema(type="array", @SWG\Items(ref="#/definitions/Client"))
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
@ -45,11 +46,12 @@ class ClientApiController extends BaseAPIController
|
|||||||
->orderBy('created_at', 'desc')
|
->orderBy('created_at', 'desc')
|
||||||
->withTrashed();
|
->withTrashed();
|
||||||
|
|
||||||
// Filter by email
|
|
||||||
if ($email = Input::get('email')) {
|
if ($email = Input::get('email')) {
|
||||||
$clients = $clients->whereHas('contacts', function ($query) use ($email) {
|
$clients = $clients->whereHas('contacts', function ($query) use ($email) {
|
||||||
$query->where('email', $email);
|
$query->where('email', $email);
|
||||||
});
|
});
|
||||||
|
} elseif ($idNumber = Input::get('id_number')) {
|
||||||
|
$clients = $clients->whereIdNumber($idNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->listResponse($clients);
|
return $this->listResponse($clients);
|
||||||
@ -58,8 +60,15 @@ class ClientApiController extends BaseAPIController
|
|||||||
/**
|
/**
|
||||||
* @SWG\Get(
|
* @SWG\Get(
|
||||||
* path="/clients/{client_id}",
|
* path="/clients/{client_id}",
|
||||||
* summary="Individual Client",
|
* summary="Retrieve a client",
|
||||||
|
* operationId="getClient",
|
||||||
* tags={"client"},
|
* tags={"client"},
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="path",
|
||||||
|
* name="client_id",
|
||||||
|
* type="integer",
|
||||||
|
* required=true
|
||||||
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
* response=200,
|
* response=200,
|
||||||
* description="A single client",
|
* description="A single client",
|
||||||
@ -79,11 +88,12 @@ class ClientApiController extends BaseAPIController
|
|||||||
/**
|
/**
|
||||||
* @SWG\Post(
|
* @SWG\Post(
|
||||||
* path="/clients",
|
* path="/clients",
|
||||||
* tags={"client"},
|
|
||||||
* summary="Create a client",
|
* summary="Create a client",
|
||||||
|
* operationId="createClient",
|
||||||
|
* tags={"client"},
|
||||||
* @SWG\Parameter(
|
* @SWG\Parameter(
|
||||||
* in="body",
|
* in="body",
|
||||||
* name="body",
|
* name="client",
|
||||||
* @SWG\Schema(ref="#/definitions/Client")
|
* @SWG\Schema(ref="#/definitions/Client")
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
@ -107,16 +117,23 @@ class ClientApiController extends BaseAPIController
|
|||||||
/**
|
/**
|
||||||
* @SWG\Put(
|
* @SWG\Put(
|
||||||
* path="/clients/{client_id}",
|
* path="/clients/{client_id}",
|
||||||
* tags={"client"},
|
|
||||||
* summary="Update a client",
|
* summary="Update a client",
|
||||||
|
* operationId="updateClient",
|
||||||
|
* tags={"client"},
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="path",
|
||||||
|
* name="client_id",
|
||||||
|
* type="integer",
|
||||||
|
* required=true
|
||||||
|
* ),
|
||||||
* @SWG\Parameter(
|
* @SWG\Parameter(
|
||||||
* in="body",
|
* in="body",
|
||||||
* name="body",
|
* name="client",
|
||||||
* @SWG\Schema(ref="#/definitions/Client")
|
* @SWG\Schema(ref="#/definitions/Client")
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
* response=200,
|
* response=200,
|
||||||
* description="Update client",
|
* description="Updated client",
|
||||||
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Client"))
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Client"))
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
@ -145,16 +162,18 @@ class ClientApiController extends BaseAPIController
|
|||||||
/**
|
/**
|
||||||
* @SWG\Delete(
|
* @SWG\Delete(
|
||||||
* path="/clients/{client_id}",
|
* path="/clients/{client_id}",
|
||||||
* tags={"client"},
|
|
||||||
* summary="Delete a client",
|
* summary="Delete a client",
|
||||||
|
* operationId="deleteClient",
|
||||||
|
* tags={"client"},
|
||||||
* @SWG\Parameter(
|
* @SWG\Parameter(
|
||||||
* in="body",
|
* in="path",
|
||||||
* name="body",
|
* name="client_id",
|
||||||
* @SWG\Schema(ref="#/definitions/Client")
|
* type="integer",
|
||||||
|
* required=true
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
* response=200,
|
* response=200,
|
||||||
* description="Delete client",
|
* description="Deleted client",
|
||||||
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Client"))
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Client"))
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
|
@ -68,6 +68,7 @@ class ClientPortalController extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
$account->loadLocalizationSettings($client);
|
$account->loadLocalizationSettings($client);
|
||||||
|
$this->invoiceRepo->clearGatewayFee($invoice);
|
||||||
|
|
||||||
if (! Input::has('phantomjs') && ! session('silent:' . $client->id) && ! Session::has($invitation->invitation_key)
|
if (! Input::has('phantomjs') && ! session('silent:' . $client->id) && ! Session::has($invitation->invitation_key)
|
||||||
&& (! Auth::check() || Auth::user()->account_id != $invoice->account_id)) {
|
&& (! Auth::check() || Auth::user()->account_id != $invoice->account_id)) {
|
||||||
@ -146,6 +147,7 @@ class ClientPortalController extends BaseController
|
|||||||
'paymentTypes' => $paymentTypes,
|
'paymentTypes' => $paymentTypes,
|
||||||
'paymentURL' => $paymentURL,
|
'paymentURL' => $paymentURL,
|
||||||
'phantomjs' => Input::has('phantomjs'),
|
'phantomjs' => Input::has('phantomjs'),
|
||||||
|
'gatewayTypeId' => count($paymentTypes) == 1 ? $paymentTypes[0]['gatewayTypeId'] : false,
|
||||||
];
|
];
|
||||||
|
|
||||||
if ($paymentDriver = $account->paymentDriver($invitation, GATEWAY_TYPE_CREDIT_CARD)) {
|
if ($paymentDriver = $account->paymentDriver($invitation, GATEWAY_TYPE_CREDIT_CARD)) {
|
||||||
@ -521,7 +523,7 @@ class ClientPortalController extends BaseController
|
|||||||
'account' => $account,
|
'account' => $account,
|
||||||
'title' => trans('texts.credits'),
|
'title' => trans('texts.credits'),
|
||||||
'entityType' => ENTITY_CREDIT,
|
'entityType' => ENTITY_CREDIT,
|
||||||
'columns' => Utils::trans(['credit_date', 'credit_amount', 'credit_balance']),
|
'columns' => Utils::trans(['credit_date', 'credit_amount', 'credit_balance', 'notes']),
|
||||||
];
|
];
|
||||||
|
|
||||||
return response()->view('public_list', $data);
|
return response()->view('public_list', $data);
|
||||||
|
182
app/Http/Controllers/ContactApiController.php
Normal file
182
app/Http/Controllers/ContactApiController.php
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Requests\ContactRequest;
|
||||||
|
use App\Http\Requests\CreateContactRequest;
|
||||||
|
use App\Http\Requests\UpdateContactRequest;
|
||||||
|
use App\Models\Contact;
|
||||||
|
use App\Ninja\Repositories\ContactRepository;
|
||||||
|
use Input;
|
||||||
|
use Response;
|
||||||
|
use Utils;
|
||||||
|
use App\Services\ContactService;
|
||||||
|
|
||||||
|
class ContactApiController extends BaseAPIController
|
||||||
|
{
|
||||||
|
protected $contactRepo;
|
||||||
|
protected $contactService;
|
||||||
|
|
||||||
|
protected $entityType = ENTITY_CONTACT;
|
||||||
|
|
||||||
|
public function __construct(ContactRepository $contactRepo, ContactService $contactService)
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
|
||||||
|
$this->contactRepo = $contactRepo;
|
||||||
|
$this->contactService = $contactService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @SWG\Get(
|
||||||
|
* path="/contacts",
|
||||||
|
* summary="List contacts",
|
||||||
|
* tags={"contact"},
|
||||||
|
* @SWG\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="A list of contacts",
|
||||||
|
* @SWG\Schema(type="array", @SWG\Items(ref="#/definitions/Contact"))
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="an ""unexpected"" error"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$contacts = Contact::scope()
|
||||||
|
->withTrashed()
|
||||||
|
->orderBy('created_at', 'desc');
|
||||||
|
|
||||||
|
return $this->listResponse($contacts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @SWG\Get(
|
||||||
|
* path="/contacts/{contact_id}",
|
||||||
|
* summary="Retrieve a contact",
|
||||||
|
* tags={"contact"},
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="path",
|
||||||
|
* name="contact_id",
|
||||||
|
* type="integer",
|
||||||
|
* required=true
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="A single contact",
|
||||||
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Contact"))
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="an ""unexpected"" error"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function show(ContactRequest $request)
|
||||||
|
{
|
||||||
|
return $this->itemResponse($request->entity());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @SWG\Post(
|
||||||
|
* path="/contacts",
|
||||||
|
* tags={"contact"},
|
||||||
|
* summary="Create a contact",
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="body",
|
||||||
|
* name="contact",
|
||||||
|
* @SWG\Schema(ref="#/definitions/Contact")
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="New contact",
|
||||||
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Contact"))
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="an ""unexpected"" error"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function store(CreateContactRequest $request)
|
||||||
|
{
|
||||||
|
$contact = $this->contactService->save($request->input());
|
||||||
|
|
||||||
|
return $this->itemResponse($contact);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @SWG\Put(
|
||||||
|
* path="/contacts/{contact_id}",
|
||||||
|
* tags={"contact"},
|
||||||
|
* summary="Update a contact",
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="path",
|
||||||
|
* name="contact_id",
|
||||||
|
* type="integer",
|
||||||
|
* required=true
|
||||||
|
* ),
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="body",
|
||||||
|
* name="contact",
|
||||||
|
* @SWG\Schema(ref="#/definitions/Contact")
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Updated contact",
|
||||||
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Contact"))
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="an ""unexpected"" error"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*
|
||||||
|
* @param mixed $publicId
|
||||||
|
*/
|
||||||
|
public function update(UpdateContactRequest $request, $publicId)
|
||||||
|
{
|
||||||
|
if ($request->action) {
|
||||||
|
return $this->handleAction($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $request->input();
|
||||||
|
$data['public_id'] = $publicId;
|
||||||
|
$contact = $this->contactService->save($data, $request->entity());
|
||||||
|
|
||||||
|
return $this->itemResponse($contact);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @SWG\Delete(
|
||||||
|
* path="/contacts/{contact_id}",
|
||||||
|
* tags={"contact"},
|
||||||
|
* summary="Delete a contact",
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="path",
|
||||||
|
* name="contact_id",
|
||||||
|
* type="integer",
|
||||||
|
* required=true
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Deleted contact",
|
||||||
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Contact"))
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="an ""unexpected"" error"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function destroy(UpdateContactRequest $request)
|
||||||
|
{
|
||||||
|
$contact = $request->entity();
|
||||||
|
|
||||||
|
$this->contactRepo->delete($contact);
|
||||||
|
|
||||||
|
return $this->itemResponse($contact);
|
||||||
|
}
|
||||||
|
}
|
@ -2,8 +2,9 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Http\Requests\CreateDocumentRequest;
|
|
||||||
use App\Http\Requests\DocumentRequest;
|
use App\Http\Requests\DocumentRequest;
|
||||||
|
use App\Http\Requests\CreateDocumentRequest;
|
||||||
|
use App\Http\Requests\UpdateDocumentRequest;
|
||||||
use App\Models\Document;
|
use App\Models\Document;
|
||||||
use App\Ninja\Repositories\DocumentRepository;
|
use App\Ninja\Repositories\DocumentRepository;
|
||||||
|
|
||||||
@ -37,11 +38,12 @@ class DocumentAPIController extends BaseAPIController
|
|||||||
/**
|
/**
|
||||||
* @SWG\Get(
|
* @SWG\Get(
|
||||||
* path="/documents",
|
* path="/documents",
|
||||||
* summary="List of document",
|
* summary="List document",
|
||||||
|
* operationId="listDocuments",
|
||||||
* tags={"document"},
|
* tags={"document"},
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
* response=200,
|
* response=200,
|
||||||
* description="A list with documents",
|
* description="A list of documents",
|
||||||
* @SWG\Schema(type="array", @SWG\Items(ref="#/definitions/Document"))
|
* @SWG\Schema(type="array", @SWG\Items(ref="#/definitions/Document"))
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
@ -61,6 +63,29 @@ class DocumentAPIController extends BaseAPIController
|
|||||||
* @param DocumentRequest $request
|
* @param DocumentRequest $request
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Http\Response|\Redirect|\Symfony\Component\HttpFoundation\StreamedResponse
|
* @return \Illuminate\Http\Response|\Redirect|\Symfony\Component\HttpFoundation\StreamedResponse
|
||||||
|
*
|
||||||
|
* @SWG\Get(
|
||||||
|
* path="/documents/{document_id}",
|
||||||
|
* summary="Download a document",
|
||||||
|
* operationId="getDocument",
|
||||||
|
* tags={"document"},
|
||||||
|
* produces={"application/octet-stream"},
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="path",
|
||||||
|
* name="document_id",
|
||||||
|
* type="integer",
|
||||||
|
* required=true
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="A file",
|
||||||
|
* @SWG\Schema(type="file")
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="an ""unexpected"" error"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
*/
|
*/
|
||||||
public function show(DocumentRequest $request)
|
public function show(DocumentRequest $request)
|
||||||
{
|
{
|
||||||
@ -76,11 +101,12 @@ class DocumentAPIController extends BaseAPIController
|
|||||||
/**
|
/**
|
||||||
* @SWG\Post(
|
* @SWG\Post(
|
||||||
* path="/documents",
|
* path="/documents",
|
||||||
* tags={"document"},
|
|
||||||
* summary="Create a document",
|
* summary="Create a document",
|
||||||
|
* operationId="createDocument",
|
||||||
|
* tags={"document"},
|
||||||
* @SWG\Parameter(
|
* @SWG\Parameter(
|
||||||
* in="body",
|
* in="body",
|
||||||
* name="body",
|
* name="document",
|
||||||
* @SWG\Schema(ref="#/definitions/Document")
|
* @SWG\Schema(ref="#/definitions/Document")
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
@ -100,4 +126,36 @@ class DocumentAPIController extends BaseAPIController
|
|||||||
|
|
||||||
return $this->itemResponse($document);
|
return $this->itemResponse($document);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @SWG\Delete(
|
||||||
|
* path="/documents/{document_id}",
|
||||||
|
* summary="Delete a document",
|
||||||
|
* operationId="deleteDocument",
|
||||||
|
* tags={"document"},
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="path",
|
||||||
|
* name="document_id",
|
||||||
|
* type="integer",
|
||||||
|
* required=true
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Deleted document",
|
||||||
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Document"))
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="an ""unexpected"" error"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function destroy(UpdateDocumentRequest $request)
|
||||||
|
{
|
||||||
|
$entity = $request->entity();
|
||||||
|
|
||||||
|
$this->documentRepo->delete($entity);
|
||||||
|
|
||||||
|
return $this->itemResponse($entity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Http\Requests\CreateExpenseRequest;
|
|
||||||
use App\Http\Requests\ExpenseRequest;
|
use App\Http\Requests\ExpenseRequest;
|
||||||
|
use App\Http\Requests\CreateExpenseRequest;
|
||||||
use App\Http\Requests\UpdateExpenseRequest;
|
use App\Http\Requests\UpdateExpenseRequest;
|
||||||
use App\Models\Expense;
|
use App\Models\Expense;
|
||||||
use App\Ninja\Repositories\ExpenseRepository;
|
use App\Ninja\Repositories\ExpenseRepository;
|
||||||
@ -28,11 +28,12 @@ class ExpenseApiController extends BaseAPIController
|
|||||||
/**
|
/**
|
||||||
* @SWG\Get(
|
* @SWG\Get(
|
||||||
* path="/expenses",
|
* path="/expenses",
|
||||||
* summary="List of expenses",
|
* summary="List expenses",
|
||||||
|
* operationId="listExpenses",
|
||||||
* tags={"expense"},
|
* tags={"expense"},
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
* response=200,
|
* response=200,
|
||||||
* description="A list with expenses",
|
* description="A list of expenses",
|
||||||
* @SWG\Schema(type="array", @SWG\Items(ref="#/definitions/Expense"))
|
* @SWG\Schema(type="array", @SWG\Items(ref="#/definitions/Expense"))
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
@ -51,14 +52,43 @@ class ExpenseApiController extends BaseAPIController
|
|||||||
return $this->listResponse($expenses);
|
return $this->listResponse($expenses);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @SWG\Get(
|
||||||
|
* path="/expenses/{expense_id}",
|
||||||
|
* summary="Retrieve an expense",
|
||||||
|
* operationId="getExpense",
|
||||||
|
* tags={"expense"},
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="path",
|
||||||
|
* name="expense_id",
|
||||||
|
* type="integer",
|
||||||
|
* required=true
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="A single expense",
|
||||||
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Expense"))
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="an ""unexpected"" error"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function show(ExpenseRequest $request)
|
||||||
|
{
|
||||||
|
return $this->itemResponse($request->entity());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @SWG\Post(
|
* @SWG\Post(
|
||||||
* path="/expenses",
|
* path="/expenses",
|
||||||
|
* summary="Create an expense",
|
||||||
|
* operationId="createExpense",
|
||||||
* tags={"expense"},
|
* tags={"expense"},
|
||||||
* summary="Create a expense",
|
|
||||||
* @SWG\Parameter(
|
* @SWG\Parameter(
|
||||||
* in="body",
|
* in="body",
|
||||||
* name="body",
|
* name="expense",
|
||||||
* @SWG\Schema(ref="#/definitions/Expense")
|
* @SWG\Schema(ref="#/definitions/Expense")
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
@ -86,16 +116,23 @@ class ExpenseApiController extends BaseAPIController
|
|||||||
/**
|
/**
|
||||||
* @SWG\Put(
|
* @SWG\Put(
|
||||||
* path="/expenses/{expense_id}",
|
* path="/expenses/{expense_id}",
|
||||||
|
* summary="Update an expense",
|
||||||
|
* operationId="updateExpense",
|
||||||
* tags={"expense"},
|
* tags={"expense"},
|
||||||
* summary="Update a expense",
|
* @SWG\Parameter(
|
||||||
|
* in="path",
|
||||||
|
* name="expense_id",
|
||||||
|
* type="integer",
|
||||||
|
* required=true
|
||||||
|
* ),
|
||||||
* @SWG\Parameter(
|
* @SWG\Parameter(
|
||||||
* in="body",
|
* in="body",
|
||||||
* name="body",
|
* name="expense",
|
||||||
* @SWG\Schema(ref="#/definitions/Expense")
|
* @SWG\Schema(ref="#/definitions/Expense")
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
* response=200,
|
* response=200,
|
||||||
* description="Update expense",
|
* description="Updated expense",
|
||||||
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Expense"))
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Expense"))
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
@ -122,16 +159,18 @@ class ExpenseApiController extends BaseAPIController
|
|||||||
/**
|
/**
|
||||||
* @SWG\Delete(
|
* @SWG\Delete(
|
||||||
* path="/expenses/{expense_id}",
|
* path="/expenses/{expense_id}",
|
||||||
|
* summary="Delete an expense",
|
||||||
|
* operationId="deleteExpense",
|
||||||
* tags={"expense"},
|
* tags={"expense"},
|
||||||
* summary="Delete a expense",
|
|
||||||
* @SWG\Parameter(
|
* @SWG\Parameter(
|
||||||
* in="body",
|
* in="path",
|
||||||
* name="body",
|
* name="expense_id",
|
||||||
* @SWG\Schema(ref="#/definitions/Expense")
|
* type="integer",
|
||||||
|
* required=true
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
* response=200,
|
* response=200,
|
||||||
* description="Delete expense",
|
* description="Deleted expense",
|
||||||
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Expense"))
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Expense"))
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
@ -140,7 +179,7 @@ class ExpenseApiController extends BaseAPIController
|
|||||||
* )
|
* )
|
||||||
* )
|
* )
|
||||||
*/
|
*/
|
||||||
public function destroy(ExpenseRequest $request)
|
public function destroy(UpdateExpenseRequest $request)
|
||||||
{
|
{
|
||||||
$expense = $request->entity();
|
$expense = $request->entity();
|
||||||
|
|
||||||
|
@ -2,8 +2,10 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Requests\ExpenseCategoryRequest;
|
||||||
use App\Http\Requests\CreateExpenseCategoryRequest;
|
use App\Http\Requests\CreateExpenseCategoryRequest;
|
||||||
use App\Http\Requests\UpdateExpenseCategoryRequest;
|
use App\Http\Requests\UpdateExpenseCategoryRequest;
|
||||||
|
use App\Models\ExpenseCategory;
|
||||||
use App\Ninja\Repositories\ExpenseCategoryRepository;
|
use App\Ninja\Repositories\ExpenseCategoryRepository;
|
||||||
use App\Services\ExpenseCategoryService;
|
use App\Services\ExpenseCategoryService;
|
||||||
use Input;
|
use Input;
|
||||||
@ -22,14 +24,69 @@ class ExpenseCategoryApiController extends BaseAPIController
|
|||||||
$this->categoryService = $categoryService;
|
$this->categoryService = $categoryService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @SWG\Get(
|
||||||
|
* path="/expense_categories",
|
||||||
|
* summary="List expense categories",
|
||||||
|
* operationId="listExpenseCategories",
|
||||||
|
* tags={"expense_category"},
|
||||||
|
* @SWG\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="A list of expense categories",
|
||||||
|
* @SWG\Schema(type="array", @SWG\Items(ref="#/definitions/ExpenseCategory"))
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="an ""unexpected"" error"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$clients = ExpenseCategory::scope()
|
||||||
|
->orderBy('created_at', 'desc')
|
||||||
|
->withTrashed();
|
||||||
|
|
||||||
|
return $this->listResponse($clients);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @SWG\Get(
|
||||||
|
* path="/expense_categories/{expense_category_id}",
|
||||||
|
* summary="Retrieve an Expense Category",
|
||||||
|
* operationId="getExpenseCategory",
|
||||||
|
* tags={"expense_category"},
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="path",
|
||||||
|
* name="expense_category_id",
|
||||||
|
* type="integer",
|
||||||
|
* required=true
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="A single expense categroy",
|
||||||
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/ExpenseCategory"))
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="an ""unexpected"" error"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function show(ExpenseCategory $request)
|
||||||
|
{
|
||||||
|
return $this->itemResponse($request->entity());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @SWG\Post(
|
* @SWG\Post(
|
||||||
* path="/expense_categories",
|
* path="/expense_categories",
|
||||||
* tags={"expense_category"},
|
|
||||||
* summary="Create an expense category",
|
* summary="Create an expense category",
|
||||||
|
* operationId="createExpenseCategory",
|
||||||
|
* tags={"expense_category"},
|
||||||
* @SWG\Parameter(
|
* @SWG\Parameter(
|
||||||
* in="body",
|
* in="body",
|
||||||
* name="body",
|
* name="expense_category",
|
||||||
* @SWG\Schema(ref="#/definitions/ExpenseCategory")
|
* @SWG\Schema(ref="#/definitions/ExpenseCategory")
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
@ -53,16 +110,23 @@ class ExpenseCategoryApiController extends BaseAPIController
|
|||||||
/**
|
/**
|
||||||
* @SWG\Put(
|
* @SWG\Put(
|
||||||
* path="/expense_categories/{expense_category_id}",
|
* path="/expense_categories/{expense_category_id}",
|
||||||
* tags={"expense_category"},
|
|
||||||
* summary="Update an expense category",
|
* summary="Update an expense category",
|
||||||
|
* operationId="updateExpenseCategory",
|
||||||
|
* tags={"expense_category"},
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="path",
|
||||||
|
* name="expense_category_id",
|
||||||
|
* type="integer",
|
||||||
|
* required=true
|
||||||
|
* ),
|
||||||
* @SWG\Parameter(
|
* @SWG\Parameter(
|
||||||
* in="body",
|
* in="body",
|
||||||
* name="body",
|
* name="expense_category",
|
||||||
* @SWG\Schema(ref="#/definitions/ExpenseCategory")
|
* @SWG\Schema(ref="#/definitions/ExpenseCategory")
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
* response=200,
|
* response=200,
|
||||||
* description="Update expense category",
|
* description="Updated expense category",
|
||||||
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/ExpenseCategory"))
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/ExpenseCategory"))
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
@ -77,4 +141,36 @@ class ExpenseCategoryApiController extends BaseAPIController
|
|||||||
|
|
||||||
return $this->itemResponse($category);
|
return $this->itemResponse($category);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @SWG\Delete(
|
||||||
|
* path="/expense_categories/{expense_category_id}",
|
||||||
|
* summary="Delete an expense category",
|
||||||
|
* operationId="deleteExpenseCategory",
|
||||||
|
* tags={"expense_category"},
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="path",
|
||||||
|
* name="expense_category_id",
|
||||||
|
* type="integer",
|
||||||
|
* required=true
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Deleted expense category",
|
||||||
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/ExpenseCategory"))
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="an ""unexpected"" error"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function destroy(UpdateExpenseCategoryRequest $request)
|
||||||
|
{
|
||||||
|
$entity = $request->entity();
|
||||||
|
|
||||||
|
$this->expenseCategoryRepo->delete($entity);
|
||||||
|
|
||||||
|
return $this->itemResponse($entity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,12 +65,6 @@ class HomeController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function invoiceNow()
|
public function invoiceNow()
|
||||||
{
|
{
|
||||||
if (Auth::check() && Input::get('new_company')) {
|
|
||||||
Session::put(PREV_USER_ID, Auth::user()->id);
|
|
||||||
Auth::user()->clearSession();
|
|
||||||
Auth::logout();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Track the referral/campaign code
|
// Track the referral/campaign code
|
||||||
if (Input::has('rc')) {
|
if (Input::has('rc')) {
|
||||||
Session::set(SESSION_REFERRAL_CODE, Input::get('rc'));
|
Session::set(SESSION_REFERRAL_CODE, Input::get('rc'));
|
||||||
|
@ -2,57 +2,92 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
use App\Services\ImportService;
|
use App\Services\ImportService;
|
||||||
|
use App\Jobs\ImportData;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Input;
|
use Input;
|
||||||
use Redirect;
|
use Redirect;
|
||||||
use Session;
|
use Session;
|
||||||
use Utils;
|
use Utils;
|
||||||
use View;
|
use View;
|
||||||
|
use Auth;
|
||||||
|
|
||||||
class ImportController extends BaseController
|
class ImportController extends BaseController
|
||||||
{
|
{
|
||||||
public function __construct(ImportService $importService)
|
public function __construct(ImportService $importService)
|
||||||
{
|
{
|
||||||
//parent::__construct();
|
|
||||||
|
|
||||||
$this->importService = $importService;
|
$this->importService = $importService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function doImport()
|
public function doImport(Request $request)
|
||||||
{
|
{
|
||||||
|
if (! Auth::user()->confirmed) {
|
||||||
|
return redirect('/settings/' . ACCOUNT_IMPORT_EXPORT)->withError(trans('texts.confirm_account_to_import'));
|
||||||
|
}
|
||||||
|
|
||||||
$source = Input::get('source');
|
$source = Input::get('source');
|
||||||
$files = [];
|
$files = [];
|
||||||
|
$timestamp = time();
|
||||||
|
|
||||||
foreach (ImportService::$entityTypes as $entityType) {
|
foreach (ImportService::$entityTypes as $entityType) {
|
||||||
if (Input::file("{$entityType}_file")) {
|
$fileName = $entityType;
|
||||||
$files[$entityType] = Input::file("{$entityType}_file")->getRealPath();
|
if ($request->hasFile($fileName)) {
|
||||||
if ($source === IMPORT_CSV) {
|
$file = $request->file($fileName);
|
||||||
Session::forget("{$entityType}-data");
|
$destinationPath = storage_path() . '/import';
|
||||||
|
$extension = $file->getClientOriginalExtension();
|
||||||
|
|
||||||
|
if (! in_array($extension, ['csv', 'xls', 'xlsx', 'json'])) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$newFileName = sprintf('%s_%s_%s.%s', Auth::user()->account_id, $timestamp, $fileName, $extension);
|
||||||
|
$file->move($destinationPath, $newFileName);
|
||||||
|
$files[$entityType] = $newFileName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! count($files)) {
|
if (! count($files)) {
|
||||||
Session::flash('error', trans('texts.select_file'));
|
Session::flash('error', trans('texts.select_file'));
|
||||||
|
|
||||||
return Redirect::to('/settings/' . ACCOUNT_IMPORT_EXPORT);
|
return Redirect::to('/settings/' . ACCOUNT_IMPORT_EXPORT);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if ($source === IMPORT_CSV) {
|
if ($source === IMPORT_CSV) {
|
||||||
$data = $this->importService->mapCSV($files);
|
$data = $this->importService->mapCSV($files);
|
||||||
|
return View::make('accounts.import_map', [
|
||||||
return View::make('accounts.import_map', ['data' => $data]);
|
'data' => $data,
|
||||||
|
'timestamp' => $timestamp,
|
||||||
|
]);
|
||||||
} elseif ($source === IMPORT_JSON) {
|
} elseif ($source === IMPORT_JSON) {
|
||||||
$results = $this->importService->importJSON($files[IMPORT_JSON]);
|
$includeData = filter_var(Input::get('data'), FILTER_VALIDATE_BOOLEAN);
|
||||||
|
$includeSettings = filter_var(Input::get('settings'), FILTER_VALIDATE_BOOLEAN);
|
||||||
return $this->showResult($results);
|
if (config('queue.default') === 'sync') {
|
||||||
|
$results = $this->importService->importJSON($files[IMPORT_JSON], $includeData, $includeSettings);
|
||||||
|
$message = $this->importService->presentResults($results, $includeSettings);
|
||||||
|
} else {
|
||||||
|
$settings = [
|
||||||
|
'files' => $files,
|
||||||
|
'include_data' => $includeData,
|
||||||
|
'include_settings' => $includeSettings,
|
||||||
|
];
|
||||||
|
$this->dispatch(new ImportData(Auth::user(), IMPORT_JSON, $settings));
|
||||||
|
$message = trans('texts.import_started');
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$results = $this->importService->importFiles($source, $files);
|
if (config('queue.default') === 'sync') {
|
||||||
|
$results = $this->importService->importFiles($source, $files);
|
||||||
return $this->showResult($results);
|
$message = $this->importService->presentResults($results);
|
||||||
|
} else {
|
||||||
|
$settings = [
|
||||||
|
'files' => $files,
|
||||||
|
'source' => $source,
|
||||||
|
];
|
||||||
|
$this->dispatch(new ImportData(Auth::user(), false, $settings));
|
||||||
|
$message = trans('texts.import_started');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return redirect('/settings/' . ACCOUNT_IMPORT_EXPORT)->withWarning($message);
|
||||||
} catch (Exception $exception) {
|
} catch (Exception $exception) {
|
||||||
Utils::logError($exception);
|
Utils::logError($exception);
|
||||||
Session::flash('error', $exception->getMessage());
|
Session::flash('error', $exception->getMessage());
|
||||||
@ -63,13 +98,24 @@ class ImportController extends BaseController
|
|||||||
|
|
||||||
public function doImportCSV()
|
public function doImportCSV()
|
||||||
{
|
{
|
||||||
$map = Input::get('map');
|
|
||||||
$headers = Input::get('headers');
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$results = $this->importService->importCSV($map, $headers);
|
$map = Input::get('map');
|
||||||
|
$headers = Input::get('headers');
|
||||||
|
$timestamp = Input::get('timestamp');
|
||||||
|
if (config('queue.default') === 'sync') {
|
||||||
|
$results = $this->importService->importCSV($map, $headers, $timestamp);
|
||||||
|
$message = $this->importService->presentResults($results);
|
||||||
|
} else {
|
||||||
|
$settings = [
|
||||||
|
'timestamp' => $timestamp,
|
||||||
|
'map' => $map,
|
||||||
|
'headers' => $headers,
|
||||||
|
];
|
||||||
|
$this->dispatch(new ImportData(Auth::user(), IMPORT_CSV, $settings));
|
||||||
|
$message = trans('texts.import_started');
|
||||||
|
}
|
||||||
|
|
||||||
return $this->showResult($results);
|
return redirect('/settings/' . ACCOUNT_IMPORT_EXPORT)->withWarning($message);
|
||||||
} catch (Exception $exception) {
|
} catch (Exception $exception) {
|
||||||
Utils::logError($exception);
|
Utils::logError($exception);
|
||||||
Session::flash('error', $exception->getMessage());
|
Session::flash('error', $exception->getMessage());
|
||||||
@ -77,32 +123,4 @@ class ImportController extends BaseController
|
|||||||
return Redirect::to('/settings/' . ACCOUNT_IMPORT_EXPORT);
|
return Redirect::to('/settings/' . ACCOUNT_IMPORT_EXPORT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function showResult($results)
|
|
||||||
{
|
|
||||||
$message = '';
|
|
||||||
$skipped = [];
|
|
||||||
|
|
||||||
foreach ($results as $entityType => $entityResults) {
|
|
||||||
if ($count = count($entityResults[RESULT_SUCCESS])) {
|
|
||||||
$message .= trans("texts.created_{$entityType}s", ['count' => $count]) . '<br/>';
|
|
||||||
}
|
|
||||||
if (count($entityResults[RESULT_FAILURE])) {
|
|
||||||
$skipped = array_merge($skipped, $entityResults[RESULT_FAILURE]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count($skipped)) {
|
|
||||||
$message .= '<p/>' . trans('texts.failed_to_import') . '<br/>';
|
|
||||||
foreach ($skipped as $skip) {
|
|
||||||
$message .= json_encode($skip) . '<br/>';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($message) {
|
|
||||||
Session::flash('warning', $message);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Redirect::to('/settings/' . ACCOUNT_IMPORT_EXPORT);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Http\Requests\CreateInvoiceAPIRequest;
|
|
||||||
use App\Http\Requests\InvoiceRequest;
|
use App\Http\Requests\InvoiceRequest;
|
||||||
|
use App\Http\Requests\CreateInvoiceAPIRequest;
|
||||||
use App\Http\Requests\UpdateInvoiceAPIRequest;
|
use App\Http\Requests\UpdateInvoiceAPIRequest;
|
||||||
use App\Jobs\SendInvoiceEmail;
|
use App\Jobs\SendInvoiceEmail;
|
||||||
use App\Jobs\SendPaymentEmail;
|
use App\Jobs\SendPaymentEmail;
|
||||||
@ -42,11 +42,12 @@ class InvoiceApiController extends BaseAPIController
|
|||||||
/**
|
/**
|
||||||
* @SWG\Get(
|
* @SWG\Get(
|
||||||
* path="/invoices",
|
* path="/invoices",
|
||||||
* summary="List of invoices",
|
* summary="List invoices",
|
||||||
|
* operationId="listInvoices",
|
||||||
* tags={"invoice"},
|
* tags={"invoice"},
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
* response=200,
|
* response=200,
|
||||||
* description="A list with invoices",
|
* description="A list of invoices",
|
||||||
* @SWG\Schema(type="array", @SWG\Items(ref="#/definitions/Invoice"))
|
* @SWG\Schema(type="array", @SWG\Items(ref="#/definitions/Invoice"))
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
@ -62,14 +63,25 @@ class InvoiceApiController extends BaseAPIController
|
|||||||
->with('invoice_items', 'client')
|
->with('invoice_items', 'client')
|
||||||
->orderBy('created_at', 'desc');
|
->orderBy('created_at', 'desc');
|
||||||
|
|
||||||
|
// Filter by invoice number
|
||||||
|
if ($invoiceNumber = Input::get('invoice_number')) {
|
||||||
|
$invoices->whereInvoiceNumber($invoiceNumber);
|
||||||
|
}
|
||||||
|
|
||||||
return $this->listResponse($invoices);
|
return $this->listResponse($invoices);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @SWG\Get(
|
* @SWG\Get(
|
||||||
* path="/invoices/{invoice_id}",
|
* path="/invoices/{invoice_id}",
|
||||||
* summary="Individual Invoice",
|
* summary="Retrieve an Invoice",
|
||||||
* tags={"invoice"},
|
* tags={"invoice"},
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="path",
|
||||||
|
* name="invoice_id",
|
||||||
|
* type="integer",
|
||||||
|
* required=true
|
||||||
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
* response=200,
|
* response=200,
|
||||||
* description="A single invoice",
|
* description="A single invoice",
|
||||||
@ -89,11 +101,11 @@ class InvoiceApiController extends BaseAPIController
|
|||||||
/**
|
/**
|
||||||
* @SWG\Post(
|
* @SWG\Post(
|
||||||
* path="/invoices",
|
* path="/invoices",
|
||||||
* tags={"invoice"},
|
|
||||||
* summary="Create an invoice",
|
* summary="Create an invoice",
|
||||||
|
* tags={"invoice"},
|
||||||
* @SWG\Parameter(
|
* @SWG\Parameter(
|
||||||
* in="body",
|
* in="body",
|
||||||
* name="body",
|
* name="invoice",
|
||||||
* @SWG\Schema(ref="#/definitions/Invoice")
|
* @SWG\Schema(ref="#/definitions/Invoice")
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
@ -297,27 +309,38 @@ class InvoiceApiController extends BaseAPIController
|
|||||||
{
|
{
|
||||||
$invoice = $request->entity();
|
$invoice = $request->entity();
|
||||||
|
|
||||||
$this->dispatch(new SendInvoiceEmail($invoice));
|
//$this->dispatch(new SendInvoiceEmail($invoice));
|
||||||
|
$result = app('App\Ninja\Mailers\ContactMailer')->sendInvoice($invoice);
|
||||||
|
|
||||||
|
if ($result !== true) {
|
||||||
|
return $this->errorResponse($result, 500);
|
||||||
|
}
|
||||||
|
|
||||||
$response = json_encode(RESULT_SUCCESS, JSON_PRETTY_PRINT);
|
|
||||||
$headers = Utils::getApiHeaders();
|
$headers = Utils::getApiHeaders();
|
||||||
|
$response = json_encode(RESULT_SUCCESS, JSON_PRETTY_PRINT);
|
||||||
|
|
||||||
return Response::make($response, 200, $headers);
|
return Response::make($response, 200, $headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @SWG\Put(
|
* @SWG\Put(
|
||||||
* path="/invoices",
|
* path="/invoices/{invoice_id}",
|
||||||
* tags={"invoice"},
|
|
||||||
* summary="Update an invoice",
|
* summary="Update an invoice",
|
||||||
|
* tags={"invoice"},
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="path",
|
||||||
|
* name="invoice_id",
|
||||||
|
* type="integer",
|
||||||
|
* required=true
|
||||||
|
* ),
|
||||||
* @SWG\Parameter(
|
* @SWG\Parameter(
|
||||||
* in="body",
|
* in="body",
|
||||||
* name="body",
|
* name="invoice",
|
||||||
* @SWG\Schema(ref="#/definitions/Invoice")
|
* @SWG\Schema(ref="#/definitions/Invoice")
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
* response=200,
|
* response=200,
|
||||||
* description="Update invoice",
|
* description="Updated invoice",
|
||||||
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Invoice"))
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Invoice"))
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
@ -352,17 +375,18 @@ class InvoiceApiController extends BaseAPIController
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @SWG\Delete(
|
* @SWG\Delete(
|
||||||
* path="/invoices",
|
* path="/invoices/{invoice_id}",
|
||||||
* tags={"invoice"},
|
|
||||||
* summary="Delete an invoice",
|
* summary="Delete an invoice",
|
||||||
|
* tags={"invoice"},
|
||||||
* @SWG\Parameter(
|
* @SWG\Parameter(
|
||||||
* in="body",
|
* in="path",
|
||||||
* name="body",
|
* name="invoice_id",
|
||||||
* @SWG\Schema(ref="#/definitions/Invoice")
|
* type="integer",
|
||||||
|
* required=true
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
* response=200,
|
* response=200,
|
||||||
* description="Delete invoice",
|
* description="Deleted invoice",
|
||||||
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Invoice"))
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Invoice"))
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
|
@ -289,7 +289,7 @@ class InvoiceController extends BaseController
|
|||||||
$taxRateOptions = $account->present()->taxRateOptions;
|
$taxRateOptions = $account->present()->taxRateOptions;
|
||||||
if ($invoice->exists) {
|
if ($invoice->exists) {
|
||||||
foreach ($invoice->getTaxes() as $key => $rate) {
|
foreach ($invoice->getTaxes() as $key => $rate) {
|
||||||
$key = '0 ' . $key;
|
$key = '0 ' . $key; // mark it as a standard exclusive rate option
|
||||||
if (isset($taxRateOptions[$key])) {
|
if (isset($taxRateOptions[$key])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -302,6 +302,7 @@ class OnlinePaymentController extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
Auth::onceUsingId($account->users[0]->id);
|
Auth::onceUsingId($account->users[0]->id);
|
||||||
|
$account->loadLocalizationSettings();
|
||||||
$product = Product::scope(Input::get('product_id'))->first();
|
$product = Product::scope(Input::get('product_id'))->first();
|
||||||
|
|
||||||
if (! $product) {
|
if (! $product) {
|
||||||
@ -330,6 +331,8 @@ class OnlinePaymentController extends BaseController
|
|||||||
$data = [
|
$data = [
|
||||||
'currency_id' => $account->currency_id,
|
'currency_id' => $account->currency_id,
|
||||||
'contact' => Input::all(),
|
'contact' => Input::all(),
|
||||||
|
'custom_value1' => Input::get('custom_client1'),
|
||||||
|
'custom_value2' => Input::get('custom_client2'),
|
||||||
];
|
];
|
||||||
$client = $clientRepo->save($data, $client);
|
$client = $clientRepo->save($data, $client);
|
||||||
}
|
}
|
||||||
@ -343,6 +346,8 @@ class OnlinePaymentController extends BaseController
|
|||||||
'start_date' => Input::get('start_date', date('Y-m-d')),
|
'start_date' => Input::get('start_date', date('Y-m-d')),
|
||||||
'tax_rate1' => $account->default_tax_rate ? $account->default_tax_rate->rate : 0,
|
'tax_rate1' => $account->default_tax_rate ? $account->default_tax_rate->rate : 0,
|
||||||
'tax_name1' => $account->default_tax_rate ? $account->default_tax_rate->name : '',
|
'tax_name1' => $account->default_tax_rate ? $account->default_tax_rate->name : '',
|
||||||
|
'custom_text_value1' => Input::get('custom_invoice1'),
|
||||||
|
'custom_text_value2' => Input::get('custom_invoice2'),
|
||||||
'invoice_items' => [[
|
'invoice_items' => [[
|
||||||
'product_key' => $product->product_key,
|
'product_key' => $product->product_key,
|
||||||
'notes' => $product->notes,
|
'notes' => $product->notes,
|
||||||
@ -350,6 +355,8 @@ class OnlinePaymentController extends BaseController
|
|||||||
'qty' => 1,
|
'qty' => 1,
|
||||||
'tax_rate1' => $product->default_tax_rate ? $product->default_tax_rate->rate : 0,
|
'tax_rate1' => $product->default_tax_rate ? $product->default_tax_rate->rate : 0,
|
||||||
'tax_name1' => $product->default_tax_rate ? $product->default_tax_rate->name : '',
|
'tax_name1' => $product->default_tax_rate ? $product->default_tax_rate->name : '',
|
||||||
|
'custom_value1' => Input::get('custom_product1') ?: $product->custom_value1,
|
||||||
|
'custom_value2' => Input::get('custom_product2') ?: $product->custom_value2,
|
||||||
]],
|
]],
|
||||||
];
|
];
|
||||||
$invoice = $invoiceService->save($data);
|
$invoice = $invoiceService->save($data);
|
||||||
@ -364,9 +371,15 @@ class OnlinePaymentController extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($gatewayTypeAlias) {
|
if ($gatewayTypeAlias) {
|
||||||
return redirect()->to($invitation->getLink('payment') . "/{$gatewayTypeAlias}");
|
$link = $invitation->getLink('payment') . "/{$gatewayTypeAlias}";
|
||||||
} else {
|
} else {
|
||||||
return redirect()->to($invitation->getLink());
|
$link = $invitation->getLink();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filter_var(Input::get('return_link'), FILTER_VALIDATE_BOOLEAN)) {
|
||||||
|
return $link;
|
||||||
|
} else {
|
||||||
|
return redirect()->to($link);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Requests\PaymentRequest;
|
||||||
use App\Http\Requests\CreatePaymentAPIRequest;
|
use App\Http\Requests\CreatePaymentAPIRequest;
|
||||||
use App\Http\Requests\UpdatePaymentRequest;
|
use App\Http\Requests\UpdatePaymentRequest;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
@ -28,11 +29,12 @@ class PaymentApiController extends BaseAPIController
|
|||||||
/**
|
/**
|
||||||
* @SWG\Get(
|
* @SWG\Get(
|
||||||
* path="/payments",
|
* path="/payments",
|
||||||
|
* summary="List payments",
|
||||||
|
* operationId="listPayments",
|
||||||
* tags={"payment"},
|
* tags={"payment"},
|
||||||
* summary="List of payments",
|
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
* response=200,
|
* response=200,
|
||||||
* description="A list with payments",
|
* description="A list of payments",
|
||||||
* @SWG\Schema(type="array", @SWG\Items(ref="#/definitions/Payment"))
|
* @SWG\Schema(type="array", @SWG\Items(ref="#/definitions/Payment"))
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
@ -52,18 +54,20 @@ class PaymentApiController extends BaseAPIController
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @SWG\Put(
|
* @SWG\Get(
|
||||||
* path="/payments/{payment_id",
|
* path="/payments/{payment_id}",
|
||||||
* summary="Update a payment",
|
* summary="Retrieve a payment",
|
||||||
|
* operationId="getPayment",
|
||||||
* tags={"payment"},
|
* tags={"payment"},
|
||||||
* @SWG\Parameter(
|
* @SWG\Parameter(
|
||||||
* in="body",
|
* in="path",
|
||||||
* name="body",
|
* name="payment_id",
|
||||||
* @SWG\Schema(ref="#/definitions/Payment")
|
* type="integer",
|
||||||
|
* required=true
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
* response=200,
|
* response=200,
|
||||||
* description="Update payment",
|
* description="A single payment",
|
||||||
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Payment"))
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Payment"))
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
@ -71,30 +75,21 @@ class PaymentApiController extends BaseAPIController
|
|||||||
* description="an ""unexpected"" error"
|
* description="an ""unexpected"" error"
|
||||||
* )
|
* )
|
||||||
* )
|
* )
|
||||||
*
|
|
||||||
* @param mixed $publicId
|
|
||||||
*/
|
*/
|
||||||
public function update(UpdatePaymentRequest $request, $publicId)
|
public function show(PaymentRequest $request)
|
||||||
{
|
{
|
||||||
if ($request->action) {
|
return $this->itemResponse($request->entity());
|
||||||
return $this->handleAction($request);
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = $request->input();
|
|
||||||
$data['public_id'] = $publicId;
|
|
||||||
$payment = $this->paymentRepo->save($data, $request->entity());
|
|
||||||
|
|
||||||
return $this->itemResponse($payment);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @SWG\Post(
|
* @SWG\Post(
|
||||||
* path="/payments",
|
* path="/payments",
|
||||||
* summary="Create a payment",
|
* summary="Create a payment",
|
||||||
|
* operationId="createPayment",
|
||||||
* tags={"payment"},
|
* tags={"payment"},
|
||||||
* @SWG\Parameter(
|
* @SWG\Parameter(
|
||||||
* in="body",
|
* in="body",
|
||||||
* name="body",
|
* name="payment",
|
||||||
* @SWG\Schema(ref="#/definitions/Payment")
|
* @SWG\Schema(ref="#/definitions/Payment")
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
@ -123,18 +118,63 @@ class PaymentApiController extends BaseAPIController
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @SWG\Delete(
|
* @SWG\Put(
|
||||||
* path="/payments/{payment_id}",
|
* path="/payments/{payment_id}",
|
||||||
* summary="Delete a payment",
|
* summary="Update a payment",
|
||||||
|
* operationId="updatePayment",
|
||||||
* tags={"payment"},
|
* tags={"payment"},
|
||||||
* @SWG\Parameter(
|
* @SWG\Parameter(
|
||||||
|
* in="path",
|
||||||
|
* name="payment_id",
|
||||||
|
* type="integer",
|
||||||
|
* required=true
|
||||||
|
* ),
|
||||||
|
* @SWG\Parameter(
|
||||||
* in="body",
|
* in="body",
|
||||||
* name="body",
|
* name="payment",
|
||||||
* @SWG\Schema(ref="#/definitions/Payment")
|
* @SWG\Schema(ref="#/definitions/Payment")
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
* response=200,
|
* response=200,
|
||||||
* description="Delete payment",
|
* description="Updated payment",
|
||||||
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Payment"))
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="an ""unexpected"" error"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*
|
||||||
|
* @param mixed $publicId
|
||||||
|
*/
|
||||||
|
public function update(UpdatePaymentRequest $request, $publicId)
|
||||||
|
{
|
||||||
|
if ($request->action) {
|
||||||
|
return $this->handleAction($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $request->input();
|
||||||
|
$data['public_id'] = $publicId;
|
||||||
|
$payment = $this->paymentRepo->save($data, $request->entity());
|
||||||
|
|
||||||
|
return $this->itemResponse($payment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @SWG\Delete(
|
||||||
|
* path="/payments/{payment_id}",
|
||||||
|
* summary="Delete a payment",
|
||||||
|
* operationId="deletePayment",
|
||||||
|
* tags={"payment"},
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="path",
|
||||||
|
* name="payment_id",
|
||||||
|
* type="integer",
|
||||||
|
* required=true
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Deleted payment",
|
||||||
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Payment"))
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Payment"))
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
@ -147,7 +187,7 @@ class PaymentApiController extends BaseAPIController
|
|||||||
{
|
{
|
||||||
$payment = $request->entity();
|
$payment = $request->entity();
|
||||||
|
|
||||||
$this->clientRepo->delete($payment);
|
$this->paymentRepo->delete($payment);
|
||||||
|
|
||||||
return $this->itemResponse($payment);
|
return $this->itemResponse($payment);
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ use App\Http\Requests\CreatePaymentRequest;
|
|||||||
use App\Http\Requests\PaymentRequest;
|
use App\Http\Requests\PaymentRequest;
|
||||||
use App\Http\Requests\UpdatePaymentRequest;
|
use App\Http\Requests\UpdatePaymentRequest;
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
|
use App\Models\Credit;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
use App\Ninja\Datatables\PaymentDatatable;
|
use App\Ninja\Datatables\PaymentDatatable;
|
||||||
use App\Ninja\Mailers\ContactMailer;
|
use App\Ninja\Mailers\ContactMailer;
|
||||||
@ -89,7 +90,7 @@ class PaymentController extends BaseController
|
|||||||
{
|
{
|
||||||
$invoices = Invoice::scope()
|
$invoices = Invoice::scope()
|
||||||
->invoices()
|
->invoices()
|
||||||
->where('invoices.balance', '>', 0)
|
->where('invoices.balance', '!=', 0)
|
||||||
->with('client', 'invoice_status')
|
->with('client', 'invoice_status')
|
||||||
->orderBy('invoice_number')->get();
|
->orderBy('invoice_number')->get();
|
||||||
|
|
||||||
@ -180,17 +181,28 @@ class PaymentController extends BaseController
|
|||||||
{
|
{
|
||||||
// check payment has been marked sent
|
// check payment has been marked sent
|
||||||
$request->invoice->markSentIfUnsent();
|
$request->invoice->markSentIfUnsent();
|
||||||
|
|
||||||
$input = $request->input();
|
$input = $request->input();
|
||||||
$input['invoice_id'] = Invoice::getPrivateId($input['invoice']);
|
$amount = Utils::parseFloat($input['amount']);
|
||||||
$input['client_id'] = Client::getPrivateId($input['client']);
|
$credit = false;
|
||||||
$payment = $this->paymentRepo->save($input);
|
|
||||||
|
// if the payment amount is more than the balance create a credit
|
||||||
|
if ($amount > $request->invoice->balance) {
|
||||||
|
$credit = Credit::createNew();
|
||||||
|
$credit->client_id = $request->invoice->client_id;
|
||||||
|
$credit->credit_date = date_create()->format('Y-m-d');
|
||||||
|
$credit->amount = $credit->balance = $amount - $request->invoice->balance;
|
||||||
|
$credit->private_notes = trans('texts.credit_created_by', ['transaction_reference' => $input['transaction_reference']]);
|
||||||
|
$credit->save();
|
||||||
|
$input['amount'] = $request->invoice->balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
$payment = $this->paymentService->save($input);
|
||||||
|
|
||||||
if (Input::get('email_receipt')) {
|
if (Input::get('email_receipt')) {
|
||||||
$this->contactMailer->sendPaymentConfirmation($payment);
|
$this->contactMailer->sendPaymentConfirmation($payment);
|
||||||
Session::flash('message', trans('texts.created_payment_emailed_client'));
|
Session::flash('message', trans($credit ? 'texts.created_payment_and_credit_emailed_client' : 'texts.created_payment_emailed_client'));
|
||||||
} else {
|
} else {
|
||||||
Session::flash('message', trans('texts.created_payment'));
|
Session::flash('message', trans($credit ? 'texts.created_payment_and_credit' : 'texts.created_payment'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->to($payment->client->getRoute() . '#payments');
|
return redirect()->to($payment->client->getRoute() . '#payments');
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Requests\ProductRequest;
|
||||||
use App\Http\Requests\CreateProductRequest;
|
use App\Http\Requests\CreateProductRequest;
|
||||||
use App\Http\Requests\UpdateProductRequest;
|
use App\Http\Requests\UpdateProductRequest;
|
||||||
use App\Models\Product;
|
use App\Models\Product;
|
||||||
@ -37,11 +38,12 @@ class ProductApiController extends BaseAPIController
|
|||||||
/**
|
/**
|
||||||
* @SWG\Get(
|
* @SWG\Get(
|
||||||
* path="/products",
|
* path="/products",
|
||||||
* summary="List of products",
|
* summary="List products",
|
||||||
|
* operationId="listProducts",
|
||||||
* tags={"product"},
|
* tags={"product"},
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
* response=200,
|
* response=200,
|
||||||
* description="A list with products",
|
* description="A list of products",
|
||||||
* @SWG\Schema(type="array", @SWG\Items(ref="#/definitions/Product"))
|
* @SWG\Schema(type="array", @SWG\Items(ref="#/definitions/Product"))
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
@ -59,11 +61,40 @@ class ProductApiController extends BaseAPIController
|
|||||||
return $this->listResponse($products);
|
return $this->listResponse($products);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @SWG\Get(
|
||||||
|
* path="/products/{product_id}",
|
||||||
|
* summary="Retrieve a product",
|
||||||
|
* operationId="getProduct",
|
||||||
|
* tags={"product"},
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="path",
|
||||||
|
* name="product_id",
|
||||||
|
* type="integer",
|
||||||
|
* required=true
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="A single product",
|
||||||
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Product"))
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="an ""unexpected"" error"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function show(ProductRequest $request)
|
||||||
|
{
|
||||||
|
return $this->itemResponse($request->entity());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @SWG\Post(
|
* @SWG\Post(
|
||||||
* path="/products",
|
* path="/products",
|
||||||
* tags={"product"},
|
|
||||||
* summary="Create a product",
|
* summary="Create a product",
|
||||||
|
* operationId="createProduct",
|
||||||
|
* tags={"product"},
|
||||||
* @SWG\Parameter(
|
* @SWG\Parameter(
|
||||||
* in="body",
|
* in="body",
|
||||||
* name="body",
|
* name="body",
|
||||||
@ -90,16 +121,23 @@ class ProductApiController extends BaseAPIController
|
|||||||
/**
|
/**
|
||||||
* @SWG\Put(
|
* @SWG\Put(
|
||||||
* path="/products/{product_id}",
|
* path="/products/{product_id}",
|
||||||
* tags={"product"},
|
|
||||||
* summary="Update a product",
|
* summary="Update a product",
|
||||||
|
* operationId="updateProduct",
|
||||||
|
* tags={"product"},
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="path",
|
||||||
|
* name="product_id",
|
||||||
|
* type="integer",
|
||||||
|
* required=true
|
||||||
|
* ),
|
||||||
* @SWG\Parameter(
|
* @SWG\Parameter(
|
||||||
* in="body",
|
* in="body",
|
||||||
* name="body",
|
* name="product",
|
||||||
* @SWG\Schema(ref="#/definitions/Product")
|
* @SWG\Schema(ref="#/definitions/Product")
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
* response=200,
|
* response=200,
|
||||||
* description="Update product",
|
* description="Updated product",
|
||||||
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Product"))
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Product"))
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
@ -122,4 +160,36 @@ class ProductApiController extends BaseAPIController
|
|||||||
|
|
||||||
return $this->itemResponse($product);
|
return $this->itemResponse($product);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @SWG\Delete(
|
||||||
|
* path="/products/{product_id}",
|
||||||
|
* summary="Delete a product",
|
||||||
|
* operationId="deleteProduct",
|
||||||
|
* tags={"product"},
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="path",
|
||||||
|
* name="product_id",
|
||||||
|
* type="integer",
|
||||||
|
* required=true
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Deleted product",
|
||||||
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Product"))
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="an ""unexpected"" error"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function destroy(UpdateProductRequest $request)
|
||||||
|
{
|
||||||
|
$product = $request->entity();
|
||||||
|
|
||||||
|
$this->productRepo->delete($product);
|
||||||
|
|
||||||
|
return $this->itemResponse($product);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ namespace App\Http\Controllers;
|
|||||||
use App\Models\Product;
|
use App\Models\Product;
|
||||||
use App\Models\TaxRate;
|
use App\Models\TaxRate;
|
||||||
use App\Ninja\Datatables\ProductDatatable;
|
use App\Ninja\Datatables\ProductDatatable;
|
||||||
|
use App\Ninja\Repositories\ProductRepository;
|
||||||
use App\Services\ProductService;
|
use App\Services\ProductService;
|
||||||
use Auth;
|
use Auth;
|
||||||
use Input;
|
use Input;
|
||||||
@ -24,16 +25,22 @@ class ProductController extends BaseController
|
|||||||
*/
|
*/
|
||||||
protected $productService;
|
protected $productService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ProductRepository
|
||||||
|
*/
|
||||||
|
protected $productRepo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ProductController constructor.
|
* ProductController constructor.
|
||||||
*
|
*
|
||||||
* @param ProductService $productService
|
* @param ProductService $productService
|
||||||
*/
|
*/
|
||||||
public function __construct(ProductService $productService)
|
public function __construct(ProductService $productService, ProductRepository $productRepo)
|
||||||
{
|
{
|
||||||
//parent::__construct();
|
//parent::__construct();
|
||||||
|
|
||||||
$this->productService = $productService;
|
$this->productService = $productService;
|
||||||
|
$this->productRepo = $productRepo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -137,11 +144,7 @@ class ProductController extends BaseController
|
|||||||
$product = Product::createNew();
|
$product = Product::createNew();
|
||||||
}
|
}
|
||||||
|
|
||||||
$product->product_key = trim(Input::get('product_key'));
|
$this->productRepo->save(Input::all(), $product);
|
||||||
$product->notes = trim(Input::get('notes'));
|
|
||||||
$product->cost = trim(Input::get('cost'));
|
|
||||||
$product->fill(Input::all());
|
|
||||||
$product->save();
|
|
||||||
|
|
||||||
$message = $productPublicId ? trans('texts.updated_product') : trans('texts.created_product');
|
$message = $productPublicId ? trans('texts.updated_product') : trans('texts.created_product');
|
||||||
Session::flash('message', $message);
|
Session::flash('message', $message);
|
||||||
|
@ -6,7 +6,7 @@ use App\Models\Invoice;
|
|||||||
use App\Ninja\Repositories\InvoiceRepository;
|
use App\Ninja\Repositories\InvoiceRepository;
|
||||||
use Response;
|
use Response;
|
||||||
|
|
||||||
class QuoteApiController extends BaseAPIController
|
class QuoteApiController extends InvoiceAPIController
|
||||||
{
|
{
|
||||||
protected $invoiceRepo;
|
protected $invoiceRepo;
|
||||||
|
|
||||||
@ -19,22 +19,23 @@ class QuoteApiController extends BaseAPIController
|
|||||||
$this->invoiceRepo = $invoiceRepo;
|
$this->invoiceRepo = $invoiceRepo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @SWG\Get(
|
* @SWG\Get(
|
||||||
* path="/quotes",
|
* path="/quotes",
|
||||||
* tags={"quote"},
|
* summary="List quotes",
|
||||||
* summary="List of quotes",
|
* operationId="listQuotes",
|
||||||
* @SWG\Response(
|
* tags={"quote"},
|
||||||
* response=200,
|
* @SWG\Response(
|
||||||
* description="A list with quotes",
|
* response=200,
|
||||||
* @SWG\Schema(type="array", @SWG\Items(ref="#/definitions/Invoice"))
|
* description="A list of quotes",
|
||||||
* ),
|
* @SWG\Schema(type="array", @SWG\Items(ref="#/definitions/Invoice"))
|
||||||
* @SWG\Response(
|
* ),
|
||||||
* response="default",
|
* @SWG\Response(
|
||||||
* description="an ""unexpected"" error"
|
* response="default",
|
||||||
* )
|
* description="an ""unexpected"" error"
|
||||||
* )
|
* )
|
||||||
*/
|
* )
|
||||||
|
*/
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
$invoices = Invoice::scope()
|
$invoices = Invoice::scope()
|
||||||
|
@ -67,6 +67,7 @@ class ReportController extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
$reportTypes = [
|
$reportTypes = [
|
||||||
|
'activity',
|
||||||
'aging',
|
'aging',
|
||||||
'client',
|
'client',
|
||||||
'expense',
|
'expense',
|
||||||
@ -76,6 +77,7 @@ class ReportController extends BaseController
|
|||||||
'profit_and_loss',
|
'profit_and_loss',
|
||||||
'task',
|
'task',
|
||||||
'tax_rate',
|
'tax_rate',
|
||||||
|
'quote',
|
||||||
];
|
];
|
||||||
|
|
||||||
$params = [
|
$params = [
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Requests\TaskRequest;
|
||||||
use App\Http\Requests\UpdateTaskRequest;
|
use App\Http\Requests\UpdateTaskRequest;
|
||||||
use App\Models\Task;
|
use App\Models\Task;
|
||||||
use App\Ninja\Repositories\TaskRepository;
|
use App\Ninja\Repositories\TaskRepository;
|
||||||
@ -26,11 +27,12 @@ class TaskApiController extends BaseAPIController
|
|||||||
/**
|
/**
|
||||||
* @SWG\Get(
|
* @SWG\Get(
|
||||||
* path="/tasks",
|
* path="/tasks",
|
||||||
|
* summary="List tasks",
|
||||||
|
* operationId="listTasks",
|
||||||
* tags={"task"},
|
* tags={"task"},
|
||||||
* summary="List of tasks",
|
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
* response=200,
|
* response=200,
|
||||||
* description="A list with tasks",
|
* description="A list of tasks",
|
||||||
* @SWG\Schema(type="array", @SWG\Items(ref="#/definitions/Task"))
|
* @SWG\Schema(type="array", @SWG\Items(ref="#/definitions/Task"))
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
@ -49,14 +51,43 @@ class TaskApiController extends BaseAPIController
|
|||||||
return $this->listResponse($tasks);
|
return $this->listResponse($tasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @SWG\Get(
|
||||||
|
* path="/tasks/{task_id}",
|
||||||
|
* summary="Retrieve a task",
|
||||||
|
* operationId="getTask",
|
||||||
|
* tags={"task"},
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="path",
|
||||||
|
* name="task_id",
|
||||||
|
* type="integer",
|
||||||
|
* required=true
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="A single task",
|
||||||
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Task"))
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="an ""unexpected"" error"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function show(TaskRequest $request)
|
||||||
|
{
|
||||||
|
return $this->itemResponse($request->entity());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @SWG\Post(
|
* @SWG\Post(
|
||||||
* path="/tasks",
|
* path="/tasks",
|
||||||
* tags={"task"},
|
|
||||||
* summary="Create a task",
|
* summary="Create a task",
|
||||||
|
* operationId="createTask",
|
||||||
|
* tags={"task"},
|
||||||
* @SWG\Parameter(
|
* @SWG\Parameter(
|
||||||
* in="body",
|
* in="body",
|
||||||
* name="body",
|
* name="task",
|
||||||
* @SWG\Schema(ref="#/definitions/Task")
|
* @SWG\Schema(ref="#/definitions/Task")
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
@ -90,9 +121,16 @@ class TaskApiController extends BaseAPIController
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @SWG\Put(
|
* @SWG\Put(
|
||||||
* path="/task/{task_id}",
|
* path="/tasks/{task_id}",
|
||||||
* tags={"task"},
|
|
||||||
* summary="Update a task",
|
* summary="Update a task",
|
||||||
|
* operationId="updateTask",
|
||||||
|
* tags={"task"},
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="path",
|
||||||
|
* name="task_id",
|
||||||
|
* type="integer",
|
||||||
|
* required=true
|
||||||
|
* ),
|
||||||
* @SWG\Parameter(
|
* @SWG\Parameter(
|
||||||
* in="body",
|
* in="body",
|
||||||
* name="body",
|
* name="body",
|
||||||
@ -117,4 +155,36 @@ class TaskApiController extends BaseAPIController
|
|||||||
|
|
||||||
return $this->itemResponse($task);
|
return $this->itemResponse($task);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @SWG\Delete(
|
||||||
|
* path="/tasks/{task_id}",
|
||||||
|
* summary="Delete a task",
|
||||||
|
* operationId="deleteTask",
|
||||||
|
* tags={"task"},
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="path",
|
||||||
|
* name="task_id",
|
||||||
|
* type="integer",
|
||||||
|
* required=true
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Deleted task",
|
||||||
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Task"))
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="an ""unexpected"" error"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function destroy(UpdateTaskRequest $request)
|
||||||
|
{
|
||||||
|
$task = $request->entity();
|
||||||
|
|
||||||
|
$this->taskRepo->delete($task);
|
||||||
|
|
||||||
|
return $this->itemResponse($task);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,7 @@ class TaskController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function store(CreateTaskRequest $request)
|
public function store(CreateTaskRequest $request)
|
||||||
{
|
{
|
||||||
return $this->save();
|
return $this->save($request);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -202,7 +202,7 @@ class TaskController extends BaseController
|
|||||||
{
|
{
|
||||||
$task = $request->entity();
|
$task = $request->entity();
|
||||||
|
|
||||||
return $this->save($task->public_id);
|
return $this->save($request, $task->public_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -222,7 +222,7 @@ class TaskController extends BaseController
|
|||||||
*
|
*
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
private function save($publicId = null)
|
private function save($request, $publicId = null)
|
||||||
{
|
{
|
||||||
$action = Input::get('action');
|
$action = Input::get('action');
|
||||||
|
|
||||||
@ -230,7 +230,7 @@ class TaskController extends BaseController
|
|||||||
return self::bulk();
|
return self::bulk();
|
||||||
}
|
}
|
||||||
|
|
||||||
$task = $this->taskRepo->save($publicId, Input::all());
|
$task = $this->taskRepo->save($publicId, $request->input());
|
||||||
|
|
||||||
if ($publicId) {
|
if ($publicId) {
|
||||||
Session::flash('message', trans('texts.updated_task'));
|
Session::flash('message', trans('texts.updated_task'));
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Requests\TaxRateRequest;
|
||||||
use App\Http\Requests\CreateTaxRateRequest;
|
use App\Http\Requests\CreateTaxRateRequest;
|
||||||
use App\Http\Requests\UpdateTaxRateRequest;
|
use App\Http\Requests\UpdateTaxRateRequest;
|
||||||
use App\Models\TaxRate;
|
use App\Models\TaxRate;
|
||||||
@ -34,11 +35,12 @@ class TaxRateApiController extends BaseAPIController
|
|||||||
/**
|
/**
|
||||||
* @SWG\Get(
|
* @SWG\Get(
|
||||||
* path="/tax_rates",
|
* path="/tax_rates",
|
||||||
* summary="List of tax rates",
|
* summary="List tax rates",
|
||||||
|
* operationId="listTaxRates",
|
||||||
* tags={"tax_rate"},
|
* tags={"tax_rate"},
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
* response=200,
|
* response=200,
|
||||||
* description="A list with tax rates",
|
* description="A list of tax rates",
|
||||||
* @SWG\Schema(type="array", @SWG\Items(ref="#/definitions/TaxRate"))
|
* @SWG\Schema(type="array", @SWG\Items(ref="#/definitions/TaxRate"))
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
@ -56,14 +58,43 @@ class TaxRateApiController extends BaseAPIController
|
|||||||
return $this->listResponse($taxRates);
|
return $this->listResponse($taxRates);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @SWG\Get(
|
||||||
|
* path="/tax_rates/{tax_rate_id}",
|
||||||
|
* summary="Retrieve a tax rate",
|
||||||
|
* operationId="getTaxRate",
|
||||||
|
* tags={"tax_rate"},
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="path",
|
||||||
|
* name="tax_rate_id",
|
||||||
|
* type="integer",
|
||||||
|
* required=true
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="A single tax rate",
|
||||||
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/TaxRate"))
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="an ""unexpected"" error"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function show(TaxRateRequest $request)
|
||||||
|
{
|
||||||
|
return $this->itemResponse($request->entity());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @SWG\Post(
|
* @SWG\Post(
|
||||||
* path="/tax_rates",
|
* path="/tax_rates",
|
||||||
* tags={"tax_rate"},
|
|
||||||
* summary="Create a tax rate",
|
* summary="Create a tax rate",
|
||||||
|
* operationId="createTaxRate",
|
||||||
|
* tags={"tax_rate"},
|
||||||
* @SWG\Parameter(
|
* @SWG\Parameter(
|
||||||
* in="body",
|
* in="body",
|
||||||
* name="body",
|
* name="tax_rate",
|
||||||
* @SWG\Schema(ref="#/definitions/TaxRate")
|
* @SWG\Schema(ref="#/definitions/TaxRate")
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
@ -87,16 +118,23 @@ class TaxRateApiController extends BaseAPIController
|
|||||||
/**
|
/**
|
||||||
* @SWG\Put(
|
* @SWG\Put(
|
||||||
* path="/tax_rates/{tax_rate_id}",
|
* path="/tax_rates/{tax_rate_id}",
|
||||||
* tags={"tax_rate"},
|
|
||||||
* summary="Update a tax rate",
|
* summary="Update a tax rate",
|
||||||
|
* operationId="updateTaxRate",
|
||||||
|
* tags={"tax_rate"},
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="path",
|
||||||
|
* name="tax_rate_id",
|
||||||
|
* type="integer",
|
||||||
|
* required=true
|
||||||
|
* ),
|
||||||
* @SWG\Parameter(
|
* @SWG\Parameter(
|
||||||
* in="body",
|
* in="body",
|
||||||
* name="body",
|
* name="tax_rate",
|
||||||
* @SWG\Schema(ref="#/definitions/TaxRate")
|
* @SWG\Schema(ref="#/definitions/TaxRate")
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
* response=200,
|
* response=200,
|
||||||
* description="Update tax rate",
|
* description="Updated tax rate",
|
||||||
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/TaxRate"))
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/TaxRate"))
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
@ -119,4 +157,36 @@ class TaxRateApiController extends BaseAPIController
|
|||||||
|
|
||||||
return $this->itemResponse($taxRate);
|
return $this->itemResponse($taxRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @SWG\Delete(
|
||||||
|
* path="/tax_rates/{tax_rate_id}",
|
||||||
|
* summary="Delete a tax rate",
|
||||||
|
* operationId="deleteTaxRate",
|
||||||
|
* tags={"tax_rate"},
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="path",
|
||||||
|
* name="tax_rate_id",
|
||||||
|
* type="integer",
|
||||||
|
* required=true
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Deleted tax rate",
|
||||||
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/TaxRate"))
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="an ""unexpected"" error"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function destroy(UpdateTaxRateRequest $request)
|
||||||
|
{
|
||||||
|
$entity = $request->entity();
|
||||||
|
|
||||||
|
$this->taxRateRepo->delete($entity);
|
||||||
|
|
||||||
|
return $this->itemResponse($entity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -145,7 +145,7 @@ class TokenController extends BaseController
|
|||||||
} else {
|
} else {
|
||||||
$token = AccountToken::createNew();
|
$token = AccountToken::createNew();
|
||||||
$token->name = trim(Input::get('name'));
|
$token->name = trim(Input::get('name'));
|
||||||
$token->token = str_random(RANDOM_KEY_LENGTH);
|
$token->token = strtolower(str_random(RANDOM_KEY_LENGTH));
|
||||||
}
|
}
|
||||||
|
|
||||||
$token->save();
|
$token->save();
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Requests\UserRequest;
|
||||||
use App\Http\Requests\CreateUserRequest;
|
use App\Http\Requests\CreateUserRequest;
|
||||||
use App\Http\Requests\UpdateUserRequest;
|
use App\Http\Requests\UpdateUserRequest;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
@ -25,22 +26,117 @@ class UserApiController extends BaseAPIController
|
|||||||
$this->userRepo = $userRepo;
|
$this->userRepo = $userRepo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @SWG\Get(
|
||||||
|
* path="/users",
|
||||||
|
* summary="List users",
|
||||||
|
* operationId="listUsers",
|
||||||
|
* tags={"user"},
|
||||||
|
* @SWG\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="A list of users",
|
||||||
|
* @SWG\Schema(type="array", @SWG\Items(ref="#/definitions/User"))
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="an ""unexpected"" error"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
$users = User::whereAccountId(Auth::user()->account_id)
|
$users = User::whereAccountId(Auth::user()->account_id)
|
||||||
->withTrashed()
|
->withTrashed()
|
||||||
->orderBy('created_at', 'desc');
|
->orderBy('created_at', 'desc');
|
||||||
|
|
||||||
return $this->listResponse($users);
|
return $this->listResponse($users);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|
* @SWG\Get(
|
||||||
|
* path="/users/{user_id}",
|
||||||
|
* summary="Retrieve a user",
|
||||||
|
* operationId="getUser",
|
||||||
|
* tags={"client"},
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="path",
|
||||||
|
* name="user_id",
|
||||||
|
* type="integer",
|
||||||
|
* required=true
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="A single user",
|
||||||
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/User"))
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="an ""unexpected"" error"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function show(UserRequest $request)
|
||||||
|
{
|
||||||
|
return $this->itemResponse($request->entity());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @SWG\Post(
|
||||||
|
* path="/users",
|
||||||
|
* summary="Create a user",
|
||||||
|
* operationId="createUser",
|
||||||
|
* tags={"user"},
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="body",
|
||||||
|
* name="user",
|
||||||
|
* @SWG\Schema(ref="#/definitions/User")
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="New user",
|
||||||
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/User"))
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="an ""unexpected"" error"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
public function store(CreateUserRequest $request)
|
public function store(CreateUserRequest $request)
|
||||||
{
|
{
|
||||||
return $this->save($request);
|
return $this->save($request);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @SWG\Put(
|
||||||
|
* path="/users/{user_id}",
|
||||||
|
* summary="Update a user",
|
||||||
|
* operationId="updateUser",
|
||||||
|
* tags={"user"},
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="path",
|
||||||
|
* name="user_id",
|
||||||
|
* type="integer",
|
||||||
|
* required=true
|
||||||
|
* ),
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="body",
|
||||||
|
* name="user",
|
||||||
|
* @SWG\Schema(ref="#/definitions/User")
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Updated user",
|
||||||
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/User"))
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="an ""unexpected"" error"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*
|
||||||
|
* @param mixed $userPublicId
|
||||||
|
*/
|
||||||
public function update(UpdateUserRequest $request, $userPublicId)
|
public function update(UpdateUserRequest $request, $userPublicId)
|
||||||
{
|
{
|
||||||
$user = Auth::user();
|
$user = Auth::user();
|
||||||
@ -66,4 +162,36 @@ class UserApiController extends BaseAPIController
|
|||||||
|
|
||||||
return $this->response($data);
|
return $this->response($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @SWG\Delete(
|
||||||
|
* path="/users/{user_id}",
|
||||||
|
* summary="Delete a user",
|
||||||
|
* operationId="deleteUser",
|
||||||
|
* tags={"user"},
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="path",
|
||||||
|
* name="user_id",
|
||||||
|
* type="integer",
|
||||||
|
* required=true
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Deleted user",
|
||||||
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/User"))
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="an ""unexpected"" error"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function destroy(UpdateUserRequest $request)
|
||||||
|
{
|
||||||
|
$entity = $request->entity();
|
||||||
|
|
||||||
|
$this->userRepo->delete($entity);
|
||||||
|
|
||||||
|
return $this->itemResponse($entity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -199,8 +199,8 @@ class UserController extends BaseController
|
|||||||
$user->username = trim(Input::get('email'));
|
$user->username = trim(Input::get('email'));
|
||||||
$user->email = trim(Input::get('email'));
|
$user->email = trim(Input::get('email'));
|
||||||
$user->registered = true;
|
$user->registered = true;
|
||||||
$user->password = str_random(RANDOM_KEY_LENGTH);
|
$user->password = strtolower(str_random(RANDOM_KEY_LENGTH));
|
||||||
$user->confirmation_code = str_random(RANDOM_KEY_LENGTH);
|
$user->confirmation_code = strtolower(str_random(RANDOM_KEY_LENGTH));
|
||||||
$user->public_id = $lastUser->public_id + 1;
|
$user->public_id = $lastUser->public_id + 1;
|
||||||
if (Auth::user()->hasFeature(FEATURE_USER_PERMISSIONS)) {
|
if (Auth::user()->hasFeature(FEATURE_USER_PERMISSIONS)) {
|
||||||
$user->is_admin = boolval(Input::get('is_admin'));
|
$user->is_admin = boolval(Input::get('is_admin'));
|
||||||
@ -210,7 +210,7 @@ class UserController extends BaseController
|
|||||||
|
|
||||||
$user->save();
|
$user->save();
|
||||||
|
|
||||||
if (! $user->confirmed) {
|
if (! $user->confirmed && Input::get('action') === 'email') {
|
||||||
$this->userMailer->sendConfirmation($user, Auth::user());
|
$this->userMailer->sendConfirmation($user, Auth::user());
|
||||||
$message = trans('texts.sent_invite');
|
$message = trans('texts.sent_invite');
|
||||||
} else {
|
} else {
|
||||||
|
@ -2,10 +2,9 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
// vendor
|
use App\Http\Requests\VendorRequest;
|
||||||
use App\Http\Requests\CreateVendorRequest;
|
use App\Http\Requests\CreateVendorRequest;
|
||||||
use App\Http\Requests\UpdateVendorRequest;
|
use App\Http\Requests\UpdateVendorRequest;
|
||||||
use App\Http\Requests\VendorRequest;
|
|
||||||
use App\Models\Vendor;
|
use App\Models\Vendor;
|
||||||
use App\Ninja\Repositories\VendorRepository;
|
use App\Ninja\Repositories\VendorRepository;
|
||||||
use Input;
|
use Input;
|
||||||
@ -35,11 +34,12 @@ class VendorApiController extends BaseAPIController
|
|||||||
/**
|
/**
|
||||||
* @SWG\Get(
|
* @SWG\Get(
|
||||||
* path="/vendors",
|
* path="/vendors",
|
||||||
* summary="List of vendors",
|
* summary="List vendors",
|
||||||
|
* operationId="listVendors",
|
||||||
* tags={"vendor"},
|
* tags={"vendor"},
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
* response=200,
|
* response=200,
|
||||||
* description="A list with vendors",
|
* description="A list of vendors",
|
||||||
* @SWG\Schema(type="array", @SWG\Items(ref="#/definitions/Vendor"))
|
* @SWG\Schema(type="array", @SWG\Items(ref="#/definitions/Vendor"))
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
@ -57,14 +57,43 @@ class VendorApiController extends BaseAPIController
|
|||||||
return $this->listResponse($vendors);
|
return $this->listResponse($vendors);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @SWG\Get(
|
||||||
|
* path="/vendors/{vendor_id}",
|
||||||
|
* summary="Retrieve a vendor",
|
||||||
|
* operationId="getVendor",
|
||||||
|
* tags={"client"},
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="path",
|
||||||
|
* name="vendor_id",
|
||||||
|
* type="integer",
|
||||||
|
* required=true
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="A single vendor",
|
||||||
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Vendor"))
|
||||||
|
* ),
|
||||||
|
* @SWG\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="an ""unexpected"" error"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function show(VendorRequest $request)
|
||||||
|
{
|
||||||
|
return $this->itemResponse($request->entity());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @SWG\Post(
|
* @SWG\Post(
|
||||||
* path="/vendors",
|
* path="/vendors",
|
||||||
* tags={"vendor"},
|
|
||||||
* summary="Create a vendor",
|
* summary="Create a vendor",
|
||||||
|
* operationId="createVendor",
|
||||||
|
* tags={"vendor"},
|
||||||
* @SWG\Parameter(
|
* @SWG\Parameter(
|
||||||
* in="body",
|
* in="body",
|
||||||
* name="body",
|
* name="vendor",
|
||||||
* @SWG\Schema(ref="#/definitions/Vendor")
|
* @SWG\Schema(ref="#/definitions/Vendor")
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
@ -92,16 +121,23 @@ class VendorApiController extends BaseAPIController
|
|||||||
/**
|
/**
|
||||||
* @SWG\Put(
|
* @SWG\Put(
|
||||||
* path="/vendors/{vendor_id}",
|
* path="/vendors/{vendor_id}",
|
||||||
* tags={"vendor"},
|
|
||||||
* summary="Update a vendor",
|
* summary="Update a vendor",
|
||||||
|
* operationId="updateVendor",
|
||||||
|
* tags={"vendor"},
|
||||||
|
* @SWG\Parameter(
|
||||||
|
* in="path",
|
||||||
|
* name="vendor_id",
|
||||||
|
* type="integer",
|
||||||
|
* required=true
|
||||||
|
* ),
|
||||||
* @SWG\Parameter(
|
* @SWG\Parameter(
|
||||||
* in="body",
|
* in="body",
|
||||||
* name="body",
|
* name="vendor",
|
||||||
* @SWG\Schema(ref="#/definitions/Vendor")
|
* @SWG\Schema(ref="#/definitions/Vendor")
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
* response=200,
|
* response=200,
|
||||||
* description="Update vendor",
|
* description="Updated vendor",
|
||||||
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Vendor"))
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Vendor"))
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
@ -130,16 +166,18 @@ class VendorApiController extends BaseAPIController
|
|||||||
/**
|
/**
|
||||||
* @SWG\Delete(
|
* @SWG\Delete(
|
||||||
* path="/vendors/{vendor_id}",
|
* path="/vendors/{vendor_id}",
|
||||||
* tags={"vendor"},
|
|
||||||
* summary="Delete a vendor",
|
* summary="Delete a vendor",
|
||||||
|
* operationId="deleteVendor",
|
||||||
|
* tags={"vendor"},
|
||||||
* @SWG\Parameter(
|
* @SWG\Parameter(
|
||||||
* in="body",
|
* in="path",
|
||||||
* name="body",
|
* name="vendor_id",
|
||||||
* @SWG\Schema(ref="#/definitions/Vendor")
|
* type="integer",
|
||||||
|
* required=true
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
* response=200,
|
* response=200,
|
||||||
* description="Delete vendor",
|
* description="Deleted vendor",
|
||||||
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Vendor"))
|
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Vendor"))
|
||||||
* ),
|
* ),
|
||||||
* @SWG\Response(
|
* @SWG\Response(
|
||||||
@ -148,7 +186,7 @@ class VendorApiController extends BaseAPIController
|
|||||||
* )
|
* )
|
||||||
* )
|
* )
|
||||||
*/
|
*/
|
||||||
public function destroy(VendorRequest $request)
|
public function destroy(UpdateVendorRequest $request)
|
||||||
{
|
{
|
||||||
$vendor = $request->entity();
|
$vendor = $request->entity();
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Http;
|
namespace App\Http;
|
||||||
|
|
||||||
|
|
||||||
use Illuminate\Foundation\Http\Kernel as HttpKernel;
|
use Illuminate\Foundation\Http\Kernel as HttpKernel;
|
||||||
|
|
||||||
class Kernel extends HttpKernel
|
class Kernel extends HttpKernel
|
||||||
@ -34,6 +34,6 @@ class Kernel extends HttpKernel
|
|||||||
'permissions.required' => 'App\Http\Middleware\PermissionsRequired',
|
'permissions.required' => 'App\Http\Middleware\PermissionsRequired',
|
||||||
'guest' => 'App\Http\Middleware\RedirectIfAuthenticated',
|
'guest' => 'App\Http\Middleware\RedirectIfAuthenticated',
|
||||||
'api' => 'App\Http\Middleware\ApiCheck',
|
'api' => 'App\Http\Middleware\ApiCheck',
|
||||||
'cors' => '\App\Http\Middleware\Cors',
|
'cors' => '\Barryvdh\Cors\HandleCors',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -56,12 +56,14 @@ class Authenticate
|
|||||||
$contact_key = session('contact_key');
|
$contact_key = session('contact_key');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$contact = false;
|
||||||
if ($contact_key) {
|
if ($contact_key) {
|
||||||
$contact = $this->getContact($contact_key);
|
$contact = $this->getContact($contact_key);
|
||||||
} elseif ($invitation = $this->getInvitation($request->invitation_key)) {
|
} elseif ($invitation = $this->getInvitation($request->invitation_key)) {
|
||||||
$contact = $invitation->contact;
|
$contact = $invitation->contact;
|
||||||
Session::put('contact_key', $contact->contact_key);
|
Session::put('contact_key', $contact->contact_key);
|
||||||
} else {
|
}
|
||||||
|
if (! $contact) {
|
||||||
return \Redirect::to('client/sessionexpired');
|
return \Redirect::to('client/sessionexpired');
|
||||||
}
|
}
|
||||||
$account = $contact->account;
|
$account = $contact->account;
|
||||||
@ -113,6 +115,7 @@ class Authenticate
|
|||||||
|
|
||||||
// check for extra params at end of value (from website feature)
|
// check for extra params at end of value (from website feature)
|
||||||
list($key) = explode('&', $key);
|
list($key) = explode('&', $key);
|
||||||
|
$key = substr($key, 0, RANDOM_KEY_LENGTH);
|
||||||
|
|
||||||
$invitation = Invitation::withTrashed()->where('invitation_key', '=', $key)->first();
|
$invitation = Invitation::withTrashed()->where('invitation_key', '=', $key)->first();
|
||||||
if ($invitation && ! $invitation->is_deleted) {
|
if ($invitation && ! $invitation->is_deleted) {
|
||||||
|
8
app/Http/Requests/ContactRequest.php
Normal file
8
app/Http/Requests/ContactRequest.php
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
class ContactRequest extends EntityRequest
|
||||||
|
{
|
||||||
|
protected $entityType = ENTITY_CONTACT;
|
||||||
|
}
|
31
app/Http/Requests/CreateContactRequest.php
Normal file
31
app/Http/Requests/CreateContactRequest.php
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
class CreateContactRequest extends ContactRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize()
|
||||||
|
{
|
||||||
|
return $this->user()->can('create', ENTITY_CONTACT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'first_name' => 'required',
|
||||||
|
'last_name' => 'required',
|
||||||
|
'email' => 'required',
|
||||||
|
'client_id' => 'required',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -26,7 +26,7 @@ class CreatePaymentAPIRequest extends PaymentRequest
|
|||||||
if (! $this->invoice_id || ! $this->amount) {
|
if (! $this->invoice_id || ! $this->amount) {
|
||||||
return [
|
return [
|
||||||
'invoice_id' => 'required|numeric|min:1',
|
'invoice_id' => 'required|numeric|min:1',
|
||||||
'amount' => 'required|numeric|min:0.01',
|
'amount' => 'required|numeric|not_in:0',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,10 +28,15 @@ class CreatePaymentRequest extends PaymentRequest
|
|||||||
->invoices()
|
->invoices()
|
||||||
->firstOrFail();
|
->firstOrFail();
|
||||||
|
|
||||||
|
$this->merge([
|
||||||
|
'invoice_id' => $invoice->id,
|
||||||
|
'client_id' => $invoice->client->id,
|
||||||
|
]);
|
||||||
|
|
||||||
$rules = [
|
$rules = [
|
||||||
'client' => 'required', // TODO: change to client_id once views are updated
|
'client' => 'required', // TODO: change to client_id once views are updated
|
||||||
'invoice' => 'required', // TODO: change to invoice_id once views are updated
|
'invoice' => 'required', // TODO: change to invoice_id once views are updated
|
||||||
'amount' => "required|numeric|between:0.01,{$invoice->balance}",
|
'amount' => 'required|numeric|not_in:0',
|
||||||
'payment_date' => 'required',
|
'payment_date' => 'required',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
namespace App\Http\Requests;
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
use App\Models\ExpenseCategory;
|
use App\Models\ExpenseCategory;
|
||||||
|
use App\Models\Vendor;
|
||||||
|
|
||||||
class ExpenseRequest extends EntityRequest
|
class ExpenseRequest extends EntityRequest
|
||||||
{
|
{
|
||||||
@ -24,11 +25,37 @@ class ExpenseRequest extends EntityRequest
|
|||||||
{
|
{
|
||||||
$input = $this->all();
|
$input = $this->all();
|
||||||
|
|
||||||
if ($this->expense_category_id) {
|
// check if we're creating a new expense category
|
||||||
|
if ($this->expense_category_id == '-1') {
|
||||||
|
$data = [
|
||||||
|
'name' => trim($this->expense_category_name)
|
||||||
|
];
|
||||||
|
if (ExpenseCategory::validate($data) === true) {
|
||||||
|
$category = app('App\Ninja\Repositories\ExpenseCategoryRepository')->save($data);
|
||||||
|
$input['expense_category_id'] = $category->id;
|
||||||
|
} else {
|
||||||
|
$input['expense_category_id'] = null;
|
||||||
|
}
|
||||||
|
} elseif ($this->expense_category_id) {
|
||||||
$input['expense_category_id'] = ExpenseCategory::getPrivateId($this->expense_category_id);
|
$input['expense_category_id'] = ExpenseCategory::getPrivateId($this->expense_category_id);
|
||||||
$this->replace($input);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check if we're creating a new vendor
|
||||||
|
if ($this->vendor_id == '-1') {
|
||||||
|
$data = [
|
||||||
|
'name' => trim($this->vendor_name)
|
||||||
|
];
|
||||||
|
if (Vendor::validate($data) === true) {
|
||||||
|
$vendor = app('App\Ninja\Repositories\VendorRepository')->save($data);
|
||||||
|
// TODO change to private id once service is refactored
|
||||||
|
$input['vendor_id'] = $vendor->public_id;
|
||||||
|
} else {
|
||||||
|
$input['vendor_id'] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->replace($input);
|
||||||
|
|
||||||
return $this->all();
|
return $this->all();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ class SaveClientPortalSettings extends Request
|
|||||||
$input['subdomain'] = null;
|
$input['subdomain'] = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->replace($input);
|
$this->replace($input);
|
||||||
|
|
||||||
return $this->all();
|
return $this->all();
|
||||||
|
@ -23,6 +23,7 @@ class SaveEmailSettings extends Request
|
|||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'bcc_email' => 'email',
|
'bcc_email' => 'email',
|
||||||
|
'reply_to_email' => 'email',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,33 @@
|
|||||||
|
|
||||||
namespace App\Http\Requests;
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use App\Models\Client;
|
||||||
|
use App\Models\Project;
|
||||||
|
|
||||||
class TaskRequest extends EntityRequest
|
class TaskRequest extends EntityRequest
|
||||||
{
|
{
|
||||||
protected $entityType = ENTITY_TASK;
|
protected $entityType = ENTITY_TASK;
|
||||||
|
|
||||||
|
public function sanitize()
|
||||||
|
{
|
||||||
|
$input = $this->all();
|
||||||
|
|
||||||
|
// check if we're creating a new project
|
||||||
|
if ($this->project_id == '-1') {
|
||||||
|
$project = [
|
||||||
|
'name' => trim($this->project_name),
|
||||||
|
'client_id' => Client::getPrivateId($this->client),
|
||||||
|
];
|
||||||
|
if (Project::validate($project) === true) {
|
||||||
|
$project = app('App\Ninja\Repositories\ProjectRepository')->save($project);
|
||||||
|
$input['project_id'] = $project->public_id;
|
||||||
|
} else {
|
||||||
|
$input['project_id'] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->replace($input);
|
||||||
|
|
||||||
|
return $this->all();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
30
app/Http/Requests/UpdateContactRequest.php
Normal file
30
app/Http/Requests/UpdateContactRequest.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
class UpdateContactRequest extends ContactRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize()
|
||||||
|
{
|
||||||
|
return $this->user()->can('edit', $this->entity());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'first_name' => 'required',
|
||||||
|
'last_name' => 'required',
|
||||||
|
'email' => 'required',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
8
app/Http/Requests/UserRequest.php
Normal file
8
app/Http/Requests/UserRequest.php
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
class UserRequest extends EntityRequest
|
||||||
|
{
|
||||||
|
protected $entityType = ENTITY_USER;
|
||||||
|
}
|
@ -113,6 +113,10 @@ if (Utils::isReseller()) {
|
|||||||
Route::post('/reseller_stats', 'AppController@stats');
|
Route::post('/reseller_stats', 'AppController@stats');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Utils::isTravis()) {
|
||||||
|
Route::get('/check_data', 'AppController@checkData');
|
||||||
|
}
|
||||||
|
|
||||||
Route::group(['middleware' => 'auth:user'], function () {
|
Route::group(['middleware' => 'auth:user'], function () {
|
||||||
Route::get('dashboard', 'DashboardController@index');
|
Route::get('dashboard', 'DashboardController@index');
|
||||||
Route::get('dashboard_chart_data/{group_by}/{start_date}/{end_date}/{currency_id}/{include_expenses}', 'DashboardController@chartData');
|
Route::get('dashboard_chart_data/{group_by}/{start_date}/{end_date}/{currency_id}/{include_expenses}', 'DashboardController@chartData');
|
||||||
@ -126,7 +130,7 @@ Route::group(['middleware' => 'auth:user'], function () {
|
|||||||
|
|
||||||
Route::get('settings/user_details', 'AccountController@showUserDetails');
|
Route::get('settings/user_details', 'AccountController@showUserDetails');
|
||||||
Route::post('settings/user_details', 'AccountController@saveUserDetails');
|
Route::post('settings/user_details', 'AccountController@saveUserDetails');
|
||||||
Route::post('settings/payment_gateway_limits', 'AccountController@savePaymentGatewayLimits');
|
Route::post('settings/payment_gateway_limits', 'AccountGatewayController@savePaymentGatewayLimits');
|
||||||
Route::post('users/change_password', 'UserController@changePassword');
|
Route::post('users/change_password', 'UserController@changePassword');
|
||||||
|
|
||||||
Route::resource('clients', 'ClientController');
|
Route::resource('clients', 'ClientController');
|
||||||
@ -253,6 +257,7 @@ Route::group([
|
|||||||
|
|
||||||
Route::post('settings/change_plan', 'AccountController@changePlan');
|
Route::post('settings/change_plan', 'AccountController@changePlan');
|
||||||
Route::post('settings/cancel_account', 'AccountController@cancelAccount');
|
Route::post('settings/cancel_account', 'AccountController@cancelAccount');
|
||||||
|
Route::post('settings/purge_data', 'AccountController@purgeData');
|
||||||
Route::post('settings/company_details', 'AccountController@updateDetails');
|
Route::post('settings/company_details', 'AccountController@updateDetails');
|
||||||
Route::post('settings/{section?}', 'AccountController@doSection');
|
Route::post('settings/{section?}', 'AccountController@doSection');
|
||||||
|
|
||||||
@ -303,12 +308,11 @@ Route::group(['middleware' => 'api', 'prefix' => 'api/v1'], function () {
|
|||||||
Route::get('accounts', 'AccountApiController@show');
|
Route::get('accounts', 'AccountApiController@show');
|
||||||
Route::put('accounts', 'AccountApiController@update');
|
Route::put('accounts', 'AccountApiController@update');
|
||||||
Route::resource('clients', 'ClientApiController');
|
Route::resource('clients', 'ClientApiController');
|
||||||
|
Route::resource('contacts', 'ContactApiController');
|
||||||
Route::get('quotes', 'QuoteApiController@index');
|
Route::get('quotes', 'QuoteApiController@index');
|
||||||
Route::get('invoices', 'InvoiceApiController@index');
|
|
||||||
Route::get('download/{invoice_id}', 'InvoiceApiController@download');
|
Route::get('download/{invoice_id}', 'InvoiceApiController@download');
|
||||||
Route::resource('invoices', 'InvoiceApiController');
|
Route::resource('invoices', 'InvoiceApiController');
|
||||||
Route::resource('payments', 'PaymentApiController');
|
Route::resource('payments', 'PaymentApiController');
|
||||||
Route::get('tasks', 'TaskApiController@index');
|
|
||||||
Route::resource('tasks', 'TaskApiController');
|
Route::resource('tasks', 'TaskApiController');
|
||||||
Route::post('hooks', 'IntegrationController@subscribe');
|
Route::post('hooks', 'IntegrationController@subscribe');
|
||||||
Route::post('email_invoice', 'InvoiceApiController@emailInvoice');
|
Route::post('email_invoice', 'InvoiceApiController@emailInvoice');
|
||||||
@ -359,6 +363,9 @@ Route::get('/feed', function () {
|
|||||||
Route::get('/comments/feed', function () {
|
Route::get('/comments/feed', function () {
|
||||||
return Redirect::to(NINJA_WEB_URL.'/comments/feed', 301);
|
return Redirect::to(NINJA_WEB_URL.'/comments/feed', 301);
|
||||||
});
|
});
|
||||||
|
Route::get('/terms', function () {
|
||||||
|
return Redirect::to(NINJA_WEB_URL.'/terms', 301);
|
||||||
|
});
|
||||||
|
|
||||||
/*
|
/*
|
||||||
if (Utils::isNinjaDev())
|
if (Utils::isNinjaDev())
|
||||||
|
80
app/Jobs/ImportData.php
Normal file
80
app/Jobs/ImportData.php
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Monolog\Logger;
|
||||||
|
use App\Services\ImportService;
|
||||||
|
use App\Ninja\Mailers\UserMailer;
|
||||||
|
use Auth;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class SendInvoiceEmail.
|
||||||
|
*/
|
||||||
|
class ImportData extends Job implements ShouldQueue
|
||||||
|
{
|
||||||
|
use InteractsWithQueue, SerializesModels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var User
|
||||||
|
*/
|
||||||
|
protected $user;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $settings;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*
|
||||||
|
* @param mixed $files
|
||||||
|
* @param mixed $settings
|
||||||
|
*/
|
||||||
|
public function __construct($user, $type, $settings)
|
||||||
|
{
|
||||||
|
$this->user = $user;
|
||||||
|
$this->type = $type;
|
||||||
|
$this->settings = $settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the job.
|
||||||
|
*
|
||||||
|
* @param ContactMailer $mailer
|
||||||
|
*/
|
||||||
|
public function handle(ImportService $importService, UserMailer $userMailer)
|
||||||
|
{
|
||||||
|
$includeSettings = false;
|
||||||
|
|
||||||
|
Auth::onceUsingId($this->user->id);
|
||||||
|
$this->user->account->loadLocalizationSettings();
|
||||||
|
|
||||||
|
if ($this->type === IMPORT_JSON) {
|
||||||
|
$includeData = $this->settings['include_data'];
|
||||||
|
$includeSettings = $this->settings['include_settings'];
|
||||||
|
$files = $this->settings['files'];
|
||||||
|
$results = $importService->importJSON($files[IMPORT_JSON], $includeData, $includeSettings);
|
||||||
|
} elseif ($this->type === IMPORT_CSV) {
|
||||||
|
$map = $this->settings['map'];
|
||||||
|
$headers = $this->settings['headers'];
|
||||||
|
$timestamp = $this->settings['timestamp'];
|
||||||
|
$results = $importService->importCSV($map, $headers, $timestamp);
|
||||||
|
} else {
|
||||||
|
$source = $this->settings['source'];
|
||||||
|
$files = $this->settings['files'];
|
||||||
|
$results = $importService->importFiles($source, $files);
|
||||||
|
}
|
||||||
|
|
||||||
|
$subject = trans('texts.import_complete');
|
||||||
|
$message = $importService->presentResults($results, $includeSettings);
|
||||||
|
$userMailer->sendMessage($this->user, $subject, $message);
|
||||||
|
}
|
||||||
|
}
|
61
app/Jobs/PurgeAccountData.php
Normal file
61
app/Jobs/PurgeAccountData.php
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
use App\Jobs\Job;
|
||||||
|
use App\Models\Document;
|
||||||
|
use Auth;
|
||||||
|
use DB;
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
class PurgeAccountData extends Job
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Execute the job.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$user = Auth::user();
|
||||||
|
$account = $user->account;
|
||||||
|
|
||||||
|
if (! $user->is_admin) {
|
||||||
|
throw new Exception(trans('texts.forbidden'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete the documents from cloud storage
|
||||||
|
Document::scope()->each(function ($item, $key) {
|
||||||
|
$item->delete();
|
||||||
|
});
|
||||||
|
|
||||||
|
$tables = [
|
||||||
|
'activities',
|
||||||
|
'invitations',
|
||||||
|
'account_gateway_tokens',
|
||||||
|
'payment_methods',
|
||||||
|
'credits',
|
||||||
|
'expense_categories',
|
||||||
|
'expenses',
|
||||||
|
'invoice_items',
|
||||||
|
'payments',
|
||||||
|
'invoices',
|
||||||
|
'tasks',
|
||||||
|
'projects',
|
||||||
|
'products',
|
||||||
|
'vendor_contacts',
|
||||||
|
'vendors',
|
||||||
|
'contacts',
|
||||||
|
'clients',
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($tables as $table) {
|
||||||
|
DB::table($table)->where('account_id', '=', $user->account_id)->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
$account->invoice_number_counter = 1;
|
||||||
|
$account->quote_number_counter = 1;
|
||||||
|
$account->client_number_counter = 1;
|
||||||
|
$account->save();
|
||||||
|
}
|
||||||
|
}
|
@ -26,11 +26,6 @@ class SendInvoiceEmail extends Job implements ShouldQueue
|
|||||||
*/
|
*/
|
||||||
protected $reminder;
|
protected $reminder;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $pdfString;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
@ -44,11 +39,10 @@ class SendInvoiceEmail extends Job implements ShouldQueue
|
|||||||
* @param bool $reminder
|
* @param bool $reminder
|
||||||
* @param mixed $pdfString
|
* @param mixed $pdfString
|
||||||
*/
|
*/
|
||||||
public function __construct(Invoice $invoice, $reminder = false, $pdfString = false, $template = false)
|
public function __construct(Invoice $invoice, $reminder = false, $template = false)
|
||||||
{
|
{
|
||||||
$this->invoice = $invoice;
|
$this->invoice = $invoice;
|
||||||
$this->reminder = $reminder;
|
$this->reminder = $reminder;
|
||||||
$this->pdfString = $pdfString;
|
|
||||||
$this->template = $template;
|
$this->template = $template;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,7 +53,7 @@ class SendInvoiceEmail extends Job implements ShouldQueue
|
|||||||
*/
|
*/
|
||||||
public function handle(ContactMailer $mailer)
|
public function handle(ContactMailer $mailer)
|
||||||
{
|
{
|
||||||
$mailer->sendInvoice($this->invoice, $this->reminder, $this->pdfString, $this->template);
|
$mailer->sendInvoice($this->invoice, $this->reminder, $this->template);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -394,6 +394,7 @@ class Utils
|
|||||||
'user_name' => Auth::check() ? Auth::user()->getDisplayName() : '',
|
'user_name' => Auth::check() ? Auth::user()->getDisplayName() : '',
|
||||||
'method' => Request::method(),
|
'method' => Request::method(),
|
||||||
'url' => Input::get('url', Request::url()),
|
'url' => Input::get('url', Request::url()),
|
||||||
|
'previous' => url()->previous(),
|
||||||
'user_agent' => isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '',
|
'user_agent' => isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '',
|
||||||
'ip' => Request::getClientIp(),
|
'ip' => Request::getClientIp(),
|
||||||
'count' => Session::get('error_count', 0),
|
'count' => Session::get('error_count', 0),
|
||||||
|
@ -5,7 +5,9 @@ namespace App\Listeners;
|
|||||||
use App\Events\UserLoggedIn;
|
use App\Events\UserLoggedIn;
|
||||||
use App\Events\UserSignedUp;
|
use App\Events\UserSignedUp;
|
||||||
use App\Libraries\HistoryUtils;
|
use App\Libraries\HistoryUtils;
|
||||||
|
use App\Models\Gateway;
|
||||||
use App\Ninja\Repositories\AccountRepository;
|
use App\Ninja\Repositories\AccountRepository;
|
||||||
|
use Utils;
|
||||||
use Auth;
|
use Auth;
|
||||||
use Carbon;
|
use Carbon;
|
||||||
use Session;
|
use Session;
|
||||||
@ -65,5 +67,10 @@ class HandleUserLoggedIn
|
|||||||
} elseif ($account->isLogoTooLarge()) {
|
} elseif ($account->isLogoTooLarge()) {
|
||||||
Session::flash('warning', trans('texts.logo_too_large', ['size' => $account->getLogoSize() . 'KB']));
|
Session::flash('warning', trans('texts.logo_too_large', ['size' => $account->getLogoSize() . 'KB']));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check custom gateway id is correct
|
||||||
|
if (! Utils::isNinja() && Gateway::find(GATEWAY_CUSTOM)->name !== 'Custom') {
|
||||||
|
Session::flash('error', trans('texts.error_incorrect_gateway_ids'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -153,6 +153,14 @@ class InvoiceListener
|
|||||||
|
|
||||||
public function jobFailed(JobExceptionOccurred $exception)
|
public function jobFailed(JobExceptionOccurred $exception)
|
||||||
{
|
{
|
||||||
|
if ($errorEmail = env('ERROR_EMAIL')) {
|
||||||
|
\Mail::raw(print_r($exception->data, true), function ($message) use ($errorEmail) {
|
||||||
|
$message->to($errorEmail)
|
||||||
|
->from(CONTACT_EMAIL)
|
||||||
|
->subject('Job failed');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Utils::logError($exception->exception);
|
Utils::logError($exception->exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,51 +48,131 @@ class Account extends Eloquent
|
|||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
|
'timezone_id',
|
||||||
|
'date_format_id',
|
||||||
|
'datetime_format_id',
|
||||||
|
'currency_id',
|
||||||
'name',
|
'name',
|
||||||
'id_number',
|
|
||||||
'vat_number',
|
|
||||||
'work_email',
|
|
||||||
'website',
|
|
||||||
'work_phone',
|
|
||||||
'address1',
|
'address1',
|
||||||
'address2',
|
'address2',
|
||||||
'city',
|
'city',
|
||||||
'state',
|
'state',
|
||||||
'postal_code',
|
'postal_code',
|
||||||
'country_id',
|
'country_id',
|
||||||
'size_id',
|
'invoice_terms',
|
||||||
'industry_id',
|
|
||||||
'email_footer',
|
'email_footer',
|
||||||
'timezone_id',
|
'industry_id',
|
||||||
'date_format_id',
|
'size_id',
|
||||||
'datetime_format_id',
|
|
||||||
'currency_id',
|
|
||||||
'language_id',
|
|
||||||
'military_time',
|
|
||||||
'invoice_taxes',
|
'invoice_taxes',
|
||||||
'invoice_item_taxes',
|
'invoice_item_taxes',
|
||||||
|
'invoice_design_id',
|
||||||
|
'work_phone',
|
||||||
|
'work_email',
|
||||||
|
'language_id',
|
||||||
|
'custom_label1',
|
||||||
|
'custom_value1',
|
||||||
|
'custom_label2',
|
||||||
|
'custom_value2',
|
||||||
|
'custom_client_label1',
|
||||||
|
'custom_client_label2',
|
||||||
|
'fill_products',
|
||||||
|
'update_products',
|
||||||
|
'primary_color',
|
||||||
|
'secondary_color',
|
||||||
|
'hide_quantity',
|
||||||
|
'hide_paid_to_date',
|
||||||
|
'custom_invoice_label1',
|
||||||
|
'custom_invoice_label2',
|
||||||
|
'custom_invoice_taxes1',
|
||||||
|
'custom_invoice_taxes2',
|
||||||
|
'vat_number',
|
||||||
|
'invoice_number_prefix',
|
||||||
|
'invoice_number_counter',
|
||||||
|
'quote_number_prefix',
|
||||||
|
'quote_number_counter',
|
||||||
|
'share_counter',
|
||||||
|
'id_number',
|
||||||
|
'email_template_invoice',
|
||||||
|
'email_template_quote',
|
||||||
|
'email_template_payment',
|
||||||
|
'token_billing_type_id',
|
||||||
|
'invoice_footer',
|
||||||
|
'pdf_email_attachment',
|
||||||
|
'font_size',
|
||||||
|
'invoice_labels',
|
||||||
|
'custom_design',
|
||||||
'show_item_taxes',
|
'show_item_taxes',
|
||||||
|
'military_time',
|
||||||
|
'email_subject_invoice',
|
||||||
|
'email_subject_quote',
|
||||||
|
'email_subject_payment',
|
||||||
|
'email_subject_reminder1',
|
||||||
|
'email_subject_reminder2',
|
||||||
|
'email_subject_reminder3',
|
||||||
|
'email_template_reminder1',
|
||||||
|
'email_template_reminder2',
|
||||||
|
'email_template_reminder3',
|
||||||
|
'enable_reminder1',
|
||||||
|
'enable_reminder2',
|
||||||
|
'enable_reminder3',
|
||||||
|
'num_days_reminder1',
|
||||||
|
'num_days_reminder2',
|
||||||
|
'num_days_reminder3',
|
||||||
|
'custom_invoice_text_label1',
|
||||||
|
'custom_invoice_text_label2',
|
||||||
'default_tax_rate_id',
|
'default_tax_rate_id',
|
||||||
'enable_second_tax_rate',
|
'recurring_hour',
|
||||||
'include_item_taxes_inline',
|
'invoice_number_pattern',
|
||||||
'start_of_week',
|
'quote_number_pattern',
|
||||||
'financial_year_start',
|
'quote_terms',
|
||||||
'enable_client_portal',
|
'email_design_id',
|
||||||
'enable_client_portal_dashboard',
|
'enable_email_markup',
|
||||||
|
'website',
|
||||||
|
'direction_reminder1',
|
||||||
|
'direction_reminder2',
|
||||||
|
'direction_reminder3',
|
||||||
|
'field_reminder1',
|
||||||
|
'field_reminder2',
|
||||||
|
'field_reminder3',
|
||||||
|
'header_font_id',
|
||||||
|
'body_font_id',
|
||||||
|
'auto_convert_quote',
|
||||||
|
'all_pages_footer',
|
||||||
|
'all_pages_header',
|
||||||
|
'show_currency_code',
|
||||||
'enable_portal_password',
|
'enable_portal_password',
|
||||||
'send_portal_password',
|
'send_portal_password',
|
||||||
|
'custom_invoice_item_label1',
|
||||||
|
'custom_invoice_item_label2',
|
||||||
|
'recurring_invoice_number_prefix',
|
||||||
|
'enable_client_portal',
|
||||||
|
'invoice_fields',
|
||||||
|
'invoice_embed_documents',
|
||||||
|
'document_email_attachment',
|
||||||
|
'enable_client_portal_dashboard',
|
||||||
|
'page_size',
|
||||||
|
'live_preview',
|
||||||
|
'invoice_number_padding',
|
||||||
|
'enable_second_tax_rate',
|
||||||
|
'auto_bill_on_due_date',
|
||||||
|
'start_of_week',
|
||||||
'enable_buy_now_buttons',
|
'enable_buy_now_buttons',
|
||||||
|
'include_item_taxes_inline',
|
||||||
|
'financial_year_start',
|
||||||
|
'enabled_modules',
|
||||||
|
'enabled_dashboard_sections',
|
||||||
'show_accept_invoice_terms',
|
'show_accept_invoice_terms',
|
||||||
'show_accept_quote_terms',
|
'show_accept_quote_terms',
|
||||||
'require_invoice_signature',
|
'require_invoice_signature',
|
||||||
'require_quote_signature',
|
'require_quote_signature',
|
||||||
'pdf_email_attachment',
|
'client_number_prefix',
|
||||||
'document_email_attachment',
|
'client_number_counter',
|
||||||
'email_design_id',
|
'client_number_pattern',
|
||||||
'enable_email_markup',
|
|
||||||
'domain_id',
|
|
||||||
'payment_terms',
|
'payment_terms',
|
||||||
|
'reset_counter_frequency_id',
|
||||||
'payment_type_id',
|
'payment_type_id',
|
||||||
|
'gateway_fee_enabled',
|
||||||
|
'reset_counter_date',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -189,6 +269,22 @@ class Account extends Eloquent
|
|||||||
return $this->hasMany('App\Models\AccountGateway');
|
return $this->hasMany('App\Models\AccountGateway');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||||
|
*/
|
||||||
|
public function account_gateway_settings()
|
||||||
|
{
|
||||||
|
return $this->hasMany('App\Models\AccountGatewaySettings');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||||
|
*/
|
||||||
|
public function account_email_settings()
|
||||||
|
{
|
||||||
|
return $this->hasOne('App\Models\AccountEmailSettings');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||||
*/
|
*/
|
||||||
@ -402,6 +498,22 @@ class Account extends Eloquent
|
|||||||
return $user->getDisplayName();
|
return $user->getDisplayName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getGatewaySettings($gatewayTypeId)
|
||||||
|
{
|
||||||
|
if (! $this->relationLoaded('account_gateway_settings')) {
|
||||||
|
$this->load('account_gateway_settings');
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->account_gateway_settings as $settings) {
|
||||||
|
if ($settings->gateway_type_id == $gatewayTypeId) {
|
||||||
|
return $settings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
@ -887,6 +999,8 @@ class Account extends Eloquent
|
|||||||
$invoice->start_date = Utils::today();
|
$invoice->start_date = Utils::today();
|
||||||
$invoice->invoice_design_id = $this->invoice_design_id;
|
$invoice->invoice_design_id = $this->invoice_design_id;
|
||||||
$invoice->client_id = $clientId;
|
$invoice->client_id = $clientId;
|
||||||
|
$invoice->custom_taxes1 = $this->custom_invoice_taxes1;
|
||||||
|
$invoice->custom_taxes2 = $this->custom_invoice_taxes2;
|
||||||
|
|
||||||
if ($entityType === ENTITY_RECURRING_INVOICE) {
|
if ($entityType === ENTITY_RECURRING_INVOICE) {
|
||||||
$invoice->invoice_number = microtime(true);
|
$invoice->invoice_number = microtime(true);
|
||||||
|
32
app/Models/AccountEmailSettings.php
Normal file
32
app/Models/AccountEmailSettings.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Eloquent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Account.
|
||||||
|
*/
|
||||||
|
class AccountEmailSettings extends Eloquent
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $fillable = [
|
||||||
|
'bcc_email',
|
||||||
|
'reply_to_email',
|
||||||
|
'email_subject_invoice',
|
||||||
|
'email_subject_quote',
|
||||||
|
'email_subject_payment',
|
||||||
|
'email_template_invoice',
|
||||||
|
'email_template_quote',
|
||||||
|
'email_template_payment',
|
||||||
|
'email_subject_reminder1',
|
||||||
|
'email_subject_reminder2',
|
||||||
|
'email_subject_reminder3',
|
||||||
|
'email_template_reminder1',
|
||||||
|
'email_template_reminder2',
|
||||||
|
'email_template_reminder3',
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Utils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class AccountGatewaySettings.
|
* Class AccountGatewaySettings.
|
||||||
*/
|
*/
|
||||||
@ -12,6 +14,18 @@ class AccountGatewaySettings extends EntityModel
|
|||||||
*/
|
*/
|
||||||
protected $dates = ['updated_at'];
|
protected $dates = ['updated_at'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $fillable = [
|
||||||
|
'fee_amount',
|
||||||
|
'fee_percent',
|
||||||
|
'fee_tax_name1',
|
||||||
|
'fee_tax_rate1',
|
||||||
|
'fee_tax_name2',
|
||||||
|
'fee_tax_rate2',
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
@ -29,4 +43,29 @@ class AccountGatewaySettings extends EntityModel
|
|||||||
{
|
{
|
||||||
// to Disable created_at
|
// to Disable created_at
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function areFeesEnabled()
|
||||||
|
{
|
||||||
|
return floatval($this->fee_amount) || floatval($this->fee_percent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasTaxes()
|
||||||
|
{
|
||||||
|
return floatval($this->fee_tax_rate1) || floatval($this->fee_tax_rate1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function feesToString()
|
||||||
|
{
|
||||||
|
$parts = [];
|
||||||
|
|
||||||
|
if (floatval($this->fee_amount) != 0) {
|
||||||
|
$parts[] = Utils::formatMoney($this->fee_amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (floatval($this->fee_percent) != 0) {
|
||||||
|
$parts[] = (floor($this->fee_percent * 1000) / 1000) . '%';
|
||||||
|
}
|
||||||
|
|
||||||
|
return join(' + ', $parts);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,8 @@ class Client extends EntityModel
|
|||||||
'language_id',
|
'language_id',
|
||||||
'payment_terms',
|
'payment_terms',
|
||||||
'website',
|
'website',
|
||||||
|
'invoice_number_counter',
|
||||||
|
'quote_number_counter',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -136,7 +138,7 @@ class Client extends EntityModel
|
|||||||
'email' => 'email',
|
'email' => 'email',
|
||||||
'mobile|phone' => 'phone',
|
'mobile|phone' => 'phone',
|
||||||
'name|organization' => 'name',
|
'name|organization' => 'name',
|
||||||
'street2|address2' => 'address2',
|
'apt|street2|address2' => 'address2',
|
||||||
'street|address|address1' => 'address1',
|
'street|address|address1' => 'address1',
|
||||||
'city' => 'city',
|
'city' => 'city',
|
||||||
'state|province' => 'state',
|
'state|province' => 'state',
|
||||||
@ -145,7 +147,7 @@ class Client extends EntityModel
|
|||||||
'note' => 'notes',
|
'note' => 'notes',
|
||||||
'site|website' => 'website',
|
'site|website' => 'website',
|
||||||
'vat' => 'vat_number',
|
'vat' => 'vat_number',
|
||||||
'id|number' => 'id_number',
|
'number' => 'id_number',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,7 +290,7 @@ class Client extends EntityModel
|
|||||||
if (isset($data['contact_key']) && $this->account->account_key == env('NINJA_LICENSE_ACCOUNT_KEY')) {
|
if (isset($data['contact_key']) && $this->account->account_key == env('NINJA_LICENSE_ACCOUNT_KEY')) {
|
||||||
$contact->contact_key = $data['contact_key'];
|
$contact->contact_key = $data['contact_key'];
|
||||||
} else {
|
} else {
|
||||||
$contact->contact_key = str_random(RANDOM_KEY_LENGTH);
|
$contact->contact_key = strtolower(str_random(RANDOM_KEY_LENGTH));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,4 +145,32 @@ class Company extends Eloquent
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function processRefund($user)
|
||||||
|
{
|
||||||
|
if (! $this->payment) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$account = $this->accounts()->first();
|
||||||
|
$planDetails = $account->getPlanDetails(false, false);
|
||||||
|
|
||||||
|
if (! empty($planDetails['started'])) {
|
||||||
|
$deadline = clone $planDetails['started'];
|
||||||
|
$deadline->modify('+30 days');
|
||||||
|
|
||||||
|
if ($deadline >= date_create()) {
|
||||||
|
$accountRepo = app('App\Ninja\Repositories\AccountRepository');
|
||||||
|
$ninjaAccount = $accountRepo->getNinjaAccount();
|
||||||
|
$paymentDriver = $ninjaAccount->paymentDriver();
|
||||||
|
$paymentDriver->refundPayment($this->payment);
|
||||||
|
|
||||||
|
\Log::info("Refunded Plan Payment: {$account->name} - {$user->email} - Deadline: {$deadline->format('Y-m-d')}");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -119,7 +119,7 @@ class Contact extends EntityModel implements AuthenticatableContract, CanResetPa
|
|||||||
public function getContactKeyAttribute($contact_key)
|
public function getContactKeyAttribute($contact_key)
|
||||||
{
|
{
|
||||||
if (empty($contact_key) && $this->id) {
|
if (empty($contact_key) && $this->id) {
|
||||||
$this->contact_key = $contact_key = str_random(RANDOM_KEY_LENGTH);
|
$this->contact_key = $contact_key = strtolower(str_random(RANDOM_KEY_LENGTH));
|
||||||
static::where('id', $this->id)->update(['contact_key' => $contact_key]);
|
static::where('id', $this->id)->update(['contact_key' => $contact_key]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,14 @@ class Credit extends EntityModel
|
|||||||
*/
|
*/
|
||||||
protected $presenter = 'App\Ninja\Presenters\CreditPresenter';
|
protected $presenter = 'App\Ninja\Presenters\CreditPresenter';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $fillable = [
|
||||||
|
'public_notes',
|
||||||
|
'private_notes',
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
*/
|
*/
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Str;
|
||||||
use Auth;
|
use Auth;
|
||||||
use Eloquent;
|
use Eloquent;
|
||||||
use Utils;
|
use Utils;
|
||||||
@ -95,6 +96,10 @@ class EntityModel extends Eloquent
|
|||||||
*/
|
*/
|
||||||
public static function getPrivateId($publicId)
|
public static function getPrivateId($publicId)
|
||||||
{
|
{
|
||||||
|
if (! $publicId) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
$className = get_called_class();
|
$className = get_called_class();
|
||||||
|
|
||||||
return $className::scope($publicId)->withTrashed()->value('id');
|
return $className::scope($publicId)->withTrashed()->value('id');
|
||||||
@ -254,16 +259,22 @@ class EntityModel extends Eloquent
|
|||||||
* @param $data
|
* @param $data
|
||||||
* @param $entityType
|
* @param $entityType
|
||||||
* @param mixed $entity
|
* @param mixed $entity
|
||||||
*
|
* TODO Remove $entityType parameter
|
||||||
* @return bool|string
|
* @return bool|string
|
||||||
*/
|
*/
|
||||||
public static function validate($data, $entityType, $entity = false)
|
public static function validate($data, $entityType = false, $entity = false)
|
||||||
{
|
{
|
||||||
|
if (! $entityType) {
|
||||||
|
$className = get_called_class();
|
||||||
|
$entityBlank = new $className();
|
||||||
|
$entityType = $entityBlank->getEntityType();
|
||||||
|
}
|
||||||
|
|
||||||
// Use the API request if it exists
|
// Use the API request if it exists
|
||||||
$action = $entity ? 'update' : 'create';
|
$action = $entity ? 'update' : 'create';
|
||||||
$requestClass = sprintf('App\\Http\\Requests\\%s%sAPIRequest', ucwords($action), ucwords($entityType));
|
$requestClass = sprintf('App\\Http\\Requests\\%s%sAPIRequest', ucwords($action), Str::studly($entityType));
|
||||||
if (! class_exists($requestClass)) {
|
if (! class_exists($requestClass)) {
|
||||||
$requestClass = sprintf('App\\Http\\Requests\\%s%sRequest', ucwords($action), ucwords($entityType));
|
$requestClass = sprintf('App\\Http\\Requests\\%s%sRequest', ucwords($action), Str::studly($entityType));
|
||||||
}
|
}
|
||||||
|
|
||||||
$request = new $requestClass();
|
$request = new $requestClass();
|
||||||
|
@ -59,6 +59,7 @@ class Gateway extends Eloquent
|
|||||||
GATEWAY_PAYPAL_EXPRESS,
|
GATEWAY_PAYPAL_EXPRESS,
|
||||||
GATEWAY_BITPAY,
|
GATEWAY_BITPAY,
|
||||||
GATEWAY_DWOLLA,
|
GATEWAY_DWOLLA,
|
||||||
|
GATEWAY_CUSTOM,
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -76,6 +76,10 @@ class Invitation extends EntityModel
|
|||||||
$iframe_url = $account->iframe_url;
|
$iframe_url = $account->iframe_url;
|
||||||
$url = trim(SITE_URL, '/');
|
$url = trim(SITE_URL, '/');
|
||||||
|
|
||||||
|
if (env('REQUIRE_HTTPS')) {
|
||||||
|
$url = str_replace('http://', 'https://', $url);
|
||||||
|
}
|
||||||
|
|
||||||
if ($account->hasFeature(FEATURE_CUSTOM_URL)) {
|
if ($account->hasFeature(FEATURE_CUSTOM_URL)) {
|
||||||
if (Utils::isNinjaProd()) {
|
if (Utils::isNinjaProd()) {
|
||||||
$url = $account->present()->clientPortalLink();
|
$url = $account->present()->clientPortalLink();
|
||||||
|
@ -10,6 +10,7 @@ use App\Events\QuoteWasCreated;
|
|||||||
use App\Events\QuoteWasUpdated;
|
use App\Events\QuoteWasUpdated;
|
||||||
use App\Libraries\CurlUtils;
|
use App\Libraries\CurlUtils;
|
||||||
use App\Models\Activity;
|
use App\Models\Activity;
|
||||||
|
use App\Models\Traits\ChargesFees;
|
||||||
use DateTime;
|
use DateTime;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
use Laracasts\Presenter\PresentableTrait;
|
use Laracasts\Presenter\PresentableTrait;
|
||||||
@ -23,6 +24,7 @@ class Invoice extends EntityModel implements BalanceAffecting
|
|||||||
{
|
{
|
||||||
use PresentableTrait;
|
use PresentableTrait;
|
||||||
use OwnedByClientTrait;
|
use OwnedByClientTrait;
|
||||||
|
use ChargesFees;
|
||||||
use SoftDeletes {
|
use SoftDeletes {
|
||||||
SoftDeletes::trashed as parentTrashed;
|
SoftDeletes::trashed as parentTrashed;
|
||||||
}
|
}
|
||||||
@ -62,9 +64,10 @@ class Invoice extends EntityModel implements BalanceAffecting
|
|||||||
*/
|
*/
|
||||||
public static $patternFields = [
|
public static $patternFields = [
|
||||||
'counter',
|
'counter',
|
||||||
'custom1',
|
'clientCounter',
|
||||||
'custom2',
|
'clientIdNumber',
|
||||||
'idNumber',
|
'clientCustom1',
|
||||||
|
'clientCustom2',
|
||||||
'userId',
|
'userId',
|
||||||
'year',
|
'year',
|
||||||
'date:',
|
'date:',
|
||||||
@ -539,7 +542,7 @@ class Invoice extends EntityModel implements BalanceAffecting
|
|||||||
public function updatePaidStatus($save = true)
|
public function updatePaidStatus($save = true)
|
||||||
{
|
{
|
||||||
$statusId = false;
|
$statusId = false;
|
||||||
if ($this->amount > 0 && $this->balance == 0) {
|
if ($this->amount != 0 && $this->balance == 0) {
|
||||||
$statusId = INVOICE_STATUS_PAID;
|
$statusId = INVOICE_STATUS_PAID;
|
||||||
} elseif ($this->balance > 0 && $this->balance < $this->amount) {
|
} elseif ($this->balance > 0 && $this->balance < $this->amount) {
|
||||||
$statusId = INVOICE_STATUS_PARTIAL;
|
$statusId = INVOICE_STATUS_PARTIAL;
|
||||||
@ -573,6 +576,13 @@ class Invoice extends EntityModel implements BalanceAffecting
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$balanceAdjustment = floatval($balanceAdjustment);
|
||||||
|
$partial = floatval($partial);
|
||||||
|
|
||||||
|
if (! $balanceAdjustment && $this->partial == $partial) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$this->balance = $this->balance + $balanceAdjustment;
|
$this->balance = $this->balance + $balanceAdjustment;
|
||||||
|
|
||||||
if ($this->partial > 0) {
|
if ($this->partial > 0) {
|
||||||
@ -580,6 +590,13 @@ class Invoice extends EntityModel implements BalanceAffecting
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->save();
|
$this->save();
|
||||||
|
|
||||||
|
// mark fees as paid
|
||||||
|
if ($balanceAdjustment != 0 && $this->account->gateway_fee_enabled) {
|
||||||
|
if ($invoiceItem = $this->getGatewayFeeItem()) {
|
||||||
|
$invoiceItem->markFeePaid();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -610,7 +627,7 @@ class Invoice extends EntityModel implements BalanceAffecting
|
|||||||
|
|
||||||
public function canBePaid()
|
public function canBePaid()
|
||||||
{
|
{
|
||||||
return floatval($this->balance) > 0 && ! $this->is_deleted && $this->isInvoice();
|
return floatval($this->balance) != 0 && ! $this->is_deleted && $this->isInvoice();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function calcStatusLabel($status, $class, $entityType, $quoteInvoiceId)
|
public static function calcStatusLabel($status, $class, $entityType, $quoteInvoiceId)
|
||||||
@ -752,7 +769,16 @@ class Invoice extends EntityModel implements BalanceAffecting
|
|||||||
*/
|
*/
|
||||||
public function getRequestedAmount()
|
public function getRequestedAmount()
|
||||||
{
|
{
|
||||||
return $this->partial > 0 ? $this->partial : $this->balance;
|
$fee = 0;
|
||||||
|
if ($this->account->gateway_fee_enabled) {
|
||||||
|
$fee = $this->getGatewayFee();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->partial > 0) {
|
||||||
|
return $this->partial + $fee;
|
||||||
|
} else {
|
||||||
|
return $this->balance;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -868,6 +894,7 @@ class Invoice extends EntityModel implements BalanceAffecting
|
|||||||
'page_size',
|
'page_size',
|
||||||
'include_item_taxes_inline',
|
'include_item_taxes_inline',
|
||||||
'invoice_fields',
|
'invoice_fields',
|
||||||
|
'show_currency_code',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
foreach ($this->invoice_items as $invoiceItem) {
|
foreach ($this->invoice_items as $invoiceItem) {
|
||||||
@ -1231,6 +1258,10 @@ class Invoice extends EntityModel implements BalanceAffecting
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Utils::isTravis()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
$invitation = $this->invitations[0];
|
$invitation = $this->invitations[0];
|
||||||
$link = $invitation->getLink('view', true);
|
$link = $invitation->getLink('view', true);
|
||||||
$pdfString = false;
|
$pdfString = false;
|
||||||
@ -1238,26 +1269,35 @@ class Invoice extends EntityModel implements BalanceAffecting
|
|||||||
try {
|
try {
|
||||||
if (env('PHANTOMJS_BIN_PATH')) {
|
if (env('PHANTOMJS_BIN_PATH')) {
|
||||||
$pdfString = CurlUtils::phantom('GET', $link . '?phantomjs=true&phantomjs_secret=' . env('PHANTOMJS_SECRET'));
|
$pdfString = CurlUtils::phantom('GET', $link . '?phantomjs=true&phantomjs_secret=' . env('PHANTOMJS_SECRET'));
|
||||||
} elseif ($key = env('PHANTOMJS_CLOUD_KEY')) {
|
}
|
||||||
if (Utils::isNinjaDev()) {
|
|
||||||
$link = env('TEST_LINK');
|
if (! $pdfString && (Utils::isNinja() || ! env('PHANTOMJS_BIN_PATH'))) {
|
||||||
|
if ($key = env('PHANTOMJS_CLOUD_KEY')) {
|
||||||
|
if (Utils::isNinjaDev()) {
|
||||||
|
$link = env('TEST_LINK');
|
||||||
|
}
|
||||||
|
$url = "http://api.phantomjscloud.com/api/browser/v2/{$key}/?request=%7Burl:%22{$link}?phantomjs=true%22,renderType:%22html%22%7D";
|
||||||
|
$pdfString = CurlUtils::get($url);
|
||||||
}
|
}
|
||||||
$url = "http://api.phantomjscloud.com/api/browser/v2/{$key}/?request=%7Burl:%22{$link}?phantomjs=true%22,renderType:%22html%22%7D";
|
|
||||||
$pdfString = CurlUtils::get($url);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$pdfString = strip_tags($pdfString);
|
$pdfString = strip_tags($pdfString);
|
||||||
} catch (\Exception $exception) {
|
} catch (\Exception $exception) {
|
||||||
Utils::logError("PhantomJS - Failed to create pdf: {$exception->getMessage()}");
|
Utils::logError("PhantomJS - Failed to load: {$exception->getMessage()}");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! $pdfString || strlen($pdfString) < 200) {
|
if (! $pdfString || strlen($pdfString) < 200) {
|
||||||
Utils::logError("PhantomJS - Failed to create pdf: {$pdfString}");
|
Utils::logError("PhantomJS - Invalid response: {$pdfString}");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Utils::decodePDF($pdfString);
|
if ($pdf = Utils::decodePDF($pdfString)) {
|
||||||
|
return $pdf;
|
||||||
|
} else {
|
||||||
|
Utils::logError("PhantomJS - Unable to decode: {$pdfString}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1473,7 +1513,7 @@ class Invoice extends EntityModel implements BalanceAffecting
|
|||||||
}
|
}
|
||||||
|
|
||||||
Invoice::creating(function ($invoice) {
|
Invoice::creating(function ($invoice) {
|
||||||
if (! $invoice->is_recurring) {
|
if (! $invoice->is_recurring && $invoice->amount >= 0) {
|
||||||
$invoice->account->incrementCounter($invoice);
|
$invoice->account->incrementCounter($invoice);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -39,6 +39,7 @@ class InvoiceItem extends EntityModel
|
|||||||
'tax_rate1',
|
'tax_rate1',
|
||||||
'tax_name2',
|
'tax_name2',
|
||||||
'tax_rate2',
|
'tax_rate2',
|
||||||
|
'invoice_item_type_id',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -72,4 +73,28 @@ class InvoiceItem extends EntityModel
|
|||||||
{
|
{
|
||||||
return $this->belongsTo('App\Models\Account');
|
return $this->belongsTo('App\Models\Account');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function amount()
|
||||||
|
{
|
||||||
|
$amount = $this->cost * $this->qty;
|
||||||
|
$preTaxAmount = $amount;
|
||||||
|
|
||||||
|
if ($this->tax_rate1) {
|
||||||
|
$amount += $preTaxAmount * $this->tax_rate1 / 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->tax_rate2) {
|
||||||
|
$amount += $preTaxAmount * $this->tax_rate2 / 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function markFeePaid()
|
||||||
|
{
|
||||||
|
if ($this->invoice_item_type_id == INVOICE_ITEM_TYPE_PENDING_GATEWAY_FEE) {
|
||||||
|
$this->invoice_item_type_id = INVOICE_ITEM_TYPE_PAID_GATEWAY_FEE;
|
||||||
|
$this->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -205,7 +205,7 @@ class Task extends EntityModel
|
|||||||
public function scopeDateRange($query, $startDate, $endDate)
|
public function scopeDateRange($query, $startDate, $endDate)
|
||||||
{
|
{
|
||||||
$query->whereRaw('cast(substring(time_log, 3, 10) as unsigned) >= ' . $startDate->format('U'));
|
$query->whereRaw('cast(substring(time_log, 3, 10) as unsigned) >= ' . $startDate->format('U'));
|
||||||
$query->whereRaw('cast(substring(time_log, 3, 10) as unsigned) <= ' . $endDate->format('U'));
|
$query->whereRaw('cast(substring(time_log, 3, 10) as unsigned) <= ' . $endDate->modify('+1 day')->format('U'));
|
||||||
|
|
||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
|
75
app/Models/Traits/ChargesFees.php
Normal file
75
app/Models/Traits/ChargesFees.php
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models\Traits;
|
||||||
|
|
||||||
|
use App\Models\GatewayType;
|
||||||
|
use App\Models\InvoiceItem;
|
||||||
|
use App\Models\AccountGatewaySettings;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class ChargesFees
|
||||||
|
*/
|
||||||
|
trait ChargesFees
|
||||||
|
{
|
||||||
|
public function calcGatewayFee($gatewayTypeId = false, $includeTax = false)
|
||||||
|
{
|
||||||
|
$account = $this->account;
|
||||||
|
$settings = $account->getGatewaySettings($gatewayTypeId);
|
||||||
|
$fee = 0;
|
||||||
|
|
||||||
|
if (! $account->gateway_fee_enabled) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($settings->fee_amount) {
|
||||||
|
$fee += $settings->fee_amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($settings->fee_percent) {
|
||||||
|
$amount = $this->partial > 0 ? $this->partial : $this->balance;
|
||||||
|
$fee += $amount * $settings->fee_percent / 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate final amount with tax
|
||||||
|
if ($includeTax) {
|
||||||
|
$preTaxFee = $fee;
|
||||||
|
|
||||||
|
if ($settings->fee_tax_rate1) {
|
||||||
|
$fee += $preTaxFee * $settings->fee_tax_rate1 / 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($settings->fee_tax_rate2) {
|
||||||
|
$fee += $preTaxFee * $settings->fee_tax_rate2 / 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return round($fee, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getGatewayFee()
|
||||||
|
{
|
||||||
|
$account = $this->account;
|
||||||
|
|
||||||
|
if (! $account->gateway_fee_enabled) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$item = $this->getGatewayFeeItem();
|
||||||
|
return $item ? $item->amount() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getGatewayFeeItem()
|
||||||
|
{
|
||||||
|
if (! $this->relationLoaded('invoice_items')) {
|
||||||
|
$this->load('invoice_items');
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->invoice_items as $item) {
|
||||||
|
if ($item->invoice_item_type_id == INVOICE_ITEM_TYPE_PENDING_GATEWAY_FEE) {
|
||||||
|
return $item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@ -39,6 +39,10 @@ trait GeneratesNumbers
|
|||||||
$number = $prefix . str_pad($counter, $this->invoice_number_padding, '0', STR_PAD_LEFT);
|
$number = $prefix . str_pad($counter, $this->invoice_number_padding, '0', STR_PAD_LEFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($entity->recurring_invoice_id) {
|
||||||
|
$number = $this->recurring_invoice_number_prefix . $number;
|
||||||
|
}
|
||||||
|
|
||||||
if ($entity->isEntityType(ENTITY_CLIENT)) {
|
if ($entity->isEntityType(ENTITY_CLIENT)) {
|
||||||
$check = Client::scope(false, $this->id)->whereIdNumber($number)->withTrashed()->first();
|
$check = Client::scope(false, $this->id)->whereIdNumber($number)->withTrashed()->first();
|
||||||
} else {
|
} else {
|
||||||
@ -66,10 +70,6 @@ trait GeneratesNumbers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($entity->recurring_invoice_id) {
|
|
||||||
$number = $this->recurring_invoice_number_prefix . $number;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $number;
|
return $number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,7 +125,7 @@ trait GeneratesNumbers
|
|||||||
{
|
{
|
||||||
$pattern = $invoice->invoice_type_id == INVOICE_TYPE_QUOTE ? $this->quote_number_pattern : $this->invoice_number_pattern;
|
$pattern = $invoice->invoice_type_id == INVOICE_TYPE_QUOTE ? $this->quote_number_pattern : $this->invoice_number_pattern;
|
||||||
|
|
||||||
return strstr($pattern, '$custom') || strstr($pattern, '$idNumber');
|
return strstr($pattern, '$client') !== false || strstr($pattern, '$idNumber') !== false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -167,10 +167,7 @@ trait GeneratesNumbers
|
|||||||
}
|
}
|
||||||
|
|
||||||
$pattern = str_replace($search, $replace, $pattern);
|
$pattern = str_replace($search, $replace, $pattern);
|
||||||
|
$pattern = $this->getClientInvoiceNumber($pattern, $entity);
|
||||||
if ($entity->client_id) {
|
|
||||||
$pattern = $this->getClientInvoiceNumber($pattern, $entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $pattern;
|
return $pattern;
|
||||||
}
|
}
|
||||||
@ -183,7 +180,7 @@ trait GeneratesNumbers
|
|||||||
*/
|
*/
|
||||||
private function getClientInvoiceNumber($pattern, $invoice)
|
private function getClientInvoiceNumber($pattern, $invoice)
|
||||||
{
|
{
|
||||||
if (! $invoice->client) {
|
if (! $invoice->client_id) {
|
||||||
return $pattern;
|
return $pattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,12 +188,21 @@ trait GeneratesNumbers
|
|||||||
'{$custom1}',
|
'{$custom1}',
|
||||||
'{$custom2}',
|
'{$custom2}',
|
||||||
'{$idNumber}',
|
'{$idNumber}',
|
||||||
|
'{$clientCustom1}',
|
||||||
|
'{$clientCustom2}',
|
||||||
|
'{$clientIdNumber}',
|
||||||
|
'{$clientCounter}',
|
||||||
];
|
];
|
||||||
|
|
||||||
$replace = [
|
$replace = [
|
||||||
$invoice->client->custom_value1,
|
$invoice->client->custom_value1,
|
||||||
$invoice->client->custom_value2,
|
$invoice->client->custom_value2,
|
||||||
$invoice->client->id_number,
|
$invoice->client->id_number,
|
||||||
|
$invoice->client->custom_value1, // backwards compatibility
|
||||||
|
$invoice->client->custom_value2,
|
||||||
|
$invoice->client->id_number,
|
||||||
|
str_pad($invoice->client->invoice_number_counter, $this->invoice_number_padding, '0', STR_PAD_LEFT),
|
||||||
|
str_pad($invoice->client->quote_number_counter, $this->invoice_number_padding, '0', STR_PAD_LEFT),
|
||||||
];
|
];
|
||||||
|
|
||||||
return str_replace($search, $replace, $pattern);
|
return str_replace($search, $replace, $pattern);
|
||||||
@ -225,7 +231,9 @@ trait GeneratesNumbers
|
|||||||
*/
|
*/
|
||||||
public function previewNextInvoiceNumber($entityType = ENTITY_INVOICE)
|
public function previewNextInvoiceNumber($entityType = ENTITY_INVOICE)
|
||||||
{
|
{
|
||||||
$invoice = $this->createInvoice($entityType);
|
$client = \App\Models\Client::scope()->first();
|
||||||
|
|
||||||
|
$invoice = $this->createInvoice($entityType, $client ? $client->id : 0);
|
||||||
|
|
||||||
return $this->getNextNumber($invoice);
|
return $this->getNextNumber($invoice);
|
||||||
}
|
}
|
||||||
@ -239,17 +247,87 @@ trait GeneratesNumbers
|
|||||||
if ($this->client_number_counter) {
|
if ($this->client_number_counter) {
|
||||||
$this->client_number_counter += 1;
|
$this->client_number_counter += 1;
|
||||||
}
|
}
|
||||||
} elseif ($entity->isType(INVOICE_TYPE_QUOTE) && ! $this->share_counter) {
|
$this->save();
|
||||||
$this->quote_number_counter += 1;
|
return;
|
||||||
} else {
|
|
||||||
$this->invoice_number_counter += 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->save();
|
if ($this->usesClientInvoiceCounter()) {
|
||||||
|
if ($entity->isType(INVOICE_TYPE_QUOTE) && ! $this->share_counter) {
|
||||||
|
$entity->client->quote_number_counter += 1;
|
||||||
|
} else {
|
||||||
|
$entity->client->invoice_number_counter += 1;
|
||||||
|
}
|
||||||
|
$entity->client->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->usesInvoiceCounter()) {
|
||||||
|
if ($entity->isType(INVOICE_TYPE_QUOTE) && ! $this->share_counter) {
|
||||||
|
$this->quote_number_counter += 1;
|
||||||
|
} else {
|
||||||
|
$this->invoice_number_counter += 1;
|
||||||
|
}
|
||||||
|
$this->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function usesInvoiceCounter()
|
||||||
|
{
|
||||||
|
return strpos($this->invoice_number_pattern, '{$counter}') !== false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function usesClientInvoiceCounter()
|
||||||
|
{
|
||||||
|
return strpos($this->invoice_number_pattern, '{$clientCounter}') !== false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function clientNumbersEnabled()
|
public function clientNumbersEnabled()
|
||||||
{
|
{
|
||||||
return $this->hasFeature(FEATURE_INVOICE_SETTINGS) && $this->client_number_counter;
|
return $this->hasFeature(FEATURE_INVOICE_SETTINGS) && $this->client_number_counter > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function checkCounterReset()
|
||||||
|
{
|
||||||
|
if (! $this->reset_counter_frequency_id || ! $this->reset_counter_date) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$timezone = $this->getTimezone();
|
||||||
|
$resetDate = Carbon::parse($this->reset_counter_date, $timezone);
|
||||||
|
|
||||||
|
if (! $resetDate->isToday()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($this->reset_counter_frequency_id) {
|
||||||
|
case FREQUENCY_WEEKLY:
|
||||||
|
$resetDate->addWeek();
|
||||||
|
break;
|
||||||
|
case FREQUENCY_TWO_WEEKS:
|
||||||
|
$resetDate->addWeeks(2);
|
||||||
|
break;
|
||||||
|
case FREQUENCY_FOUR_WEEKS:
|
||||||
|
$resetDate->addWeeks(4);
|
||||||
|
break;
|
||||||
|
case FREQUENCY_MONTHLY:
|
||||||
|
$resetDate->addMonth();
|
||||||
|
break;
|
||||||
|
case FREQUENCY_TWO_MONTHS:
|
||||||
|
$resetDate->addMonths(2);
|
||||||
|
break;
|
||||||
|
case FREQUENCY_THREE_MONTHS:
|
||||||
|
$resetDate->addMonths(3);
|
||||||
|
break;
|
||||||
|
case FREQUENCY_SIX_MONTHS:
|
||||||
|
$resetDate->addMonths(6);
|
||||||
|
break;
|
||||||
|
case FREQUENCY_ANNUALLY:
|
||||||
|
$resetDate->addYear();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->reset_counter_date = $resetDate->format('Y-m-d');
|
||||||
|
$this->invoice_number_counter = 1;
|
||||||
|
$this->quote_number_counter = 1;
|
||||||
|
$this->save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,14 +96,16 @@ trait PresentsInvoice
|
|||||||
'client.client_name',
|
'client.client_name',
|
||||||
'client.id_number',
|
'client.id_number',
|
||||||
'client.vat_number',
|
'client.vat_number',
|
||||||
|
'client.website',
|
||||||
|
'client.work_phone',
|
||||||
'client.address1',
|
'client.address1',
|
||||||
'client.address2',
|
'client.address2',
|
||||||
'client.city_state_postal',
|
'client.city_state_postal',
|
||||||
'client.postal_city_state',
|
'client.postal_city_state',
|
||||||
'client.country',
|
'client.country',
|
||||||
|
'client.contact_name',
|
||||||
'client.email',
|
'client.email',
|
||||||
'client.phone',
|
'client.phone',
|
||||||
'client.contact_name',
|
|
||||||
'client.custom_value1',
|
'client.custom_value1',
|
||||||
'client.custom_value2',
|
'client.custom_value2',
|
||||||
'.blank',
|
'.blank',
|
||||||
@ -138,6 +140,8 @@ trait PresentsInvoice
|
|||||||
list($entityType, $fieldName) = explode('.', $field);
|
list($entityType, $fieldName) = explode('.', $field);
|
||||||
if (substr($fieldName, 0, 6) == 'custom') {
|
if (substr($fieldName, 0, 6) == 'custom') {
|
||||||
$fields[$section][$field] = $labels[$field];
|
$fields[$section][$field] = $labels[$field];
|
||||||
|
} elseif (in_array($field, ['client.phone', 'client.email'])) {
|
||||||
|
$fields[$section][$field] = trans('texts.contact_' . $fieldName);
|
||||||
} else {
|
} else {
|
||||||
$fields[$section][$field] = $labels[$fieldName];
|
$fields[$section][$field] = $labels[$fieldName];
|
||||||
}
|
}
|
||||||
@ -208,7 +212,7 @@ trait PresentsInvoice
|
|||||||
'website',
|
'website',
|
||||||
'phone',
|
'phone',
|
||||||
'blank',
|
'blank',
|
||||||
'adjustment',
|
'surcharge',
|
||||||
'tax_invoice',
|
'tax_invoice',
|
||||||
'tax_quote',
|
'tax_quote',
|
||||||
'statement',
|
'statement',
|
||||||
@ -216,6 +220,13 @@ trait PresentsInvoice
|
|||||||
'your_statement',
|
'your_statement',
|
||||||
'statement_issued_to',
|
'statement_issued_to',
|
||||||
'statement_to',
|
'statement_to',
|
||||||
|
'credit_note',
|
||||||
|
'credit_date',
|
||||||
|
'credit_number',
|
||||||
|
'credit_issued_to',
|
||||||
|
'credit_to',
|
||||||
|
'your_credit',
|
||||||
|
'work_phone',
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($fields as $field) {
|
foreach ($fields as $field) {
|
||||||
|
@ -33,7 +33,7 @@ trait SendsEmails
|
|||||||
{
|
{
|
||||||
if ($this->hasFeature(FEATURE_CUSTOM_EMAILS)) {
|
if ($this->hasFeature(FEATURE_CUSTOM_EMAILS)) {
|
||||||
$field = "email_subject_{$entityType}";
|
$field = "email_subject_{$entityType}";
|
||||||
$value = $this->$field;
|
$value = $this->account_email_settings->$field;
|
||||||
|
|
||||||
if ($value) {
|
if ($value) {
|
||||||
return preg_replace("/\r\n|\r|\n/", ' ', $value);
|
return preg_replace("/\r\n|\r|\n/", ' ', $value);
|
||||||
@ -84,7 +84,7 @@ trait SendsEmails
|
|||||||
|
|
||||||
if ($this->hasFeature(FEATURE_CUSTOM_EMAILS)) {
|
if ($this->hasFeature(FEATURE_CUSTOM_EMAILS)) {
|
||||||
$field = "email_template_{$entityType}";
|
$field = "email_template_{$entityType}";
|
||||||
$template = $this->$field;
|
$template = $this->account_email_settings->$field;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! $template) {
|
if (! $template) {
|
||||||
@ -158,20 +158,27 @@ trait SendsEmails
|
|||||||
|
|
||||||
public function setTemplateDefaults($type, $subject, $body)
|
public function setTemplateDefaults($type, $subject, $body)
|
||||||
{
|
{
|
||||||
|
$settings = $this->account_email_settings;
|
||||||
|
|
||||||
if ($subject) {
|
if ($subject) {
|
||||||
$this->{"email_subject_" . $type} = $subject;
|
$settings->{"email_subject_" . $type} = $subject;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($body) {
|
if ($body) {
|
||||||
$this->{"email_template_" . $type} = $body;
|
$settings->{"email_template_" . $type} = $body;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->save();
|
$settings->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBccEmail()
|
public function getBccEmail()
|
||||||
{
|
{
|
||||||
return $this->isPro() ? $this->bcc_email : false;
|
return $this->isPro() ? $this->account_email_settings->bcc_email : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getReplyToEmail()
|
||||||
|
{
|
||||||
|
return $this->isPro() ? $this->account_email_settings->reply_to_email : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFromEmail()
|
public function getFromEmail()
|
||||||
|
@ -263,7 +263,7 @@ class User extends Authenticatable
|
|||||||
// if the user changes their email then they need to reconfirm it
|
// if the user changes their email then they need to reconfirm it
|
||||||
if ($user->isEmailBeingChanged()) {
|
if ($user->isEmailBeingChanged()) {
|
||||||
$user->confirmed = 0;
|
$user->confirmed = 0;
|
||||||
$user->confirmation_code = str_random(RANDOM_KEY_LENGTH);
|
$user->confirmation_code = strtolower(str_random(RANDOM_KEY_LENGTH));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ use Utils;
|
|||||||
class AccountGatewayDatatable extends EntityDatatable
|
class AccountGatewayDatatable extends EntityDatatable
|
||||||
{
|
{
|
||||||
private static $accountGateways;
|
private static $accountGateways;
|
||||||
|
private static $accountGatewaySettings;
|
||||||
|
|
||||||
public $entityType = ENTITY_ACCOUNT_GATEWAY;
|
public $entityType = ENTITY_ACCOUNT_GATEWAY;
|
||||||
|
|
||||||
@ -19,7 +20,7 @@ class AccountGatewayDatatable extends EntityDatatable
|
|||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
[
|
[
|
||||||
'name',
|
'gateway',
|
||||||
function ($model) {
|
function ($model) {
|
||||||
if ($model->deleted_at) {
|
if ($model->deleted_at) {
|
||||||
return $model->name;
|
return $model->name;
|
||||||
@ -62,26 +63,16 @@ class AccountGatewayDatatable extends EntityDatatable
|
|||||||
[
|
[
|
||||||
'limit',
|
'limit',
|
||||||
function ($model) {
|
function ($model) {
|
||||||
if ($model->gateway_id == GATEWAY_CUSTOM) {
|
$gatewayTypes = $this->getGatewayTypes($model->id, $model->gateway_id);
|
||||||
$gatewayTypes = [GATEWAY_TYPE_CUSTOM];
|
|
||||||
} else {
|
|
||||||
$accountGateway = $this->getAccountGateway($model->id);
|
|
||||||
$paymentDriver = $accountGateway->paymentDriver();
|
|
||||||
$gatewayTypes = $paymentDriver->gatewayTypes();
|
|
||||||
$gatewayTypes = array_diff($gatewayTypes, [GATEWAY_TYPE_TOKEN]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$html = '';
|
$html = '';
|
||||||
foreach ($gatewayTypes as $gatewayTypeId) {
|
foreach ($gatewayTypes as $gatewayTypeId) {
|
||||||
$accountGatewaySettings = AccountGatewaySettings::scope()->where('account_gateway_settings.gateway_type_id',
|
$accountGatewaySettings = $this->getAccountGatewaySetting($gatewayTypeId);
|
||||||
'=', $gatewayTypeId)->first();
|
$gatewayType = Utils::getFromCache($gatewayTypeId, 'gatewayTypes');
|
||||||
$gatewayType = GatewayType::find($gatewayTypeId);
|
|
||||||
|
|
||||||
if (count($gatewayTypes) > 1) {
|
if (count($gatewayTypes) > 1) {
|
||||||
if ($html) {
|
if ($html) {
|
||||||
$html .= '<br>';
|
$html .= '<br>';
|
||||||
}
|
}
|
||||||
|
|
||||||
$html .= $gatewayType->name . ' — ';
|
$html .= $gatewayType->name . ' — ';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,6 +94,38 @@ class AccountGatewayDatatable extends EntityDatatable
|
|||||||
return $html;
|
return $html;
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'fees',
|
||||||
|
function ($model) {
|
||||||
|
if (! $model->gateway_fee_enabled) {
|
||||||
|
return trans('texts.fees_disabled');
|
||||||
|
}
|
||||||
|
|
||||||
|
$gatewayTypes = $this->getGatewayTypes($model->id, $model->gateway_id);
|
||||||
|
$html = '';
|
||||||
|
foreach ($gatewayTypes as $gatewayTypeId) {
|
||||||
|
$accountGatewaySettings = $this->getAccountGatewaySetting($gatewayTypeId);
|
||||||
|
if (! $accountGatewaySettings || ! $accountGatewaySettings->areFeesEnabled()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$gatewayType = Utils::getFromCache($gatewayTypeId, 'gatewayTypes');
|
||||||
|
|
||||||
|
if (count($gatewayTypes) > 1) {
|
||||||
|
if ($html) {
|
||||||
|
$html .= '<br>';
|
||||||
|
}
|
||||||
|
$html .= $gatewayType->name . ' — ';
|
||||||
|
}
|
||||||
|
$html .= $accountGatewaySettings->feesToString();
|
||||||
|
|
||||||
|
if ($accountGatewaySettings->hasTaxes()) {
|
||||||
|
$html .= ' + ' . trans('texts.tax');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return $html ?: trans('texts.no_fees');
|
||||||
|
},
|
||||||
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,15 +183,9 @@ class AccountGatewayDatatable extends EntityDatatable
|
|||||||
|
|
||||||
foreach (Cache::get('gatewayTypes') as $gatewayType) {
|
foreach (Cache::get('gatewayTypes') as $gatewayType) {
|
||||||
$actions[] = [
|
$actions[] = [
|
||||||
trans('texts.set_limits', ['gateway_type' => $gatewayType->name]),
|
trans('texts.set_limits_fees', ['gateway_type' => $gatewayType->name]),
|
||||||
function () use ($gatewayType) {
|
function () use ($gatewayType) {
|
||||||
$accountGatewaySettings = AccountGatewaySettings::scope()
|
return "javascript:showLimitsModal('{$gatewayType->name}', {$gatewayType->id})";
|
||||||
->where('account_gateway_settings.gateway_type_id', '=', $gatewayType->id)
|
|
||||||
->first();
|
|
||||||
$min = $accountGatewaySettings && $accountGatewaySettings->min_limit !== null ? $accountGatewaySettings->min_limit : 'null';
|
|
||||||
$max = $accountGatewaySettings && $accountGatewaySettings->max_limit !== null ? $accountGatewaySettings->max_limit : 'null';
|
|
||||||
|
|
||||||
return "javascript:showLimitsModal('{$gatewayType->name}', {$gatewayType->id}, $min, $max)";
|
|
||||||
},
|
},
|
||||||
function ($model) use ($gatewayType) {
|
function ($model) use ($gatewayType) {
|
||||||
// Only show this action if the given gateway supports this gateway type
|
// Only show this action if the given gateway supports this gateway type
|
||||||
@ -176,10 +193,7 @@ class AccountGatewayDatatable extends EntityDatatable
|
|||||||
return $gatewayType->id == GATEWAY_TYPE_CUSTOM;
|
return $gatewayType->id == GATEWAY_TYPE_CUSTOM;
|
||||||
} else {
|
} else {
|
||||||
$accountGateway = $this->getAccountGateway($model->id);
|
$accountGateway = $this->getAccountGateway($model->id);
|
||||||
$paymentDriver = $accountGateway->paymentDriver();
|
return $accountGateway->paymentDriver()->supportsGatewayType($gatewayType->id);
|
||||||
$gatewayTypes = $paymentDriver->gatewayTypes();
|
|
||||||
|
|
||||||
return in_array($gatewayType->id, $gatewayTypes);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@ -198,4 +212,30 @@ class AccountGatewayDatatable extends EntityDatatable
|
|||||||
|
|
||||||
return static::$accountGateways[$id];
|
return static::$accountGateways[$id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getAccountGatewaySetting($gatewayTypeId)
|
||||||
|
{
|
||||||
|
if (isset(static::$accountGatewaySettings[$gatewayTypeId])) {
|
||||||
|
return static::$accountGatewaySettings[$gatewayTypeId];
|
||||||
|
}
|
||||||
|
|
||||||
|
static::$accountGatewaySettings[$gatewayTypeId] = AccountGatewaySettings::scope()
|
||||||
|
->where('account_gateway_settings.gateway_type_id', '=', $gatewayTypeId)->first();
|
||||||
|
|
||||||
|
return static::$accountGatewaySettings[$gatewayTypeId];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getGatewayTypes($id, $gatewayId)
|
||||||
|
{
|
||||||
|
if ($gatewayId == GATEWAY_CUSTOM) {
|
||||||
|
$gatewayTypes = [GATEWAY_TYPE_CUSTOM];
|
||||||
|
} else {
|
||||||
|
$accountGateway = $this->getAccountGateway($id);
|
||||||
|
$paymentDriver = $accountGateway->paymentDriver();
|
||||||
|
$gatewayTypes = $paymentDriver->gatewayTypes();
|
||||||
|
$gatewayTypes = array_diff($gatewayTypes, [GATEWAY_TYPE_TOKEN]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $gatewayTypes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,13 @@ class ClientDatatable extends EntityDatatable
|
|||||||
return link_to("clients/{$model->public_id}", $model->email ?: '')->toHtml();
|
return link_to("clients/{$model->public_id}", $model->email ?: '')->toHtml();
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'id_number',
|
||||||
|
function ($model) {
|
||||||
|
return $model->id_number;
|
||||||
|
},
|
||||||
|
Auth::user()->account->clientNumbersEnabled()
|
||||||
|
],
|
||||||
[
|
[
|
||||||
'client_created_at',
|
'client_created_at',
|
||||||
function ($model) {
|
function ($model) {
|
||||||
|
@ -41,10 +41,16 @@ class CreditDatatable extends EntityDatatable
|
|||||||
'credit_date',
|
'credit_date',
|
||||||
function ($model) {
|
function ($model) {
|
||||||
if (! Auth::user()->can('viewByOwner', [ENTITY_CREDIT, $model->user_id])) {
|
if (! Auth::user()->can('viewByOwner', [ENTITY_CREDIT, $model->user_id])) {
|
||||||
return Utils::fromSqlDate($model->credit_date);
|
return Utils::fromSqlDate($model->credit_date_sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
return link_to("credits/{$model->public_id}/edit", Utils::fromSqlDate($model->credit_date))->toHtml();
|
return link_to("credits/{$model->public_id}/edit", Utils::fromSqlDate($model->credit_date_sql))->toHtml();
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'public_notes',
|
||||||
|
function ($model) {
|
||||||
|
return $model->public_notes;
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
@ -49,10 +49,10 @@ class ExpenseDatatable extends EntityDatatable
|
|||||||
'expense_date',
|
'expense_date',
|
||||||
function ($model) {
|
function ($model) {
|
||||||
if (! Auth::user()->can('viewByOwner', [ENTITY_EXPENSE, $model->user_id])) {
|
if (! Auth::user()->can('viewByOwner', [ENTITY_EXPENSE, $model->user_id])) {
|
||||||
return Utils::fromSqlDate($model->expense_date);
|
return Utils::fromSqlDate($model->expense_date_sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
return link_to("expenses/{$model->public_id}/edit", Utils::fromSqlDate($model->expense_date))->toHtml();
|
return link_to("expenses/{$model->public_id}/edit", Utils::fromSqlDate($model->expense_date_sql))->toHtml();
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
@ -73,7 +73,12 @@ class ExpenseDatatable extends EntityDatatable
|
|||||||
[
|
[
|
||||||
'category',
|
'category',
|
||||||
function ($model) {
|
function ($model) {
|
||||||
return $model->category != null ? substr($model->category, 0, 100) : '';
|
$category = $model->category != null ? substr($model->category, 0, 100) : '';
|
||||||
|
if (! Auth::user()->can('editByOwner', [ENTITY_EXPENSE_CATEGORY, $model->category_user_id])) {
|
||||||
|
return $category;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $model->category_public_id ? link_to("expense_categories/{$model->category_public_id}/edit", $category)->toHtml() : '';
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
@ -41,7 +41,7 @@ class InvoiceDatatable extends EntityDatatable
|
|||||||
[
|
[
|
||||||
'date',
|
'date',
|
||||||
function ($model) {
|
function ($model) {
|
||||||
return Utils::fromSqlDate($model->date);
|
return Utils::fromSqlDate($model->invoice_date);
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
@ -65,7 +65,7 @@ class InvoiceDatatable extends EntityDatatable
|
|||||||
[
|
[
|
||||||
$entityType == ENTITY_INVOICE ? 'due_date' : 'valid_until',
|
$entityType == ENTITY_INVOICE ? 'due_date' : 'valid_until',
|
||||||
function ($model) {
|
function ($model) {
|
||||||
return Utils::fromSqlDate($model->due_date);
|
return Utils::fromSqlDate($model->due_date_sql);
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
@ -129,7 +129,7 @@ class InvoiceDatatable extends EntityDatatable
|
|||||||
return "javascript:submitForm_{$entityType}('markPaid', {$model->public_id})";
|
return "javascript:submitForm_{$entityType}('markPaid', {$model->public_id})";
|
||||||
},
|
},
|
||||||
function ($model) use ($entityType) {
|
function ($model) use ($entityType) {
|
||||||
return $entityType == ENTITY_INVOICE && $model->balance > 0 && Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]);
|
return $entityType == ENTITY_INVOICE && $model->balance != 0 && Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]);
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
@ -173,7 +173,7 @@ class InvoiceDatatable extends EntityDatatable
|
|||||||
|
|
||||||
private function getStatusLabel($model)
|
private function getStatusLabel($model)
|
||||||
{
|
{
|
||||||
$class = Invoice::calcStatusClass($model->invoice_status_id, $model->balance, $model->due_date, $model->is_recurring);
|
$class = Invoice::calcStatusClass($model->invoice_status_id, $model->balance, $model->due_date_sql, $model->is_recurring);
|
||||||
$label = Invoice::calcStatusLabel($model->invoice_status_name, $class, $this->entityType, $model->quote_invoice_id);
|
$label = Invoice::calcStatusLabel($model->invoice_status_name, $class, $this->entityType, $model->quote_invoice_id);
|
||||||
|
|
||||||
return "<h4><div class=\"label label-{$class}\">$label</div></h4>";
|
return "<h4><div class=\"label label-{$class}\">$label</div></h4>";
|
||||||
|
@ -92,7 +92,7 @@ class PaymentDatatable extends EntityDatatable
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'payment_date',
|
'date',
|
||||||
function ($model) {
|
function ($model) {
|
||||||
if ($model->is_deleted) {
|
if ($model->is_deleted) {
|
||||||
return Utils::dateToString($model->payment_date);
|
return Utils::dateToString($model->payment_date);
|
||||||
|
@ -5,6 +5,7 @@ namespace App\Ninja\Datatables;
|
|||||||
use Auth;
|
use Auth;
|
||||||
use URL;
|
use URL;
|
||||||
use Utils;
|
use Utils;
|
||||||
|
use App\Models\Invoice;
|
||||||
|
|
||||||
class RecurringInvoiceDatatable extends EntityDatatable
|
class RecurringInvoiceDatatable extends EntityDatatable
|
||||||
{
|
{
|
||||||
@ -32,19 +33,19 @@ class RecurringInvoiceDatatable extends EntityDatatable
|
|||||||
[
|
[
|
||||||
'start_date',
|
'start_date',
|
||||||
function ($model) {
|
function ($model) {
|
||||||
return Utils::fromSqlDate($model->start_date);
|
return Utils::fromSqlDate($model->start_date_sql);
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'last_sent',
|
'last_sent',
|
||||||
function ($model) {
|
function ($model) {
|
||||||
return Utils::fromSqlDate($model->last_sent_date);
|
return Utils::fromSqlDate($model->last_sent_date_sql);
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'end_date',
|
'end_date',
|
||||||
function ($model) {
|
function ($model) {
|
||||||
return Utils::fromSqlDate($model->end_date);
|
return Utils::fromSqlDate($model->end_date_sql);
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
@ -53,9 +54,27 @@ class RecurringInvoiceDatatable extends EntityDatatable
|
|||||||
return Utils::formatMoney($model->amount, $model->currency_id, $model->country_id);
|
return Utils::formatMoney($model->amount, $model->currency_id, $model->country_id);
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'status',
|
||||||
|
function ($model) {
|
||||||
|
return self::getStatusLabel($model);
|
||||||
|
},
|
||||||
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getStatusLabel($model)
|
||||||
|
{
|
||||||
|
$class = Invoice::calcStatusClass($model->invoice_status_id, $model->balance, $model->due_date_sql, $model->is_recurring);
|
||||||
|
$label = Invoice::calcStatusLabel($model->invoice_status_name, $class, $this->entityType, $model->quote_invoice_id);
|
||||||
|
|
||||||
|
if ($model->invoice_status_id == INVOICE_STATUS_SENT && (! $model->last_sent_date_sql || $model->last_sent_date_sql == '0000-00-00')) {
|
||||||
|
$label = trans('texts.pending');
|
||||||
|
}
|
||||||
|
|
||||||
|
return "<h4><div class=\"label label-{$class}\">$label</div></h4>";
|
||||||
|
}
|
||||||
|
|
||||||
public function actions()
|
public function actions()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
|
@ -39,7 +39,7 @@ class VendorDatatable extends EntityDatatable
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'date',
|
'client_created_at',
|
||||||
function ($model) {
|
function ($model) {
|
||||||
return Utils::timestampToDateString(strtotime($model->created_at));
|
return Utils::timestampToDateString(strtotime($model->created_at));
|
||||||
},
|
},
|
||||||
|
@ -36,7 +36,7 @@ class ContactMailer extends Mailer
|
|||||||
*
|
*
|
||||||
* @return bool|null|string
|
* @return bool|null|string
|
||||||
*/
|
*/
|
||||||
public function sendInvoice(Invoice $invoice, $reminder = false, $pdfString = false, $template = false)
|
public function sendInvoice(Invoice $invoice, $reminder = false, $template = false)
|
||||||
{
|
{
|
||||||
if ($invoice->is_recurring) {
|
if ($invoice->is_recurring) {
|
||||||
return false;
|
return false;
|
||||||
@ -61,8 +61,9 @@ class ContactMailer extends Mailer
|
|||||||
$emailSubject = !empty($template['subject']) ? $template['subject'] : $account->getEmailSubject($reminder ?: $entityType);
|
$emailSubject = !empty($template['subject']) ? $template['subject'] : $account->getEmailSubject($reminder ?: $entityType);
|
||||||
|
|
||||||
$sent = false;
|
$sent = false;
|
||||||
|
$pdfString = false;
|
||||||
|
|
||||||
if ($account->attachPDF() && ! $pdfString) {
|
if ($account->attachPDF()) {
|
||||||
$pdfString = $invoice->getPDFString();
|
$pdfString = $invoice->getPDFString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,7 +199,7 @@ class ContactMailer extends Mailer
|
|||||||
}
|
}
|
||||||
|
|
||||||
$subject = $this->templateService->processVariables($subject, $variables);
|
$subject = $this->templateService->processVariables($subject, $variables);
|
||||||
$fromEmail = $user->email;
|
$fromEmail = $account->getReplyToEmail() ?: $user->email;
|
||||||
$view = $account->getTemplateView(ENTITY_INVOICE);
|
$view = $account->getTemplateView(ENTITY_INVOICE);
|
||||||
|
|
||||||
$response = $this->sendTo($invitation->contact->email, $fromEmail, $account->getDisplayName(), $subject, $view, $data);
|
$response = $this->sendTo($invitation->contact->email, $fromEmail, $account->getDisplayName(), $subject, $view, $data);
|
||||||
@ -290,9 +291,10 @@ class ContactMailer extends Mailer
|
|||||||
$data['invoice_id'] = $payment->invoice->id;
|
$data['invoice_id'] = $payment->invoice->id;
|
||||||
|
|
||||||
$view = $account->getTemplateView('payment_confirmation');
|
$view = $account->getTemplateView('payment_confirmation');
|
||||||
|
$fromEmail = $account->getReplyToEmail() ?: $user->email;
|
||||||
|
|
||||||
if ($user->email && $contact->email) {
|
if ($user->email && $contact->email) {
|
||||||
$this->sendTo($contact->email, $user->email, $accountName, $subject, $view, $data);
|
$this->sendTo($contact->email, $fromEmail, $accountName, $subject, $view, $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
$account->loadLocalizationSettings();
|
$account->loadLocalizationSettings();
|
||||||
|
@ -58,12 +58,7 @@ class UserMailer extends Mailer
|
|||||||
$view = ($notificationType == 'approved' ? ENTITY_QUOTE : ENTITY_INVOICE) . "_{$notificationType}";
|
$view = ($notificationType == 'approved' ? ENTITY_QUOTE : ENTITY_INVOICE) . "_{$notificationType}";
|
||||||
$account = $user->account;
|
$account = $user->account;
|
||||||
$client = $invoice->client;
|
$client = $invoice->client;
|
||||||
|
$link = $invoice->present()->multiAccountLink;
|
||||||
if ($account->hasMultipleAccounts()) {
|
|
||||||
$link = url(sprintf('/account/%s?redirect_to=%s', $account->account_key, $invoice->present()->path));
|
|
||||||
} else {
|
|
||||||
$link = $invoice->present()->url;
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'entityType' => $entityType,
|
'entityType' => $entityType,
|
||||||
@ -116,6 +111,26 @@ class UserMailer extends Mailer
|
|||||||
$this->sendTo($user->email, CONTACT_EMAIL, CONTACT_NAME, $subject, $view, $data);
|
$this->sendTo($user->email, CONTACT_EMAIL, CONTACT_NAME, $subject, $view, $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Invitation $invitation
|
||||||
|
*/
|
||||||
|
public function sendMessage($user, $subject, $message, $invoice = false)
|
||||||
|
{
|
||||||
|
if (! $user->email) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$view = 'user_message';
|
||||||
|
$data = [
|
||||||
|
'userName' => $user->getDisplayName(),
|
||||||
|
'primaryMessage' => $subject,
|
||||||
|
'secondaryMessage' => $message,
|
||||||
|
'invoiceLink' => $invoice ? $invoice->present()->multiAccountLink : false,
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->sendTo($user->email, CONTACT_EMAIL, CONTACT_NAME, $subject, $view, $data);
|
||||||
|
}
|
||||||
|
|
||||||
public function sendSecurityCode($user, $code)
|
public function sendSecurityCode($user, $code)
|
||||||
{
|
{
|
||||||
if (! $user->email) {
|
if (! $user->email) {
|
||||||
|
44
app/Ninja/OAuth/OAuth.php
Normal file
44
app/Ninja/OAuth/OAuth.php
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<?php namespace App\Ninja\OAuth;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
|
|
||||||
|
class OAuth {
|
||||||
|
|
||||||
|
private $providerInstance;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getProvider($provider)
|
||||||
|
{
|
||||||
|
switch ($provider)
|
||||||
|
{
|
||||||
|
case 'google';
|
||||||
|
$this->providerInstance = new Providers\Google();
|
||||||
|
return $this;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTokenResponse($token)
|
||||||
|
{
|
||||||
|
$email = null;
|
||||||
|
$user = null;
|
||||||
|
|
||||||
|
if($this->providerInstance)
|
||||||
|
$user = User::where('email', $this->providerInstance->getTokenResponse($token))->first();
|
||||||
|
|
||||||
|
if ($user)
|
||||||
|
return $user;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
?>
|
23
app/Ninja/OAuth/Providers/Google.php
Normal file
23
app/Ninja/OAuth/Providers/Google.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php namespace App\Ninja\OAuth\Providers;
|
||||||
|
|
||||||
|
class Google implements ProviderInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
public function getTokenResponse($token)
|
||||||
|
{
|
||||||
|
|
||||||
|
$client = new \Google_Client(['client_id' => env('GOOGLE_CLIENT_ID','')]);
|
||||||
|
$payload = $client->verifyIdToken($token);
|
||||||
|
if ($payload)
|
||||||
|
return $this->harvestEmail($payload);
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function harvestEmail($payload)
|
||||||
|
{
|
||||||
|
return $payload['email'];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
9
app/Ninja/OAuth/Providers/ProviderInterface.php
Normal file
9
app/Ninja/OAuth/Providers/ProviderInterface.php
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?php namespace App\Ninja\OAuth\Providers;
|
||||||
|
|
||||||
|
interface ProviderInterface
|
||||||
|
{
|
||||||
|
public function getTokenResponse($token);
|
||||||
|
|
||||||
|
public function harvestEmail($response);
|
||||||
|
|
||||||
|
}
|
@ -132,6 +132,12 @@ class BasePaymentDriver
|
|||||||
return redirect()->to('view/' . $this->invitation->invitation_key);
|
return redirect()->to('view/' . $this->invitation->invitation_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (! $this->isGatewayType(GATEWAY_TYPE_TOKEN)) {
|
||||||
|
// apply gateway fees
|
||||||
|
$invoicRepo = app('App\Ninja\Repositories\InvoiceRepository');
|
||||||
|
$invoicRepo->setGatewayFee($this->invoice(), $this->gatewayType);
|
||||||
|
}
|
||||||
|
|
||||||
if ($this->isGatewayType(GATEWAY_TYPE_TOKEN) || $gateway->is_offsite) {
|
if ($this->isGatewayType(GATEWAY_TYPE_TOKEN) || $gateway->is_offsite) {
|
||||||
if (Session::has('error')) {
|
if (Session::has('error')) {
|
||||||
Session::reflash();
|
Session::reflash();
|
||||||
@ -161,6 +167,7 @@ class BasePaymentDriver
|
|||||||
'invoiceNumber' => $this->invoice()->invoice_number,
|
'invoiceNumber' => $this->invoice()->invoice_number,
|
||||||
'client' => $this->client(),
|
'client' => $this->client(),
|
||||||
'contact' => $this->invitation->contact,
|
'contact' => $this->invitation->contact,
|
||||||
|
'invitation' => $this->invitation,
|
||||||
'gatewayType' => $this->gatewayType,
|
'gatewayType' => $this->gatewayType,
|
||||||
'currencyId' => $this->client()->getCurrencyId(),
|
'currencyId' => $this->client()->getCurrencyId(),
|
||||||
'currencyCode' => $this->client()->getCurrencyCode(),
|
'currencyCode' => $this->client()->getCurrencyCode(),
|
||||||
@ -262,6 +269,9 @@ class BasePaymentDriver
|
|||||||
->firstOrFail();
|
->firstOrFail();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$invoicRepo = app('App\Ninja\Repositories\InvoiceRepository');
|
||||||
|
$invoicRepo->setGatewayFee($this->invoice(), $paymentMethod->payment_type->gateway_type_id);
|
||||||
|
|
||||||
if (! $this->meetsGatewayTypeLimits($paymentMethod->payment_type->gateway_type_id)) {
|
if (! $this->meetsGatewayTypeLimits($paymentMethod->payment_type->gateway_type_id)) {
|
||||||
// The customer must have hacked the URL
|
// The customer must have hacked the URL
|
||||||
Session::flash('error', trans('texts.limits_not_met'));
|
Session::flash('error', trans('texts.limits_not_met'));
|
||||||
@ -854,6 +864,8 @@ class BasePaymentDriver
|
|||||||
$label = trans('texts.payment_type_on_file', ['type' => $paymentMethod->payment_type->name]);
|
$label = trans('texts.payment_type_on_file', ['type' => $paymentMethod->payment_type->name]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$label .= $this->invoice()->present()->gatewayFee($paymentMethod->payment_type->gateway_type_id);
|
||||||
|
|
||||||
$links[] = [
|
$links[] = [
|
||||||
'url' => $url,
|
'url' => $url,
|
||||||
'label' => $label,
|
'label' => $label,
|
||||||
@ -886,6 +898,8 @@ class BasePaymentDriver
|
|||||||
$label = trans("texts.{$gatewayTypeAlias}");
|
$label = trans("texts.{$gatewayTypeAlias}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$label .= $this->invoice()->present()->gatewayFee($gatewayTypeId);
|
||||||
|
|
||||||
$links[] = [
|
$links[] = [
|
||||||
'gatewayTypeId' => $gatewayTypeId,
|
'gatewayTypeId' => $gatewayTypeId,
|
||||||
'url' => $url,
|
'url' => $url,
|
||||||
@ -896,6 +910,11 @@ class BasePaymentDriver
|
|||||||
return $links;
|
return $links;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function supportsGatewayType($gatewayTypeId)
|
||||||
|
{
|
||||||
|
return in_array($gatewayTypeId, $this->gatewayTypes());
|
||||||
|
}
|
||||||
|
|
||||||
protected function meetsGatewayTypeLimits($gatewayTypeId)
|
protected function meetsGatewayTypeLimits($gatewayTypeId)
|
||||||
{
|
{
|
||||||
if (! $gatewayTypeId) {
|
if (! $gatewayTypeId) {
|
||||||
@ -925,17 +944,6 @@ class BasePaymentDriver
|
|||||||
$account = $this->account();
|
$account = $this->account();
|
||||||
$url = URL::to("/payment/{$this->invitation->invitation_key}/{$gatewayTypeAlias}");
|
$url = URL::to("/payment/{$this->invitation->invitation_key}/{$gatewayTypeAlias}");
|
||||||
|
|
||||||
$gatewayTypeId = GatewayType::getIdFromAlias($gatewayTypeAlias);
|
|
||||||
|
|
||||||
// PayPal doesn't allow being run in an iframe so we need to open in new tab
|
|
||||||
if ($gatewayTypeId === GATEWAY_TYPE_PAYPAL) {
|
|
||||||
$url .= '#braintree_paypal';
|
|
||||||
|
|
||||||
if ($account->iframe_url) {
|
|
||||||
return 'javascript:window.open("' . $url . '", "_blank")';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $url;
|
return $url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ namespace App\Ninja\PaymentDrivers;
|
|||||||
use Braintree\Customer;
|
use Braintree\Customer;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Session;
|
use Session;
|
||||||
|
use App\Models\GatewayType;
|
||||||
|
|
||||||
class BraintreePaymentDriver extends BasePaymentDriver
|
class BraintreePaymentDriver extends BasePaymentDriver
|
||||||
{
|
{
|
||||||
@ -62,6 +63,17 @@ class BraintreePaymentDriver extends BasePaymentDriver
|
|||||||
return $customer instanceof Customer;
|
return $customer instanceof Customer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function paymentUrl($gatewayTypeAlias)
|
||||||
|
{
|
||||||
|
$url = parent::paymentUrl($gatewayTypeAlias);
|
||||||
|
|
||||||
|
if (GatewayType::getIdFromAlias($gatewayTypeAlias) === GATEWAY_TYPE_PAYPAL) {
|
||||||
|
$url .= '#braintree_paypal';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
|
||||||
protected function paymentDetails($paymentMethod = false)
|
protected function paymentDetails($paymentMethod = false)
|
||||||
{
|
{
|
||||||
$data = parent::paymentDetails($paymentMethod);
|
$data = parent::paymentDetails($paymentMethod);
|
||||||
|
@ -17,6 +17,7 @@ class PayPalExpressPaymentDriver extends BasePaymentDriver
|
|||||||
|
|
||||||
$data['ButtonSource'] = 'InvoiceNinja_SP';
|
$data['ButtonSource'] = 'InvoiceNinja_SP';
|
||||||
$data['solutionType'] = 'Sole'; // show 'Pay with credit card' option
|
$data['solutionType'] = 'Sole'; // show 'Pay with credit card' option
|
||||||
|
$data['transactionId'] = $data['transactionId'] . '-' . time();
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
@ -27,4 +28,17 @@ class PayPalExpressPaymentDriver extends BasePaymentDriver
|
|||||||
|
|
||||||
return $payment;
|
return $payment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function paymentUrl($gatewayTypeAlias)
|
||||||
|
{
|
||||||
|
$url = parent::paymentUrl($gatewayTypeAlias);
|
||||||
|
|
||||||
|
// PayPal doesn't allow being run in an iframe so we need to open in new tab
|
||||||
|
if ($this->account()->iframe_url) {
|
||||||
|
return 'javascript:window.open("' . $url . '", "_blank")';
|
||||||
|
} else {
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -56,12 +56,14 @@ class WePayPaymentDriver extends BasePaymentDriver
|
|||||||
$data['transaction_id'] = $transactionId;
|
$data['transaction_id'] = $transactionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
$data['applicationFee'] = (env('WEPAY_APP_FEE_MULTIPLIER') * $data['amount']) + env('WEPAY_APP_FEE_FIXED');
|
|
||||||
$data['feePayer'] = env('WEPAY_FEE_PAYER');
|
$data['feePayer'] = env('WEPAY_FEE_PAYER');
|
||||||
$data['callbackUri'] = $this->accountGateway->getWebhookUrl();
|
$data['callbackUri'] = $this->accountGateway->getWebhookUrl();
|
||||||
|
|
||||||
if ($this->isGatewayType(GATEWAY_TYPE_BANK_TRANSFER, $paymentMethod)) {
|
if ($this->isGatewayType(GATEWAY_TYPE_BANK_TRANSFER, $paymentMethod)) {
|
||||||
$data['paymentMethodType'] = 'payment_bank';
|
$data['paymentMethodType'] = 'payment_bank';
|
||||||
|
$data['applicationFee'] = (env('WEPAY_APP_FEE_ACH_MULTIPLIER') * $data['amount']) + env('WEPAY_APP_FEE_FIXED');
|
||||||
|
} else {
|
||||||
|
$data['applicationFee'] = (env('WEPAY_APP_FEE_CC_MULTIPLIER') * $data['amount']) + env('WEPAY_APP_FEE_FIXED');
|
||||||
}
|
}
|
||||||
|
|
||||||
$data['transaction_rbits'] = $this->invoice()->present()->rBits;
|
$data['transaction_rbits'] = $this->invoice()->present()->rBits;
|
||||||
|
@ -149,4 +149,28 @@ class AccountPresenter extends Presenter
|
|||||||
|
|
||||||
return $options;
|
return $options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function customTextFields()
|
||||||
|
{
|
||||||
|
$fields = [
|
||||||
|
'custom_client_label1' => 'custom_client1',
|
||||||
|
'custom_client_label2' => 'custom_client2',
|
||||||
|
'custom_invoice_text_label1' => 'custom_invoice1',
|
||||||
|
'custom_invoice_text_label2' => 'custom_invoice2',
|
||||||
|
'custom_invoice_item_label1' => 'custom_product1',
|
||||||
|
'custom_invoice_item_label2' => 'custom_product2',
|
||||||
|
];
|
||||||
|
$data = [];
|
||||||
|
|
||||||
|
foreach ($fields as $key => $val) {
|
||||||
|
if ($this->$key) {
|
||||||
|
$data[$this->$key] = [
|
||||||
|
'value' => $val,
|
||||||
|
'name' => $val,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -225,7 +225,7 @@ class InvoicePresenter extends EntityPresenter
|
|||||||
$actions[] = ['url' => url("quotes/{$invoice->quote_id}/edit"), 'label' => trans('texts.view_quote')];
|
$actions[] = ['url' => url("quotes/{$invoice->quote_id}/edit"), 'label' => trans('texts.view_quote')];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$invoice->deleted_at && ! $invoice->is_recurring && $invoice->balance > 0) {
|
if (!$invoice->deleted_at && ! $invoice->is_recurring && $invoice->balance != 0) {
|
||||||
$actions[] = ['url' => 'javascript:submitBulkAction("markPaid")', 'label' => trans('texts.mark_paid')];
|
$actions[] = ['url' => 'javascript:submitBulkAction("markPaid")', 'label' => trans('texts.mark_paid')];
|
||||||
$actions[] = ['url' => 'javascript:onPaymentClick()', 'label' => trans('texts.enter_payment')];
|
$actions[] = ['url' => 'javascript:onPaymentClick()', 'label' => trans('texts.enter_payment')];
|
||||||
}
|
}
|
||||||
@ -252,4 +252,45 @@ class InvoicePresenter extends EntityPresenter
|
|||||||
|
|
||||||
return $actions;
|
return $actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function gatewayFee($gatewayTypeId = false)
|
||||||
|
{
|
||||||
|
$invoice = $this->entity;
|
||||||
|
$account = $invoice->account;
|
||||||
|
|
||||||
|
if (! $account->gateway_fee_enabled) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$settings = $account->getGatewaySettings($gatewayTypeId);
|
||||||
|
|
||||||
|
if (! $settings || ! $settings->areFeesEnabled()) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$fee = $invoice->calcGatewayFee($gatewayTypeId, true);
|
||||||
|
$fee = $account->formatMoney($fee, $invoice->client);
|
||||||
|
|
||||||
|
if (floatval($settings->fee_amount) < 0 || floatval($settings->fee_percent) < 0) {
|
||||||
|
$label = trans('texts.discount');
|
||||||
|
} else {
|
||||||
|
$label = trans('texts.fee');
|
||||||
|
}
|
||||||
|
|
||||||
|
return ' - ' . $fee . ' ' . $label;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function multiAccountLink()
|
||||||
|
{
|
||||||
|
$invoice = $this->entity;
|
||||||
|
$account = $invoice->account;
|
||||||
|
|
||||||
|
if ($account->hasMultipleAccounts()) {
|
||||||
|
$link = url(sprintf('/account/%s?redirect_to=%s', $account->account_key, $invoice->present()->path));
|
||||||
|
} else {
|
||||||
|
$link = $invoice->present()->url;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $link;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ class AbstractReport
|
|||||||
|
|
||||||
public function run()
|
public function run()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function results()
|
public function results()
|
||||||
@ -66,7 +67,7 @@ class AbstractReport
|
|||||||
|
|
||||||
if (strpos($field, 'date') !== false) {
|
if (strpos($field, 'date') !== false) {
|
||||||
$class[] = 'group-date-' . (isset($this->options['group_dates_by']) ? $this->options['group_dates_by'] : 'monthyear');
|
$class[] = 'group-date-' . (isset($this->options['group_dates_by']) ? $this->options['group_dates_by'] : 'monthyear');
|
||||||
} elseif (in_array($field, ['client', 'vendor', 'product', 'method', 'category'])) {
|
} elseif (in_array($field, ['client', 'vendor', 'product', 'user', 'method', 'category', 'project'])) {
|
||||||
$class[] = 'group-letter-100';
|
$class[] = 'group-letter-100';
|
||||||
} elseif (in_array($field, ['amount', 'paid', 'balance'])) {
|
} elseif (in_array($field, ['amount', 'paid', 'balance'])) {
|
||||||
$class[] = 'group-number-50';
|
$class[] = 'group-number-50';
|
||||||
|
41
app/Ninja/Reports/ActivityReport.php
Normal file
41
app/Ninja/Reports/ActivityReport.php
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Ninja\Reports;
|
||||||
|
|
||||||
|
use App\Models\Activity;
|
||||||
|
use Auth;
|
||||||
|
|
||||||
|
class ActivityReport extends AbstractReport
|
||||||
|
{
|
||||||
|
public $columns = [
|
||||||
|
'date',
|
||||||
|
'client',
|
||||||
|
'user',
|
||||||
|
'activity',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
$account = Auth::user()->account;
|
||||||
|
|
||||||
|
$startDate = $this->startDate->format('Y-m-d');
|
||||||
|
$endDate = $this->endDate->format('Y-m-d');
|
||||||
|
|
||||||
|
$activities = Activity::scope()
|
||||||
|
->with('client.contacts', 'user', 'invoice', 'payment', 'credit', 'task', 'expense', 'account')
|
||||||
|
->whereRaw("DATE(created_at) >= \"{$startDate}\" and DATE(created_at) <= \"$endDate\"")
|
||||||
|
->orderBy('id', 'desc');
|
||||||
|
|
||||||
|
foreach ($activities->get() as $activity) {
|
||||||
|
$client = $activity->client;
|
||||||
|
$this->data[] = [
|
||||||
|
$activity->present()->createdAt,
|
||||||
|
$client ? ($this->isExport ? $client->getDisplayName() : $client->present()->link) : '',
|
||||||
|
$activity->present()->user,
|
||||||
|
$activity->getMessage(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -22,6 +22,7 @@ class AgingReport extends AbstractReport
|
|||||||
$account = Auth::user()->account;
|
$account = Auth::user()->account;
|
||||||
|
|
||||||
$clients = Client::scope()
|
$clients = Client::scope()
|
||||||
|
->orderBy('name')
|
||||||
->withArchived()
|
->withArchived()
|
||||||
->with('contacts')
|
->with('contacts')
|
||||||
->with(['invoices' => function ($query) {
|
->with(['invoices' => function ($query) {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user