mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Merge branch 'release-2.5.2'
Conflicts: app/Http/Controllers/AppController.php app/Http/routes.php app/Models/Account.php app/Models/Invitation.php composer.json composer.lock resources/lang/de/texts.php resources/lang/fr/texts.php resources/views/header.blade.php
This commit is contained in:
commit
da911d090e
26
.env.example
26
.env.example
@ -43,4 +43,28 @@ API_SECRET=password
|
||||
#GOOGLE_CLIENT_SECRET=
|
||||
#GOOGLE_OAUTH_REDIRECT=http://ninja.dev/auth/google
|
||||
|
||||
#GOOGLE_MAPS_API_KEY=
|
||||
#GOOGLE_MAPS_API_KEY=
|
||||
|
||||
#S3_KEY=
|
||||
#S3_SECRET=
|
||||
#S3_REGION=
|
||||
#S3_BUCKET=
|
||||
|
||||
#RACKSPACE_USERNAME=
|
||||
#RACKSPACE_KEY=
|
||||
#RACKSPACE_CONTAINER=
|
||||
#RACKSPACE_REGION=
|
||||
|
||||
#RACKSPACE_TEMP_URL_SECRET=
|
||||
|
||||
# If this is set to anything, the URL secret will be set the next
|
||||
# time a file is downloaded through the client portal.
|
||||
# Only set this temporarily, as it slows things down.
|
||||
#RACKSPACE_TEMP_URL_SECRET_SET=
|
||||
|
||||
#DOCUMENT_FILESYSTEM=
|
||||
|
||||
#MAX_DOCUMENT_SIZE # KB
|
||||
#MAX_EMAIL_DOCUMENTS_SIZE # Total KB
|
||||
#MAX_ZIP_DOCUMENTS_SIZE # Total KB (uncompressed)
|
||||
#DOCUMENT_PREVIEW_SIZE # Pixels
|
138
.htaccess
138
.htaccess
@ -6,3 +6,141 @@
|
||||
# https://coderwall.com/p/erbaig/laravel-s-htaccess-to-remove-public-from-url
|
||||
# RewriteRule ^(.*)$ public/$1 [L]
|
||||
</IfModule>
|
||||
|
||||
# https://github.com/h5bp/server-configs-apache/blob/master/dist/.htaccess
|
||||
|
||||
|
||||
# ######################################################################
|
||||
# # INTERNET EXPLORER #
|
||||
# ######################################################################
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# | Iframes cookies |
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
# Allow cookies to be set from iframes in Internet Explorer.
|
||||
#
|
||||
# https://msdn.microsoft.com/en-us/library/ms537343.aspx
|
||||
# http://www.w3.org/TR/2000/CR-P3P-20001215/
|
||||
|
||||
<IfModule mod_headers.c>
|
||||
Header set P3P "policyref=\"/w3c/p3p.xml\", CP=\"IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\""
|
||||
</IfModule>
|
||||
|
||||
|
||||
# ######################################################################
|
||||
# # MEDIA TYPES AND CHARACTER ENCODINGS #
|
||||
# ######################################################################
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# | Character encodings |
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
# Serve all resources labeled as `text/html` or `text/plain`
|
||||
# with the media type `charset` parameter set to `UTF-8`.
|
||||
#
|
||||
# https://httpd.apache.org/docs/current/mod/core.html#adddefaultcharset
|
||||
|
||||
AddDefaultCharset utf-8
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
# Serve the following file types with the media type `charset`
|
||||
# parameter set to `UTF-8`.
|
||||
#
|
||||
# https://httpd.apache.org/docs/current/mod/mod_mime.html#addcharset
|
||||
|
||||
<IfModule mod_mime.c>
|
||||
AddCharset utf-8 .atom \
|
||||
.bbaw \
|
||||
.css \
|
||||
.geojson \
|
||||
.js \
|
||||
.json \
|
||||
.jsonld \
|
||||
.manifest \
|
||||
.rdf \
|
||||
.rss \
|
||||
.topojson \
|
||||
.vtt \
|
||||
.webapp \
|
||||
.webmanifest \
|
||||
.xloc \
|
||||
.xml
|
||||
</IfModule>
|
||||
|
||||
|
||||
# ######################################################################
|
||||
# # WEB PERFORMANCE #
|
||||
# ######################################################################
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# | Compression |
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
<IfModule mod_deflate.c>
|
||||
|
||||
# Force compression for mangled headers.
|
||||
# https://developer.yahoo.com/blogs/ydn/pushing-beyond-gzipping-25601.html
|
||||
|
||||
<IfModule mod_setenvif.c>
|
||||
<IfModule mod_headers.c>
|
||||
SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding
|
||||
RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding
|
||||
</IfModule>
|
||||
</IfModule>
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
# Map certain file types to the specified encoding type in order to
|
||||
# make Apache serve them with the appropriate `Content-Encoding` HTTP
|
||||
# response header (this will NOT make Apache compress them!).
|
||||
|
||||
# If the following file types wouldn't be served without the appropriate
|
||||
# `Content-Enable` HTTP response header, client applications (e.g.:
|
||||
# browsers) wouldn't know that they first need to uncompress the response,
|
||||
# and thus, wouldn't be able to understand the content.
|
||||
|
||||
# http://httpd.apache.org/docs/current/mod/mod_mime.html#addencoding
|
||||
|
||||
<IfModule mod_mime.c>
|
||||
AddEncoding gzip svgz
|
||||
</IfModule>
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
# Compress all output labeled with one of the following media types.
|
||||
|
||||
# IMPORTANT: For Apache versions below 2.3.7 you don't need to enable
|
||||
# `mod_filter` and can remove the `<IfModule mod_filter.c>` & `</IfModule>`
|
||||
# lines as `AddOutputFilterByType` is still in the core directives.
|
||||
|
||||
<IfModule mod_filter.c>
|
||||
AddOutputFilterByType DEFLATE "application/atom+xml" \
|
||||
"application/javascript" \
|
||||
"application/json" \
|
||||
"application/ld+json" \
|
||||
"application/manifest+json" \
|
||||
"application/rdf+xml" \
|
||||
"application/rss+xml" \
|
||||
"application/schema+json" \
|
||||
"application/vnd.geo+json" \
|
||||
"application/vnd.ms-fontobject" \
|
||||
"application/x-font-ttf" \
|
||||
"application/x-web-app-manifest+json" \
|
||||
"application/xhtml+xml" \
|
||||
"application/xml" \
|
||||
"font/opentype" \
|
||||
"image/svg+xml" \
|
||||
"image/x-icon" \
|
||||
"text/cache-manifest" \
|
||||
"text/css" \
|
||||
"text/html" \
|
||||
"text/javascript" \
|
||||
"text/plain" \
|
||||
"text/vtt" \
|
||||
"text/x-component" \
|
||||
"text/xml"
|
||||
</IfModule>
|
||||
|
||||
</IfModule>
|
@ -45,7 +45,8 @@ before_script:
|
||||
- php artisan key:generate --no-interaction
|
||||
- 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/REQUIRE_HTTPS=false/NINJA_DEV=true/g' .env
|
||||
- sed -i '$a NINJA_DEV=true' .env
|
||||
- sed -i '$a TRAVIS=true' .env
|
||||
# create the database and user
|
||||
- mysql -u root -e "create database IF NOT EXISTS ninja;"
|
||||
- mysql -u root -e "GRANT ALL PRIVILEGES ON ninja.* To 'ninja'@'localhost' IDENTIFIED BY 'ninja'; FLUSH PRIVILEGES;"
|
||||
@ -87,7 +88,10 @@ after_script:
|
||||
- mysql -u root -e 'select * from clients;' ninja
|
||||
- mysql -u root -e 'select * from invoices;' ninja
|
||||
- mysql -u root -e 'select * from invoice_items;' ninja
|
||||
- cat storage/logs/laravel.log
|
||||
- mysql -u root -e 'select * from payments;' ninja
|
||||
- mysql -u root -e 'select * from credits;' ninja
|
||||
- cat storage/logs/laravel-error.log
|
||||
- cat storage/logs/laravel-info.log
|
||||
|
||||
notifications:
|
||||
email:
|
||||
|
@ -95,6 +95,7 @@ module.exports = function(grunt) {
|
||||
'public/vendor/bootstrap-datepicker/dist/locales/bootstrap-datepicker.no.min.js',
|
||||
'public/vendor/bootstrap-datepicker/dist/locales/bootstrap-datepicker.es.min.js',
|
||||
'public/vendor/bootstrap-datepicker/dist/locales/bootstrap-datepicker.sv.min.js',
|
||||
'public/vendor/dropzone/dist/min/dropzone.min.js',
|
||||
'public/vendor/typeahead.js/dist/typeahead.jquery.min.js',
|
||||
'public/vendor/accounting/accounting.min.js',
|
||||
'public/vendor/spectrum/spectrum.js',
|
||||
@ -137,6 +138,7 @@ module.exports = function(grunt) {
|
||||
'public/vendor/datatables-bootstrap3/BS3/assets/css/datatables.css',
|
||||
'public/vendor/font-awesome/css/font-awesome.min.css',
|
||||
'public/vendor/bootstrap-datepicker/dist/css/bootstrap-datepicker3.css',
|
||||
'public/vendor/dropzone/dist/min/dropzone.min.css',
|
||||
'public/vendor/spectrum/spectrum.css',
|
||||
'public/css/bootstrap-combobox.css',
|
||||
'public/css/typeahead.js-bootstrap.css',
|
||||
@ -169,7 +171,7 @@ module.exports = function(grunt) {
|
||||
'public/js/pdf_viewer.js',
|
||||
'public/js/compatibility.js',
|
||||
'public/js/pdfmake.min.js',
|
||||
'public/js/vfs_fonts.js',
|
||||
'public/js/vfs.js',
|
||||
],
|
||||
dest: 'public/pdf.built.js',
|
||||
nonull: true
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?php namespace app\Commands;
|
||||
<?php namespace App\Commands;
|
||||
|
||||
abstract class Command
|
||||
{
|
||||
|
172
app/Console/Commands/CreateTestData.php
Normal file
172
app/Console/Commands/CreateTestData.php
Normal file
@ -0,0 +1,172 @@
|
||||
<?php namespace App\Console\Commands;
|
||||
|
||||
use stdClass;
|
||||
use Auth;
|
||||
use DB;
|
||||
use Utils;
|
||||
use Artisan;
|
||||
use Illuminate\Console\Command;
|
||||
use Faker\Factory;
|
||||
use App\Models\User;
|
||||
|
||||
use App\Ninja\Repositories\ClientRepository;
|
||||
use App\Ninja\Repositories\InvoiceRepository;
|
||||
use App\Ninja\Repositories\PaymentRepository;
|
||||
use App\Ninja\Repositories\VendorRepository;
|
||||
use App\Ninja\Repositories\ExpenseRepository;
|
||||
|
||||
class CreateTestData extends Command
|
||||
{
|
||||
//protected $name = 'ninja:create-test-data';
|
||||
protected $description = 'Create Test Data';
|
||||
protected $signature = 'ninja:create-test-data {count=1}';
|
||||
|
||||
protected $token;
|
||||
|
||||
public function __construct(
|
||||
ClientRepository $clientRepo,
|
||||
InvoiceRepository $invoiceRepo,
|
||||
PaymentRepository $paymentRepo,
|
||||
VendorRepository $vendorRepo,
|
||||
ExpenseRepository $expenseRepo)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->faker = Factory::create();
|
||||
|
||||
$this->clientRepo = $clientRepo;
|
||||
$this->invoiceRepo = $invoiceRepo;
|
||||
$this->paymentRepo = $paymentRepo;
|
||||
$this->vendorRepo = $vendorRepo;
|
||||
$this->expenseRepo = $expenseRepo;
|
||||
}
|
||||
|
||||
public function fire()
|
||||
{
|
||||
if (Utils::isNinjaProd()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->info(date('Y-m-d').' Running CreateTestData...');
|
||||
|
||||
Auth::loginUsingId(1);
|
||||
$this->count = $this->argument('count');
|
||||
|
||||
$this->createClients();
|
||||
$this->createVendors();
|
||||
|
||||
$this->info('Done');
|
||||
}
|
||||
|
||||
private function createClients()
|
||||
{
|
||||
for ($i=0; $i<$this->count; $i++) {
|
||||
$data = [
|
||||
'name' => $this->faker->name,
|
||||
'address1' => $this->faker->streetAddress,
|
||||
'address2' => $this->faker->secondaryAddress,
|
||||
'city' => $this->faker->city,
|
||||
'state' => $this->faker->state,
|
||||
'postal_code' => $this->faker->postcode,
|
||||
'contacts' => [[
|
||||
'first_name' => $this->faker->firstName,
|
||||
'last_name' => $this->faker->lastName,
|
||||
'email' => $this->faker->safeEmail,
|
||||
'phone' => $this->faker->phoneNumber,
|
||||
]]
|
||||
];
|
||||
|
||||
$client = $this->clientRepo->save($data);
|
||||
$this->info('Client: ' . $client->name);
|
||||
|
||||
$this->createInvoices($client);
|
||||
}
|
||||
}
|
||||
|
||||
private function createInvoices($client)
|
||||
{
|
||||
for ($i=0; $i<$this->count; $i++) {
|
||||
$data = [
|
||||
'client_id' => $client->id,
|
||||
'invoice_items' => [[
|
||||
'product_key' => $this->faker->word,
|
||||
'qty' => $this->faker->randomDigit + 1,
|
||||
'cost' => $this->faker->randomFloat(2, 1, 10),
|
||||
'notes' => $this->faker->text($this->faker->numberBetween(50, 300))
|
||||
]]
|
||||
];
|
||||
|
||||
$invoice = $this->invoiceRepo->save($data);
|
||||
$this->info('Invoice: ' . $invoice->invoice_number);
|
||||
|
||||
$this->createPayment($client, $invoice);
|
||||
}
|
||||
}
|
||||
|
||||
private function createPayment($client, $invoice)
|
||||
{
|
||||
$data = [
|
||||
'invoice_id' => $invoice->id,
|
||||
'client_id' => $client->id,
|
||||
'amount' => $this->faker->randomFloat(2, 0, $invoice->amount)
|
||||
];
|
||||
|
||||
$payment = $this->paymentRepo->save($data);
|
||||
|
||||
$this->info('Payment: ' . $payment->amount);
|
||||
}
|
||||
|
||||
private function createVendors()
|
||||
{
|
||||
for ($i=0; $i<$this->count; $i++) {
|
||||
$data = [
|
||||
'name' => $this->faker->name,
|
||||
'address1' => $this->faker->streetAddress,
|
||||
'address2' => $this->faker->secondaryAddress,
|
||||
'city' => $this->faker->city,
|
||||
'state' => $this->faker->state,
|
||||
'postal_code' => $this->faker->postcode,
|
||||
'vendor_contacts' => [[
|
||||
'first_name' => $this->faker->firstName,
|
||||
'last_name' => $this->faker->lastName,
|
||||
'email' => $this->faker->safeEmail,
|
||||
'phone' => $this->faker->phoneNumber,
|
||||
]]
|
||||
];
|
||||
|
||||
$vendor = $this->vendorRepo->save($data);
|
||||
$this->info('Vendor: ' . $vendor->name);
|
||||
|
||||
$this->createExpense($vendor);
|
||||
}
|
||||
}
|
||||
|
||||
private function createExpense($vendor)
|
||||
{
|
||||
for ($i=0; $i<$this->count; $i++) {
|
||||
$data = [
|
||||
'vendor_id' => $vendor->id,
|
||||
'amount' => $this->faker->randomFloat(2, 1, 10),
|
||||
'expense_date' => null,
|
||||
'public_notes' => null,
|
||||
];
|
||||
|
||||
$expense = $this->expenseRepo->save($data);
|
||||
$this->info('Expense: ' . $expense->amount);
|
||||
}
|
||||
}
|
||||
|
||||
protected function getArguments()
|
||||
{
|
||||
return array(
|
||||
//array('example', InputArgument::REQUIRED, 'An example argument.'),
|
||||
);
|
||||
}
|
||||
|
||||
protected function getOptions()
|
||||
{
|
||||
return array(
|
||||
//array('example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
<?php namespace app\Console\Commands;
|
||||
<?php namespace App\Console\Commands;
|
||||
|
||||
use File;
|
||||
use Illuminate\Console\Command;
|
||||
|
57
app/Console/Commands/PruneData.php
Normal file
57
app/Console/Commands/PruneData.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php namespace App\Console\Commands;
|
||||
|
||||
use DB;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class PruneData extends Command
|
||||
{
|
||||
protected $name = 'ninja:prune-data';
|
||||
protected $description = 'Delete inactive accounts';
|
||||
|
||||
public function fire()
|
||||
{
|
||||
$this->info(date('Y-m-d').' Running PruneData...');
|
||||
|
||||
// delete accounts who never registered, didn't create any invoices,
|
||||
// hansn't logged in within the past 6 months and isn't linked to another account
|
||||
$sql = 'select a.id
|
||||
from (select id, last_login from accounts) a
|
||||
left join users u on u.account_id = a.id and u.public_id = 0
|
||||
left join invoices i on i.account_id = a.id
|
||||
left join user_accounts ua1 on ua1.user_id1 = u.id
|
||||
left join user_accounts ua2 on ua2.user_id2 = u.id
|
||||
left join user_accounts ua3 on ua3.user_id3 = u.id
|
||||
left join user_accounts ua4 on ua4.user_id4 = u.id
|
||||
left join user_accounts ua5 on ua5.user_id5 = u.id
|
||||
where u.registered = 0
|
||||
and a.last_login < DATE_SUB(now(), INTERVAL 6 MONTH)
|
||||
and (ua1.id is null and ua2.id is null and ua3.id is null and ua4.id is null and ua5.id is null)
|
||||
group by a.id
|
||||
having count(i.id) = 0';
|
||||
|
||||
$results = DB::select($sql);
|
||||
|
||||
foreach ($results as $result) {
|
||||
$this->info("Deleting {$result->id}");
|
||||
DB::table('accounts')
|
||||
->where('id', '=', $result->id)
|
||||
->delete();
|
||||
}
|
||||
|
||||
$this->info('Done');
|
||||
}
|
||||
|
||||
protected function getArguments()
|
||||
{
|
||||
return array(
|
||||
//array('example', InputArgument::REQUIRED, 'An example argument.'),
|
||||
);
|
||||
}
|
||||
|
||||
protected function getOptions()
|
||||
{
|
||||
return array(
|
||||
//array('example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null),
|
||||
);
|
||||
}
|
||||
}
|
41
app/Console/Commands/RemoveOrphanedDocuments.php
Normal file
41
app/Console/Commands/RemoveOrphanedDocuments.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php namespace App\Console\Commands;
|
||||
|
||||
use DateTime;
|
||||
use App\Models\Document;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class RemoveOrphanedDocuments extends Command
|
||||
{
|
||||
protected $name = 'ninja:remove-orphaned-documents';
|
||||
protected $description = 'Removes old documents not associated with an expense or invoice';
|
||||
|
||||
public function fire()
|
||||
{
|
||||
$this->info(date('Y-m-d').' Running RemoveOrphanedDocuments...');
|
||||
|
||||
$documents = Document::whereRaw('invoice_id IS NULL AND expense_id IS NULL AND updated_at <= ?', array(new DateTime('-1 hour')))
|
||||
->get();
|
||||
|
||||
$this->info(count($documents).' orphaned document(s) found');
|
||||
|
||||
foreach ($documents as $document) {
|
||||
$document->delete();
|
||||
}
|
||||
|
||||
$this->info('Done');
|
||||
}
|
||||
|
||||
protected function getArguments()
|
||||
{
|
||||
return array(
|
||||
//array('example', InputArgument::REQUIRED, 'An example argument.'),
|
||||
);
|
||||
}
|
||||
|
||||
protected function getOptions()
|
||||
{
|
||||
return array(
|
||||
//array('example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null),
|
||||
);
|
||||
}
|
||||
}
|
@ -36,7 +36,7 @@ class SendReminders extends Command
|
||||
$this->info(count($accounts).' accounts found');
|
||||
|
||||
foreach ($accounts as $account) {
|
||||
if (!$account->isPro()) {
|
||||
if (!$account->hasFeature(FEATURE_EMAIL_TEMPLATES_REMINDERS)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ use DateTime;
|
||||
use Illuminate\Console\Command;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use App\Models\Account;
|
||||
use App\Models\Company;
|
||||
use App\Ninja\Mailers\ContactMailer as Mailer;
|
||||
use App\Ninja\Repositories\AccountRepository;
|
||||
|
||||
@ -30,32 +30,44 @@ class SendRenewalInvoices extends Command
|
||||
$today = new DateTime();
|
||||
$sentTo = [];
|
||||
|
||||
// get all accounts with pro plans expiring in 10 days
|
||||
$accounts = Account::whereRaw('datediff(curdate(), pro_plan_paid) = 355')
|
||||
// get all accounts with plans expiring in 10 days
|
||||
$companies = Company::whereRaw('datediff(plan_expires, curdate()) = 10')
|
||||
->orderBy('id')
|
||||
->get();
|
||||
$this->info(count($accounts).' accounts found');
|
||||
$this->info(count($companies).' companies found');
|
||||
|
||||
foreach ($accounts as $account) {
|
||||
// don't send multiple invoices to multi-company users
|
||||
if ($userAccountId = $this->accountRepo->getUserAccountId($account)) {
|
||||
if (isset($sentTo[$userAccountId])) {
|
||||
continue;
|
||||
} else {
|
||||
$sentTo[$userAccountId] = true;
|
||||
}
|
||||
foreach ($companies as $company) {
|
||||
if (!count($company->accounts)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
$account = $company->accounts->sortBy('id')->first();
|
||||
$plan = $company->plan;
|
||||
$term = $company->plan_term;
|
||||
|
||||
if ($company->pending_plan) {
|
||||
$plan = $company->pending_plan;
|
||||
$term = $company->pending_term;
|
||||
}
|
||||
|
||||
if ($plan == PLAN_FREE || !$plan || !$term ){
|
||||
continue;
|
||||
}
|
||||
|
||||
$client = $this->accountRepo->getNinjaClient($account);
|
||||
$invitation = $this->accountRepo->createNinjaInvoice($client, $account);
|
||||
$invitation = $this->accountRepo->createNinjaInvoice($client, $account, $plan, $term);
|
||||
|
||||
// set the due date to 10 days from now
|
||||
$invoice = $invitation->invoice;
|
||||
$invoice->due_date = date('Y-m-d', strtotime('+ 10 days'));
|
||||
$invoice->save();
|
||||
|
||||
$this->mailer->sendInvoice($invoice);
|
||||
$this->info("Sent invoice to {$client->getDisplayName()}");
|
||||
if ($term == PLAN_TERM_YEARLY) {
|
||||
$this->mailer->sendInvoice($invoice);
|
||||
$this->info("Sent {$term}ly {$plan} invoice to {$client->getDisplayName()}");
|
||||
} else {
|
||||
$this->info("Created {$term}ly {$plan} invoice for {$client->getDisplayName()}");
|
||||
}
|
||||
}
|
||||
|
||||
$this->info('Done');
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?php namespace app\Console\Commands;
|
||||
<?php namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use App\Services\BankAccountService;
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?php namespace app\Console;
|
||||
<?php namespace App\Console;
|
||||
|
||||
use Utils;
|
||||
use Illuminate\Console\Scheduling\Schedule;
|
||||
@ -13,8 +13,11 @@ class Kernel extends ConsoleKernel
|
||||
*/
|
||||
protected $commands = [
|
||||
'App\Console\Commands\SendRecurringInvoices',
|
||||
'App\Console\Commands\RemoveOrphanedDocuments',
|
||||
'App\Console\Commands\ResetData',
|
||||
'App\Console\Commands\CheckData',
|
||||
'App\Console\Commands\PruneData',
|
||||
'App\Console\Commands\CreateTestData',
|
||||
'App\Console\Commands\SendRenewalInvoices',
|
||||
'App\Console\Commands\ChargeRenewalInvoices',
|
||||
'App\Console\Commands\SendReminders',
|
||||
|
@ -4,7 +4,11 @@ use Redirect;
|
||||
use Utils;
|
||||
use Exception;
|
||||
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use Illuminate\Http\Exception\HttpResponseException;
|
||||
use Illuminate\Auth\Access\AuthorizationException;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
use Illuminate\Foundation\Validation\ValidationException;
|
||||
|
||||
class Handler extends ExceptionHandler {
|
||||
|
||||
@ -14,7 +18,10 @@ class Handler extends ExceptionHandler {
|
||||
* @var array
|
||||
*/
|
||||
protected $dontReport = [
|
||||
'Symfony\Component\HttpKernel\Exception\HttpException'
|
||||
AuthorizationException::class,
|
||||
HttpException::class,
|
||||
ModelNotFoundException::class,
|
||||
ValidationException::class,
|
||||
];
|
||||
|
||||
/**
|
||||
@ -27,7 +34,12 @@ class Handler extends ExceptionHandler {
|
||||
*/
|
||||
public function report(Exception $e)
|
||||
{
|
||||
if (Utils::isNinja()) {
|
||||
// don't show these errors in the logs
|
||||
if ($e instanceof HttpResponseException) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Utils::isNinja() && ! Utils::isTravis()) {
|
||||
Utils::logError(Utils::getErrorString($e));
|
||||
return false;
|
||||
} else {
|
||||
@ -60,7 +72,9 @@ class Handler extends ExceptionHandler {
|
||||
}
|
||||
|
||||
// In production, except for maintenance mode, we'll show a custom error screen
|
||||
if (Utils::isNinjaProd() && !Utils::isDownForMaintenance()) {
|
||||
if (Utils::isNinjaProd()
|
||||
&& !Utils::isDownForMaintenance()
|
||||
&& !($e instanceof HttpResponseException)) {
|
||||
$data = [
|
||||
'error' => get_class($e),
|
||||
'hideHeader' => true,
|
||||
|
@ -34,6 +34,13 @@ class AccountApiController extends BaseAPIController
|
||||
$this->accountRepo = $accountRepo;
|
||||
}
|
||||
|
||||
public function ping()
|
||||
{
|
||||
$headers = Utils::getApiHeaders();
|
||||
|
||||
return Response::make(RESULT_SUCCESS, 200, $headers);
|
||||
}
|
||||
|
||||
public function register(RegisterRequest $request)
|
||||
{
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
@ -83,20 +83,23 @@ class AppController extends BaseController
|
||||
return Redirect::to('/');
|
||||
}
|
||||
|
||||
$_ENV['APP_ENV']='production';
|
||||
$_ENV['APP_DEBUG']=$app['debug'];
|
||||
$_ENV['APP_URL']=$app['url'];
|
||||
$_ENV['APP_KEY']=$app['key'];
|
||||
$_ENV['DB_TYPE']=$dbType;
|
||||
$_ENV['DB_HOST']=$database['type']['host'];
|
||||
$_ENV['DB_DATABASE']=$database['type']['database'];
|
||||
$_ENV['DB_USERNAME']=$database['type']['username'];
|
||||
$_ENV['DB_PASSWORD']=$database['type']['password'];
|
||||
$_ENV['MAIL_DRIVER']=$mail['driver'];
|
||||
$_ENV['MAIL_PORT']=$mail['port'];
|
||||
$_ENV['MAIL_ENCRYPTION']=$mail['encryption'];
|
||||
$_ENV['MAIL_HOST']=$mail['host'];
|
||||
$_ENV['MAIL_USERNAME']=$mail['username'];;
|
||||
$_ENV['APP_ENV'] = 'production';
|
||||
$_ENV['APP_DEBUG'] = $app['debug'];
|
||||
$_ENV['APP_URL'] = $app['url'];
|
||||
$_ENV['APP_KEY'] = $app['key'];
|
||||
$_ENV['DB_TYPE'] = $dbType;
|
||||
$_ENV['DB_HOST'] = $database['type']['host'];
|
||||
$_ENV['DB_DATABASE'] = $database['type']['database'];
|
||||
$_ENV['DB_USERNAME'] = $database['type']['username'];
|
||||
$_ENV['DB_PASSWORD'] = $database['type']['password'];
|
||||
$_ENV['MAIL_DRIVER'] = $mail['driver'];
|
||||
$_ENV['MAIL_PORT'] = $mail['port'];
|
||||
$_ENV['MAIL_ENCRYPTION'] = $mail['encryption'];
|
||||
$_ENV['MAIL_HOST'] = $mail['host'];
|
||||
$_ENV['MAIL_USERNAME'] = $mail['username'];
|
||||
$_ENV['MAIL_FROM_NAME'] = $mail['from']['name'];
|
||||
$_ENV['MAIL_PASSWORD'] = $mail['password'];
|
||||
$_ENV['PHANTOMJS_CLOUD_KEY'] = 'a-demo-key-with-low-quota-per-ip-address';
|
||||
|
||||
$config = '';
|
||||
foreach ($_ENV as $key => $val) {
|
||||
@ -175,9 +178,12 @@ class AppController extends BaseController
|
||||
|
||||
$config = '';
|
||||
foreach ($_ENV as $key => $val) {
|
||||
if (preg_match('/\s/',$val)) {
|
||||
$val = "'{$val}'";
|
||||
}
|
||||
if (is_array($val)) {
|
||||
continue;
|
||||
}
|
||||
if (preg_match('/\s/', $val)) {
|
||||
$val = "'{$val}'";
|
||||
}
|
||||
$config .= "{$key}={$val}\n";
|
||||
}
|
||||
|
||||
@ -260,18 +266,7 @@ class AppController extends BaseController
|
||||
Cache::flush();
|
||||
Session::flush();
|
||||
Artisan::call('migrate', array('--force' => true));
|
||||
foreach ([
|
||||
'PaymentLibraries',
|
||||
'Fonts',
|
||||
'Banks',
|
||||
'InvoiceStatus',
|
||||
'Currencies',
|
||||
'DateFormats',
|
||||
'InvoiceDesigns',
|
||||
'PaymentTerms',
|
||||
] as $seeder) {
|
||||
Artisan::call('db:seed', array('--force' => true, '--class' => "{$seeder}Seeder"));
|
||||
}
|
||||
Artisan::call('db:seed', array('--force' => true, '--class' => "UpdateSeeder"));
|
||||
Event::fire(new UserSettingsChanged());
|
||||
Session::flash('message', trans('texts.processed_updates'));
|
||||
} catch (Exception $e) {
|
||||
@ -300,7 +295,7 @@ class AppController extends BaseController
|
||||
|
||||
public function stats()
|
||||
{
|
||||
if (Input::get('password') != env('RESELLER_PASSWORD')) {
|
||||
if ( ! hash_equals(Input::get('password'), env('RESELLER_PASSWORD'))) {
|
||||
sleep(3);
|
||||
return '';
|
||||
}
|
||||
@ -323,4 +318,4 @@ class AppController extends BaseController
|
||||
|
||||
return json_encode($data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -133,6 +133,9 @@ class AuthController extends Controller {
|
||||
if (Auth::check() && !Auth::user()->registered) {
|
||||
$account = Auth::user()->account;
|
||||
$this->accountRepo->unlinkAccount($account);
|
||||
if ($account->company->accounts->count() == 1) {
|
||||
$account->company->forceDelete();
|
||||
}
|
||||
$account->forceDelete();
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,9 @@
|
||||
|
||||
use Session;
|
||||
use Utils;
|
||||
use Auth;
|
||||
use Log;
|
||||
use Input;
|
||||
use Response;
|
||||
use Request;
|
||||
use League\Fractal;
|
||||
@ -9,8 +12,10 @@ use League\Fractal\Manager;
|
||||
use League\Fractal\Resource\Item;
|
||||
use League\Fractal\Resource\Collection;
|
||||
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
|
||||
use App\Models\EntityModel;
|
||||
use App\Ninja\Serializers\ArraySerializer;
|
||||
use League\Fractal\Serializer\JsonApiSerializer;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
|
||||
/**
|
||||
* @SWG\Swagger(
|
||||
@ -62,6 +67,74 @@ class BaseAPIController extends Controller
|
||||
} else {
|
||||
$this->manager->setSerializer(new ArraySerializer());
|
||||
}
|
||||
|
||||
if (Utils::isNinjaDev()) {
|
||||
\DB::enableQueryLog();
|
||||
}
|
||||
}
|
||||
|
||||
protected function handleAction($request)
|
||||
{
|
||||
$entity = $request->entity();
|
||||
$action = $request->action;
|
||||
|
||||
$repo = Utils::toCamelCase($this->entityType) . 'Repo';
|
||||
|
||||
$this->$repo->$action($entity);
|
||||
|
||||
return $this->itemResponse($entity);
|
||||
}
|
||||
|
||||
protected function listResponse($query)
|
||||
{
|
||||
$transformerClass = EntityModel::getTransformerName($this->entityType);
|
||||
$transformer = new $transformerClass(Auth::user()->account, Input::get('serializer'));
|
||||
|
||||
$includes = $transformer->getDefaultIncludes();
|
||||
$includes = $this->getRequestIncludes($includes);
|
||||
|
||||
$query->with($includes);
|
||||
|
||||
if ($updatedAt = Input::get('updated_at')) {
|
||||
$updatedAt = date('Y-m-d H:i:s', $updatedAt);
|
||||
$query->where(function($query) use ($includes, $updatedAt) {
|
||||
$query->where('updated_at', '>=', $updatedAt);
|
||||
foreach ($includes as $include) {
|
||||
$query->orWhereHas($include, function($query) use ($updatedAt) {
|
||||
$query->where('updated_at', '>=', $updatedAt);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if ($clientPublicId = Input::get('client_id')) {
|
||||
$filter = function($query) use ($clientPublicId) {
|
||||
$query->where('public_id', '=', $clientPublicId);
|
||||
};
|
||||
$query->whereHas('client', $filter);
|
||||
}
|
||||
|
||||
if ( ! Utils::hasPermission('view_all')){
|
||||
if ($this->entityType == ENTITY_USER) {
|
||||
$query->where('id', '=', Auth::user()->id);
|
||||
} else {
|
||||
$query->where('user_id', '=', Auth::user()->id);
|
||||
}
|
||||
}
|
||||
|
||||
$data = $this->createCollection($query, $transformer, $this->entityType);
|
||||
|
||||
return $this->response($data);
|
||||
}
|
||||
|
||||
protected function itemResponse($item)
|
||||
{
|
||||
$transformerClass = EntityModel::getTransformerName($this->entityType);
|
||||
$transformer = new $transformerClass(Auth::user()->account, Input::get('serializer'));
|
||||
|
||||
$data = $this->createItem($item, $transformer, $this->entityType);
|
||||
|
||||
return $this->response($data);
|
||||
}
|
||||
|
||||
protected function createItem($data, $transformer, $entityType)
|
||||
@ -74,23 +147,31 @@ class BaseAPIController extends Controller
|
||||
return $this->manager->createData($resource)->toArray();
|
||||
}
|
||||
|
||||
protected function createCollection($data, $transformer, $entityType, $paginator = false)
|
||||
protected function createCollection($query, $transformer, $entityType)
|
||||
{
|
||||
if ($this->serializer && $this->serializer != API_SERIALIZER_JSON) {
|
||||
$entityType = null;
|
||||
}
|
||||
|
||||
$resource = new Collection($data, $transformer, $entityType);
|
||||
|
||||
if ($paginator) {
|
||||
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
|
||||
if (is_a($query, "Illuminate\Database\Eloquent\Builder")) {
|
||||
$limit = min(MAX_API_PAGE_SIZE, Input::get('per_page', DEFAULT_API_PAGE_SIZE));
|
||||
$resource = new Collection($query->get(), $transformer, $entityType);
|
||||
$resource->setPaginator(new IlluminatePaginatorAdapter($query->paginate($limit)));
|
||||
} else {
|
||||
$resource = new Collection($query, $transformer, $entityType);
|
||||
}
|
||||
|
||||
|
||||
return $this->manager->createData($resource)->toArray();
|
||||
}
|
||||
|
||||
protected function response($response)
|
||||
{
|
||||
if (Utils::isNinjaDev()) {
|
||||
$count = count(\DB::getQueryLog());
|
||||
Log::info(Request::method() . ' - ' . Request::url() . ": $count queries");
|
||||
Log::info(json_encode(\DB::getQueryLog()));
|
||||
}
|
||||
|
||||
$index = Request::get('index') ?: 'data';
|
||||
|
||||
if ($index == 'none') {
|
||||
@ -123,26 +204,21 @@ class BaseAPIController extends Controller
|
||||
|
||||
}
|
||||
|
||||
|
||||
protected function getIncluded()
|
||||
protected function getRequestIncludes($data)
|
||||
{
|
||||
$data = ['user'];
|
||||
|
||||
$included = Request::get('include');
|
||||
$included = explode(',', $included);
|
||||
|
||||
foreach ($included as $include) {
|
||||
if ($include == 'invoices') {
|
||||
$data[] = 'invoices.invoice_items';
|
||||
$data[] = 'invoices.user';
|
||||
} elseif ($include == 'client') {
|
||||
$data[] = 'client.contacts';
|
||||
} elseif ($include == 'clients') {
|
||||
$data[] = 'clients.contacts';
|
||||
$data[] = 'clients.user';
|
||||
} elseif ($include == 'vendors') {
|
||||
$data[] = 'vendors.vendorcontacts';
|
||||
$data[] = 'vendors.user';
|
||||
}
|
||||
elseif ($include) {
|
||||
$data[] = 'vendors.vendor_contacts';
|
||||
} elseif ($include) {
|
||||
$data[] = $include;
|
||||
}
|
||||
}
|
||||
|
@ -2,13 +2,16 @@
|
||||
|
||||
use App\Http\Middleware\PermissionsRequired;
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Input;
|
||||
use Auth;
|
||||
use Utils;
|
||||
|
||||
class BaseController extends Controller
|
||||
{
|
||||
use DispatchesJobs;
|
||||
use DispatchesJobs, AuthorizesRequests;
|
||||
|
||||
protected $model = 'App\Models\EntityModel';
|
||||
protected $entityType;
|
||||
|
||||
/**
|
||||
* Setup the layout used by the controller.
|
||||
@ -21,40 +24,4 @@ class BaseController extends Controller
|
||||
$this->layout = View::make($this->layout);
|
||||
}
|
||||
}
|
||||
|
||||
protected function checkViewPermission($object, &$response = null){
|
||||
if(!$object->canView()){
|
||||
$response = response('Unauthorized.', 401);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function checkEditPermission($object, &$response = null){
|
||||
if(!$object->canEdit()){
|
||||
$response = response('Unauthorized.', 401);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function checkCreatePermission(&$response = null){
|
||||
if(!call_user_func(array($this->model, 'canCreate'))){
|
||||
$response = response('Unauthorized.', 401);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function checkUpdatePermission($input, &$response = null){
|
||||
$creating = empty($input['public_id']) || $input['public_id'] == '-1';
|
||||
|
||||
if($creating){
|
||||
return $this->checkCreatePermission($response);
|
||||
}
|
||||
else{
|
||||
$object = call_user_func(array($this->model, 'scope'), $input['public_id'])->firstOrFail();
|
||||
return $this->checkEditPermission($object, $response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,27 +10,19 @@ use App\Ninja\Repositories\ClientRepository;
|
||||
use App\Http\Requests\CreateClientRequest;
|
||||
use App\Http\Controllers\BaseAPIController;
|
||||
use App\Ninja\Transformers\ClientTransformer;
|
||||
use App\Services\ClientService;
|
||||
use App\Http\Requests\UpdateClientRequest;
|
||||
|
||||
class ClientApiController extends BaseAPIController
|
||||
{
|
||||
protected $clientRepo;
|
||||
protected $clientService;
|
||||
|
||||
public function __construct(ClientRepository $clientRepo, ClientService $clientService)
|
||||
protected $entityType = ENTITY_CLIENT;
|
||||
|
||||
public function __construct(ClientRepository $clientRepo)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->clientRepo = $clientRepo;
|
||||
$this->clientService = $clientService;
|
||||
}
|
||||
|
||||
public function ping()
|
||||
{
|
||||
$headers = Utils::getApiHeaders();
|
||||
|
||||
return Response::make('', 200, $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -52,27 +44,17 @@ class ClientApiController extends BaseAPIController
|
||||
public function index()
|
||||
{
|
||||
$clients = Client::scope()
|
||||
->with($this->getIncluded())
|
||||
->orderBy('created_at', 'desc')->withTrashed();
|
||||
->orderBy('created_at', 'desc')
|
||||
->withTrashed();
|
||||
|
||||
// Filter by email
|
||||
if (Input::has('email')) {
|
||||
|
||||
$email = Input::get('email');
|
||||
if ($email = Input::get('email')) {
|
||||
$clients = $clients->whereHas('contacts', function ($query) use ($email) {
|
||||
$query->where('email', $email);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
$clients = $clients->paginate();
|
||||
|
||||
$transformer = new ClientTransformer(Auth::user()->account, Input::get('serializer'));
|
||||
$paginator = Client::scope()->withTrashed()->paginate();
|
||||
|
||||
$data = $this->createCollection($clients, $transformer, ENTITY_CLIENT, $paginator);
|
||||
|
||||
return $this->response($data);
|
||||
|
||||
return $this->listResponse($clients);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -100,14 +82,7 @@ class ClientApiController extends BaseAPIController
|
||||
{
|
||||
$client = $this->clientRepo->save($request->input());
|
||||
|
||||
$client = Client::scope($client->public_id)
|
||||
->with('country', 'contacts', 'industry', 'size', 'currency')
|
||||
->first();
|
||||
|
||||
$transformer = new ClientTransformer(Auth::user()->account, Input::get('serializer'));
|
||||
$data = $this->createItem($client, $transformer, ENTITY_CLIENT);
|
||||
|
||||
return $this->response($data);
|
||||
return $this->itemResponse($client);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -134,51 +109,15 @@ class ClientApiController extends BaseAPIController
|
||||
|
||||
public function update(UpdateClientRequest $request, $publicId)
|
||||
{
|
||||
if ($request->action == ACTION_ARCHIVE) {
|
||||
|
||||
|
||||
$client = Client::scope($publicId)->withTrashed()->first();
|
||||
|
||||
if(!$client)
|
||||
return $this->errorResponse(['message'=>'Record not found'], 400);
|
||||
|
||||
$this->clientRepo->archive($client);
|
||||
|
||||
$transformer = new ClientTransformer(Auth::user()->account, Input::get('serializer'));
|
||||
$data = $this->createItem($client, $transformer, ENTITY_CLIENT);
|
||||
|
||||
return $this->response($data);
|
||||
if ($request->action) {
|
||||
return $this->handleAction($request);
|
||||
}
|
||||
else if ($request->action == ACTION_RESTORE){
|
||||
|
||||
$client = Client::scope($publicId)->withTrashed()->first();
|
||||
|
||||
if(!$client)
|
||||
return $this->errorResponse(['message'=>'Client not found.'], 400);
|
||||
|
||||
$this->clientRepo->restore($client);
|
||||
|
||||
$transformer = new ClientTransformer(Auth::user()->account, Input::get('serializer'));
|
||||
$data = $this->createItem($client, $transformer, ENTITY_CLIENT);
|
||||
|
||||
return $this->response($data);
|
||||
}
|
||||
|
||||
|
||||
$data = $request->input();
|
||||
$data['public_id'] = $publicId;
|
||||
$this->clientRepo->save($data);
|
||||
$client = $this->clientRepo->save($data, $request->entity());
|
||||
|
||||
$client = Client::scope($publicId)
|
||||
->with('country', 'contacts', 'industry', 'size', 'currency')
|
||||
->first();
|
||||
|
||||
if(!$client)
|
||||
return $this->errorResponse(['message'=>'Client not found.'],400);
|
||||
|
||||
$transformer = new ClientTransformer(Auth::user()->account, Input::get('serializer'));
|
||||
$data = $this->createItem($client, $transformer, ENTITY_CLIENT);
|
||||
|
||||
return $this->response($data);
|
||||
return $this->itemResponse($client);
|
||||
}
|
||||
|
||||
|
||||
@ -204,23 +143,13 @@ class ClientApiController extends BaseAPIController
|
||||
* )
|
||||
*/
|
||||
|
||||
public function destroy($publicId)
|
||||
public function destroy(UpdateClientRequest $request)
|
||||
{
|
||||
|
||||
$client = Client::scope($publicId)->withTrashed()->first();
|
||||
$client = $request->entity();
|
||||
|
||||
$this->clientRepo->delete($client);
|
||||
|
||||
$client = Client::scope($publicId)
|
||||
->with('country', 'contacts', 'industry', 'size', 'currency')
|
||||
->withTrashed()
|
||||
->first();
|
||||
|
||||
$transformer = new ClientTransformer(Auth::user()->account, Input::get('serializer'));
|
||||
$data = $this->createItem($client, $transformer, ENTITY_CLIENT);
|
||||
|
||||
return $this->response($data);
|
||||
|
||||
return $this->itemResponse($client);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -33,7 +33,7 @@ class AuthController extends Controller {
|
||||
$client = $invoice->client;
|
||||
$account = $client->account;
|
||||
|
||||
$data['hideLogo'] = $account->isWhiteLabel();
|
||||
$data['hideLogo'] = $account->hasFeature(FEATURE_WHITE_LABEL);
|
||||
$data['clientViewCSS'] = $account->clientViewCSS();
|
||||
$data['clientFontUrl'] = $account->getFontsUrl();
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ class PasswordController extends Controller {
|
||||
$client = $invoice->client;
|
||||
$account = $client->account;
|
||||
|
||||
$data['hideLogo'] = $account->isWhiteLabel();
|
||||
$data['hideLogo'] = $account->hasFeature(FEATURE_WHITE_LABEL);
|
||||
$data['clientViewCSS'] = $account->clientViewCSS();
|
||||
$data['clientFontUrl'] = $account->getFontsUrl();
|
||||
}
|
||||
@ -117,7 +117,7 @@ class PasswordController extends Controller {
|
||||
$client = $invoice->client;
|
||||
$account = $client->account;
|
||||
|
||||
$data['hideLogo'] = $account->isWhiteLabel();
|
||||
$data['hideLogo'] = $account->hasFeature(FEATURE_WHITE_LABEL);
|
||||
$data['clientViewCSS'] = $account->clientViewCSS();
|
||||
$data['clientFontUrl'] = $account->getFontsUrl();
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ use App\Models\Task;
|
||||
use App\Ninja\Repositories\ClientRepository;
|
||||
use App\Services\ClientService;
|
||||
|
||||
use App\Http\Requests\ClientRequest;
|
||||
use App\Http\Requests\CreateClientRequest;
|
||||
use App\Http\Requests\UpdateClientRequest;
|
||||
|
||||
@ -35,7 +36,7 @@ class ClientController extends BaseController
|
||||
{
|
||||
protected $clientService;
|
||||
protected $clientRepo;
|
||||
protected $model = 'App\Models\Client';
|
||||
protected $entityType = ENTITY_CLIENT;
|
||||
|
||||
public function __construct(ClientRepository $clientRepo, ClientService $clientService)
|
||||
{
|
||||
@ -81,13 +82,7 @@ class ClientController extends BaseController
|
||||
*/
|
||||
public function store(CreateClientRequest $request)
|
||||
{
|
||||
$data = $request->input();
|
||||
|
||||
if(!$this->checkUpdatePermission($data, $response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
$client = $this->clientService->save($data);
|
||||
$client = $this->clientService->save($request->input());
|
||||
|
||||
Session::flash('message', trans('texts.created_client'));
|
||||
|
||||
@ -100,38 +95,35 @@ class ClientController extends BaseController
|
||||
* @param int $id
|
||||
* @return Response
|
||||
*/
|
||||
public function show($publicId)
|
||||
public function show(ClientRequest $request)
|
||||
{
|
||||
$client = Client::withTrashed()->scope($publicId)->with('contacts', 'size', 'industry')->firstOrFail();
|
||||
|
||||
if(!$this->checkViewPermission($client, $response)){
|
||||
return $response;
|
||||
}
|
||||
$client = $request->entity();
|
||||
|
||||
$user = Auth::user();
|
||||
Utils::trackViewed($client->getDisplayName(), ENTITY_CLIENT);
|
||||
|
||||
$actionLinks = [];
|
||||
if(Task::canCreate()){
|
||||
$actionLinks[] = ['label' => trans('texts.new_task'), 'url' => '/tasks/create/'.$client->public_id];
|
||||
if($user->can('create', ENTITY_TASK)){
|
||||
$actionLinks[] = ['label' => trans('texts.new_task'), 'url' => URL::to('/tasks/create/'.$client->public_id)];
|
||||
}
|
||||
if (Utils::isPro() && Invoice::canCreate()) {
|
||||
$actionLinks[] = ['label' => trans('texts.new_quote'), 'url' => '/quotes/create/'.$client->public_id];
|
||||
if (Utils::hasFeature(FEATURE_QUOTES) && $user->can('create', ENTITY_INVOICE)) {
|
||||
$actionLinks[] = ['label' => trans('texts.new_quote'), 'url' => URL::to('/quotes/create/'.$client->public_id)];
|
||||
}
|
||||
|
||||
if(!empty($actionLinks)){
|
||||
$actionLinks[] = \DropdownButton::DIVIDER;
|
||||
}
|
||||
|
||||
if(Payment::canCreate()){
|
||||
$actionLinks[] = ['label' => trans('texts.enter_payment'), 'url' => '/payments/create/'.$client->public_id];
|
||||
if($user->can('create', ENTITY_PAYMENT)){
|
||||
$actionLinks[] = ['label' => trans('texts.enter_payment'), 'url' => URL::to('/payments/create/'.$client->public_id)];
|
||||
}
|
||||
|
||||
if(Credit::canCreate()){
|
||||
$actionLinks[] = ['label' => trans('texts.enter_credit'), 'url' => '/credits/create/'.$client->public_id];
|
||||
if($user->can('create', ENTITY_CREDIT)){
|
||||
$actionLinks[] = ['label' => trans('texts.enter_credit'), 'url' => URL::to('/credits/create/'.$client->public_id)];
|
||||
}
|
||||
|
||||
if(Expense::canCreate()){
|
||||
$actionLinks[] = ['label' => trans('texts.enter_expense'), 'url' => '/expenses/create/0/'.$client->public_id];
|
||||
if($user->can('create', ENTITY_EXPENSE)){
|
||||
$actionLinks[] = ['label' => trans('texts.enter_expense'), 'url' => URL::to('/expenses/create/0/'.$client->public_id)];
|
||||
}
|
||||
|
||||
$data = array(
|
||||
@ -154,12 +146,8 @@ class ClientController extends BaseController
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function create()
|
||||
public function create(ClientRequest $request)
|
||||
{
|
||||
if(!$this->checkCreatePermission($response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
if (Client::scope()->withTrashed()->count() > Auth::user()->getMaxNumClients()) {
|
||||
return View::make('error', ['hideHeader' => true, 'error' => "Sorry, you've exceeded the limit of ".Auth::user()->getMaxNumClients()." clients"]);
|
||||
}
|
||||
@ -182,18 +170,14 @@ class ClientController extends BaseController
|
||||
* @param int $id
|
||||
* @return Response
|
||||
*/
|
||||
public function edit($publicId)
|
||||
public function edit(ClientRequest $request)
|
||||
{
|
||||
$client = Client::scope($publicId)->with('contacts')->firstOrFail();
|
||||
|
||||
if(!$this->checkEditPermission($client, $response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
$client = $request->entity();
|
||||
|
||||
$data = [
|
||||
'client' => $client,
|
||||
'method' => 'PUT',
|
||||
'url' => 'clients/'.$publicId,
|
||||
'url' => 'clients/'.$client->public_id,
|
||||
'title' => trans('texts.edit_client'),
|
||||
];
|
||||
|
||||
@ -201,7 +185,7 @@ class ClientController extends BaseController
|
||||
|
||||
if (Auth::user()->account->isNinjaAccount()) {
|
||||
if ($account = Account::whereId($client->public_id)->first()) {
|
||||
$data['proPlanPaid'] = $account['pro_plan_paid'];
|
||||
$data['planDetails'] = $account->getPlanDetails(false, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -232,13 +216,7 @@ class ClientController extends BaseController
|
||||
*/
|
||||
public function update(UpdateClientRequest $request)
|
||||
{
|
||||
$data = $request->input();
|
||||
|
||||
if(!$this->checkUpdatePermission($data, $response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
$client = $this->clientService->save($data);
|
||||
$client = $this->clientService->save($request->input(), $request->entity());
|
||||
|
||||
Session::flash('message', trans('texts.updated_client'));
|
||||
|
||||
|
@ -12,12 +12,13 @@ use App\Models\Client;
|
||||
use App\Services\CreditService;
|
||||
use App\Ninja\Repositories\CreditRepository;
|
||||
use App\Http\Requests\CreateCreditRequest;
|
||||
use App\Http\Requests\CreditRequest;
|
||||
|
||||
class CreditController extends BaseController
|
||||
{
|
||||
protected $creditRepo;
|
||||
protected $creditService;
|
||||
protected $model = 'App\Models\Credit';
|
||||
protected $entityType = ENTITY_CREDIT;
|
||||
|
||||
public function __construct(CreditRepository $creditRepo, CreditService $creditService)
|
||||
{
|
||||
@ -55,32 +56,26 @@ class CreditController extends BaseController
|
||||
return $this->creditService->getDatatable($clientPublicId, Input::get('sSearch'));
|
||||
}
|
||||
|
||||
public function create($clientPublicId = 0)
|
||||
public function create(CreditRequest $request)
|
||||
{
|
||||
if(!$this->checkCreatePermission($response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'clientPublicId' => Input::old('client') ? Input::old('client') : $clientPublicId,
|
||||
//'invoicePublicId' => Input::old('invoice') ? Input::old('invoice') : $invoicePublicId,
|
||||
'clientPublicId' => Input::old('client') ? Input::old('client') : ($request->client_id ?: 0),
|
||||
'credit' => null,
|
||||
'method' => 'POST',
|
||||
'url' => 'credits',
|
||||
'title' => trans('texts.new_credit'),
|
||||
//'invoices' => Invoice::scope()->with('client', 'invoice_status')->orderBy('invoice_number')->get(),
|
||||
'clients' => Client::scope()->with('contacts')->orderBy('name')->get(), );
|
||||
'clients' => Client::scope()->with('contacts')->orderBy('name')->get(),
|
||||
);
|
||||
|
||||
return View::make('credits.edit', $data);
|
||||
}
|
||||
|
||||
/*
|
||||
public function edit($publicId)
|
||||
{
|
||||
$credit = Credit::scope($publicId)->firstOrFail();
|
||||
|
||||
if(!$this->checkEditPermission($credit, $response)){
|
||||
return $response;
|
||||
}
|
||||
$this->authorize('edit', $credit);
|
||||
|
||||
$credit->credit_date = Utils::fromSqlDate($credit->credit_date);
|
||||
|
||||
@ -94,7 +89,8 @@ class CreditController extends BaseController
|
||||
|
||||
return View::make('credit.edit', $data);
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
public function store(CreateCreditRequest $request)
|
||||
{
|
||||
$credit = $this->creditRepo->save($request->input());
|
||||
|
@ -11,7 +11,7 @@ class DashboardController extends BaseController
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$view_all = !Auth::user()->hasPermission('view_all');
|
||||
$view_all = Auth::user()->hasPermission('view_all');
|
||||
$user_id = Auth::user()->id;
|
||||
|
||||
// total_income, billed_clients, invoice_sent and active_clients
|
||||
@ -105,6 +105,7 @@ class DashboardController extends BaseController
|
||||
->where('contacts.deleted_at', '=', null)
|
||||
->where('invoices.is_recurring', '=', false)
|
||||
//->where('invoices.is_quote', '=', false)
|
||||
->where('invoices.quote_invoice_id', '=', null)
|
||||
->where('invoices.balance', '>', 0)
|
||||
->where('invoices.is_deleted', '=', false)
|
||||
->where('invoices.deleted_at', '=', null)
|
||||
@ -129,6 +130,7 @@ class DashboardController extends BaseController
|
||||
->where('invoices.deleted_at', '=', null)
|
||||
->where('invoices.is_recurring', '=', false)
|
||||
//->where('invoices.is_quote', '=', false)
|
||||
->where('invoices.quote_invoice_id', '=', null)
|
||||
->where('invoices.balance', '>', 0)
|
||||
->where('invoices.is_deleted', '=', false)
|
||||
->where('contacts.is_primary', '=', true)
|
||||
|
123
app/Http/Controllers/DocumentController.php
Normal file
123
app/Http/Controllers/DocumentController.php
Normal file
@ -0,0 +1,123 @@
|
||||
<?php namespace App\Http\Controllers;
|
||||
|
||||
use Datatable;
|
||||
use Input;
|
||||
use Redirect;
|
||||
use Session;
|
||||
use URL;
|
||||
use Utils;
|
||||
use View;
|
||||
use Validator;
|
||||
use Response;
|
||||
use App\Models\Document;
|
||||
use App\Ninja\Repositories\DocumentRepository;
|
||||
|
||||
use App\Http\Requests\DocumentRequest;
|
||||
use App\Http\Requests\CreateDocumentRequest;
|
||||
|
||||
class DocumentController extends BaseController
|
||||
{
|
||||
protected $documentRepo;
|
||||
protected $entityType = ENTITY_DOCUMENT;
|
||||
|
||||
public function __construct(DocumentRepository $documentRepo)
|
||||
{
|
||||
// parent::__construct();
|
||||
|
||||
$this->documentRepo = $documentRepo;
|
||||
}
|
||||
|
||||
public function get(DocumentRequest $request)
|
||||
{
|
||||
return static::getDownloadResponse($request->entity());
|
||||
}
|
||||
|
||||
public static function getDownloadResponse($document){
|
||||
$direct_url = $document->getDirectUrl();
|
||||
if($direct_url){
|
||||
return redirect($direct_url);
|
||||
}
|
||||
|
||||
$stream = $document->getStream();
|
||||
|
||||
if($stream){
|
||||
$headers = [
|
||||
'Content-Type' => Document::$types[$document->type]['mime'],
|
||||
'Content-Length' => $document->size,
|
||||
];
|
||||
|
||||
$response = Response::stream(function() use ($stream) {
|
||||
fpassthru($stream);
|
||||
}, 200, $headers);
|
||||
}
|
||||
else{
|
||||
$response = Response::make($document->getRaw(), 200);
|
||||
$response->header('content-type', Document::$types[$document->type]['mime']);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function getPreview(DocumentRequest $request)
|
||||
{
|
||||
$document = $request->entity();
|
||||
|
||||
if(empty($document->preview)){
|
||||
return Response::view('error', array('error'=>'Preview does not exist!'), 404);
|
||||
}
|
||||
|
||||
$direct_url = $document->getDirectPreviewUrl();
|
||||
if($direct_url){
|
||||
return redirect($direct_url);
|
||||
}
|
||||
|
||||
$previewType = pathinfo($document->preview, PATHINFO_EXTENSION);
|
||||
$response = Response::make($document->getRawPreview(), 200);
|
||||
$response->header('content-type', Document::$types[$previewType]['mime']);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function getVFSJS(DocumentRequest $request, $publicId, $name)
|
||||
{
|
||||
$document = $request->entity();
|
||||
|
||||
if(substr($name, -3)=='.js'){
|
||||
$name = substr($name, 0, -3);
|
||||
}
|
||||
|
||||
if(!$document->isPDFEmbeddable()){
|
||||
return Response::view('error', array('error'=>'Image does not exist!'), 404);
|
||||
}
|
||||
|
||||
$content = $document->preview?$document->getRawPreview():$document->getRaw();
|
||||
$content = 'ninjaAddVFSDoc('.json_encode(intval($publicId).'/'.strval($name)).',"'.base64_encode($content).'")';
|
||||
$response = Response::make($content, 200);
|
||||
$response->header('content-type', 'text/javascript');
|
||||
$response->header('cache-control', 'max-age=31536000');
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function postUpload(CreateDocumentRequest $request)
|
||||
{
|
||||
if (!Utils::hasFeature(FEATURE_DOCUMENTS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$result = $this->documentRepo->upload(Input::all()['file'], $doc_array);
|
||||
|
||||
if(is_string($result)){
|
||||
return Response::json([
|
||||
'error' => $result,
|
||||
'code' => 400
|
||||
], 400);
|
||||
} else {
|
||||
return Response::json([
|
||||
'error' => false,
|
||||
'document' => $doc_array,
|
||||
'code' => 200
|
||||
], 200);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
<?php namespace App\Http\Controllers;
|
||||
// vendor
|
||||
|
||||
use App\Models\Expense;
|
||||
use app\Ninja\Repositories\ExpenseRepository;
|
||||
use App\Ninja\Transformers\ExpenseTransformer;
|
||||
@ -16,6 +16,8 @@ class ExpenseApiController extends BaseAPIController
|
||||
protected $expenseRepo;
|
||||
protected $expenseService;
|
||||
|
||||
protected $entityType = ENTITY_EXPENSE;
|
||||
|
||||
public function __construct(ExpenseRepository $expenseRepo, ExpenseService $expenseService)
|
||||
{
|
||||
parent::__construct();
|
||||
@ -26,20 +28,12 @@ class ExpenseApiController extends BaseAPIController
|
||||
|
||||
public function index()
|
||||
{
|
||||
|
||||
$expenses = Expense::scope()
|
||||
->withTrashed()
|
||||
->with('client', 'invoice', 'vendor')
|
||||
->orderBy('created_at','desc');
|
||||
|
||||
$expenses = $expenses->paginate();
|
||||
|
||||
$transformer = new ExpenseTransformer(Auth::user()->account, Input::get('serializer'));
|
||||
$paginator = Expense::scope()->withTrashed()->paginate();
|
||||
|
||||
$data = $this->createCollection($expenses, $transformer, ENTITY_EXPENSE, $paginator);
|
||||
|
||||
return $this->response($data);
|
||||
|
||||
return $this->listResponse($expenses);
|
||||
}
|
||||
|
||||
public function update()
|
||||
|
@ -17,6 +17,8 @@ use App\Models\Expense;
|
||||
use App\Models\Client;
|
||||
use App\Services\ExpenseService;
|
||||
use App\Ninja\Repositories\ExpenseRepository;
|
||||
|
||||
use App\Http\Requests\ExpenseRequest;
|
||||
use App\Http\Requests\CreateExpenseRequest;
|
||||
use App\Http\Requests\UpdateExpenseRequest;
|
||||
|
||||
@ -25,7 +27,7 @@ class ExpenseController extends BaseController
|
||||
// Expenses
|
||||
protected $expenseRepo;
|
||||
protected $expenseService;
|
||||
protected $model = 'App\Models\Expense';
|
||||
protected $entityType = ENTITY_EXPENSE;
|
||||
|
||||
public function __construct(ExpenseRepository $expenseRepo, ExpenseService $expenseService)
|
||||
{
|
||||
@ -69,42 +71,35 @@ class ExpenseController extends BaseController
|
||||
return $this->expenseService->getDatatableVendor($vendorPublicId);
|
||||
}
|
||||
|
||||
public function create($vendorPublicId = null, $clientPublicId = null)
|
||||
public function create(ExpenseRequest $request)
|
||||
{
|
||||
if(!$this->checkCreatePermission($response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
if($vendorPublicId != 0) {
|
||||
$vendor = Vendor::scope($vendorPublicId)->with('vendorcontacts')->firstOrFail();
|
||||
if ($request->vendor_id != 0) {
|
||||
$vendor = Vendor::scope($request->vendor_id)->with('vendor_contacts')->firstOrFail();
|
||||
} else {
|
||||
$vendor = null;
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'vendorPublicId' => Input::old('vendor') ? Input::old('vendor') : $vendorPublicId,
|
||||
'vendorPublicId' => Input::old('vendor') ? Input::old('vendor') : $request->vendor_id,
|
||||
'expense' => null,
|
||||
'method' => 'POST',
|
||||
'url' => 'expenses',
|
||||
'title' => trans('texts.new_expense'),
|
||||
'vendors' => Vendor::scope()->with('vendorcontacts')->orderBy('name')->get(),
|
||||
'vendors' => Vendor::scope()->with('vendor_contacts')->orderBy('name')->get(),
|
||||
'vendor' => $vendor,
|
||||
'clients' => Client::scope()->with('contacts')->orderBy('name')->get(),
|
||||
'clientPublicId' => $clientPublicId,
|
||||
);
|
||||
'clientPublicId' => $request->client_id,
|
||||
);
|
||||
|
||||
$data = array_merge($data, self::getViewModel());
|
||||
|
||||
return View::make('expenses.edit', $data);
|
||||
}
|
||||
|
||||
public function edit($publicId)
|
||||
public function edit(ExpenseRequest $request)
|
||||
{
|
||||
$expense = Expense::scope($publicId)->firstOrFail();
|
||||
|
||||
if(!$this->checkEditPermission($expense, $response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
$expense = $request->entity();
|
||||
|
||||
$expense->expense_date = Utils::fromSqlDate($expense->expense_date);
|
||||
|
||||
$actions = [];
|
||||
@ -112,15 +107,6 @@ class ExpenseController extends BaseController
|
||||
$actions[] = ['url' => URL::to("invoices/{$expense->invoice->public_id}/edit"), 'label' => trans("texts.view_invoice")];
|
||||
} else {
|
||||
$actions[] = ['url' => 'javascript:submitAction("invoice")', 'label' => trans("texts.invoice_expense")];
|
||||
|
||||
/*
|
||||
// check for any open invoices
|
||||
$invoices = $task->client_id ? $this->invoiceRepo->findOpenInvoices($task->client_id) : [];
|
||||
|
||||
foreach ($invoices as $invoice) {
|
||||
$actions[] = ['url' => 'javascript:submitAction("add_to_invoice", '.$invoice->public_id.')', 'label' => trans("texts.add_to_invoice", ["invoice" => $invoice->invoice_number])];
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
$actions[] = \DropdownButton::DIVIDER;
|
||||
@ -135,10 +121,10 @@ class ExpenseController extends BaseController
|
||||
'vendor' => null,
|
||||
'expense' => $expense,
|
||||
'method' => 'PUT',
|
||||
'url' => 'expenses/'.$publicId,
|
||||
'url' => 'expenses/'.$expense->public_id,
|
||||
'title' => 'Edit Expense',
|
||||
'actions' => $actions,
|
||||
'vendors' => Vendor::scope()->with('vendorcontacts')->orderBy('name')->get(),
|
||||
'vendors' => Vendor::scope()->with('vendor_contacts')->orderBy('name')->get(),
|
||||
'vendorPublicId' => $expense->vendor ? $expense->vendor->public_id : null,
|
||||
'clients' => Client::scope()->with('contacts')->orderBy('name')->get(),
|
||||
'clientPublicId' => $expense->client ? $expense->client->public_id : null,
|
||||
@ -146,12 +132,6 @@ class ExpenseController extends BaseController
|
||||
|
||||
$data = array_merge($data, self::getViewModel());
|
||||
|
||||
if (Auth::user()->account->isNinjaAccount()) {
|
||||
if ($account = Account::whereId($client->public_id)->first()) {
|
||||
$data['proPlanPaid'] = $account['pro_plan_paid'];
|
||||
}
|
||||
}
|
||||
|
||||
return View::make('expenses.edit', $data);
|
||||
}
|
||||
|
||||
@ -163,7 +143,10 @@ class ExpenseController extends BaseController
|
||||
*/
|
||||
public function update(UpdateExpenseRequest $request)
|
||||
{
|
||||
$expense = $this->expenseService->save($request->input());
|
||||
$data = $request->input();
|
||||
$data['documents'] = $request->file('documents');
|
||||
|
||||
$expense = $this->expenseService->save($data, $request->entity());
|
||||
|
||||
Session::flash('message', trans('texts.updated_expense'));
|
||||
|
||||
@ -177,7 +160,10 @@ class ExpenseController extends BaseController
|
||||
|
||||
public function store(CreateExpenseRequest $request)
|
||||
{
|
||||
$expense = $this->expenseService->save($request->input());
|
||||
$data = $request->input();
|
||||
$data['documents'] = $request->file('documents');
|
||||
|
||||
$expense = $this->expenseService->save($data);
|
||||
|
||||
Session::flash('message', trans('texts.created_expense'));
|
||||
|
||||
@ -195,8 +181,7 @@ class ExpenseController extends BaseController
|
||||
$expenses = Expense::scope($ids)->with('client')->get();
|
||||
$clientPublicId = null;
|
||||
$currencyId = null;
|
||||
$data = [];
|
||||
|
||||
|
||||
// Validate that either all expenses do not have a client or if there is a client, it is the same client
|
||||
foreach ($expenses as $expense)
|
||||
{
|
||||
@ -220,19 +205,11 @@ class ExpenseController extends BaseController
|
||||
Session::flash('error', trans('texts.expense_error_invoiced'));
|
||||
return Redirect::to('expenses');
|
||||
}
|
||||
|
||||
$account = Auth::user()->account;
|
||||
$data[] = [
|
||||
'publicId' => $expense->public_id,
|
||||
'description' => $expense->public_notes,
|
||||
'qty' => 1,
|
||||
'cost' => $expense->present()->converted_amount,
|
||||
];
|
||||
}
|
||||
|
||||
return Redirect::to("invoices/create/{$clientPublicId}")
|
||||
->with('expenseCurrencyId', $currencyId)
|
||||
->with('expenses', $data);
|
||||
->with('expenses', $ids);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -164,12 +164,12 @@ class ExportController extends BaseController
|
||||
|
||||
if ($request->input(ENTITY_VENDOR)) {
|
||||
$data['clients'] = Vendor::scope()
|
||||
->with('user', 'vendorcontacts', 'country')
|
||||
->with('user', 'vendor_contacts', 'country')
|
||||
->withArchived()
|
||||
->get();
|
||||
|
||||
$data['vendor_contacts'] = VendorContact::scope()
|
||||
->with('user', 'vendor.contacts')
|
||||
->with('user', 'vendor.vendor_contacts')
|
||||
->withTrashed()
|
||||
->get();
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?php namespace app\Http\Controllers;
|
||||
<?php namespace App\Http\Controllers;
|
||||
|
||||
use Utils;
|
||||
use View;
|
||||
|
@ -18,14 +18,17 @@ use App\Ninja\Repositories\InvoiceRepository;
|
||||
use App\Ninja\Mailers\ContactMailer as Mailer;
|
||||
use App\Http\Controllers\BaseAPIController;
|
||||
use App\Ninja\Transformers\InvoiceTransformer;
|
||||
use App\Http\Requests\CreateInvoiceRequest;
|
||||
use App\Http\Requests\UpdateInvoiceRequest;
|
||||
use App\Http\Requests\InvoiceRequest;
|
||||
use App\Http\Requests\CreateInvoiceAPIRequest;
|
||||
use App\Http\Requests\UpdateInvoiceAPIRequest;
|
||||
use App\Services\InvoiceService;
|
||||
|
||||
class InvoiceApiController extends BaseAPIController
|
||||
{
|
||||
protected $invoiceRepo;
|
||||
|
||||
protected $entityType = ENTITY_INVOICE;
|
||||
|
||||
public function __construct(InvoiceService $invoiceService, InvoiceRepository $invoiceRepo, ClientRepository $clientRepo, PaymentRepository $paymentRepo, Mailer $mailer)
|
||||
{
|
||||
parent::__construct();
|
||||
@ -55,36 +58,12 @@ class InvoiceApiController extends BaseAPIController
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$paginator = Invoice::scope()->withTrashed();
|
||||
$invoices = Invoice::scope()->withTrashed()
|
||||
->with(array_merge(['invoice_items'], $this->getIncluded()));
|
||||
$invoices = Invoice::scope()
|
||||
->withTrashed()
|
||||
->with('invoice_items', 'client')
|
||||
->orderBy('created_at', 'desc');
|
||||
|
||||
if ($clientPublicId = Input::get('client_id')) {
|
||||
$filter = function($query) use ($clientPublicId) {
|
||||
$query->where('public_id', '=', $clientPublicId);
|
||||
};
|
||||
$invoices->whereHas('client', $filter);
|
||||
$paginator->whereHas('client', $filter);
|
||||
}
|
||||
|
||||
$invoices = $invoices->orderBy('created_at', 'desc')->paginate();
|
||||
|
||||
/*
|
||||
// Add the first invitation link to the data
|
||||
foreach ($invoices as $key => $invoice) {
|
||||
foreach ($invoice->invitations as $subKey => $invitation) {
|
||||
$invoices[$key]['link'] = $invitation->getLink();
|
||||
}
|
||||
unset($invoice['invitations']);
|
||||
}
|
||||
*/
|
||||
|
||||
$transformer = new InvoiceTransformer(Auth::user()->account, Input::get('serializer'));
|
||||
$paginator = $paginator->paginate();
|
||||
|
||||
$data = $this->createCollection($invoices, $transformer, 'invoices', $paginator);
|
||||
|
||||
return $this->response($data);
|
||||
return $this->listResponse($invoices);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -104,18 +83,9 @@ class InvoiceApiController extends BaseAPIController
|
||||
* )
|
||||
*/
|
||||
|
||||
public function show($publicId)
|
||||
public function show(InvoiceRequest $request)
|
||||
{
|
||||
|
||||
$invoice = Invoice::scope($publicId)->withTrashed()->first();
|
||||
|
||||
if(!$invoice)
|
||||
return $this->errorResponse(['message'=>'Invoice does not exist!'], 404);
|
||||
|
||||
$transformer = new InvoiceTransformer(\Auth::user()->account, Input::get('serializer'));
|
||||
$data = $this->createItem($invoice, $transformer, 'invoice');
|
||||
|
||||
return $this->response($data);
|
||||
return $this->itemResponse($request->entity());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -139,7 +109,7 @@ class InvoiceApiController extends BaseAPIController
|
||||
* )
|
||||
* )
|
||||
*/
|
||||
public function store(CreateInvoiceRequest $request)
|
||||
public function store(CreateInvoiceAPIRequest $request)
|
||||
{
|
||||
$data = Input::all();
|
||||
$error = null;
|
||||
@ -166,6 +136,7 @@ class InvoiceApiController extends BaseAPIController
|
||||
'state',
|
||||
'postal_code',
|
||||
'private_notes',
|
||||
'currency_code',
|
||||
] as $field) {
|
||||
if (isset($data[$field])) {
|
||||
$clientData[$field] = $data[$field];
|
||||
@ -209,11 +180,11 @@ class InvoiceApiController extends BaseAPIController
|
||||
}
|
||||
}
|
||||
|
||||
$invoice = Invoice::scope($invoice->public_id)->with('client', 'invoice_items', 'invitations')->first();
|
||||
$transformer = new InvoiceTransformer(\Auth::user()->account, Input::get('serializer'));
|
||||
$data = $this->createItem($invoice, $transformer, 'invoice');
|
||||
|
||||
return $this->response($data);
|
||||
$invoice = Invoice::scope($invoice->public_id)
|
||||
->with('client', 'invoice_items', 'invitations')
|
||||
->first();
|
||||
|
||||
return $this->itemResponse($invoice);
|
||||
}
|
||||
|
||||
private function prepareData($data, $client)
|
||||
@ -258,10 +229,11 @@ class InvoiceApiController extends BaseAPIController
|
||||
// initialize the line items
|
||||
if (isset($data['product_key']) || isset($data['cost']) || isset($data['notes']) || isset($data['qty'])) {
|
||||
$data['invoice_items'] = [self::prepareItem($data)];
|
||||
|
||||
// make sure the tax isn't applied twice (for the invoice and the line item)
|
||||
unset($data['invoice_items'][0]['tax_name']);
|
||||
unset($data['invoice_items'][0]['tax_rate']);
|
||||
unset($data['invoice_items'][0]['tax_name1']);
|
||||
unset($data['invoice_items'][0]['tax_rate1']);
|
||||
unset($data['invoice_items'][0]['tax_name2']);
|
||||
unset($data['invoice_items'][0]['tax_rate2']);
|
||||
} else {
|
||||
foreach ($data['invoice_items'] as $index => $item) {
|
||||
$data['invoice_items'][$index] = self::prepareItem($item);
|
||||
@ -298,36 +270,21 @@ class InvoiceApiController extends BaseAPIController
|
||||
$item[$key] = $val;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
||||
public function emailInvoice()
|
||||
public function emailInvoice(InvoiceRequest $request)
|
||||
{
|
||||
$data = Input::all();
|
||||
$error = null;
|
||||
$invoice = $request->entity();
|
||||
|
||||
$invoice = Invoice::scope($data['id'])->withTrashed()->first();
|
||||
|
||||
if(!$invoice)
|
||||
return $this->errorResponse(['message'=>'Invoice does not exist.'], 400);
|
||||
|
||||
|
||||
$this->mailer->sendInvoice($invoice, false, false);
|
||||
|
||||
|
||||
if($error) {
|
||||
return $this->errorResponse(['message'=>'There was an error sending the invoice'], 400);
|
||||
}
|
||||
else {
|
||||
$response = json_encode(RESULT_SUCCESS, JSON_PRETTY_PRINT);
|
||||
}
|
||||
$this->mailer->sendInvoice($invoice);
|
||||
|
||||
$response = json_encode(RESULT_SUCCESS, JSON_PRETTY_PRINT);
|
||||
$headers = Utils::getApiHeaders();
|
||||
return Response::make($response, $error ? 400 : 200, $headers);
|
||||
return Response::make($response, 200, $headers);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @SWG\Put(
|
||||
* path="/invoices",
|
||||
@ -349,45 +306,25 @@ class InvoiceApiController extends BaseAPIController
|
||||
* )
|
||||
* )
|
||||
*/
|
||||
public function update(UpdateInvoiceRequest $request, $publicId)
|
||||
public function update(UpdateInvoiceAPIRequest $request, $publicId)
|
||||
{
|
||||
if ($request->action == ACTION_ARCHIVE) {
|
||||
$invoice = Invoice::scope($publicId)->firstOrFail();
|
||||
$this->invoiceRepo->archive($invoice);
|
||||
|
||||
$transformer = new InvoiceTransformer(\Auth::user()->account, Input::get('serializer'));
|
||||
$data = $this->createItem($invoice, $transformer, 'invoice');
|
||||
|
||||
return $this->response($data);
|
||||
}
|
||||
else if ($request->action == ACTION_CONVERT) {
|
||||
$quote = Invoice::scope($publicId)->firstOrFail();
|
||||
if ($request->action == ACTION_CONVERT) {
|
||||
$quote = $request->entity();
|
||||
$invoice = $this->invoiceRepo->cloneInvoice($quote, $quote->id);
|
||||
|
||||
$transformer = new InvoiceTransformer(\Auth::user()->account, Input::get('serializer'));
|
||||
$data = $this->createItem($invoice, $transformer, 'invoice');
|
||||
|
||||
return $this->response($data);
|
||||
}
|
||||
else if ($request->action == ACTION_RESTORE) {
|
||||
$invoice = Invoice::scope($publicId)->withTrashed()->firstOrFail();
|
||||
$this->invoiceRepo->restore($invoice);
|
||||
|
||||
$transformer = new InvoiceTransformer(\Auth::user()->account, Input::get('serializer'));
|
||||
$data = $this->createItem($invoice, $transformer, 'invoice');
|
||||
|
||||
return $this->response($data);
|
||||
return $this->itemResponse($invoice);
|
||||
} elseif ($request->action) {
|
||||
return $this->handleAction($request);
|
||||
}
|
||||
|
||||
$data = $request->input();
|
||||
$data['public_id'] = $publicId;
|
||||
$this->invoiceService->save($data);
|
||||
$this->invoiceService->save($data, $request->entity());
|
||||
|
||||
$invoice = Invoice::scope($publicId)->with('client', 'invoice_items', 'invitations')->firstOrFail();
|
||||
$transformer = new InvoiceTransformer(\Auth::user()->account, Input::get('serializer'));
|
||||
$data = $this->createItem($invoice, $transformer, 'invoice');
|
||||
|
||||
return $this->response($data);
|
||||
$invoice = Invoice::scope($publicId)
|
||||
->with('client', 'invoice_items', 'invitations')
|
||||
->firstOrFail();
|
||||
|
||||
return $this->itemResponse($invoice);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -412,18 +349,13 @@ class InvoiceApiController extends BaseAPIController
|
||||
* )
|
||||
*/
|
||||
|
||||
public function destroy($publicId)
|
||||
public function destroy(UpdateInvoiceAPIRequest $request)
|
||||
{
|
||||
$data['public_id'] = $publicId;
|
||||
$invoice = Invoice::scope($publicId)->firstOrFail();
|
||||
|
||||
$invoice = $request->entity();
|
||||
|
||||
$this->invoiceRepo->delete($invoice);
|
||||
|
||||
$transformer = new InvoiceTransformer(\Auth::user()->account, Input::get('serializer'));
|
||||
$data = $this->createItem($invoice, $transformer, 'invoice');
|
||||
|
||||
return $this->response($data);
|
||||
|
||||
return $this->itemResponse($invoice);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -17,26 +17,32 @@ use App\Models\Invoice;
|
||||
use App\Models\Client;
|
||||
use App\Models\Account;
|
||||
use App\Models\Product;
|
||||
use App\Models\Expense;
|
||||
use App\Models\TaxRate;
|
||||
use App\Models\InvoiceDesign;
|
||||
use App\Models\Activity;
|
||||
use App\Ninja\Mailers\ContactMailer as Mailer;
|
||||
use App\Ninja\Repositories\InvoiceRepository;
|
||||
use App\Ninja\Repositories\ClientRepository;
|
||||
use App\Ninja\Repositories\DocumentRepository;
|
||||
use App\Services\InvoiceService;
|
||||
use App\Services\RecurringInvoiceService;
|
||||
use App\Http\Requests\SaveInvoiceWithClientRequest;
|
||||
|
||||
use App\Http\Requests\InvoiceRequest;
|
||||
use App\Http\Requests\CreateInvoiceRequest;
|
||||
use App\Http\Requests\UpdateInvoiceRequest;
|
||||
|
||||
class InvoiceController extends BaseController
|
||||
{
|
||||
protected $mailer;
|
||||
protected $invoiceRepo;
|
||||
protected $clientRepo;
|
||||
protected $documentRepo;
|
||||
protected $invoiceService;
|
||||
protected $recurringInvoiceService;
|
||||
protected $model = 'App\Models\Invoice';
|
||||
protected $entityType = ENTITY_INVOICE;
|
||||
|
||||
public function __construct(Mailer $mailer, InvoiceRepository $invoiceRepo, ClientRepository $clientRepo, InvoiceService $invoiceService, RecurringInvoiceService $recurringInvoiceService)
|
||||
public function __construct(Mailer $mailer, InvoiceRepository $invoiceRepo, ClientRepository $clientRepo, InvoiceService $invoiceService, DocumentRepository $documentRepo, RecurringInvoiceService $recurringInvoiceService)
|
||||
{
|
||||
// parent::__construct();
|
||||
|
||||
@ -85,20 +91,13 @@ class InvoiceController extends BaseController
|
||||
return $this->recurringInvoiceService->getDatatable($accountId, $clientPublicId, ENTITY_RECURRING_INVOICE, $search);
|
||||
}
|
||||
|
||||
public function edit($publicId, $clone = false)
|
||||
public function edit(InvoiceRequest $request, $publicId, $clone = false)
|
||||
{
|
||||
$account = Auth::user()->account;
|
||||
$invoice = Invoice::scope($publicId)
|
||||
->with('invitations', 'account.country', 'client.contacts', 'client.country', 'invoice_items', 'payments')
|
||||
->withTrashed()
|
||||
->firstOrFail();
|
||||
|
||||
if(!$this->checkEditPermission($invoice, $response)){
|
||||
return $response;
|
||||
}
|
||||
$invoice = $request->entity()->load('invitations', 'account.country', 'client.contacts', 'client.country', 'invoice_items', 'documents', 'expenses', 'expenses.documents', 'payments');
|
||||
|
||||
$entityType = $invoice->getEntityType();
|
||||
|
||||
|
||||
$contactIds = DB::table('invitations')
|
||||
->join('contacts', 'contacts.id', '=', 'invitations.contact_id')
|
||||
->where('invitations.invoice_id', '=', $invoice->id)
|
||||
@ -119,7 +118,7 @@ class InvoiceController extends BaseController
|
||||
} else {
|
||||
Utils::trackViewed($invoice->getDisplayName().' - '.$invoice->client->getDisplayName(), $invoice->getEntityType());
|
||||
$method = 'PUT';
|
||||
$url = "{$entityType}s/{$publicId}";
|
||||
$url = "{$entityType}s/{$invoice->public_id}";
|
||||
$clients->whereId($invoice->client_id);
|
||||
}
|
||||
|
||||
@ -129,7 +128,11 @@ class InvoiceController extends BaseController
|
||||
$invoice->start_date = Utils::fromSqlDate($invoice->start_date);
|
||||
$invoice->end_date = Utils::fromSqlDate($invoice->end_date);
|
||||
$invoice->last_sent_date = Utils::fromSqlDate($invoice->last_sent_date);
|
||||
$invoice->is_pro = Auth::user()->isPro();
|
||||
$invoice->features = [
|
||||
'customize_invoice_design' => Auth::user()->hasFeature(FEATURE_CUSTOMIZE_INVOICE_DESIGN),
|
||||
'remove_created_by' => Auth::user()->hasFeature(FEATURE_REMOVE_CREATED_BY),
|
||||
'invoice_settings' => Auth::user()->hasFeature(FEATURE_INVOICE_SETTINGS),
|
||||
];
|
||||
|
||||
$actions = [
|
||||
['url' => 'javascript:onCloneClick()', 'label' => trans("texts.clone_{$entityType}")],
|
||||
@ -191,7 +194,7 @@ class InvoiceController extends BaseController
|
||||
'isRecurring' => $invoice->is_recurring,
|
||||
'actions' => $actions,
|
||||
'lastSent' => $lastSent);
|
||||
$data = array_merge($data, self::getViewModel());
|
||||
$data = array_merge($data, self::getViewModel($invoice));
|
||||
|
||||
if ($clone) {
|
||||
$data['formIsChanged'] = true;
|
||||
@ -211,6 +214,7 @@ class InvoiceController extends BaseController
|
||||
$contact->email_error = $invitation->email_error;
|
||||
$contact->invitation_link = $invitation->getLink();
|
||||
$contact->invitation_viewed = $invitation->viewed_date && $invitation->viewed_date != '0000-00-00 00:00:00' ? $invitation->viewed_date : false;
|
||||
$contact->invitation_openend = $invitation->opened_date && $invitation->opened_date != '0000-00-00 00:00:00' ? $invitation->opened_date : false;
|
||||
$contact->invitation_status = $contact->email_error ? false : $invitation->getStatus();
|
||||
}
|
||||
}
|
||||
@ -223,25 +227,27 @@ class InvoiceController extends BaseController
|
||||
return View::make('invoices.edit', $data);
|
||||
}
|
||||
|
||||
public function create($clientPublicId = 0, $isRecurring = false)
|
||||
public function create(InvoiceRequest $request, $clientPublicId = 0, $isRecurring = false)
|
||||
{
|
||||
if(!$this->checkCreatePermission($response)){
|
||||
return $response;
|
||||
}
|
||||
$account = Auth::user()->account;
|
||||
|
||||
$account = Auth::user()->account;
|
||||
$entityType = $isRecurring ? ENTITY_RECURRING_INVOICE : ENTITY_INVOICE;
|
||||
$clientId = null;
|
||||
|
||||
if ($clientPublicId) {
|
||||
$clientId = Client::getPrivateId($clientPublicId);
|
||||
if ($request->client_id) {
|
||||
$clientId = Client::getPrivateId($request->client_id);
|
||||
}
|
||||
|
||||
$invoice = $account->createInvoice($entityType, $clientId);
|
||||
$invoice->public_id = 0;
|
||||
|
||||
if (Session::get('expenses')) {
|
||||
$invoice->expenses = Expense::scope(Session::get('expenses'))->with('documents')->get();
|
||||
}
|
||||
|
||||
|
||||
$clients = Client::scope()->with('contacts', 'country')->orderBy('name');
|
||||
if(!Auth::user()->hasPermission('view_all')){
|
||||
if (!Auth::user()->hasPermission('view_all')) {
|
||||
$clients = $clients->where('clients.user_id', '=', Auth::user()->id);
|
||||
}
|
||||
|
||||
@ -253,17 +259,17 @@ class InvoiceController extends BaseController
|
||||
'url' => 'invoices',
|
||||
'title' => trans('texts.new_invoice'),
|
||||
];
|
||||
$data = array_merge($data, self::getViewModel());
|
||||
$data = array_merge($data, self::getViewModel($invoice));
|
||||
|
||||
return View::make('invoices.edit', $data);
|
||||
}
|
||||
|
||||
public function createRecurring($clientPublicId = 0)
|
||||
public function createRecurring(InvoiceRequest $request, $clientPublicId = 0)
|
||||
{
|
||||
return self::create($clientPublicId, true);
|
||||
return self::create($request, $clientPublicId, true);
|
||||
}
|
||||
|
||||
private static function getViewModel()
|
||||
private static function getViewModel($invoice)
|
||||
{
|
||||
$recurringHelp = '';
|
||||
foreach (preg_split("/((\r?\n)|(\r\n?))/", trans('texts.recurring_help')) as $line) {
|
||||
@ -324,11 +330,37 @@ class InvoiceController extends BaseController
|
||||
}
|
||||
}
|
||||
|
||||
// Tax rate $options
|
||||
$account = Auth::user()->account;
|
||||
$rates = TaxRate::scope()->orderBy('name')->get();
|
||||
$options = [];
|
||||
$defaultTax = false;
|
||||
|
||||
foreach ($rates as $rate) {
|
||||
$options[$rate->rate . ' ' . $rate->name] = $rate->name . ' ' . ($rate->rate+0) . '%';
|
||||
|
||||
// load default invoice tax
|
||||
if ($rate->id == $account->default_tax_rate_id) {
|
||||
$defaultTax = $rate;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for any taxes which have been deleted
|
||||
if ($invoice->exists) {
|
||||
foreach ($invoice->getTaxes() as $key => $rate) {
|
||||
if (isset($options[$key])) {
|
||||
continue;
|
||||
}
|
||||
$options[$key] = $rate['name'] . ' ' . $rate['rate'] . '%';
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'data' => Input::old('data'),
|
||||
'account' => Auth::user()->account->load('country'),
|
||||
'products' => Product::scope()->with('default_tax_rate')->orderBy('product_key')->get(),
|
||||
'taxRates' => TaxRate::scope()->orderBy('name')->get(),
|
||||
'taxRateOptions' => $options,
|
||||
'defaultTax' => $defaultTax,
|
||||
'currencies' => Cache::get('currencies'),
|
||||
'languages' => Cache::get('languages'),
|
||||
'sizes' => Cache::get('sizes'),
|
||||
@ -350,7 +382,6 @@ class InvoiceController extends BaseController
|
||||
'recurringDueDateHelp' => $recurringDueDateHelp,
|
||||
'invoiceLabels' => Auth::user()->account->getInvoiceLabels(),
|
||||
'tasks' => Session::get('tasks') ? json_encode(Session::get('tasks')) : null,
|
||||
'expenses' => Session::get('expenses') ? json_encode(Session::get('expenses')) : null,
|
||||
'expenseCurrencyId' => Session::get('expenseCurrencyId') ?: null,
|
||||
];
|
||||
|
||||
@ -361,18 +392,15 @@ class InvoiceController extends BaseController
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function store(SaveInvoiceWithClientRequest $request)
|
||||
public function store(CreateInvoiceRequest $request)
|
||||
{
|
||||
$data = $request->input();
|
||||
|
||||
if(!$this->checkUpdatePermission($data, $response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
$data['documents'] = $request->file('documents');
|
||||
|
||||
$action = Input::get('action');
|
||||
$entityType = Input::get('entityType');
|
||||
|
||||
$invoice = $this->invoiceService->save($data, true);
|
||||
$invoice = $this->invoiceService->save($data);
|
||||
$entityType = $invoice->getEntityType();
|
||||
$message = trans("texts.created_{$entityType}");
|
||||
|
||||
@ -401,26 +429,23 @@ class InvoiceController extends BaseController
|
||||
* @param int $id
|
||||
* @return Response
|
||||
*/
|
||||
public function update(SaveInvoiceWithClientRequest $request)
|
||||
public function update(UpdateInvoiceRequest $request)
|
||||
{
|
||||
$data = $request->input();
|
||||
|
||||
if(!$this->checkUpdatePermission($data, $response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
$data['documents'] = $request->file('documents');
|
||||
|
||||
$action = Input::get('action');
|
||||
$entityType = Input::get('entityType');
|
||||
|
||||
$invoice = $this->invoiceService->save($data, true);
|
||||
$invoice = $this->invoiceService->save($data, $request->entity());
|
||||
$entityType = $invoice->getEntityType();
|
||||
$message = trans("texts.updated_{$entityType}");
|
||||
Session::flash('message', $message);
|
||||
|
||||
if ($action == 'clone') {
|
||||
return $this->cloneInvoice($invoice->public_id);
|
||||
return $this->cloneInvoice($request, $invoice->public_id);
|
||||
} elseif ($action == 'convert') {
|
||||
return $this->convertQuote($invoice->public_id);
|
||||
return $this->convertQuote($request, $invoice->public_id);
|
||||
} elseif ($action == 'email') {
|
||||
return $this->emailInvoice($invoice, Input::get('pdfupload'));
|
||||
}
|
||||
@ -489,7 +514,7 @@ class InvoiceController extends BaseController
|
||||
{
|
||||
Session::reflash();
|
||||
|
||||
return Redirect::to("invoices/{$publicId}/edit");
|
||||
return Redirect::to("invoices/$publicId/edit");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -517,27 +542,31 @@ class InvoiceController extends BaseController
|
||||
}
|
||||
}
|
||||
|
||||
public function convertQuote($publicId)
|
||||
public function convertQuote(InvoiceRequest $request)
|
||||
{
|
||||
$invoice = Invoice::with('invoice_items')->scope($publicId)->firstOrFail();
|
||||
$clone = $this->invoiceService->convertQuote($invoice);
|
||||
$clone = $this->invoiceService->convertQuote($request->entity());
|
||||
|
||||
Session::flash('message', trans('texts.converted_to_invoice'));
|
||||
return Redirect::to('invoices/'.$clone->public_id);
|
||||
|
||||
return Redirect::to('invoices/' . $clone->public_id);
|
||||
}
|
||||
|
||||
public function cloneInvoice($publicId)
|
||||
public function cloneInvoice(InvoiceRequest $request, $publicId)
|
||||
{
|
||||
return self::edit($publicId, true);
|
||||
return self::edit($request, $publicId, true);
|
||||
}
|
||||
|
||||
public function invoiceHistory($publicId)
|
||||
public function invoiceHistory(InvoiceRequest $request)
|
||||
{
|
||||
$invoice = Invoice::withTrashed()->scope($publicId)->firstOrFail();
|
||||
$invoice->load('user', 'invoice_items', 'account.country', 'client.contacts', 'client.country');
|
||||
$invoice = $request->entity();
|
||||
$invoice->load('user', 'invoice_items', 'documents', 'expenses', 'expenses.documents', 'account.country', 'client.contacts', 'client.country');
|
||||
$invoice->invoice_date = Utils::fromSqlDate($invoice->invoice_date);
|
||||
$invoice->due_date = Utils::fromSqlDate($invoice->due_date);
|
||||
$invoice->is_pro = Auth::user()->isPro();
|
||||
$invoice->features = [
|
||||
'customize_invoice_design' => Auth::user()->hasFeature(FEATURE_CUSTOMIZE_INVOICE_DESIGN),
|
||||
'remove_created_by' => Auth::user()->hasFeature(FEATURE_REMOVE_CREATED_BY),
|
||||
'invoice_settings' => Auth::user()->hasFeature(FEATURE_INVOICE_SETTINGS),
|
||||
];
|
||||
$invoice->is_quote = intval($invoice->is_quote);
|
||||
|
||||
$activityTypeId = $invoice->is_quote ? ACTIVITY_TYPE_UPDATE_QUOTE : ACTIVITY_TYPE_UPDATE_INVOICE;
|
||||
@ -555,7 +584,11 @@ class InvoiceController extends BaseController
|
||||
$backup = json_decode($activity->json_backup);
|
||||
$backup->invoice_date = Utils::fromSqlDate($backup->invoice_date);
|
||||
$backup->due_date = Utils::fromSqlDate($backup->due_date);
|
||||
$backup->is_pro = Auth::user()->isPro();
|
||||
$backup->features = [
|
||||
'customize_invoice_design' => Auth::user()->hasFeature(FEATURE_CUSTOMIZE_INVOICE_DESIGN),
|
||||
'remove_created_by' => Auth::user()->hasFeature(FEATURE_REMOVE_CREATED_BY),
|
||||
'invoice_settings' => Auth::user()->hasFeature(FEATURE_INVOICE_SETTINGS),
|
||||
];
|
||||
$backup->is_quote = isset($backup->is_quote) && intval($backup->is_quote);
|
||||
$backup->account = $invoice->account->toArray();
|
||||
|
||||
|
@ -12,18 +12,21 @@ use App\Ninja\Repositories\PaymentRepository;
|
||||
use App\Http\Controllers\BaseAPIController;
|
||||
use App\Ninja\Transformers\PaymentTransformer;
|
||||
use App\Ninja\Transformers\InvoiceTransformer;
|
||||
use App\Http\Requests\UpdatePaymentRequest;
|
||||
use App\Http\Requests\CreatePaymentAPIRequest;
|
||||
|
||||
class PaymentApiController extends BaseAPIController
|
||||
{
|
||||
protected $paymentRepo;
|
||||
|
||||
protected $entityType = ENTITY_PAYMENT;
|
||||
|
||||
public function __construct(PaymentRepository $paymentRepo, ContactMailer $contactMailer)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->paymentRepo = $paymentRepo;
|
||||
$this->contactMailer = $contactMailer;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -44,85 +47,49 @@ class PaymentApiController extends BaseAPIController
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$paginator = Payment::scope();
|
||||
$payments = Payment::scope()
|
||||
->with('client.contacts', 'invitation', 'user', 'invoice')->withTrashed();
|
||||
->withTrashed()
|
||||
->with(['invoice'])
|
||||
->orderBy('created_at', 'desc');
|
||||
|
||||
if ($clientPublicId = Input::get('client_id')) {
|
||||
$filter = function($query) use ($clientPublicId) {
|
||||
$query->where('public_id', '=', $clientPublicId);
|
||||
};
|
||||
$payments->whereHas('client', $filter);
|
||||
$paginator->whereHas('client', $filter);
|
||||
}
|
||||
|
||||
$payments = $payments->orderBy('created_at', 'desc')->paginate();
|
||||
$paginator = $paginator->paginate();
|
||||
|
||||
$transformer = new PaymentTransformer(Auth::user()->account, Input::get('serializer'));
|
||||
$data = $this->createCollection($payments, $transformer, 'payments', $paginator);
|
||||
|
||||
return $this->response($data);
|
||||
return $this->listResponse($payments);
|
||||
}
|
||||
|
||||
/**
|
||||
* @SWG\Put(
|
||||
* path="/payments/{payment_id",
|
||||
* summary="Update a payment",
|
||||
* tags={"payment"},
|
||||
* @SWG\Parameter(
|
||||
* in="body",
|
||||
* name="body",
|
||||
* @SWG\Schema(ref="#/definitions/Payment")
|
||||
* ),
|
||||
* @SWG\Response(
|
||||
* response=200,
|
||||
* description="Update payment",
|
||||
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Payment"))
|
||||
* ),
|
||||
* @SWG\Response(
|
||||
* response="default",
|
||||
* description="an ""unexpected"" error"
|
||||
* )
|
||||
* )
|
||||
*/
|
||||
|
||||
/**
|
||||
* @SWG\Put(
|
||||
* path="/payments/{payment_id",
|
||||
* summary="Update a payment",
|
||||
* tags={"payment"},
|
||||
* @SWG\Parameter(
|
||||
* in="body",
|
||||
* name="body",
|
||||
* @SWG\Schema(ref="#/definitions/Payment")
|
||||
* ),
|
||||
* @SWG\Response(
|
||||
* response=200,
|
||||
* description="Update payment",
|
||||
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Payment"))
|
||||
* ),
|
||||
* @SWG\Response(
|
||||
* response="default",
|
||||
* description="an ""unexpected"" error"
|
||||
* )
|
||||
* )
|
||||
*/
|
||||
|
||||
public function update(Request $request, $publicId)
|
||||
{
|
||||
$data = Input::all();
|
||||
$data['public_id'] = $publicId;
|
||||
$error = false;
|
||||
|
||||
if ($request->action == ACTION_ARCHIVE) {
|
||||
$payment = Payment::scope($publicId)->withTrashed()->firstOrFail();
|
||||
$this->paymentRepo->archive($payment);
|
||||
|
||||
$transformer = new PaymentTransformer(\Auth::user()->account, Input::get('serializer'));
|
||||
$data = $this->createItem($payment, $transformer, 'invoice');
|
||||
|
||||
return $this->response($data);
|
||||
}
|
||||
|
||||
$payment = $this->paymentRepo->save($data);
|
||||
|
||||
if ($error) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
/*
|
||||
$invoice = Invoice::scope($data['invoice_id'])->with('client', 'invoice_items', 'invitations')->with(['payments' => function($query) {
|
||||
$query->withTrashed();
|
||||
}])->withTrashed()->first();
|
||||
*/
|
||||
|
||||
$transformer = new PaymentTransformer(\Auth::user()->account, Input::get('serializer'));
|
||||
$data = $this->createItem($payment, $transformer, 'invoice');
|
||||
|
||||
return $this->response($data);
|
||||
|
||||
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\Post(
|
||||
@ -145,89 +112,46 @@ class PaymentApiController extends BaseAPIController
|
||||
* )
|
||||
* )
|
||||
*/
|
||||
public function store()
|
||||
public function store(CreatePaymentAPIRequest $request)
|
||||
{
|
||||
$data = Input::all();
|
||||
$error = false;
|
||||
|
||||
if (isset($data['invoice_id'])) {
|
||||
$invoice = Invoice::scope($data['invoice_id'])->with('client')->first();
|
||||
|
||||
if ($invoice) {
|
||||
$data['invoice_id'] = $invoice->id;
|
||||
$data['client_id'] = $invoice->client->id;
|
||||
} else {
|
||||
$error = trans('validation.not_in', ['attribute' => 'invoice_id']);
|
||||
}
|
||||
} else {
|
||||
$error = trans('validation.not_in', ['attribute' => 'invoice_id']);
|
||||
}
|
||||
|
||||
if (!isset($data['transaction_reference'])) {
|
||||
$data['transaction_reference'] = '';
|
||||
}
|
||||
|
||||
if ($error) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$payment = $this->paymentRepo->save($data);
|
||||
$payment = $this->paymentRepo->save($request->input());
|
||||
|
||||
if (Input::get('email_receipt')) {
|
||||
$this->contactMailer->sendPaymentConfirmation($payment);
|
||||
}
|
||||
|
||||
/*
|
||||
$invoice = Invoice::scope($invoice->public_id)->with('client', 'invoice_items', 'invitations')->with(['payments' => function($query) {
|
||||
$query->withTrashed();
|
||||
}])->first();
|
||||
*/
|
||||
|
||||
$transformer = new PaymentTransformer(\Auth::user()->account, Input::get('serializer'));
|
||||
$data = $this->createItem($payment, $transformer, 'invoice');
|
||||
|
||||
return $this->response($data);
|
||||
|
||||
return $this->itemResponse($payment);
|
||||
}
|
||||
|
||||
/**
|
||||
* @SWG\Delete(
|
||||
* path="/payments/{payment_id}",
|
||||
* summary="Delete a payment",
|
||||
* tags={"payment"},
|
||||
* @SWG\Parameter(
|
||||
* in="body",
|
||||
* name="body",
|
||||
* @SWG\Schema(ref="#/definitions/Payment")
|
||||
* ),
|
||||
* @SWG\Response(
|
||||
* response=200,
|
||||
* description="Delete payment",
|
||||
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Payment"))
|
||||
* ),
|
||||
* @SWG\Response(
|
||||
* response="default",
|
||||
* description="an ""unexpected"" error"
|
||||
* )
|
||||
* )
|
||||
*/
|
||||
/**
|
||||
* @SWG\Delete(
|
||||
* path="/payments/{payment_id}",
|
||||
* summary="Delete a payment",
|
||||
* tags={"payment"},
|
||||
* @SWG\Parameter(
|
||||
* in="body",
|
||||
* name="body",
|
||||
* @SWG\Schema(ref="#/definitions/Payment")
|
||||
* ),
|
||||
* @SWG\Response(
|
||||
* response=200,
|
||||
* description="Delete payment",
|
||||
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Payment"))
|
||||
* ),
|
||||
* @SWG\Response(
|
||||
* response="default",
|
||||
* description="an ""unexpected"" error"
|
||||
* )
|
||||
* )
|
||||
*/
|
||||
|
||||
public function destroy($publicId)
|
||||
{
|
||||
public function destroy(UpdatePaymentRequest $request)
|
||||
{
|
||||
$payment = $request->entity();
|
||||
|
||||
$this->clientRepo->delete($payment);
|
||||
|
||||
$payment = Payment::scope($publicId)->withTrashed()->first();
|
||||
$invoiceId = $payment->invoice->public_id;
|
||||
return $this->itemResponse($payment);
|
||||
}
|
||||
|
||||
$this->paymentRepo->delete($payment);
|
||||
|
||||
/*
|
||||
$invoice = Invoice::scope($invoiceId)->with('client', 'invoice_items', 'invitations')->with(['payments' => function($query) {
|
||||
$query->withTrashed();
|
||||
}])->first();
|
||||
*/
|
||||
$transformer = new PaymentTransformer(\Auth::user()->account, Input::get('serializer'));
|
||||
$data = $this->createItem($payment, $transformer, 'invoice');
|
||||
|
||||
return $this->response($data);
|
||||
}
|
||||
}
|
||||
|
@ -25,12 +25,13 @@ use App\Ninja\Repositories\AccountRepository;
|
||||
use App\Ninja\Mailers\ContactMailer;
|
||||
use App\Services\PaymentService;
|
||||
|
||||
use App\Http\Requests\PaymentRequest;
|
||||
use App\Http\Requests\CreatePaymentRequest;
|
||||
use App\Http\Requests\UpdatePaymentRequest;
|
||||
|
||||
class PaymentController extends BaseController
|
||||
{
|
||||
protected $model = 'App\Models\Payment';
|
||||
protected $entityType = ENTITY_PAYMENT;
|
||||
|
||||
public function __construct(PaymentRepository $paymentRepo, InvoiceRepository $invoiceRepo, AccountRepository $accountRepo, ContactMailer $contactMailer, PaymentService $paymentService)
|
||||
{
|
||||
@ -67,12 +68,8 @@ class PaymentController extends BaseController
|
||||
return $this->paymentService->getDatatable($clientPublicId, Input::get('sSearch'));
|
||||
}
|
||||
|
||||
public function create($clientPublicId = 0, $invoicePublicId = 0)
|
||||
public function create(PaymentRequest $request)
|
||||
{
|
||||
if(!$this->checkCreatePermission($response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
$invoices = Invoice::scope()
|
||||
->where('is_recurring', '=', false)
|
||||
->where('is_quote', '=', false)
|
||||
@ -81,8 +78,8 @@ class PaymentController extends BaseController
|
||||
->orderBy('invoice_number')->get();
|
||||
|
||||
$data = array(
|
||||
'clientPublicId' => Input::old('client') ? Input::old('client') : $clientPublicId,
|
||||
'invoicePublicId' => Input::old('invoice') ? Input::old('invoice') : $invoicePublicId,
|
||||
'clientPublicId' => Input::old('client') ? Input::old('client') : ($request->client_id ?: 0),
|
||||
'invoicePublicId' => Input::old('invoice') ? Input::old('invoice') : ($request->invoice_id ?: 0),
|
||||
'invoice' => null,
|
||||
'invoices' => $invoices,
|
||||
'payment' => null,
|
||||
@ -96,14 +93,10 @@ class PaymentController extends BaseController
|
||||
return View::make('payments.edit', $data);
|
||||
}
|
||||
|
||||
public function edit($publicId)
|
||||
public function edit(PaymentRequest $request)
|
||||
{
|
||||
$payment = Payment::scope($publicId)->firstOrFail();
|
||||
|
||||
if(!$this->checkEditPermission($payment, $response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
$payment = $request->entity();
|
||||
|
||||
$payment->payment_date = Utils::fromSqlDate($payment->payment_date);
|
||||
|
||||
$data = array(
|
||||
@ -113,7 +106,7 @@ class PaymentController extends BaseController
|
||||
->with('client', 'invoice_status')->orderBy('invoice_number')->get(),
|
||||
'payment' => $payment,
|
||||
'method' => 'PUT',
|
||||
'url' => 'payments/'.$publicId,
|
||||
'url' => 'payments/'.$payment->public_id,
|
||||
'title' => trans('texts.edit_payment'),
|
||||
'paymentTypes' => Cache::get('paymentTypes'),
|
||||
'clients' => Client::scope()->with('contacts')->orderBy('name')->get(), );
|
||||
@ -191,7 +184,7 @@ class PaymentController extends BaseController
|
||||
'currencyId' => $client->getCurrencyId(),
|
||||
'currencyCode' => $client->currency ? $client->currency->code : ($account->currency ? $account->currency->code : 'USD'),
|
||||
'account' => $client->account,
|
||||
'hideLogo' => $account->isWhiteLabel(),
|
||||
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL),
|
||||
'hideHeader' => $account->isNinjaAccount(),
|
||||
'clientViewCSS' => $account->clientViewCSS(),
|
||||
'clientFontUrl' => $account->getFontsUrl(),
|
||||
@ -355,9 +348,18 @@ class PaymentController extends BaseController
|
||||
$license->save();
|
||||
}
|
||||
|
||||
return $productId == PRODUCT_INVOICE_DESIGNS ? file_get_contents(storage_path() . '/invoice_designs.txt') : 'valid';
|
||||
if ($productId == PRODUCT_INVOICE_DESIGNS) {
|
||||
return file_get_contents(storage_path() . '/invoice_designs.txt');
|
||||
} else {
|
||||
// temporary fix to enable previous version to work
|
||||
if (Input::get('get_date')) {
|
||||
return $license->created_at->format('Y-m-d');
|
||||
} else {
|
||||
return 'valid';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return 'invalid';
|
||||
return RESULT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -460,6 +462,8 @@ class PaymentController extends BaseController
|
||||
$ref = $response->getData()['m_payment_id'];
|
||||
} elseif ($accountGateway->gateway_id == GATEWAY_GOCARDLESS) {
|
||||
$ref = $response->getData()['signature'];
|
||||
} elseif ($accountGateway->gateway_id == GATEWAY_CYBERSOURCE) {
|
||||
$ref = $response->getData()['transaction_uuid'];
|
||||
} else {
|
||||
$ref = $response->getTransactionReference();
|
||||
}
|
||||
@ -482,6 +486,7 @@ class PaymentController extends BaseController
|
||||
if ($account->account_key == NINJA_ACCOUNT_KEY) {
|
||||
Session::flash('trackEventCategory', '/account');
|
||||
Session::flash('trackEventAction', '/buy_pro_plan');
|
||||
Session::flash('trackEventAmount', $payment->amount);
|
||||
}
|
||||
|
||||
return Redirect::to('view/'.$payment->invitation->invitation_key);
|
||||
@ -551,7 +556,16 @@ class PaymentController extends BaseController
|
||||
}
|
||||
|
||||
try {
|
||||
if (method_exists($gateway, 'completePurchase')
|
||||
if ($accountGateway->isGateway(GATEWAY_CYBERSOURCE)) {
|
||||
if (Input::get('decision') == 'ACCEPT') {
|
||||
$payment = $this->paymentService->createPayment($invitation, $accountGateway, $token, $payerId);
|
||||
Session::flash('message', trans('texts.applied_payment'));
|
||||
} else {
|
||||
$message = Input::get('message') . ': ' . Input::get('invalid_fields');
|
||||
Session::flash('error', $message);
|
||||
}
|
||||
return Redirect::to($invitation->getLink());
|
||||
} elseif (method_exists($gateway, 'completePurchase')
|
||||
&& !$accountGateway->isGateway(GATEWAY_TWO_CHECKOUT)
|
||||
&& !$accountGateway->isGateway(GATEWAY_CHECKOUT_COM)) {
|
||||
$details = $this->paymentService->getPaymentDetails($invitation, $accountGateway);
|
||||
@ -572,11 +586,9 @@ class PaymentController extends BaseController
|
||||
} else {
|
||||
$payment = $this->paymentService->createPayment($invitation, $accountGateway, $token, $payerId);
|
||||
Session::flash('message', trans('texts.applied_payment'));
|
||||
|
||||
return Redirect::to($invitation->getLink());
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
|
||||
$this->error('Offsite-uncaught', false, $accountGateway, $e);
|
||||
return Redirect::to($invitation->getLink());
|
||||
}
|
||||
@ -585,11 +597,7 @@ class PaymentController extends BaseController
|
||||
public function store(CreatePaymentRequest $request)
|
||||
{
|
||||
$input = $request->input();
|
||||
|
||||
if(!$this->checkUpdatePermission($input, $response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
|
||||
$input['invoice_id'] = Invoice::getPrivateId($input['invoice']);
|
||||
$input['client_id'] = Client::getPrivateId($input['client']);
|
||||
$payment = $this->paymentRepo->save($input);
|
||||
@ -606,13 +614,7 @@ class PaymentController extends BaseController
|
||||
|
||||
public function update(UpdatePaymentRequest $request)
|
||||
{
|
||||
$input = $request->input();
|
||||
|
||||
if(!$this->checkUpdatePermission($input, $response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
$payment = $this->paymentRepo->save($input);
|
||||
$payment = $this->paymentRepo->save($request->input(), $request->entity());
|
||||
|
||||
Session::flash('message', trans('texts.updated_payment'));
|
||||
|
||||
|
@ -1,103 +1,54 @@
|
||||
<?php namespace App\Http\Controllers;
|
||||
|
||||
use App\Ninja\Repositories\ProductRepository;
|
||||
use App\Ninja\Transformers\ProductTransformer;
|
||||
use Auth;
|
||||
use Str;
|
||||
use DB;
|
||||
use Datatable;
|
||||
use Utils;
|
||||
use URL;
|
||||
use View;
|
||||
use Input;
|
||||
use Session;
|
||||
use Redirect;
|
||||
|
||||
use App\Models\Product;
|
||||
use App\Models\TaxRate;
|
||||
use App\Services\ProductService;
|
||||
use App\Ninja\Repositories\ProductRepository;
|
||||
use App\Http\Requests\CreateProductRequest;
|
||||
use App\Http\Requests\UpdateProductRequest;
|
||||
|
||||
class ProductApiController extends BaseAPIController
|
||||
{
|
||||
protected $productService;
|
||||
protected $productRepo;
|
||||
|
||||
protected $entityType = ENTITY_PRODUCT;
|
||||
|
||||
protected $productRepo;
|
||||
|
||||
public function __construct(ProductService $productService, ProductRepository $productRepo)
|
||||
public function __construct(ProductRepository $productRepo)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->productService = $productService;
|
||||
$this->productRepo = $productRepo;
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$products = Product::scope()
|
||||
->withTrashed()
|
||||
->orderBy('created_at', 'desc');
|
||||
|
||||
$products = Product::scope()->withTrashed();
|
||||
$products = $products->paginate();
|
||||
|
||||
$paginator = Product::scope()->withTrashed()->paginate();
|
||||
|
||||
$transformer = new ProductTransformer(\Auth::user()->account, $this->serializer);
|
||||
$data = $this->createCollection($products, $transformer, 'products', $paginator);
|
||||
|
||||
return $this->response($data);
|
||||
|
||||
return $this->listResponse($products);
|
||||
}
|
||||
|
||||
public function getDatatable()
|
||||
public function store(CreateProductRequest $request)
|
||||
{
|
||||
return $this->productService->getDatatable(Auth::user()->account_id);
|
||||
$product = $this->productRepo->save($request->input());
|
||||
|
||||
return $this->itemResponse($product);
|
||||
}
|
||||
|
||||
public function store()
|
||||
public function update(UpdateProductRequest $request, $publicId)
|
||||
{
|
||||
return $this->save();
|
||||
}
|
||||
|
||||
public function update(\Illuminate\Http\Request $request, $publicId)
|
||||
{
|
||||
|
||||
if ($request->action == ACTION_ARCHIVE) {
|
||||
$product = Product::scope($publicId)->withTrashed()->firstOrFail();
|
||||
$this->productRepo->archive($product);
|
||||
|
||||
$transformer = new ProductTransformer(\Auth::user()->account, Input::get('serializer'));
|
||||
$data = $this->createItem($product, $transformer, 'products');
|
||||
|
||||
return $this->response($data);
|
||||
if ($request->action) {
|
||||
return $this->handleAction($request);
|
||||
}
|
||||
else
|
||||
return $this->save($publicId);
|
||||
|
||||
$data = $request->input();
|
||||
$data['public_id'] = $publicId;
|
||||
$product = $this->productRepo->save($data, $request->entity());
|
||||
|
||||
return $this->itemResponse($product);
|
||||
}
|
||||
|
||||
public function destroy($publicId)
|
||||
{
|
||||
//stub
|
||||
}
|
||||
|
||||
private function save($productPublicId = false)
|
||||
{
|
||||
if ($productPublicId) {
|
||||
$product = Product::scope($productPublicId)->firstOrFail();
|
||||
} else {
|
||||
$product = Product::createNew();
|
||||
}
|
||||
|
||||
$product->product_key = trim(Input::get('product_key'));
|
||||
$product->notes = trim(Input::get('notes'));
|
||||
$product->cost = trim(Input::get('cost'));
|
||||
//$product->default_tax_rate_id = Input::get('default_tax_rate_id');
|
||||
|
||||
$product->save();
|
||||
|
||||
$transformer = new ProductTransformer(\Auth::user()->account, Input::get('serializer'));
|
||||
$data = $this->createItem($product, $transformer, 'products');
|
||||
|
||||
return $this->response($data);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -7,27 +7,33 @@ use URL;
|
||||
use Input;
|
||||
use Utils;
|
||||
use Request;
|
||||
use Response;
|
||||
use Session;
|
||||
use Datatable;
|
||||
use App\Models\Gateway;
|
||||
use App\Models\Invitation;
|
||||
use App\Models\Document;
|
||||
use App\Ninja\Repositories\InvoiceRepository;
|
||||
use App\Ninja\Repositories\PaymentRepository;
|
||||
use App\Ninja\Repositories\ActivityRepository;
|
||||
use App\Ninja\Repositories\DocumentRepository;
|
||||
use App\Events\InvoiceInvitationWasViewed;
|
||||
use App\Events\QuoteInvitationWasViewed;
|
||||
use App\Services\PaymentService;
|
||||
use Barracuda\ArchiveStream\ZipArchive;
|
||||
|
||||
class PublicClientController extends BaseController
|
||||
{
|
||||
private $invoiceRepo;
|
||||
private $paymentRepo;
|
||||
private $documentRepo;
|
||||
|
||||
public function __construct(InvoiceRepository $invoiceRepo, PaymentRepository $paymentRepo, ActivityRepository $activityRepo, PaymentService $paymentService)
|
||||
public function __construct(InvoiceRepository $invoiceRepo, PaymentRepository $paymentRepo, ActivityRepository $activityRepo, DocumentRepository $documentRepo, PaymentService $paymentService)
|
||||
{
|
||||
$this->invoiceRepo = $invoiceRepo;
|
||||
$this->paymentRepo = $paymentRepo;
|
||||
$this->activityRepo = $activityRepo;
|
||||
$this->documentRepo = $documentRepo;
|
||||
$this->paymentService = $paymentService;
|
||||
}
|
||||
|
||||
@ -66,7 +72,11 @@ class PublicClientController extends BaseController
|
||||
|
||||
$invoice->invoice_date = Utils::fromSqlDate($invoice->invoice_date);
|
||||
$invoice->due_date = Utils::fromSqlDate($invoice->due_date);
|
||||
$invoice->is_pro = $account->isPro();
|
||||
$invoice->features = [
|
||||
'customize_invoice_design' => $account->hasFeature(FEATURE_CUSTOMIZE_INVOICE_DESIGN),
|
||||
'remove_created_by' => $account->hasFeature(FEATURE_REMOVE_CREATED_BY),
|
||||
'invoice_settings' => $account->hasFeature(FEATURE_INVOICE_SETTINGS),
|
||||
];
|
||||
$invoice->invoice_fonts = $account->getFontsData();
|
||||
|
||||
if ($invoice->invoice_design_id == CUSTOM_DESIGN) {
|
||||
@ -116,9 +126,10 @@ class PublicClientController extends BaseController
|
||||
'account' => $account,
|
||||
'showApprove' => $showApprove,
|
||||
'showBreadcrumbs' => false,
|
||||
'hideLogo' => $account->isWhiteLabel(),
|
||||
'hideHeader' => $account->isNinjaAccount(),
|
||||
'hideDashboard' => !$account->enable_client_portal,
|
||||
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL),
|
||||
'hideHeader' => $account->isNinjaAccount() || !$account->enable_client_portal,
|
||||
'hideDashboard' => !$account->enable_client_portal_dashboard,
|
||||
'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS),
|
||||
'clientViewCSS' => $account->clientViewCSS(),
|
||||
'clientFontUrl' => $account->getFontsUrl(),
|
||||
'invoice' => $invoice->hidePrivateFields(),
|
||||
@ -132,6 +143,15 @@ class PublicClientController extends BaseController
|
||||
'checkoutComDebug' => $checkoutComDebug,
|
||||
'phantomjs' => Input::has('phantomjs'),
|
||||
);
|
||||
|
||||
if($account->hasFeature(FEATURE_DOCUMENTS) && $this->canCreateZip()){
|
||||
$zipDocs = $this->getInvoiceZipDocuments($invoice, $size);
|
||||
|
||||
if(count($zipDocs) > 1){
|
||||
$data['documentsZipURL'] = URL::to("client/documents/{$invitation->invitation_key}");
|
||||
$data['documentsZipSize'] = $size;
|
||||
}
|
||||
}
|
||||
|
||||
return View::make('invoices.view', $data);
|
||||
}
|
||||
@ -196,7 +216,7 @@ class PublicClientController extends BaseController
|
||||
$client = $invoice->client;
|
||||
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
|
||||
|
||||
if (!$account->enable_client_portal) {
|
||||
if (!$account->enable_client_portal || !$account->enable_client_portal_dashboard) {
|
||||
return $this->returnError();
|
||||
}
|
||||
|
||||
@ -204,7 +224,8 @@ class PublicClientController extends BaseController
|
||||
'color' => $color,
|
||||
'account' => $account,
|
||||
'client' => $client,
|
||||
'hideLogo' => $account->isWhiteLabel(),
|
||||
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL),
|
||||
'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS),
|
||||
'clientViewCSS' => $account->clientViewCSS(),
|
||||
'clientFontUrl' => $account->getFontsUrl(),
|
||||
];
|
||||
@ -245,13 +266,20 @@ class PublicClientController extends BaseController
|
||||
if (!$invitation = $this->getInvitation()) {
|
||||
return $this->returnError();
|
||||
}
|
||||
|
||||
$account = $invitation->account;
|
||||
|
||||
if (!$account->enable_client_portal) {
|
||||
return $this->returnError();
|
||||
}
|
||||
|
||||
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
|
||||
|
||||
$data = [
|
||||
'color' => $color,
|
||||
'hideLogo' => $account->isWhiteLabel(),
|
||||
'hideDashboard' => !$account->enable_client_portal,
|
||||
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL),
|
||||
'hideDashboard' => !$account->enable_client_portal_dashboard,
|
||||
'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS),
|
||||
'clientViewCSS' => $account->clientViewCSS(),
|
||||
'clientFontUrl' => $account->getFontsUrl(),
|
||||
'title' => trans('texts.invoices'),
|
||||
@ -278,12 +306,17 @@ class PublicClientController extends BaseController
|
||||
return $this->returnError();
|
||||
}
|
||||
$account = $invitation->account;
|
||||
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
|
||||
|
||||
|
||||
if (!$account->enable_client_portal) {
|
||||
return $this->returnError();
|
||||
}
|
||||
|
||||
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
|
||||
$data = [
|
||||
'color' => $color,
|
||||
'hideLogo' => $account->isWhiteLabel(),
|
||||
'hideDashboard' => !$account->enable_client_portal,
|
||||
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL),
|
||||
'hideDashboard' => !$account->enable_client_portal_dashboard,
|
||||
'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS),
|
||||
'clientViewCSS' => $account->clientViewCSS(),
|
||||
'clientFontUrl' => $account->getFontsUrl(),
|
||||
'entityType' => ENTITY_PAYMENT,
|
||||
@ -315,13 +348,19 @@ class PublicClientController extends BaseController
|
||||
if (!$invitation = $this->getInvitation()) {
|
||||
return $this->returnError();
|
||||
}
|
||||
|
||||
$account = $invitation->account;
|
||||
|
||||
if (!$account->enable_client_portal) {
|
||||
return $this->returnError();
|
||||
}
|
||||
|
||||
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
|
||||
|
||||
$data = [
|
||||
'color' => $color,
|
||||
'hideLogo' => $account->isWhiteLabel(),
|
||||
'hideDashboard' => !$account->enable_client_portal,
|
||||
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL),
|
||||
'hideDashboard' => !$account->enable_client_portal_dashboard,
|
||||
'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS),
|
||||
'clientViewCSS' => $account->clientViewCSS(),
|
||||
'clientFontUrl' => $account->getFontsUrl(),
|
||||
'title' => trans('texts.quotes'),
|
||||
@ -342,6 +381,44 @@ class PublicClientController extends BaseController
|
||||
return $this->invoiceRepo->getClientDatatable($invitation->contact_id, ENTITY_QUOTE, Input::get('sSearch'));
|
||||
}
|
||||
|
||||
public function documentIndex()
|
||||
{
|
||||
if (!$invitation = $this->getInvitation()) {
|
||||
return $this->returnError();
|
||||
}
|
||||
|
||||
$account = $invitation->account;
|
||||
|
||||
if (!$account->enable_client_portal) {
|
||||
return $this->returnError();
|
||||
}
|
||||
|
||||
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
|
||||
$data = [
|
||||
'color' => $color,
|
||||
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL),
|
||||
'hideDashboard' => !$account->enable_client_portal_dashboard,
|
||||
'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS),
|
||||
'clientViewCSS' => $account->clientViewCSS(),
|
||||
'clientFontUrl' => $account->getFontsUrl(),
|
||||
'title' => trans('texts.documents'),
|
||||
'entityType' => ENTITY_DOCUMENT,
|
||||
'columns' => Utils::trans(['invoice_number', 'name', 'document_date', 'document_size']),
|
||||
];
|
||||
|
||||
return response()->view('public_list', $data);
|
||||
}
|
||||
|
||||
|
||||
public function documentDatatable()
|
||||
{
|
||||
if (!$invitation = $this->getInvitation()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->documentRepo->getClientDatatable($invitation->contact_id, ENTITY_DOCUMENT, Input::get('sSearch'));
|
||||
}
|
||||
|
||||
private function returnError($error = false)
|
||||
{
|
||||
return response()->view('error', [
|
||||
@ -372,5 +449,148 @@ class PublicClientController extends BaseController
|
||||
|
||||
return $invitation;
|
||||
}
|
||||
|
||||
public function getDocumentVFSJS($publicId, $name){
|
||||
if (!$invitation = $this->getInvitation()) {
|
||||
return $this->returnError();
|
||||
}
|
||||
|
||||
$clientId = $invitation->invoice->client_id;
|
||||
$document = Document::scope($publicId, $invitation->account_id)->first();
|
||||
|
||||
|
||||
if(!$document->isPDFEmbeddable()){
|
||||
return Response::view('error', array('error'=>'Image does not exist!'), 404);
|
||||
}
|
||||
|
||||
$authorized = false;
|
||||
if($document->expense && $document->expense->client_id == $invitation->invoice->client_id){
|
||||
$authorized = true;
|
||||
} else if($document->invoice && $document->invoice->client_id == $invitation->invoice->client_id){
|
||||
$authorized = true;
|
||||
}
|
||||
|
||||
if(!$authorized){
|
||||
return Response::view('error', array('error'=>'Not authorized'), 403);
|
||||
}
|
||||
|
||||
if(substr($name, -3)=='.js'){
|
||||
$name = substr($name, 0, -3);
|
||||
}
|
||||
|
||||
$content = $document->preview?$document->getRawPreview():$document->getRaw();
|
||||
$content = 'ninjaAddVFSDoc('.json_encode(intval($publicId).'/'.strval($name)).',"'.base64_encode($content).'")';
|
||||
$response = Response::make($content, 200);
|
||||
$response->header('content-type', 'text/javascript');
|
||||
$response->header('cache-control', 'max-age=31536000');
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
protected function canCreateZip(){
|
||||
return function_exists('gmp_init');
|
||||
}
|
||||
|
||||
protected function getInvoiceZipDocuments($invoice, &$size=0){
|
||||
$documents = $invoice->documents;
|
||||
|
||||
foreach($invoice->expenses as $expense){
|
||||
$documents = $documents->merge($expense->documents);
|
||||
}
|
||||
|
||||
$documents = $documents->sortBy('size');
|
||||
|
||||
$size = 0;
|
||||
$maxSize = MAX_ZIP_DOCUMENTS_SIZE * 1000;
|
||||
$toZip = array();
|
||||
foreach($documents as $document){
|
||||
if($size + $document->size > $maxSize)break;
|
||||
|
||||
if(!empty($toZip[$document->name])){
|
||||
// This name is taken
|
||||
if($toZip[$document->name]->hash != $document->hash){
|
||||
// 2 different files with the same name
|
||||
$nameInfo = pathinfo($document->name);
|
||||
|
||||
for($i = 1;; $i++){
|
||||
$name = $nameInfo['filename'].' ('.$i.').'.$nameInfo['extension'];
|
||||
|
||||
if(empty($toZip[$name])){
|
||||
$toZip[$name] = $document;
|
||||
$size += $document->size;
|
||||
break;
|
||||
} else if ($toZip[$name]->hash == $document->hash){
|
||||
// We're not adding this after all
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else{
|
||||
$toZip[$document->name] = $document;
|
||||
$size += $document->size;
|
||||
}
|
||||
}
|
||||
|
||||
return $toZip;
|
||||
}
|
||||
|
||||
public function getInvoiceDocumentsZip($invitationKey){
|
||||
if (!$invitation = $this->invoiceRepo->findInvoiceByInvitation($invitationKey)) {
|
||||
return $this->returnError();
|
||||
}
|
||||
|
||||
Session::put('invitation_key', $invitationKey); // track current invitation
|
||||
|
||||
$invoice = $invitation->invoice;
|
||||
|
||||
$toZip = $this->getInvoiceZipDocuments($invoice);
|
||||
|
||||
if(!count($toZip)){
|
||||
return Response::view('error', array('error'=>'No documents small enough'), 404);
|
||||
}
|
||||
|
||||
$zip = new ZipArchive($invitation->account->name.' Invoice '.$invoice->invoice_number.'.zip');
|
||||
return Response::stream(function() use ($toZip, $zip) {
|
||||
foreach($toZip as $name=>$document){
|
||||
$fileStream = $document->getStream();
|
||||
if($fileStream){
|
||||
$zip->init_file_stream_transfer($name, $document->size, array('time'=>$document->created_at->timestamp));
|
||||
while ($buffer = fread($fileStream, 256000))$zip->stream_file_part($buffer);
|
||||
fclose($fileStream);
|
||||
$zip->complete_file_stream();
|
||||
}
|
||||
else{
|
||||
$zip->add_file($name, $document->getRaw());
|
||||
}
|
||||
}
|
||||
$zip->finish();
|
||||
}, 200);
|
||||
}
|
||||
|
||||
public function getDocument($invitationKey, $publicId){
|
||||
if (!$invitation = $this->invoiceRepo->findInvoiceByInvitation($invitationKey)) {
|
||||
return $this->returnError();
|
||||
}
|
||||
|
||||
Session::put('invitation_key', $invitationKey); // track current invitation
|
||||
|
||||
$clientId = $invitation->invoice->client_id;
|
||||
$document = Document::scope($publicId, $invitation->account_id)->firstOrFail();
|
||||
|
||||
$authorized = false;
|
||||
if($document->expense && $document->expense->client_id == $invitation->invoice->client_id){
|
||||
$authorized = true;
|
||||
} else if($document->invoice && $document->invoice->client_id == $invitation->invoice->client_id){
|
||||
$authorized = true;
|
||||
}
|
||||
|
||||
if(!$authorized){
|
||||
return Response::view('error', array('error'=>'Not authorized'), 403);
|
||||
}
|
||||
|
||||
return DocumentController::getDownloadResponse($document);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,75 +0,0 @@
|
||||
<?php namespace App\Http\Controllers;
|
||||
|
||||
use Auth;
|
||||
use Input;
|
||||
use Utils;
|
||||
use Response;
|
||||
use App\Models\Invoice;
|
||||
use App\Ninja\Repositories\InvoiceRepository;
|
||||
use App\Http\Controllers\BaseAPIController;
|
||||
use App\Ninja\Transformers\QuoteTransformer;
|
||||
|
||||
class QuoteApiController extends BaseAPIController
|
||||
{
|
||||
protected $invoiceRepo;
|
||||
|
||||
public function __construct(InvoiceRepository $invoiceRepo)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->invoiceRepo = $invoiceRepo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @SWG\Get(
|
||||
* path="/quotes",
|
||||
* tags={"quote"},
|
||||
* summary="List of quotes",
|
||||
* @SWG\Response(
|
||||
* response=200,
|
||||
* description="A list with quotes",
|
||||
* @SWG\Schema(type="array", @SWG\Items(ref="#/definitions/Invoice"))
|
||||
* ),
|
||||
* @SWG\Response(
|
||||
* response="default",
|
||||
* description="an ""unexpected"" error"
|
||||
* )
|
||||
* )
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$paginator = Invoice::scope();
|
||||
$invoices = Invoice::scope()
|
||||
->with('client', 'invitations', 'user', 'invoice_items')
|
||||
->where('invoices.is_quote', '=', true);
|
||||
|
||||
if ($clientPublicId = Input::get('client_id')) {
|
||||
$filter = function($query) use ($clientPublicId) {
|
||||
$query->where('public_id', '=', $clientPublicId);
|
||||
};
|
||||
$invoices->whereHas('client', $filter);
|
||||
$paginator->whereHas('client', $filter);
|
||||
}
|
||||
|
||||
$invoices = $invoices->orderBy('created_at', 'desc')->paginate();
|
||||
|
||||
$transformer = new QuoteTransformer(\Auth::user()->account, Input::get('serializer'));
|
||||
$paginator = $paginator->paginate();
|
||||
|
||||
$data = $this->createCollection($invoices, $transformer, 'quotes', $paginator);
|
||||
|
||||
return $this->response($data);
|
||||
}
|
||||
|
||||
/*
|
||||
public function store()
|
||||
{
|
||||
$data = Input::all();
|
||||
$invoice = $this->invoiceRepo->save(false, $data, false);
|
||||
|
||||
$response = json_encode($invoice, JSON_PRETTY_PRINT);
|
||||
$headers = Utils::getApiHeaders();
|
||||
return Response::make($response, 200, $headers);
|
||||
}
|
||||
*/
|
||||
}
|
@ -26,6 +26,7 @@ use App\Ninja\Repositories\InvoiceRepository;
|
||||
use App\Ninja\Repositories\ClientRepository;
|
||||
use App\Events\QuoteInvitationWasApproved;
|
||||
use App\Services\InvoiceService;
|
||||
use App\Http\Requests\InvoiceRequest;
|
||||
|
||||
class QuoteController extends BaseController
|
||||
{
|
||||
@ -33,7 +34,7 @@ class QuoteController extends BaseController
|
||||
protected $invoiceRepo;
|
||||
protected $clientRepo;
|
||||
protected $invoiceService;
|
||||
protected $model = 'App\Models\Invoice';
|
||||
protected $entityType = ENTITY_INVOICE;
|
||||
|
||||
public function __construct(Mailer $mailer, InvoiceRepository $invoiceRepo, ClientRepository $clientRepo, InvoiceService $invoiceService)
|
||||
{
|
||||
@ -47,7 +48,7 @@ class QuoteController extends BaseController
|
||||
|
||||
public function index()
|
||||
{
|
||||
if (!Utils::isPro()) {
|
||||
if (!Utils::hasFeature(FEATURE_QUOTES)) {
|
||||
return Redirect::to('/invoices/create');
|
||||
}
|
||||
|
||||
@ -78,13 +79,9 @@ class QuoteController extends BaseController
|
||||
return $this->invoiceService->getDatatable($accountId, $clientPublicId, ENTITY_QUOTE, $search);
|
||||
}
|
||||
|
||||
public function create($clientPublicId = 0)
|
||||
public function create(InvoiceRequest $request, $clientPublicId = 0)
|
||||
{
|
||||
if(!$this->checkCreatePermission($response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
if (!Utils::isPro()) {
|
||||
if (!Utils::hasFeature(FEATURE_QUOTES)) {
|
||||
return Redirect::to('/invoices/create');
|
||||
}
|
||||
|
||||
@ -111,10 +108,27 @@ class QuoteController extends BaseController
|
||||
|
||||
private static function getViewModel()
|
||||
{
|
||||
// Tax rate $options
|
||||
$account = Auth::user()->account;
|
||||
$rates = TaxRate::scope()->orderBy('name')->get();
|
||||
$options = [];
|
||||
$defaultTax = false;
|
||||
|
||||
foreach ($rates as $rate) {
|
||||
$options[$rate->rate . ' ' . $rate->name] = $rate->name . ' ' . ($rate->rate+0) . '%';
|
||||
|
||||
// load default invoice tax
|
||||
if ($rate->id == $account->default_tax_rate_id) {
|
||||
$defaultTax = $rate;
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'entityType' => ENTITY_QUOTE,
|
||||
'account' => Auth::user()->account,
|
||||
'products' => Product::scope()->orderBy('id')->get(array('product_key', 'notes', 'cost', 'qty')),
|
||||
'taxRateOptions' => $options,
|
||||
'defaultTax' => $defaultTax,
|
||||
'countries' => Cache::get('countries'),
|
||||
'clients' => Client::scope()->with('contacts', 'country')->orderBy('name')->get(),
|
||||
'taxRates' => TaxRate::scope()->orderBy('name')->get(),
|
||||
|
@ -21,7 +21,7 @@ class ReportController extends BaseController
|
||||
$message = '';
|
||||
$fileName = storage_path().'/dataviz_sample.txt';
|
||||
|
||||
if (Auth::user()->account->isPro()) {
|
||||
if (Auth::user()->account->hasFeature(FEATURE_REPORTS)) {
|
||||
$account = Account::where('id', '=', Auth::user()->account->id)
|
||||
->with(['clients.invoices.invoice_items', 'clients.contacts'])
|
||||
->first();
|
||||
@ -99,13 +99,13 @@ class ReportController extends BaseController
|
||||
'title' => trans('texts.charts_and_reports'),
|
||||
];
|
||||
|
||||
if (Auth::user()->account->isPro()) {
|
||||
if (Auth::user()->account->hasFeature(FEATURE_REPORTS)) {
|
||||
if ($enableReport) {
|
||||
$isExport = $action == 'export';
|
||||
$params = array_merge($params, self::generateReport($reportType, $startDate, $endDate, $dateField, $isExport));
|
||||
|
||||
if ($isExport) {
|
||||
self::export($params['displayData'], $params['columns'], $params['reportTotals']);
|
||||
self::export($reportType, $params['displayData'], $params['columns'], $params['reportTotals']);
|
||||
}
|
||||
}
|
||||
if ($enableChart) {
|
||||
@ -514,11 +514,14 @@ class ReportController extends BaseController
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function export($data, $columns, $totals)
|
||||
private function export($reportType, $data, $columns, $totals)
|
||||
{
|
||||
$output = fopen('php://output', 'w') or Utils::fatalError();
|
||||
$reportType = trans("texts.{$reportType}s");
|
||||
$date = date('Y-m-d');
|
||||
|
||||
header('Content-Type:application/csv');
|
||||
header('Content-Disposition:attachment;filename=ninja-report.csv');
|
||||
header("Content-Disposition:attachment;filename={$date}_Ninja_{$reportType}.csv");
|
||||
|
||||
Utils::exportData($output, $data, Utils::trans($columns));
|
||||
|
||||
|
@ -13,6 +13,8 @@ class TaskApiController extends BaseAPIController
|
||||
{
|
||||
protected $taskRepo;
|
||||
|
||||
protected $entityType = ENTITY_TASK;
|
||||
|
||||
public function __construct(TaskRepository $taskRepo)
|
||||
{
|
||||
parent::__construct();
|
||||
@ -38,25 +40,11 @@ class TaskApiController extends BaseAPIController
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$paginator = Task::scope();
|
||||
$tasks = Task::scope()
|
||||
->with($this->getIncluded());
|
||||
$payments = Task::scope()
|
||||
->withTrashed()
|
||||
->orderBy('created_at', 'desc');
|
||||
|
||||
if ($clientPublicId = Input::get('client_id')) {
|
||||
$filter = function($query) use ($clientPublicId) {
|
||||
$query->where('public_id', '=', $clientPublicId);
|
||||
};
|
||||
$tasks->whereHas('client', $filter);
|
||||
$paginator->whereHas('client', $filter);
|
||||
}
|
||||
|
||||
$tasks = $tasks->orderBy('created_at', 'desc')->paginate();
|
||||
$paginator = $paginator->paginate();
|
||||
$transformer = new TaskTransformer(\Auth::user()->account, Input::get('serializer'));
|
||||
|
||||
$data = $this->createCollection($tasks, $transformer, 'tasks', $paginator);
|
||||
|
||||
return $this->response($data);
|
||||
return $this->listResponse($payments);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -18,11 +18,15 @@ use App\Ninja\Repositories\TaskRepository;
|
||||
use App\Ninja\Repositories\InvoiceRepository;
|
||||
use App\Services\TaskService;
|
||||
|
||||
use App\Http\Requests\TaskRequest;
|
||||
use App\Http\Requests\CreateTaskRequest;
|
||||
use App\Http\Requests\UpdateTaskRequest;
|
||||
|
||||
class TaskController extends BaseController
|
||||
{
|
||||
protected $taskRepo;
|
||||
protected $taskService;
|
||||
protected $model = 'App\Models\Task';
|
||||
protected $entityType = ENTITY_TASK;
|
||||
|
||||
public function __construct(TaskRepository $taskRepo, InvoiceRepository $invoiceRepo, TaskService $taskService)
|
||||
{
|
||||
@ -66,7 +70,7 @@ class TaskController extends BaseController
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function store()
|
||||
public function store(CreateTaskRequest $request)
|
||||
{
|
||||
return $this->save();
|
||||
}
|
||||
@ -83,16 +87,13 @@ class TaskController extends BaseController
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function create($clientPublicId = 0)
|
||||
public function create(TaskRequest $request)
|
||||
{
|
||||
if(!$this->checkCreatePermission($response)){
|
||||
return $response;
|
||||
}
|
||||
$this->checkTimezone();
|
||||
|
||||
$data = [
|
||||
'task' => null,
|
||||
'clientPublicId' => Input::old('client') ? Input::old('client') : $clientPublicId,
|
||||
'clientPublicId' => Input::old('client') ? Input::old('client') : ($request->client_id ?: 0),
|
||||
'method' => 'POST',
|
||||
'url' => 'tasks',
|
||||
'title' => trans('texts.new_task'),
|
||||
@ -111,15 +112,11 @@ class TaskController extends BaseController
|
||||
* @param int $id
|
||||
* @return Response
|
||||
*/
|
||||
public function edit($publicId)
|
||||
public function edit(TaskRequest $request)
|
||||
{
|
||||
$this->checkTimezone();
|
||||
|
||||
$task = Task::scope($publicId)->with('client', 'invoice')->withTrashed()->firstOrFail();
|
||||
|
||||
if(!$this->checkEditPermission($task, $response)){
|
||||
return $response;
|
||||
}
|
||||
$task = $request->entity();
|
||||
|
||||
$actions = [];
|
||||
if ($task->invoice) {
|
||||
@ -147,7 +144,7 @@ class TaskController extends BaseController
|
||||
'task' => $task,
|
||||
'clientPublicId' => $task->client ? $task->client->public_id : 0,
|
||||
'method' => 'PUT',
|
||||
'url' => 'tasks/'.$publicId,
|
||||
'url' => 'tasks/'.$task->public_id,
|
||||
'title' => trans('texts.edit_task'),
|
||||
'duration' => $task->is_running ? $task->getCurrentDuration() : $task->getDuration(),
|
||||
'actions' => $actions,
|
||||
@ -167,9 +164,11 @@ class TaskController extends BaseController
|
||||
* @param int $id
|
||||
* @return Response
|
||||
*/
|
||||
public function update($publicId)
|
||||
public function update(UpdateTaskRequest $request)
|
||||
{
|
||||
return $this->save($publicId);
|
||||
$task = $request->entity();
|
||||
|
||||
return $this->save($task->public_id);
|
||||
}
|
||||
|
||||
private static function getViewModel()
|
||||
@ -184,22 +183,10 @@ class TaskController extends BaseController
|
||||
{
|
||||
$action = Input::get('action');
|
||||
|
||||
if(!$this->checkUpdatePermission(array('public_id'=>$publicId)/* Hacky, but works */, $response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
if (in_array($action, ['archive', 'delete', 'restore'])) {
|
||||
return self::bulk();
|
||||
}
|
||||
|
||||
if ($validator = $this->taskRepo->getErrors(Input::all())) {
|
||||
$url = $publicId ? 'tasks/'.$publicId.'/edit' : 'tasks/create';
|
||||
Session::flash('error', trans('texts.task_errors'));
|
||||
return Redirect::to($url)
|
||||
->withErrors($validator)
|
||||
->withInput();
|
||||
}
|
||||
|
||||
$task = $this->taskRepo->save($publicId, Input::all());
|
||||
Session::flash('message', trans($publicId ? 'texts.updated_task' : 'texts.created_task'));
|
||||
|
||||
|
@ -1,68 +1,54 @@
|
||||
<?php namespace App\Http\Controllers;
|
||||
|
||||
use App\Services\TaxRateService;
|
||||
use App\Ninja\Repositories\TaxRateRepository;
|
||||
use App\Ninja\Transformers\TaxRateTransformer;
|
||||
use Auth;
|
||||
use App\Models\TaxRate;
|
||||
|
||||
use App\Ninja\Repositories\TaxRateRepository;
|
||||
use App\Http\Requests\CreateTaxRateRequest;
|
||||
use App\Http\Requests\UpdateTaxRateRequest;
|
||||
|
||||
class TaxRateApiController extends BaseAPIController
|
||||
{
|
||||
protected $taxRateService;
|
||||
protected $taxRateRepo;
|
||||
|
||||
protected $entityType = ENTITY_TAX_RATE;
|
||||
|
||||
public function __construct(TaxRateService $taxRateService, TaxRateRepository $taxRateRepo)
|
||||
public function __construct(TaxRateRepository $taxRateRepo)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->taxRateService = $taxRateService;
|
||||
$this->taxRateRepo = $taxRateRepo;
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$taxRates = TaxRate::scope()->withTrashed();
|
||||
$taxRates = $taxRates->paginate();
|
||||
$taxRates = TaxRate::scope()
|
||||
->withTrashed()
|
||||
->orderBy('created_at', 'desc');
|
||||
|
||||
$paginator = TaxRate::scope()->withTrashed()->paginate();
|
||||
|
||||
$transformer = new TaxRateTransformer(Auth::user()->account, $this->serializer);
|
||||
$data = $this->createCollection($taxRates, $transformer, 'tax_rates', $paginator);
|
||||
|
||||
return $this->response($data);
|
||||
return $this->listResponse($taxRates);
|
||||
}
|
||||
|
||||
public function store(CreateTaxRateRequest $request)
|
||||
{
|
||||
return $this->save($request);
|
||||
$taxRate = $this->taxRateRepo->save($request->input());
|
||||
|
||||
return $this->itemResponse($taxRate);
|
||||
}
|
||||
|
||||
public function update(UpdateTaxRateRequest $request, $taxRatePublicId)
|
||||
public function update(UpdateTaxRateRequest $request, $publicId)
|
||||
{
|
||||
$taxRate = TaxRate::scope($taxRatePublicId)->firstOrFail();
|
||||
|
||||
if ($request->action == ACTION_ARCHIVE) {
|
||||
$this->taxRateRepo->archive($taxRate);
|
||||
|
||||
$transformer = new TaxRateTransformer(Auth::user()->account, $request->serializer);
|
||||
$data = $this->createItem($taxRate, $transformer, 'tax_rates');
|
||||
|
||||
return $this->response($data);
|
||||
} else {
|
||||
return $this->save($request, $taxRate);
|
||||
if ($request->action) {
|
||||
return $this->handleAction($request);
|
||||
}
|
||||
|
||||
$data = $request->input();
|
||||
$data['public_id'] = $publicId;
|
||||
$taxRate = $this->taxRateRepo->save($data, $request->entity());
|
||||
|
||||
return $this->itemResponse($taxRate);
|
||||
}
|
||||
|
||||
private function save($request, $taxRate = false)
|
||||
public function destroy($publicId)
|
||||
{
|
||||
$taxRate = $this->taxRateRepo->save($request->input(), $taxRate);
|
||||
|
||||
$transformer = new TaxRateTransformer(\Auth::user()->account, $request->serializer);
|
||||
$data = $this->createItem($taxRate, $transformer, 'tax_rates');
|
||||
|
||||
return $this->response($data);
|
||||
//stub
|
||||
}
|
||||
}
|
||||
|
@ -75,9 +75,7 @@ class TaxRateController extends BaseController
|
||||
|
||||
public function update(UpdateTaxRateRequest $request, $publicId)
|
||||
{
|
||||
$taxRate = TaxRate::scope($publicId)->firstOrFail();
|
||||
|
||||
$this->taxRateRepo->save($request->input(), $taxRate);
|
||||
$this->taxRateRepo->save($request->input(), $request->entity());
|
||||
|
||||
Session::flash('message', trans('texts.updated_tax_rate'));
|
||||
return Redirect::to('settings/' . ACCOUNT_TAX_RATES);
|
||||
|
@ -32,7 +32,7 @@ class TokenController extends BaseController
|
||||
|
||||
public function getDatatable()
|
||||
{
|
||||
return $this->tokenService->getDatatable(Auth::user()->account_id);
|
||||
return $this->tokenService->getDatatable(Auth::user()->id);
|
||||
}
|
||||
|
||||
public function edit($publicId)
|
||||
@ -93,7 +93,7 @@ class TokenController extends BaseController
|
||||
*/
|
||||
public function save($tokenPublicId = false)
|
||||
{
|
||||
if (Auth::user()->account->isPro()) {
|
||||
if (Auth::user()->account->hasFeature(FEATURE_API)) {
|
||||
$rules = [
|
||||
'name' => 'required',
|
||||
];
|
||||
|
@ -14,6 +14,8 @@ class UserApiController extends BaseAPIController
|
||||
protected $userService;
|
||||
protected $userRepo;
|
||||
|
||||
protected $entityType = ENTITY_USER;
|
||||
|
||||
public function __construct(UserService $userService, UserRepository $userRepo)
|
||||
{
|
||||
parent::__construct();
|
||||
@ -24,16 +26,11 @@ class UserApiController extends BaseAPIController
|
||||
|
||||
public function index()
|
||||
{
|
||||
$user = Auth::user();
|
||||
$users = User::whereAccountId($user->account_id)->withTrashed();
|
||||
$users = $users->paginate();
|
||||
|
||||
$paginator = User::whereAccountId($user->account_id)->withTrashed()->paginate();
|
||||
|
||||
$transformer = new UserTransformer(Auth::user()->account, $this->serializer);
|
||||
$data = $this->createCollection($users, $transformer, 'users', $paginator);
|
||||
|
||||
return $this->response($data);
|
||||
$users = User::whereAccountId(Auth::user()->account_id)
|
||||
->withTrashed()
|
||||
->orderBy('created_at', 'desc');
|
||||
|
||||
return $this->listResponse($users);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -45,11 +42,6 @@ class UserApiController extends BaseAPIController
|
||||
|
||||
public function update(UpdateUserRequest $request, $userPublicId)
|
||||
{
|
||||
/*
|
||||
// temporary fix for ids starting at 0
|
||||
$userPublicId -= 1;
|
||||
$user = User::scope($userPublicId)->firstOrFail();
|
||||
*/
|
||||
$user = Auth::user();
|
||||
|
||||
if ($request->action == ACTION_ARCHIVE) {
|
||||
|
@ -164,7 +164,7 @@ class UserController extends BaseController
|
||||
*/
|
||||
public function save($userPublicId = false)
|
||||
{
|
||||
if (Auth::user()->isPro() && ! Auth::user()->isTrial()) {
|
||||
if (Auth::user()->hasFeature(FEATURE_USERS)) {
|
||||
$rules = [
|
||||
'first_name' => 'required',
|
||||
'last_name' => 'required',
|
||||
@ -190,8 +190,10 @@ class UserController extends BaseController
|
||||
$user->last_name = trim(Input::get('last_name'));
|
||||
$user->username = trim(Input::get('email'));
|
||||
$user->email = trim(Input::get('email'));
|
||||
$user->is_admin = boolval(Input::get('is_admin'));
|
||||
$user->permissions = Input::get('permissions');
|
||||
if (Auth::user()->hasFeature(FEATURE_USER_PERMISSIONS)) {
|
||||
$user->is_admin = boolval(Input::get('is_admin'));
|
||||
$user->permissions = Input::get('permissions');
|
||||
}
|
||||
} else {
|
||||
$lastUser = User::withTrashed()->where('account_id', '=', Auth::user()->account_id)
|
||||
->orderBy('public_id', 'DESC')->first();
|
||||
@ -202,12 +204,14 @@ class UserController extends BaseController
|
||||
$user->last_name = trim(Input::get('last_name'));
|
||||
$user->username = trim(Input::get('email'));
|
||||
$user->email = trim(Input::get('email'));
|
||||
$user->is_admin = boolval(Input::get('is_admin'));
|
||||
$user->registered = true;
|
||||
$user->password = str_random(RANDOM_KEY_LENGTH);
|
||||
$user->confirmation_code = str_random(RANDOM_KEY_LENGTH);
|
||||
$user->public_id = $lastUser->public_id + 1;
|
||||
$user->permissions = Input::get('permissions');
|
||||
if (Auth::user()->hasFeature(FEATURE_USER_PERMISSIONS)) {
|
||||
$user->is_admin = boolval(Input::get('is_admin'));
|
||||
$user->permissions = Input::get('permissions');
|
||||
}
|
||||
}
|
||||
|
||||
$user->save();
|
||||
@ -286,6 +290,9 @@ class UserController extends BaseController
|
||||
if (!Auth::user()->registered) {
|
||||
$account = Auth::user()->account;
|
||||
$this->accountRepo->unlinkAccount($account);
|
||||
if ($account->company->accounts->count() == 1) {
|
||||
$account->company->forceDelete();
|
||||
}
|
||||
$account->forceDelete();
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,8 @@ class VendorApiController extends BaseAPIController
|
||||
{
|
||||
protected $vendorRepo;
|
||||
|
||||
protected $entityType = ENTITY_VENDOR;
|
||||
|
||||
public function __construct(VendorRepository $vendorRepo)
|
||||
{
|
||||
parent::__construct();
|
||||
@ -46,17 +48,11 @@ class VendorApiController extends BaseAPIController
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$vendors = Vendor::scope()
|
||||
->with($this->getIncluded())
|
||||
$vendors = Vendor::scope()
|
||||
->withTrashed()
|
||||
->orderBy('created_at', 'desc')
|
||||
->paginate();
|
||||
->orderBy('created_at', 'desc');
|
||||
|
||||
$transformer = new VendorTransformer(Auth::user()->account, Input::get('serializer'));
|
||||
$paginator = Vendor::scope()->paginate();
|
||||
$data = $this->createCollection($vendors, $transformer, ENTITY_VENDOR, $paginator);
|
||||
|
||||
return $this->response($data);
|
||||
return $this->listResponse($vendors);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -85,11 +81,9 @@ class VendorApiController extends BaseAPIController
|
||||
$vendor = $this->vendorRepo->save($request->input());
|
||||
|
||||
$vendor = Vendor::scope($vendor->public_id)
|
||||
->with('country', 'vendorcontacts', 'industry', 'size', 'currency')
|
||||
->with('country', 'vendor_contacts', 'industry', 'size', 'currency')
|
||||
->first();
|
||||
|
||||
$transformer = new VendorTransformer(Auth::user()->account, Input::get('serializer'));
|
||||
$data = $this->createItem($vendor, $transformer, ENTITY_VENDOR);
|
||||
return $this->response($data);
|
||||
return $this->itemResponse($vendor);
|
||||
}
|
||||
}
|
||||
|
@ -23,14 +23,15 @@ use App\Models\Country;
|
||||
use App\Ninja\Repositories\VendorRepository;
|
||||
use App\Services\VendorService;
|
||||
|
||||
use App\Http\Requests\VendorRequest;
|
||||
use App\Http\Requests\CreateVendorRequest;
|
||||
use App\Http\Requests\UpdateVendorRequest;
|
||||
// vendor
|
||||
|
||||
class VendorController extends BaseController
|
||||
{
|
||||
protected $vendorService;
|
||||
protected $vendorRepo;
|
||||
protected $model = 'App\Models\Vendor';
|
||||
protected $entityType = ENTITY_VENDOR;
|
||||
|
||||
public function __construct(VendorRepository $vendorRepo, VendorService $vendorService)
|
||||
{
|
||||
@ -38,8 +39,6 @@ class VendorController extends BaseController
|
||||
|
||||
$this->vendorRepo = $vendorRepo;
|
||||
$this->vendorService = $vendorService;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -77,13 +76,7 @@ class VendorController extends BaseController
|
||||
*/
|
||||
public function store(CreateVendorRequest $request)
|
||||
{
|
||||
$data = $request->input();
|
||||
|
||||
if(!$this->checkUpdatePermission($data, $response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
$vendor = $this->vendorService->save($data);
|
||||
$vendor = $this->vendorService->save($request->input());
|
||||
|
||||
Session::flash('message', trans('texts.created_vendor'));
|
||||
|
||||
@ -96,18 +89,14 @@ class VendorController extends BaseController
|
||||
* @param int $id
|
||||
* @return Response
|
||||
*/
|
||||
public function show($publicId)
|
||||
public function show(VendorRequest $request)
|
||||
{
|
||||
$vendor = Vendor::withTrashed()->scope($publicId)->with('vendorcontacts', 'size', 'industry')->firstOrFail();
|
||||
|
||||
if(!$this->checkViewPermission($vendor, $response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
$vendor = $request->entity();
|
||||
|
||||
Utils::trackViewed($vendor->getDisplayName(), 'vendor');
|
||||
|
||||
$actionLinks = [
|
||||
['label' => trans('texts.new_vendor'), 'url' => '/vendors/create/' . $vendor->public_id]
|
||||
['label' => trans('texts.new_vendor'), 'url' => URL::to('/vendors/create/' . $vendor->public_id)]
|
||||
];
|
||||
|
||||
$data = array(
|
||||
@ -129,12 +118,8 @@ class VendorController extends BaseController
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function create()
|
||||
public function create(VendorRequest $request)
|
||||
{
|
||||
if(!$this->checkCreatePermission($response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
if (Vendor::scope()->count() > Auth::user()->getMaxNumVendors()) {
|
||||
return View::make('error', ['hideHeader' => true, 'error' => "Sorry, you've exceeded the limit of ".Auth::user()->getMaxNumVendors()." vendors"]);
|
||||
}
|
||||
@ -157,26 +142,22 @@ class VendorController extends BaseController
|
||||
* @param int $id
|
||||
* @return Response
|
||||
*/
|
||||
public function edit($publicId)
|
||||
public function edit(VendorRequest $request)
|
||||
{
|
||||
$vendor = Vendor::scope($publicId)->with('vendorcontacts')->firstOrFail();
|
||||
|
||||
if(!$this->checkEditPermission($vendor, $response)){
|
||||
return $response;
|
||||
}
|
||||
$vendor = $request->entity();
|
||||
|
||||
$data = [
|
||||
'vendor' => $vendor,
|
||||
'method' => 'PUT',
|
||||
'url' => 'vendors/'.$publicId,
|
||||
'url' => 'vendors/'.$vendor->public_id,
|
||||
'title' => trans('texts.edit_vendor'),
|
||||
];
|
||||
|
||||
$data = array_merge($data, self::getViewModel());
|
||||
|
||||
if (Auth::user()->account->isNinjaAccount()) {
|
||||
if ($account = Account::whereId($vendor->public_id)->first()) {
|
||||
$data['proPlanPaid'] = $account['pro_plan_paid'];
|
||||
if ($account = Account::whereId($client->public_id)->first()) {
|
||||
$data['planDetails'] = $account->getPlanDetails(false, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -201,13 +182,7 @@ class VendorController extends BaseController
|
||||
*/
|
||||
public function update(UpdateVendorRequest $request)
|
||||
{
|
||||
$data = $request->input();
|
||||
|
||||
if(!$this->checkUpdatePermission($data, $response)){
|
||||
return $response;
|
||||
}
|
||||
|
||||
$vendor = $this->vendorService->save($data);
|
||||
$vendor = $this->vendorService->save($request->input(), $request->entity());
|
||||
|
||||
Session::flash('message', trans('texts.updated_vendor'));
|
||||
|
||||
|
@ -34,7 +34,8 @@ class ApiCheck {
|
||||
// check for a valid token
|
||||
$token = AccountToken::where('token', '=', Request::header('X-Ninja-Token'))->first(['id', 'user_id']);
|
||||
|
||||
if ($token) {
|
||||
// check if user is archived
|
||||
if ($token && $token->user) {
|
||||
Auth::loginUsingId($token->user_id);
|
||||
Session::set('token_id', $token->id);
|
||||
} else {
|
||||
@ -47,7 +48,7 @@ class ApiCheck {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
if (!Utils::isPro() && !$loggingIn) {
|
||||
if (!Utils::hasFeature(FEATURE_API) && !$loggingIn) {
|
||||
return Response::json('API requires pro plan', 403, $headers);
|
||||
} else {
|
||||
$key = Auth::check() ? Auth::user()->account->id : $request->getClientIp();
|
||||
|
@ -42,7 +42,7 @@ class Authenticate {
|
||||
|
||||
// Does this account require portal passwords?
|
||||
$account = Account::whereId($account_id)->first();
|
||||
if(!$account->enable_portal_password || !$account->isPro()){
|
||||
if($account && (!$account->enable_portal_password || !$account->hasFeature(FEATURE_CLIENT_PORTAL_PASSWORD))){
|
||||
$authenticated = true;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?php namespace app\Http\Middleware;
|
||||
<?php namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?php namespace app\Http\Middleware;
|
||||
<?php namespace App\Http\Middleware;
|
||||
|
||||
use Request;
|
||||
use Closure;
|
||||
@ -124,7 +124,8 @@ class StartupCheck
|
||||
$licenseKey = Input::get('license_key');
|
||||
$productId = Input::get('product_id');
|
||||
|
||||
$data = trim(file_get_contents((Utils::isNinjaDev() ? SITE_URL : NINJA_APP_URL)."/claim_license?license_key={$licenseKey}&product_id={$productId}"));
|
||||
$url = (Utils::isNinjaDev() ? SITE_URL : NINJA_APP_URL) . "/claim_license?license_key={$licenseKey}&product_id={$productId}&get_date=true";
|
||||
$data = trim(file_get_contents($url));
|
||||
|
||||
if ($productId == PRODUCT_INVOICE_DESIGNS) {
|
||||
if ($data = json_decode($data)) {
|
||||
@ -140,10 +141,13 @@ class StartupCheck
|
||||
Session::flash('message', trans('texts.bought_designs'));
|
||||
}
|
||||
} elseif ($productId == PRODUCT_WHITE_LABEL) {
|
||||
if ($data == 'valid') {
|
||||
$account = Auth::user()->account;
|
||||
$account->pro_plan_paid = date_create()->format('Y-m-d');
|
||||
$account->save();
|
||||
if ($data && $data != RESULT_FAILURE) {
|
||||
$company = Auth::user()->account->company;
|
||||
$company->plan_term = PLAN_TERM_YEARLY;
|
||||
$company->plan_paid = $data;
|
||||
$company->plan_expires = date_create($data)->modify('+1 year')->format('Y-m-d');
|
||||
$company->plan = PLAN_WHITE_LABEL;
|
||||
$company->save();
|
||||
|
||||
Session::flash('message', trans('texts.bought_white_label'));
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;
|
||||
class VerifyCsrfToken extends BaseVerifier {
|
||||
|
||||
private $openRoutes = [
|
||||
'complete',
|
||||
'signup/register',
|
||||
'api/v1/*',
|
||||
'api/v1/login',
|
||||
|
18
app/Http/Requests/ClientRequest.php
Normal file
18
app/Http/Requests/ClientRequest.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?php namespace App\Http\Requests;
|
||||
|
||||
class ClientRequest extends EntityRequest {
|
||||
|
||||
protected $entityType = ENTITY_CLIENT;
|
||||
|
||||
public function entity()
|
||||
{
|
||||
$client = parent::entity();
|
||||
|
||||
// eager load the contacts
|
||||
if ($client && ! $client->relationLoaded('contacts')) {
|
||||
$client->load('contacts');
|
||||
}
|
||||
|
||||
return $client;
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
<?php namespace app\Http\Requests;
|
||||
<?php namespace App\Http\Requests;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use Illuminate\Validation\Factory;
|
||||
|
@ -1,9 +1,6 @@
|
||||
<?php namespace app\Http\Requests;
|
||||
<?php namespace App\Http\Requests;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use Illuminate\Validation\Factory;
|
||||
|
||||
class CreateClientRequest extends Request
|
||||
class CreateClientRequest extends ClientRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
@ -12,7 +9,7 @@ class CreateClientRequest extends Request
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
return $this->user()->can('create', ENTITY_CLIENT);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -26,21 +23,4 @@ class CreateClientRequest extends Request
|
||||
'contacts' => 'valid_contacts',
|
||||
];
|
||||
}
|
||||
|
||||
public function validator($factory)
|
||||
{
|
||||
// support submiting the form with a single contact record
|
||||
$input = $this->input();
|
||||
if (isset($input['contact'])) {
|
||||
$input['contacts'] = [$input['contact']];
|
||||
unset($input['contact']);
|
||||
$this->replace($input);
|
||||
}
|
||||
|
||||
return $factory->make(
|
||||
$this->input(),
|
||||
$this->container->call([$this, 'rules']),
|
||||
$this->messages()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,6 @@
|
||||
<?php namespace app\Http\Requests;
|
||||
<?php namespace App\Http\Requests;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use Illuminate\Validation\Factory;
|
||||
|
||||
class CreateCreditRequest extends Request
|
||||
class CreateCreditRequest extends CreditRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
@ -12,7 +9,7 @@ class CreateCreditRequest extends Request
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
return $this->user()->can('create', ENTITY_CREDIT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,9 +1,6 @@
|
||||
<?php namespace app\Http\Requests;
|
||||
<?php namespace App\Http\Requests;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use Illuminate\Validation\Factory;
|
||||
|
||||
class UpdateExpenseRequest extends Request
|
||||
class CreateDocumentRequest extends DocumentRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
@ -12,7 +9,7 @@ class UpdateExpenseRequest extends Request
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
return $this->user()->can('create', ENTITY_DOCUMENT);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -23,8 +20,7 @@ class UpdateExpenseRequest extends Request
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'amount' => 'required|positive',
|
||||
|
||||
];
|
||||
|
||||
}
|
||||
}
|
@ -1,9 +1,6 @@
|
||||
<?php namespace app\Http\Requests;
|
||||
<?php namespace App\Http\Requests;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use Illuminate\Validation\Factory;
|
||||
|
||||
class CreateExpenseRequest extends Request
|
||||
class CreateExpenseRequest extends ExpenseRequest
|
||||
{
|
||||
// Expenses
|
||||
/**
|
||||
@ -13,7 +10,7 @@ class CreateExpenseRequest extends Request
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
return $this->user()->can('create', ENTITY_EXPENSE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
32
app/Http/Requests/CreateInvoiceAPIRequest.php
Normal file
32
app/Http/Requests/CreateInvoiceAPIRequest.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php namespace App\Http\Requests;
|
||||
|
||||
class CreateInvoiceAPIRequest extends InvoiceRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return $this->user()->can('create', ENTITY_INVOICE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
$rules = [
|
||||
'email' => 'required_without:client_id',
|
||||
'client_id' => 'required_without:email',
|
||||
'invoice_items' => 'valid_invoice_items',
|
||||
'invoice_number' => 'unique:invoices,invoice_number,,id,account_id,' . $this->user()->account_id,
|
||||
'discount' => 'positive',
|
||||
];
|
||||
|
||||
return $rules;
|
||||
}
|
||||
}
|
@ -1,11 +1,6 @@
|
||||
<?php namespace app\Http\Requests;
|
||||
<?php namespace App\Http\Requests;
|
||||
|
||||
use Auth;
|
||||
use App\Http\Requests\Request;
|
||||
use Illuminate\Validation\Factory;
|
||||
use App\Models\Invoice;
|
||||
|
||||
class CreateInvoiceRequest extends Request
|
||||
class CreateInvoiceRequest extends InvoiceRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
@ -14,7 +9,7 @@ class CreateInvoiceRequest extends Request
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
return $this->user()->can('create', ENTITY_INVOICE);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -25,13 +20,18 @@ class CreateInvoiceRequest extends Request
|
||||
public function rules()
|
||||
{
|
||||
$rules = [
|
||||
'email' => 'required_without:client_id',
|
||||
'client_id' => 'required_without:email',
|
||||
'client.contacts' => 'valid_contacts',
|
||||
'invoice_items' => 'valid_invoice_items',
|
||||
'invoice_number' => 'unique:invoices,invoice_number,,id,account_id,'.Auth::user()->account_id,
|
||||
'invoice_number' => 'required|unique:invoices,invoice_number,,id,account_id,' . $this->user()->account_id,
|
||||
'discount' => 'positive',
|
||||
];
|
||||
|
||||
/* There's a problem parsing the dates
|
||||
if (Request::get('is_recurring') && Request::get('start_date') && Request::get('end_date')) {
|
||||
$rules['end_date'] = 'after' . Request::get('start_date');
|
||||
}
|
||||
*/
|
||||
|
||||
return $rules;
|
||||
}
|
||||
}
|
||||
|
48
app/Http/Requests/CreatePaymentAPIRequest.php
Normal file
48
app/Http/Requests/CreatePaymentAPIRequest.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php namespace App\Http\Requests;
|
||||
|
||||
use App\Models\Invoice;
|
||||
|
||||
class CreatePaymentAPIRequest extends PaymentRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return $this->user()->can('create', ENTITY_PAYMENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
if ( ! $this->invoice_id || ! $this->amount) {
|
||||
return [
|
||||
'invoice_id' => 'required',
|
||||
'amount' => 'required',
|
||||
];
|
||||
}
|
||||
|
||||
$invoice = Invoice::scope($this->invoice_id)->firstOrFail();
|
||||
|
||||
$this->merge([
|
||||
'invoice_id' => $invoice->id,
|
||||
'client_id' => $invoice->client->id,
|
||||
]);
|
||||
|
||||
$rules = array(
|
||||
'amount' => "required|less_than:{$invoice->balance}|positive",
|
||||
);
|
||||
|
||||
if ($this->payment_type_id == PAYMENT_TYPE_CREDIT) {
|
||||
$rules['payment_type_id'] = 'has_credit:' . $invoice->client->public_id . ',' . $this->amount;
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
}
|
@ -1,10 +1,8 @@
|
||||
<?php namespace app\Http\Requests;
|
||||
<?php namespace App\Http\Requests;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use Illuminate\Validation\Factory;
|
||||
use App\Models\Invoice;
|
||||
|
||||
class CreatePaymentRequest extends Request
|
||||
class CreatePaymentRequest extends PaymentRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
@ -13,7 +11,7 @@ class CreatePaymentRequest extends Request
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
return $this->user()->can('create', ENTITY_PAYMENT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,9 +1,6 @@
|
||||
<?php namespace app\Http\Requests;
|
||||
<?php namespace App\Http\Requests;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use Illuminate\Validation\Factory;
|
||||
|
||||
class CreatePaymentTermRequest extends Request
|
||||
class CreateProductRequest extends ProductRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
@ -12,7 +9,7 @@ class CreatePaymentTermRequest extends Request
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
return $this->user()->can('create', ENTITY_PRODUCT);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -23,8 +20,7 @@ class CreatePaymentTermRequest extends Request
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'num_days' => 'required',
|
||||
'name' => 'required',
|
||||
'product_key' => 'required',
|
||||
];
|
||||
}
|
||||
}
|
26
app/Http/Requests/CreateTaskRequest.php
Normal file
26
app/Http/Requests/CreateTaskRequest.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php namespace App\Http\Requests;
|
||||
|
||||
class CreateTaskRequest extends TaskRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return $this->user()->can('create', ENTITY_TASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'time_log' => 'time_log',
|
||||
];
|
||||
}
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
<?php namespace app\Http\Requests;
|
||||
<?php namespace App\Http\Requests;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use Illuminate\Validation\Factory;
|
||||
|
||||
class CreateTaxRateRequest extends Request
|
||||
class CreateTaxRateRequest extends TaxRateRequest
|
||||
{
|
||||
// Expenses
|
||||
/**
|
||||
@ -13,7 +13,7 @@ class CreateTaxRateRequest extends Request
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
return $this->user()->can('create', ENTITY_TAX_RATE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,9 +1,6 @@
|
||||
<?php namespace app\Http\Requests;
|
||||
// vendor
|
||||
use App\Http\Requests\Request;
|
||||
use Illuminate\Validation\Factory;
|
||||
<?php namespace App\Http\Requests;
|
||||
|
||||
class CreateVendorRequest extends Request
|
||||
class CreateVendorRequest extends VendorRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
@ -12,7 +9,7 @@ class CreateVendorRequest extends Request
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
return $this->user()->can('create', ENTITY_VENDOR);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -26,21 +23,4 @@ class CreateVendorRequest extends Request
|
||||
'name' => 'required',
|
||||
];
|
||||
}
|
||||
|
||||
/*
|
||||
public function validator($factory)
|
||||
{
|
||||
// support submiting the form with a single contact record
|
||||
$input = $this->input();
|
||||
if (isset($input['vendor_contact'])) {
|
||||
$input['vendor_contacts'] = [$input['vendor_contact']];
|
||||
unset($input['vendor_contact']);
|
||||
$this->replace($input);
|
||||
}
|
||||
|
||||
return $factory->make(
|
||||
$this->input(), $this->container->call([$this, 'rules']), $this->messages()
|
||||
);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
7
app/Http/Requests/CreditRequest.php
Normal file
7
app/Http/Requests/CreditRequest.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php namespace App\Http\Requests;
|
||||
|
||||
class CreditRequest extends EntityRequest {
|
||||
|
||||
protected $entityType = ENTITY_CREDIT;
|
||||
|
||||
}
|
7
app/Http/Requests/DocumentRequest.php
Normal file
7
app/Http/Requests/DocumentRequest.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php namespace App\Http\Requests;
|
||||
|
||||
class DocumentRequest extends EntityRequest {
|
||||
|
||||
protected $entityType = ENTITY_DOCUMENT;
|
||||
|
||||
}
|
57
app/Http/Requests/EntityRequest.php
Normal file
57
app/Http/Requests/EntityRequest.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php namespace App\Http\Requests;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use Input;
|
||||
use Utils;
|
||||
|
||||
class EntityRequest extends Request {
|
||||
|
||||
protected $entityType;
|
||||
private $entity;
|
||||
|
||||
public function entity()
|
||||
{
|
||||
if ($this->entity) {
|
||||
return $this->entity;
|
||||
}
|
||||
|
||||
// The entity id can appear as invoices, invoice_id, public_id or id
|
||||
$publicId = false;
|
||||
foreach (['_id', 's'] as $suffix) {
|
||||
$field = $this->entityType . $suffix;
|
||||
if ($this->$field) {
|
||||
$publicId= $this->$field;
|
||||
}
|
||||
}
|
||||
if ( ! $publicId) {
|
||||
$publicId = Input::get('public_id') ?: Input::get('id');
|
||||
}
|
||||
if ( ! $publicId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$class = Utils::getEntityClass($this->entityType);
|
||||
|
||||
if (method_exists($class, 'withTrashed')) {
|
||||
$this->entity = $class::scope($publicId)->withTrashed()->firstOrFail();
|
||||
} else {
|
||||
$this->entity = $class::scope($publicId)->firstOrFail();
|
||||
}
|
||||
|
||||
return $this->entity;
|
||||
}
|
||||
|
||||
public function authorize()
|
||||
{
|
||||
if ($this->entity()) {
|
||||
return $this->user()->can('view', $this->entity());
|
||||
} else {
|
||||
return $this->user()->can('create', $this->entityType);
|
||||
}
|
||||
}
|
||||
|
||||
public function rules()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
18
app/Http/Requests/ExpenseRequest.php
Normal file
18
app/Http/Requests/ExpenseRequest.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?php namespace App\Http\Requests;
|
||||
|
||||
class ExpenseRequest extends EntityRequest {
|
||||
|
||||
protected $entityType = ENTITY_EXPENSE;
|
||||
|
||||
public function entity()
|
||||
{
|
||||
$expense = parent::entity();
|
||||
|
||||
// eager load the documents
|
||||
if ($expense && ! $expense->relationLoaded('documents')) {
|
||||
$expense->load('documents');
|
||||
}
|
||||
|
||||
return $expense;
|
||||
}
|
||||
}
|
19
app/Http/Requests/InvoiceRequest.php
Normal file
19
app/Http/Requests/InvoiceRequest.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php namespace App\Http\Requests;
|
||||
|
||||
class InvoiceRequest extends EntityRequest {
|
||||
|
||||
protected $entityType = ENTITY_INVOICE;
|
||||
|
||||
public function entity()
|
||||
{
|
||||
$invoice = parent::entity();
|
||||
|
||||
// eager load the invoice items
|
||||
if ($invoice && ! $invoice->relationLoaded('invoice_items')) {
|
||||
$invoice->load('invoice_items');
|
||||
}
|
||||
|
||||
return $invoice;
|
||||
}
|
||||
|
||||
}
|
7
app/Http/Requests/PaymentRequest.php
Normal file
7
app/Http/Requests/PaymentRequest.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php namespace App\Http\Requests;
|
||||
|
||||
class PaymentRequest extends EntityRequest {
|
||||
|
||||
protected $entityType = ENTITY_PAYMENT;
|
||||
|
||||
}
|
6
app/Http/Requests/ProductRequest.php
Normal file
6
app/Http/Requests/ProductRequest.php
Normal file
@ -0,0 +1,6 @@
|
||||
<?php namespace App\Http\Requests;
|
||||
|
||||
class ProductRequest extends EntityRequest {
|
||||
|
||||
protected $entityType = ENTITY_PRODUCT;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
<?php namespace app\Http\Requests;
|
||||
<?php namespace App\Http\Requests;
|
||||
|
||||
use Auth;
|
||||
use App\Http\Requests\Request;
|
||||
|
@ -1,45 +0,0 @@
|
||||
<?php namespace app\Http\Requests;
|
||||
|
||||
use Auth;
|
||||
use App\Http\Requests\Request;
|
||||
use Illuminate\Validation\Factory;
|
||||
use App\Models\Invoice;
|
||||
|
||||
class SaveInvoiceWithClientRequest extends Request
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
$publicId = Request::get('public_id');
|
||||
$invoiceId = $publicId ? Invoice::getPrivateId($publicId) : '';
|
||||
|
||||
$rules = [
|
||||
'client.contacts' => 'valid_contacts',
|
||||
'invoice_items' => 'valid_invoice_items',
|
||||
'invoice_number' => 'required|unique:invoices,invoice_number,'.$invoiceId.',id,account_id,'.Auth::user()->account_id,
|
||||
'discount' => 'positive',
|
||||
];
|
||||
|
||||
/* There's a problem parsing the dates
|
||||
if (Request::get('is_recurring') && Request::get('start_date') && Request::get('end_date')) {
|
||||
$rules['end_date'] = 'after' . Request::get('start_date');
|
||||
}
|
||||
*/
|
||||
|
||||
return $rules;
|
||||
}
|
||||
}
|
7
app/Http/Requests/TaskRequest.php
Normal file
7
app/Http/Requests/TaskRequest.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php namespace App\Http\Requests;
|
||||
|
||||
class TaskRequest extends EntityRequest {
|
||||
|
||||
protected $entityType = ENTITY_TASK;
|
||||
|
||||
}
|
7
app/Http/Requests/TaxRateRequest.php
Normal file
7
app/Http/Requests/TaxRateRequest.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php namespace App\Http\Requests;
|
||||
|
||||
class TaxRateRequest extends EntityRequest {
|
||||
|
||||
protected $entityType = ENTITY_TAX_RATE;
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
<?php namespace app\Http\Requests;
|
||||
<?php namespace App\Http\Requests;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use Illuminate\Validation\Factory;
|
||||
|
@ -1,9 +1,6 @@
|
||||
<?php namespace app\Http\Requests;
|
||||
<?php namespace App\Http\Requests;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use Illuminate\Validation\Factory;
|
||||
|
||||
class UpdateClientRequest extends Request
|
||||
class UpdateClientRequest extends ClientRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
@ -12,7 +9,7 @@ class UpdateClientRequest extends Request
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
return $this->user()->can('edit', $this->entity());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,10 +1,6 @@
|
||||
<?php namespace app\Http\Requests;
|
||||
<?php namespace App\Http\Requests;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use Illuminate\Validation\Factory;
|
||||
|
||||
|
||||
class UpdateExpenseRequest extends Request
|
||||
class UpdateExpenseRequest extends ExpenseRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
@ -13,7 +9,7 @@ class UpdateExpenseRequest extends Request
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
return $this->user()->can('edit', $this->entity());
|
||||
}
|
||||
|
||||
/**
|
||||
|
36
app/Http/Requests/UpdateInvoiceAPIRequest.php
Normal file
36
app/Http/Requests/UpdateInvoiceAPIRequest.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php namespace App\Http\Requests;
|
||||
|
||||
class UpdateInvoiceAPIRequest extends InvoiceRequest
|
||||
{
|
||||
/**
|
||||
* 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()
|
||||
{
|
||||
if ($this->action == ACTION_ARCHIVE) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$invoiceId = $this->entity()->id;
|
||||
|
||||
$rules = [
|
||||
'invoice_items' => 'valid_invoice_items',
|
||||
'invoice_number' => 'unique:invoices,invoice_number,' . $invoiceId . ',id,account_id,' . $this->user()->account_id,
|
||||
'discount' => 'positive',
|
||||
];
|
||||
|
||||
return $rules;
|
||||
}
|
||||
}
|
@ -1,11 +1,6 @@
|
||||
<?php namespace app\Http\Requests;
|
||||
<?php namespace App\Http\Requests;
|
||||
|
||||
use Auth;
|
||||
use App\Http\Requests\Request;
|
||||
use Illuminate\Validation\Factory;
|
||||
use App\Models\Invoice;
|
||||
|
||||
class UpdateInvoiceRequest extends Request
|
||||
class UpdateInvoiceRequest extends InvoiceRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
@ -14,7 +9,7 @@ class UpdateInvoiceRequest extends Request
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
return $this->user()->can('edit', $this->entity());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -24,19 +19,21 @@ class UpdateInvoiceRequest extends Request
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
if ($this->action == ACTION_ARCHIVE) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$publicId = $this->route('invoices');
|
||||
$invoiceId = Invoice::getPrivateId($publicId);
|
||||
|
||||
$invoiceId = $this->entity()->id;
|
||||
|
||||
$rules = [
|
||||
'client.contacts' => 'valid_contacts',
|
||||
'invoice_items' => 'valid_invoice_items',
|
||||
'invoice_number' => 'unique:invoices,invoice_number,'.$invoiceId.',id,account_id,'.Auth::user()->account_id,
|
||||
'invoice_number' => 'required|unique:invoices,invoice_number,' . $invoiceId . ',id,account_id,' . $this->user()->account_id,
|
||||
'discount' => 'positive',
|
||||
];
|
||||
|
||||
/* There's a problem parsing the dates
|
||||
if (Request::get('is_recurring') && Request::get('start_date') && Request::get('end_date')) {
|
||||
$rules['end_date'] = 'after' . Request::get('start_date');
|
||||
}
|
||||
*/
|
||||
|
||||
return $rules;
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,6 @@
|
||||
<?php namespace app\Http\Requests;
|
||||
<?php namespace App\Http\Requests;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use Illuminate\Validation\Factory;
|
||||
|
||||
class UpdatePaymentRequest extends Request
|
||||
class UpdatePaymentRequest extends PaymentRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
@ -12,7 +9,7 @@ class UpdatePaymentRequest extends Request
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
return $this->user()->can('edit', $this->entity());
|
||||
}
|
||||
|
||||
/**
|
||||
|
26
app/Http/Requests/UpdateProductRequest.php
Normal file
26
app/Http/Requests/UpdateProductRequest.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php namespace App\Http\Requests;
|
||||
|
||||
class UpdateProductRequest extends ProductRequest
|
||||
{
|
||||
/**
|
||||
* 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 [
|
||||
'product_key' => 'required',
|
||||
];
|
||||
}
|
||||
}
|
26
app/Http/Requests/UpdateTaskRequest.php
Normal file
26
app/Http/Requests/UpdateTaskRequest.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php namespace App\Http\Requests;
|
||||
|
||||
class UpdateTaskRequest extends TaskRequest
|
||||
{
|
||||
/**
|
||||
* 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 [
|
||||
'time_log' => 'time_log',
|
||||
];
|
||||
}
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
<?php namespace app\Http\Requests;
|
||||
<?php namespace App\Http\Requests;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use Illuminate\Validation\Factory;
|
||||
|
||||
class UpdateTaxRateRequest extends Request
|
||||
class UpdateTaxRateRequest extends TaxRateRequest
|
||||
{
|
||||
// Expenses
|
||||
/**
|
||||
@ -13,7 +13,7 @@ class UpdateTaxRateRequest extends Request
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
return $this->user()->can('edit', $this->entity());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?php namespace app\Http\Requests;
|
||||
<?php namespace App\Http\Requests;
|
||||
|
||||
use Auth;
|
||||
use App\Http\Requests\Request;
|
||||
@ -14,7 +14,7 @@ class UpdateUserRequest extends Request
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
return $this->user()->can('edit', $this->entity());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,9 +1,6 @@
|
||||
<?php namespace app\Http\Requests;
|
||||
// vendor
|
||||
use App\Http\Requests\Request;
|
||||
use Illuminate\Validation\Factory;
|
||||
<?php namespace App\Http\Requests;
|
||||
|
||||
class UpdateVendorRequest extends Request
|
||||
class UpdateVendorRequest extends VendorRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
@ -12,7 +9,7 @@ class UpdateVendorRequest extends Request
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
return $this->user()->can('edit', $this->entity());
|
||||
}
|
||||
|
||||
/**
|
||||
|
19
app/Http/Requests/VendorRequest.php
Normal file
19
app/Http/Requests/VendorRequest.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php namespace App\Http\Requests;
|
||||
|
||||
class VendorRequest extends EntityRequest {
|
||||
|
||||
protected $entityType = ENTITY_VENDOR;
|
||||
|
||||
public function entity()
|
||||
{
|
||||
$vendor = parent::entity();
|
||||
|
||||
// eager load the contacts
|
||||
if ($vendor && ! $vendor->relationLoaded('vendor_contacts')) {
|
||||
$vendor->load('vendor_contacts');
|
||||
}
|
||||
|
||||
return $vendor;
|
||||
}
|
||||
|
||||
}
|
@ -43,17 +43,23 @@ Route::group(['middleware' => 'auth:client'], function() {
|
||||
Route::get('approve/{invitation_key}', 'QuoteController@approve');
|
||||
Route::get('payment/{invitation_key}/{payment_type?}', 'PaymentController@show_payment');
|
||||
Route::post('payment/{invitation_key}', 'PaymentController@do_payment');
|
||||
Route::get('complete', 'PaymentController@offsite_payment');
|
||||
Route::match(['GET', 'POST'], 'complete', 'PaymentController@offsite_payment');
|
||||
Route::get('client/quotes', 'PublicClientController@quoteIndex');
|
||||
Route::get('client/invoices', 'PublicClientController@invoiceIndex');
|
||||
Route::get('client/documents', 'PublicClientController@documentIndex');
|
||||
Route::get('client/payments', 'PublicClientController@paymentIndex');
|
||||
Route::get('client/dashboard', 'PublicClientController@dashboard');
|
||||
Route::get('client/documents/js/{documents}/{filename}', 'PublicClientController@getDocumentVFSJS');
|
||||
Route::get('client/documents/{invitation_key}/{documents}/{filename?}', 'PublicClientController@getDocument');
|
||||
Route::get('client/documents/{invitation_key}/{filename?}', 'PublicClientController@getInvoiceDocumentsZip');
|
||||
|
||||
Route::get('api/client.quotes', array('as'=>'api.client.quotes', 'uses'=>'PublicClientController@quoteDatatable'));
|
||||
Route::get('api/client.invoices', array('as'=>'api.client.invoices', 'uses'=>'PublicClientController@invoiceDatatable'));
|
||||
Route::get('api/client.documents', array('as'=>'api.client.documents', 'uses'=>'PublicClientController@documentDatatable'));
|
||||
Route::get('api/client.payments', array('as'=>'api.client.payments', 'uses'=>'PublicClientController@paymentDatatable'));
|
||||
Route::get('api/client.activity', array('as'=>'api.client.activity', 'uses'=>'PublicClientController@activityDatatable'));
|
||||
});
|
||||
|
||||
Route::get('api/client.quotes', array('as'=>'api.client.quotes', 'uses'=>'PublicClientController@quoteDatatable'));
|
||||
Route::get('api/client.invoices', array('as'=>'api.client.invoices', 'uses'=>'PublicClientController@invoiceDatatable'));
|
||||
Route::get('api/client.payments', array('as'=>'api.client.payments', 'uses'=>'PublicClientController@paymentDatatable'));
|
||||
Route::get('api/client.activity', array('as'=>'api.client.activity', 'uses'=>'PublicClientController@activityDatatable'));
|
||||
|
||||
Route::get('license', 'PaymentController@show_license_payment');
|
||||
Route::post('license', 'PaymentController@do_license_payment');
|
||||
@ -74,8 +80,8 @@ Route::post('/signup', array('as' => 'signup', 'uses' => 'Auth\AuthController@po
|
||||
Route::get('/login', array('as' => 'login', 'uses' => 'Auth\AuthController@getLoginWrapper'));
|
||||
Route::post('/login', array('as' => 'login', 'uses' => 'Auth\AuthController@postLoginWrapper'));
|
||||
Route::get('/logout', array('as' => 'logout', 'uses' => 'Auth\AuthController@getLogoutWrapper'));
|
||||
Route::get('/forgot', array('as' => 'forgot', 'uses' => 'Auth\PasswordController@getEmail'));
|
||||
Route::post('/forgot', array('as' => 'forgot', 'uses' => 'Auth\PasswordController@postEmail'));
|
||||
Route::get('/recover_password', array('as' => 'forgot', 'uses' => 'Auth\PasswordController@getEmail'));
|
||||
Route::post('/recover_password', array('as' => 'forgot', 'uses' => 'Auth\PasswordController@postEmail'));
|
||||
Route::get('/password/reset/{token}', array('as' => 'forgot', 'uses' => 'Auth\PasswordController@getReset'));
|
||||
Route::post('/password/reset', array('as' => 'forgot', 'uses' => 'Auth\PasswordController@postReset'));
|
||||
Route::get('/user/confirm/{code}', 'UserController@confirm');
|
||||
@ -84,8 +90,8 @@ Route::get('/user/confirm/{code}', 'UserController@confirm');
|
||||
Route::get('/client/login', array('as' => 'login', 'uses' => 'ClientAuth\AuthController@getLogin'));
|
||||
Route::post('/client/login', array('as' => 'login', 'uses' => 'ClientAuth\AuthController@postLogin'));
|
||||
Route::get('/client/logout', array('as' => 'logout', 'uses' => 'ClientAuth\AuthController@getLogout'));
|
||||
Route::get('/client/forgot', array('as' => 'forgot', 'uses' => 'ClientAuth\PasswordController@getEmail'));
|
||||
Route::post('/client/forgot', array('as' => 'forgot', 'uses' => 'ClientAuth\PasswordController@postEmail'));
|
||||
Route::get('/client/recover_password', array('as' => 'forgot', 'uses' => 'ClientAuth\PasswordController@getEmail'));
|
||||
Route::post('/client/recover_password', array('as' => 'forgot', 'uses' => 'ClientAuth\PasswordController@postEmail'));
|
||||
Route::get('/client/password/reset/{invitation_key}/{token}', array('as' => 'forgot', 'uses' => 'ClientAuth\PasswordController@getReset'));
|
||||
Route::post('/client/password/reset', array('as' => 'forgot', 'uses' => 'ClientAuth\PasswordController@postReset'));
|
||||
|
||||
@ -105,9 +111,11 @@ Route::group(['middleware' => 'auth:user'], function() {
|
||||
Route::get('view_archive/{entity_type}/{visible}', 'AccountController@setTrashVisible');
|
||||
Route::get('hide_message', 'HomeController@hideMessage');
|
||||
Route::get('force_inline_pdf', 'UserController@forcePDFJS');
|
||||
Route::get('account/getSearchData', array('as' => 'getSearchData', 'uses' => 'AccountController@getSearchData'));
|
||||
|
||||
Route::get('settings/user_details', 'AccountController@showUserDetails');
|
||||
Route::post('settings/user_details', 'AccountController@saveUserDetails');
|
||||
Route::post('users/change_password', 'UserController@changePassword');
|
||||
|
||||
Route::resource('clients', 'ClientController');
|
||||
Route::get('api/clients', array('as'=>'api.clients', 'uses'=>'ClientController@getDatatable'));
|
||||
@ -129,15 +137,20 @@ Route::group(['middleware' => 'auth:user'], function() {
|
||||
Route::get('invoices/create/{client_id?}', 'InvoiceController@create');
|
||||
Route::get('recurring_invoices/create/{client_id?}', 'InvoiceController@createRecurring');
|
||||
Route::get('recurring_invoices', 'RecurringInvoiceController@index');
|
||||
Route::get('invoices/{public_id}/clone', 'InvoiceController@cloneInvoice');
|
||||
Route::get('invoices/{invoices}/clone', 'InvoiceController@cloneInvoice');
|
||||
Route::post('invoices/bulk', 'InvoiceController@bulk');
|
||||
Route::post('recurring_invoices/bulk', 'InvoiceController@bulk');
|
||||
|
||||
Route::get('documents/{documents}/{filename?}', 'DocumentController@get');
|
||||
Route::get('documents/js/{documents}/{filename}', 'DocumentController@getVFSJS');
|
||||
Route::get('documents/preview/{documents}/{filename?}', 'DocumentController@getPreview');
|
||||
Route::post('document', 'DocumentController@postUpload');
|
||||
|
||||
Route::get('quotes/create/{client_id?}', 'QuoteController@create');
|
||||
Route::get('quotes/{public_id}/clone', 'InvoiceController@cloneInvoice');
|
||||
Route::get('quotes/{public_id}/edit', 'InvoiceController@edit');
|
||||
Route::put('quotes/{public_id}', 'InvoiceController@update');
|
||||
Route::get('quotes/{public_id}', 'InvoiceController@edit');
|
||||
Route::get('quotes/{invoices}/clone', 'InvoiceController@cloneInvoice');
|
||||
Route::get('quotes/{invoices}/edit', 'InvoiceController@edit');
|
||||
Route::put('quotes/{invoices}', 'InvoiceController@update');
|
||||
Route::get('quotes/{invoices}', 'InvoiceController@edit');
|
||||
Route::post('quotes', 'InvoiceController@store');
|
||||
Route::get('quotes', 'QuoteController@index');
|
||||
Route::get('api/quotes/{client_id?}', array('as'=>'api.quotes', 'uses'=>'QuoteController@getDatatable'));
|
||||
@ -178,9 +191,9 @@ Route::group([
|
||||
Route::resource('users', 'UserController');
|
||||
Route::post('users/bulk', 'UserController@bulk');
|
||||
Route::get('send_confirmation/{user_id}', 'UserController@sendConfirmation');
|
||||
Route::get('start_trial', 'AccountController@startTrial');
|
||||
Route::get('start_trial/{plan}', 'AccountController@startTrial')
|
||||
->where(['plan'=>'pro']);
|
||||
Route::get('restore_user/{user_id}', 'UserController@restoreUser');
|
||||
Route::post('users/change_password', 'UserController@changePassword');
|
||||
Route::get('/switch_account/{user_id}', 'UserController@switchAccount');
|
||||
Route::get('/unlink_account/{user_account_id}/{user_id}', 'UserController@unlinkAccount');
|
||||
Route::get('/manage_companies', 'UserController@manageCompanies');
|
||||
@ -197,21 +210,18 @@ Route::group([
|
||||
Route::resource('tax_rates', 'TaxRateController');
|
||||
Route::post('tax_rates/bulk', 'TaxRateController@bulk');
|
||||
|
||||
Route::get('settings/email_preview', 'AccountController@previewEmail');
|
||||
Route::get('company/{section}/{subSection?}', 'AccountController@redirectLegacy');
|
||||
Route::get('settings/data_visualizations', 'ReportController@d3');
|
||||
Route::get('settings/charts_and_reports', 'ReportController@showReports');
|
||||
Route::post('settings/charts_and_reports', 'ReportController@showReports');
|
||||
|
||||
Route::post('settings/change_plan', 'AccountController@changePlan');
|
||||
Route::post('settings/cancel_account', 'AccountController@cancelAccount');
|
||||
Route::post('settings/company_details', 'AccountController@updateDetails');
|
||||
Route::get('settings/{section?}', 'AccountController@showSection');
|
||||
Route::post('settings/{section?}', 'AccountController@doSection');
|
||||
|
||||
//Route::get('api/payment_terms', array('as'=>'api.payment_terms', 'uses'=>'PaymentTermController@getDatatable'));
|
||||
//Route::resource('payment_terms', 'PaymentTermController');
|
||||
//Route::post('payment_terms/bulk', 'PaymentTermController@bulk');
|
||||
|
||||
Route::get('account/getSearchData', array('as' => 'getSearchData', 'uses' => 'AccountController@getSearchData'));
|
||||
Route::post('user/setTheme', 'UserController@setTheme');
|
||||
Route::post('remove_logo', 'AccountController@removeLogo');
|
||||
Route::post('account/go_pro', 'AccountController@enableProPlan');
|
||||
@ -234,15 +244,15 @@ Route::group([
|
||||
// Route groups for API
|
||||
Route::group(['middleware' => 'api', 'prefix' => 'api/v1'], function()
|
||||
{
|
||||
Route::get('ping', 'ClientApiController@ping');
|
||||
Route::get('ping', 'AccountApiController@ping');
|
||||
Route::post('login', 'AccountApiController@login');
|
||||
Route::post('register', 'AccountApiController@register');
|
||||
Route::get('static', 'AccountApiController@getStaticData');
|
||||
Route::get('accounts', 'AccountApiController@show');
|
||||
Route::put('accounts', 'AccountApiController@update');
|
||||
Route::resource('clients', 'ClientApiController');
|
||||
Route::get('quotes', 'QuoteApiController@index');
|
||||
Route::resource('quotes', 'QuoteApiController');
|
||||
//Route::get('quotes', 'QuoteApiController@index');
|
||||
//Route::resource('quotes', 'QuoteApiController');
|
||||
Route::get('invoices', 'InvoiceApiController@index');
|
||||
Route::resource('invoices', 'InvoiceApiController');
|
||||
Route::get('payments', 'PaymentApiController@index');
|
||||
@ -268,7 +278,6 @@ Route::group(['middleware' => 'api', 'prefix' => 'api/v1'], function()
|
||||
});
|
||||
|
||||
// Redirects for legacy links
|
||||
/*
|
||||
Route::get('/rocksteady', function() {
|
||||
return Redirect::to(NINJA_WEB_URL, 301);
|
||||
});
|
||||
@ -296,7 +305,7 @@ Route::get('/compare-online-invoicing{sites?}', function() {
|
||||
Route::get('/forgot_password', function() {
|
||||
return Redirect::to(NINJA_APP_URL.'/forgot', 301);
|
||||
});
|
||||
*/
|
||||
|
||||
|
||||
if (!defined('CONTACT_EMAIL')) {
|
||||
define('CONTACT_EMAIL', Config::get('mail.from.address'));
|
||||
@ -311,6 +320,7 @@ if (!defined('CONTACT_EMAIL')) {
|
||||
define('ENTITY_CLIENT', 'client');
|
||||
define('ENTITY_CONTACT', 'contact');
|
||||
define('ENTITY_INVOICE', 'invoice');
|
||||
define('ENTITY_DOCUMENT', 'document');
|
||||
define('ENTITY_INVOICE_ITEMS', 'invoice_items');
|
||||
define('ENTITY_INVITATION', 'invitation');
|
||||
define('ENTITY_RECURRING_INVOICE', 'recurring_invoice');
|
||||
@ -344,6 +354,7 @@ if (!defined('CONTACT_EMAIL')) {
|
||||
define('ACCOUNT_LOCALIZATION', 'localization');
|
||||
define('ACCOUNT_NOTIFICATIONS', 'notifications');
|
||||
define('ACCOUNT_IMPORT_EXPORT', 'import_export');
|
||||
define('ACCOUNT_MANAGEMENT', 'account_management');
|
||||
define('ACCOUNT_PAYMENTS', 'online_payments');
|
||||
define('ACCOUNT_BANKS', 'bank_accounts');
|
||||
define('ACCOUNT_IMPORT_EXPENSES', 'import_expenses');
|
||||
@ -426,6 +437,10 @@ if (!defined('CONTACT_EMAIL')) {
|
||||
define('MAX_IFRAME_URL_LENGTH', 250);
|
||||
define('MAX_LOGO_FILE_SIZE', 200); // KB
|
||||
define('MAX_FAILED_LOGINS', 10);
|
||||
define('MAX_DOCUMENT_SIZE', env('MAX_DOCUMENT_SIZE', 10000));// KB
|
||||
define('MAX_EMAIL_DOCUMENTS_SIZE', env('MAX_EMAIL_DOCUMENTS_SIZE', 10000));// Total KB
|
||||
define('MAX_ZIP_DOCUMENTS_SIZE', env('MAX_EMAIL_DOCUMENTS_SIZE', 30000));// Total KB (uncompressed)
|
||||
define('DOCUMENT_PREVIEW_SIZE', env('DOCUMENT_PREVIEW_SIZE', 300));// pixels
|
||||
define('DEFAULT_FONT_SIZE', 9);
|
||||
define('DEFAULT_HEADER_FONT', 1);// Roboto
|
||||
define('DEFAULT_BODY_FONT', 1);// Roboto
|
||||
@ -521,6 +536,7 @@ if (!defined('CONTACT_EMAIL')) {
|
||||
define('GATEWAY_BITPAY', 42);
|
||||
define('GATEWAY_DWOLLA', 43);
|
||||
define('GATEWAY_CHECKOUT_COM', 47);
|
||||
define('GATEWAY_CYBERSOURCE', 49);
|
||||
|
||||
define('EVENT_CREATE_CLIENT', 1);
|
||||
define('EVENT_CREATE_INVOICE', 2);
|
||||
@ -534,25 +550,26 @@ if (!defined('CONTACT_EMAIL')) {
|
||||
define('NINJA_ACCOUNT_KEY', 'zg4ylmzDkdkPOT8yoKQw9LTWaoZJx79h');
|
||||
define('NINJA_GATEWAY_ID', GATEWAY_STRIPE);
|
||||
define('NINJA_GATEWAY_CONFIG', 'NINJA_GATEWAY_CONFIG');
|
||||
define('NINJA_WEB_URL', 'https://www.invoiceninja.com');
|
||||
define('NINJA_APP_URL', 'https://app.invoiceninja.com');
|
||||
define('NINJA_VERSION', '2.5.1.3');
|
||||
define('NINJA_WEB_URL', env('NINJA_WEB_URL', 'https://www.invoiceninja.com'));
|
||||
define('NINJA_APP_URL', env('NINJA_APP_URL', 'https://app.invoiceninja.com'));
|
||||
define('NINJA_DATE', '2000-01-01');
|
||||
define('NINJA_VERSION', '2.5.2' . env('NINJA_VERSION_SUFFIX'));
|
||||
|
||||
define('SOCIAL_LINK_FACEBOOK', 'https://www.facebook.com/invoiceninja');
|
||||
define('SOCIAL_LINK_TWITTER', 'https://twitter.com/invoiceninja');
|
||||
define('SOCIAL_LINK_GITHUB', 'https://github.com/invoiceninja/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_GITHUB', env('SOCIAL_LINK_GITHUB', 'https://github.com/invoiceninja/invoiceninja/'));
|
||||
|
||||
define('NINJA_FROM_EMAIL', 'maildelivery@invoiceninja.com');
|
||||
define('RELEASES_URL', 'https://trello.com/b/63BbiVVe/invoice-ninja');
|
||||
define('ZAPIER_URL', 'https://zapier.com/zapbook/invoice-ninja');
|
||||
define('OUTDATE_BROWSER_URL', 'http://browsehappy.com/');
|
||||
define('PDFMAKE_DOCS', 'http://pdfmake.org/playground.html');
|
||||
define('PHANTOMJS_CLOUD', 'http://api.phantomjscloud.com/api/browser/v2/');
|
||||
define('PHP_DATE_FORMATS', 'http://php.net/manual/en/function.date.php');
|
||||
define('REFERRAL_PROGRAM_URL', 'https://www.invoiceninja.com/referral-program/');
|
||||
define('EMAIL_MARKUP_URL', 'https://developers.google.com/gmail/markup');
|
||||
define('OFX_HOME_URL', 'http://www.ofxhome.com/index.php/home/directory/all');
|
||||
define('NINJA_FROM_EMAIL', env('NINJA_FROM_EMAIL', 'maildelivery@invoiceninja.com'));
|
||||
define('RELEASES_URL', env('RELEASES_URL', 'https://trello.com/b/63BbiVVe/invoice-ninja'));
|
||||
define('ZAPIER_URL', env('ZAPIER_URL', 'https://zapier.com/zapbook/invoice-ninja'));
|
||||
define('OUTDATE_BROWSER_URL', env('OUTDATE_BROWSER_URL', 'http://browsehappy.com/'));
|
||||
define('PDFMAKE_DOCS', env('PDFMAKE_DOCS', 'http://pdfmake.org/playground.html'));
|
||||
define('PHANTOMJS_CLOUD', env('PHANTOMJS_CLOUD', 'http://api.phantomjscloud.com/api/browser/v2/'));
|
||||
define('PHP_DATE_FORMATS', env('PHP_DATE_FORMATS', 'http://php.net/manual/en/function.date.php'));
|
||||
define('REFERRAL_PROGRAM_URL', env('REFERRAL_PROGRAM_URL', 'https://www.invoiceninja.com/referral-program/'));
|
||||
define('EMAIL_MARKUP_URL', env('EMAIL_MARKUP_URL', 'https://developers.google.com/gmail/markup'));
|
||||
define('OFX_HOME_URL', env('OFX_HOME_URL', 'http://www.ofxhome.com/index.php/home/directory/all'));
|
||||
define('GOOGLE_ANALYITCS_URL', env('GOOGLE_ANALYITCS_URL', 'https://www.google-analytics.com/collect'));
|
||||
|
||||
define('BLANK_IMAGE', 'data:image/png;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=');
|
||||
|
||||
@ -566,9 +583,12 @@ if (!defined('CONTACT_EMAIL')) {
|
||||
define('INVOICE_DESIGNS_AFFILIATE_KEY', 'T3RS74');
|
||||
define('SELF_HOST_AFFILIATE_KEY', '8S69AD');
|
||||
|
||||
define('PRO_PLAN_PRICE', 50);
|
||||
define('WHITE_LABEL_PRICE', 20);
|
||||
define('INVOICE_DESIGNS_PRICE', 10);
|
||||
define('PLAN_PRICE_PRO_MONTHLY', env('PLAN_PRICE_PRO_MONTHLY', 5));
|
||||
define('PLAN_PRICE_PRO_YEARLY', env('PLAN_PRICE_PRO_YEARLY', 50));
|
||||
define('PLAN_PRICE_ENTERPRISE_MONTHLY', env('PLAN_PRICE_ENTERPRISE_MONTHLY', 10));
|
||||
define('PLAN_PRICE_ENTERPRISE_YEARLY', env('PLAN_PRICE_ENTERPRISE_YEARLY', 100));
|
||||
define('WHITE_LABEL_PRICE', env('WHITE_LABEL_PRICE', 20));
|
||||
define('INVOICE_DESIGNS_PRICE', env('INVOICE_DESIGNS_PRICE', 10));
|
||||
|
||||
define('USER_TYPE_SELF_HOST', 'SELF_HOST');
|
||||
define('USER_TYPE_CLOUD_HOST', 'CLOUD_HOST');
|
||||
@ -577,9 +597,11 @@ if (!defined('CONTACT_EMAIL')) {
|
||||
define('TEST_USERNAME', 'user@example.com');
|
||||
define('TEST_PASSWORD', 'password');
|
||||
define('API_SECRET', 'API_SECRET');
|
||||
define('DEFAULT_API_PAGE_SIZE', 15);
|
||||
define('MAX_API_PAGE_SIZE', 100);
|
||||
|
||||
define('IOS_PRODUCTION_PUSH','ninjaIOS');
|
||||
define('IOS_DEV_PUSH','devNinjaIOS');
|
||||
define('IOS_PRODUCTION_PUSH', env('IOS_PRODUCTION_PUSH', 'ninjaIOS'));
|
||||
define('IOS_DEV_PUSH', env('IOS_DEV_PUSH', 'devNinjaIOS'));
|
||||
|
||||
define('TOKEN_BILLING_DISABLED', 1);
|
||||
define('TOKEN_BILLING_OPT_IN', 2);
|
||||
@ -629,7 +651,46 @@ if (!defined('CONTACT_EMAIL')) {
|
||||
|
||||
define('RESELLER_REVENUE_SHARE', 'A');
|
||||
define('RESELLER_LIMITED_USERS', 'B');
|
||||
|
||||
// These must be lowercase
|
||||
define('PLAN_FREE', 'free');
|
||||
define('PLAN_PRO', 'pro');
|
||||
define('PLAN_ENTERPRISE', 'enterprise');
|
||||
define('PLAN_WHITE_LABEL', 'white_label');
|
||||
define('PLAN_TERM_MONTHLY', 'month');
|
||||
define('PLAN_TERM_YEARLY', 'year');
|
||||
|
||||
// Pro
|
||||
define('FEATURE_CUSTOMIZE_INVOICE_DESIGN', 'customize_invoice_design');
|
||||
define('FEATURE_REMOVE_CREATED_BY', 'remove_created_by');
|
||||
define('FEATURE_DIFFERENT_DESIGNS', 'different_designs');
|
||||
define('FEATURE_EMAIL_TEMPLATES_REMINDERS', 'email_templates_reminders');
|
||||
define('FEATURE_INVOICE_SETTINGS', 'invoice_settings');
|
||||
define('FEATURE_CUSTOM_EMAILS', 'custom_emails');
|
||||
define('FEATURE_PDF_ATTACHMENT', 'pdf_attachment');
|
||||
define('FEATURE_MORE_INVOICE_DESIGNS', 'more_invoice_designs');
|
||||
define('FEATURE_QUOTES', 'quotes');
|
||||
define('FEATURE_REPORTS', 'reports');
|
||||
define('FEATURE_API', 'api');
|
||||
define('FEATURE_CLIENT_PORTAL_PASSWORD', 'client_portal_password');
|
||||
define('FEATURE_CUSTOM_URL', 'custom_url');
|
||||
|
||||
define('FEATURE_MORE_CLIENTS', 'more_clients'); // No trial allowed
|
||||
|
||||
// Whitelabel
|
||||
define('FEATURE_CLIENT_PORTAL_CSS', 'client_portal_css');
|
||||
define('FEATURE_WHITE_LABEL', 'feature_white_label');
|
||||
|
||||
// Enterprise
|
||||
define('FEATURE_DOCUMENTS', 'documents');
|
||||
|
||||
// No Trial allowed
|
||||
define('FEATURE_USERS', 'users');// Grandfathered for old Pro users
|
||||
define('FEATURE_USER_PERMISSIONS', 'user_permissions');
|
||||
|
||||
// Pro users who started paying on or before this date will be able to manage users
|
||||
define('PRO_USERS_GRANDFATHER_DEADLINE', '2016-05-15');
|
||||
|
||||
$creditCards = [
|
||||
1 => ['card' => 'images/credit_cards/Test-Visa-Icon.png', 'text' => 'Visa'],
|
||||
2 => ['card' => 'images/credit_cards/Test-MasterCard-Icon.png', 'text' => 'Master Card'],
|
||||
@ -679,30 +740,6 @@ if (!defined('CONTACT_EMAIL')) {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// Log all SQL queries to laravel.log
|
||||
if (Utils::isNinjaDev()) {
|
||||
Event::listen('illuminate.query', function($query, $bindings, $time, $name) {
|
||||
$data = compact('bindings', 'time', 'name');
|
||||
|
||||
// Format binding data for sql insertion
|
||||
foreach ($bindings as $i => $binding) {
|
||||
if ($binding instanceof \DateTime) {
|
||||
$bindings[$i] = $binding->format('\'Y-m-d H:i:s\'');
|
||||
} elseif (is_string($binding)) {
|
||||
$bindings[$i] = "'$binding'";
|
||||
}
|
||||
}
|
||||
|
||||
// Insert bindings into query
|
||||
$query = str_replace(array('%', '?'), array('%%', '%s'), $query);
|
||||
$query = vsprintf($query, $bindings);
|
||||
|
||||
Log::info($query, $data);
|
||||
});
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
if (Utils::isNinjaDev())
|
||||
{
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
// https://github.com/denvertimothy/OFX
|
||||
|
||||
use Utils;
|
||||
use Log;
|
||||
use SimpleXMLElement;
|
||||
|
||||
class OFX
|
||||
@ -21,13 +23,19 @@ class OFX
|
||||
$c = curl_init();
|
||||
curl_setopt($c, CURLOPT_URL, $this->bank->url);
|
||||
curl_setopt($c, CURLOPT_POST, 1);
|
||||
curl_setopt($c, CURLOPT_HTTPHEADER, array('Content-Type: application/x-ofx'));
|
||||
// User-Agent: http://www.ofxhome.com/ofxforum/viewtopic.php?pid=108091#p108091
|
||||
curl_setopt($c, CURLOPT_HTTPHEADER, array('Content-Type: application/x-ofx', 'User-Agent: httpclient'));
|
||||
curl_setopt($c, CURLOPT_POSTFIELDS, $this->request);
|
||||
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
|
||||
|
||||
$this->response = curl_exec($c);
|
||||
//print_r($this->response);
|
||||
//\Log::info(print_r($this->response, true));
|
||||
|
||||
if (Utils::isNinjaDev()) {
|
||||
Log::info(print_r($this->response, true));
|
||||
}
|
||||
|
||||
curl_close($c);
|
||||
|
||||
$tmp = explode('<OFX>', $this->response);
|
||||
$this->responseHeader = $tmp[0];
|
||||
$this->responseBody = '<OFX>'.$tmp[1];
|
||||
@ -35,14 +43,15 @@ class OFX
|
||||
public function xml()
|
||||
{
|
||||
$xml = $this->responseBody;
|
||||
self::closeTags($xml);
|
||||
$xml = self::closeTags($xml);
|
||||
$x = new SimpleXMLElement($xml);
|
||||
|
||||
return $x;
|
||||
}
|
||||
public static function closeTags(&$x)
|
||||
public static function closeTags($x)
|
||||
{
|
||||
$x = preg_replace('/(<([^<\/]+)>)(?!.*?<\/\2>)([^<]+)/', '\1\3</\2>', $x);
|
||||
$x = preg_replace('/\s+/', '', $x);
|
||||
return preg_replace('/(<([^<\/]+)>)(?!.*?<\/\2>)([^<]+)/', '\1\3</\2>', $x);
|
||||
}
|
||||
}
|
||||
|
||||
@ -224,3 +233,4 @@ class Account
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,6 +51,11 @@ class Utils
|
||||
return php_sapi_name() == 'cli';
|
||||
}
|
||||
|
||||
public static function isTravis()
|
||||
{
|
||||
return env('TRAVIS') == 'true';
|
||||
}
|
||||
|
||||
public static function isNinja()
|
||||
{
|
||||
return self::isNinjaProd() || self::isNinjaDev();
|
||||
@ -118,6 +123,11 @@ class Utils
|
||||
return Auth::check() && Auth::user()->isPro();
|
||||
}
|
||||
|
||||
public static function hasFeature($feature)
|
||||
{
|
||||
return Auth::check() && Auth::user()->hasFeature($feature);
|
||||
}
|
||||
|
||||
public static function isAdmin()
|
||||
{
|
||||
return Auth::check() && Auth::user()->is_admin;
|
||||
@ -130,7 +140,7 @@ class Utils
|
||||
|
||||
public static function hasAllPermissions($permission)
|
||||
{
|
||||
return Auth::check() && Auth::user()->hasPermissions($permission);
|
||||
return Auth::check() && Auth::user()->hasPermission($permission);
|
||||
}
|
||||
|
||||
public static function isTrial()
|
||||
@ -331,6 +341,7 @@ class Utils
|
||||
$currency = self::getFromCache($currencyId, 'currencies');
|
||||
$thousand = $currency->thousand_separator;
|
||||
$decimal = $currency->decimal_separator;
|
||||
$precision = $currency->precision;
|
||||
$code = $currency->code;
|
||||
$swapSymbol = false;
|
||||
|
||||
@ -345,7 +356,7 @@ class Utils
|
||||
}
|
||||
}
|
||||
|
||||
$value = number_format($value, $currency->precision, $decimal, $thousand);
|
||||
$value = number_format($value, $precision, $decimal, $thousand);
|
||||
$symbol = $currency->symbol;
|
||||
|
||||
if ($showCode || !$symbol) {
|
||||
@ -440,7 +451,12 @@ class Utils
|
||||
return false;
|
||||
}
|
||||
|
||||
$dateTime = new DateTime($date);
|
||||
if ($date instanceof DateTime) {
|
||||
$dateTime = $date;
|
||||
} else {
|
||||
$dateTime = new DateTime($date);
|
||||
}
|
||||
|
||||
$timestamp = $dateTime->getTimestamp();
|
||||
$format = Session::get(SESSION_DATE_FORMAT, DEFAULT_DATE_FORMAT);
|
||||
|
||||
@ -659,9 +675,14 @@ class Utils
|
||||
return $year + $offset;
|
||||
}
|
||||
|
||||
public static function getEntityClass($entityType)
|
||||
{
|
||||
return 'App\\Models\\' . static::getEntityName($entityType);
|
||||
}
|
||||
|
||||
public static function getEntityName($entityType)
|
||||
{
|
||||
return ucwords(str_replace('_', ' ', $entityType));
|
||||
return ucwords(Utils::toCamelCase($entityType));
|
||||
}
|
||||
|
||||
public static function getClientDisplayName($model)
|
||||
@ -961,38 +982,6 @@ class Utils
|
||||
return $entity1;
|
||||
}
|
||||
|
||||
public static function withinPastYear($date)
|
||||
{
|
||||
if (!$date || $date == '0000-00-00') {
|
||||
return false;
|
||||
}
|
||||
|
||||
$today = new DateTime('now');
|
||||
$datePaid = DateTime::createFromFormat('Y-m-d', $date);
|
||||
$interval = $today->diff($datePaid);
|
||||
|
||||
return $interval->y == 0;
|
||||
}
|
||||
|
||||
public static function getInterval($date)
|
||||
{
|
||||
if (!$date || $date == '0000-00-00') {
|
||||
return false;
|
||||
}
|
||||
|
||||
$today = new DateTime('now');
|
||||
$datePaid = DateTime::createFromFormat('Y-m-d', $date);
|
||||
|
||||
return $today->diff($datePaid);
|
||||
}
|
||||
|
||||
public static function withinPastTwoWeeks($date)
|
||||
{
|
||||
$interval = Utils::getInterval($date);
|
||||
|
||||
return $interval && $interval->d <= 14;
|
||||
}
|
||||
|
||||
public static function addHttp($url)
|
||||
{
|
||||
if (!preg_match("~^(?:f|ht)tps?://~i", $url)) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?php namespace app\Listeners;
|
||||
<?php namespace App\Listeners;
|
||||
|
||||
use App\Models\Invoice;
|
||||
use App\Events\ClientWasCreated;
|
||||
|
54
app/Listeners/AnalyticsListener.php
Normal file
54
app/Listeners/AnalyticsListener.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php namespace App\Listeners;
|
||||
|
||||
use Log;
|
||||
use Utils;
|
||||
use App\Events\PaymentWasCreated;
|
||||
|
||||
class AnalyticsListener
|
||||
{
|
||||
public function trackRevenue(PaymentWasCreated $event)
|
||||
{
|
||||
if ( ! Utils::isNinja() || ! env('ANALYTICS_KEY')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$payment = $event->payment;
|
||||
$invoice = $payment->invoice;
|
||||
$account = $payment->account;
|
||||
|
||||
if ($account->account_key != NINJA_ACCOUNT_KEY) {
|
||||
return;
|
||||
}
|
||||
|
||||
$analyticsId = env('ANALYTICS_KEY');
|
||||
$client = $payment->client;
|
||||
$amount = $payment->amount;
|
||||
|
||||
$base = "v=1&tid={$analyticsId}&cid{$client->public_id}&cu=USD&ti={$invoice->invoice_number}";
|
||||
|
||||
$url = $base . "&t=transaction&ta=ninja&tr={$amount}";
|
||||
$this->sendAnalytics($url);
|
||||
//Log::info($url);
|
||||
|
||||
$url = $base . "&t=item&in=plan&ip={$amount}&iq=1";
|
||||
$this->sendAnalytics($url);
|
||||
//Log::info($url);
|
||||
}
|
||||
|
||||
private function sendAnalytics($data)
|
||||
{
|
||||
$data = json_encode($data);
|
||||
$curl = curl_init();
|
||||
|
||||
$opts = [
|
||||
CURLOPT_URL => GOOGLE_ANALYITCS_URL,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_POST => 'POST',
|
||||
CURLOPT_POSTFIELDS => $data,
|
||||
];
|
||||
|
||||
curl_setopt_array($curl, $opts);
|
||||
$response = curl_exec($curl);
|
||||
curl_close($curl);
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
<?php namespace app\Listeners;
|
||||
<?php namespace App\Listeners;
|
||||
|
||||
use Carbon;
|
||||
use App\Models\Credit;
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?php namespace app\Listeners;
|
||||
<?php namespace App\Listeners;
|
||||
|
||||
use Carbon;
|
||||
use App\Models\Expense;
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?php namespace app\Listeners;
|
||||
<?php namespace App\Listeners;
|
||||
|
||||
use Utils;
|
||||
use Auth;
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?php namespace app\Listeners;
|
||||
<?php namespace App\Listeners;
|
||||
|
||||
use Utils;
|
||||
use Auth;
|
||||
@ -14,10 +14,11 @@ class InvoiceListener
|
||||
{
|
||||
public function createdInvoice(InvoiceWasCreated $event)
|
||||
{
|
||||
if (Utils::isPro()) {
|
||||
if (Utils::hasFeature(FEATURE_DIFFERENT_DESIGNS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure the account has the same design set as the invoice does
|
||||
if (Auth::check()) {
|
||||
$invoice = $event->invoice;
|
||||
$account = Auth::user()->account;
|
||||
|
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