Merge remote-tracking branch 'upstream/develop' into payments-changes

This commit is contained in:
Joshua Dwire 2016-05-10 10:25:42 -04:00
commit 41f4c98e08
208 changed files with 5828 additions and 2053 deletions

138
.htaccess
View File

@ -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>

View File

@ -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;"
@ -89,7 +90,8 @@ after_script:
- mysql -u root -e 'select * from invoice_items;' ninja
- mysql -u root -e 'select * from payments;' ninja
- mysql -u root -e 'select * from credits;' ninja
- cat storage/logs/laravel.log
- cat storage/logs/laravel-error.log
- cat storage/logs/laravel-info.log
notifications:
email:

View File

@ -1,4 +1,4 @@
<?php namespace app\Commands;
<?php namespace App\Commands;
abstract class Command
{

View 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),
);
}
}

View File

@ -1,4 +1,4 @@
<?php namespace app\Console\Commands;
<?php namespace App\Console\Commands;
use File;
use Illuminate\Console\Command;

View File

@ -62,8 +62,12 @@ class SendRenewalInvoices extends Command
$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');

View File

@ -1,4 +1,4 @@
<?php namespace app\Console\Commands;
<?php namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Services\BankAccountService;

View File

@ -1,4 +1,4 @@
<?php namespace app\Console;
<?php namespace App\Console;
use Utils;
use Illuminate\Console\Scheduling\Schedule;
@ -17,6 +17,7 @@ class Kernel extends ConsoleKernel
'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',

View File

@ -39,7 +39,7 @@ class Handler extends ExceptionHandler {
return false;
}
if (Utils::isNinja()) {
if (Utils::isNinja() && ! Utils::isTravis()) {
Utils::logError(Utils::getErrorString($e));
return false;
} else {

View File

@ -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)
{

View File

@ -246,8 +246,7 @@ class AccountController extends BaseController
public function getSearchData()
{
$account = Auth::user()->account;
$data = $this->accountRepo->getSearchData($account);
$data = $this->accountRepo->getSearchData(Auth::user());
return Response::json($data);
}
@ -1294,4 +1293,37 @@ class AccountController extends BaseController
return Redirect::to("/settings/$section/", 301);
}
public function previewEmail(\App\Services\TemplateService $templateService)
{
$template = Input::get('template');
$invoice = Invoice::scope()
->invoices()
->withTrashed()
->first();
if ( ! $invoice) {
return trans('texts.create_invoice_for_sample');
}
$account = Auth::user()->account;
// replace the variables with sample data
$data = [
'account' => $account,
'invoice' => $invoice,
'invitation' => $invoice->invitations->first(),
'client' => $invoice->client,
'amount' => $invoice->amount
];
// create the email view
$view = 'emails.' . $account->getTemplateView(ENTITY_INVOICE) . '_html';
$data = array_merge($data, [
'body' => $templateService->processVariables($template, $data),
'entityType' => ENTITY_INVOICE,
]);
return Response::view($view, $data);
}
}

View File

@ -266,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) {
@ -306,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 '';
}

View File

@ -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;
}
}

View File

@ -3,6 +3,7 @@
use App\Http\Middleware\PermissionsRequired;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Input;
use Auth;
use Utils;
@ -10,7 +11,7 @@ class BaseController extends Controller
{
use DispatchesJobs, AuthorizesRequests;
protected $entity;
protected $entityType;
/**
* Setup the layout used by the controller.
@ -23,22 +24,4 @@ class BaseController extends Controller
$this->layout = View::make($this->layout);
}
}
protected function authorizeCreate() {
$this->authorize('create', $this->entity);
}
protected function authorizeUpdate($input){
$creating = empty($input['public_id']) || $input['public_id'] == '-1';
if($creating){
$this->authorize('create', $this->entity);
}
else{
$className = Utils::getEntityName($this->entity);
$object = call_user_func(array("App\\Models\\{$className}", 'scope'), $input['public_id'])->firstOrFail();
$this->authorize('edit', $object);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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 $entity = ENTITY_CLIENT;
protected $entityType = ENTITY_CLIENT;
public function __construct(ClientRepository $clientRepo, ClientService $clientService)
{
@ -81,11 +82,7 @@ class ClientController extends BaseController
*/
public function store(CreateClientRequest $request)
{
$data = $request->input();
$this->authorizeUpdate($data);
$client = $this->clientService->save($data);
$client = $this->clientService->save($request->input());
Session::flash('message', trans('texts.created_client'));
@ -98,11 +95,9 @@ 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();
$this->authorize('view', $client);
$client = $request->entity();
$user = Auth::user();
Utils::trackViewed($client->getDisplayName(), ENTITY_CLIENT);
@ -152,10 +147,8 @@ class ClientController extends BaseController
*
* @return Response
*/
public function create()
public function create(ClientRequest $request)
{
$this->authorizeCreate();
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"]);
}
@ -178,16 +171,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();
$this->authorize('edit', $client);
$client = $request->entity();
$data = [
'client' => $client,
'method' => 'PUT',
'url' => 'clients/'.$publicId,
'url' => 'clients/'.$client->public_id,
'title' => trans('texts.edit_client'),
];
@ -226,11 +217,7 @@ class ClientController extends BaseController
*/
public function update(UpdateClientRequest $request)
{
$data = $request->input();
$this->authorizeUpdate($data);
$client = $this->clientService->save($data);
$client = $this->clientService->save($request->input(), $request->entity());
Session::flash('message', trans('texts.updated_client'));

View File

@ -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 $entity = ENTITY_CREDIT;
protected $entityType = ENTITY_CREDIT;
public function __construct(CreditRepository $creditRepo, CreditService $creditService)
{
@ -55,23 +56,21 @@ class CreditController extends BaseController
return $this->creditService->getDatatable($clientPublicId, Input::get('sSearch'));
}
public function create($clientPublicId = 0)
public function create(CreditRequest $request)
{
$this->authorizeCreate();
$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();
@ -90,7 +89,8 @@ class CreditController extends BaseController
return View::make('credit.edit', $data);
}
*/
public function store(CreateCreditRequest $request)
{
$credit = $this->creditRepo->save($request->input());

View File

@ -12,10 +12,13 @@ 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 $entity = ENTITY_DOCUMENT;
protected $entityType = ENTITY_DOCUMENT;
public function __construct(DocumentRepository $documentRepo)
{
@ -24,14 +27,9 @@ class DocumentController extends BaseController
$this->documentRepo = $documentRepo;
}
public function get($publicId)
public function get(DocumentRequest $request)
{
$document = Document::scope($publicId)
->firstOrFail();
$this->authorize('view', $document);
return static::getDownloadResponse($document);
return static::getDownloadResponse($request->entity());
}
public static function getDownloadResponse($document){
@ -60,12 +58,9 @@ class DocumentController extends BaseController
return $response;
}
public function getPreview($publicId)
public function getPreview(DocumentRequest $request)
{
$document = Document::scope($publicId)
->firstOrFail();
$this->authorize('view', $document);
$document = $request->entity();
if(empty($document->preview)){
return Response::view('error', array('error'=>'Preview does not exist!'), 404);
@ -83,16 +78,14 @@ class DocumentController extends BaseController
return $response;
}
public function getVFSJS($publicId, $name){
$document = Document::scope($publicId)
->firstOrFail();
public function getVFSJS(DocumentRequest $request, $publicId, $name)
{
$document = $request->entity();
if(substr($name, -3)=='.js'){
$name = substr($name, 0, -3);
}
$this->authorize('view', $document);
if(!$document->isPDFEmbeddable()){
return Response::view('error', array('error'=>'Image does not exist!'), 404);
}
@ -106,14 +99,12 @@ class DocumentController extends BaseController
return $response;
}
public function postUpload()
public function postUpload(CreateDocumentRequest $request)
{
if (!Utils::hasFeature(FEATURE_DOCUMENTS)) {
return;
}
$this->authorizeCreate();
$result = $this->documentRepo->upload(Input::all()['file'], $doc_array);
if(is_string($result)){

View File

@ -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()

View File

@ -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 $entity = ENTITY_EXPENSE;
protected $entityType = ENTITY_EXPENSE;
public function __construct(ExpenseRepository $expenseRepo, ExpenseService $expenseService)
{
@ -69,38 +71,35 @@ class ExpenseController extends BaseController
return $this->expenseService->getDatatableVendor($vendorPublicId);
}
public function create($vendorPublicId = null, $clientPublicId = null)
public function create(ExpenseRequest $request)
{
$this->authorizeCreate();
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)->with('documents')->firstOrFail();
$this->authorize('edit', $expense);
$expense = $request->entity();
$expense->expense_date = Utils::fromSqlDate($expense->expense_date);
$actions = [];
@ -108,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;
@ -131,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,
@ -155,10 +145,8 @@ class ExpenseController extends BaseController
{
$data = $request->input();
$data['documents'] = $request->file('documents');
$this->authorizeUpdate($data);
$expense = $this->expenseService->save($data, true);
$expense = $this->expenseService->save($data, $request->entity());
Session::flash('message', trans('texts.updated_expense'));
@ -174,9 +162,7 @@ class ExpenseController extends BaseController
{
$data = $request->input();
$data['documents'] = $request->file('documents');
$this->authorizeUpdate($data);
$expense = $this->expenseService->save($data);
Session::flash('message', trans('texts.created_expense'));

View File

@ -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();

View File

@ -1,4 +1,4 @@
<?php namespace app\Http\Controllers;
<?php namespace App\Http\Controllers;
use Utils;
use View;

View File

@ -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;
@ -210,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)
@ -300,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",
@ -351,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);
}
/**
@ -414,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);
}
}

View File

@ -27,7 +27,10 @@ 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
{
@ -37,7 +40,7 @@ class InvoiceController extends BaseController
protected $documentRepo;
protected $invoiceService;
protected $recurringInvoiceService;
protected $entity = ENTITY_INVOICE;
protected $entityType = ENTITY_INVOICE;
public function __construct(Mailer $mailer, InvoiceRepository $invoiceRepo, ClientRepository $clientRepo, InvoiceService $invoiceService, DocumentRepository $documentRepo, RecurringInvoiceService $recurringInvoiceService)
{
@ -88,18 +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', 'documents', 'expenses', 'expenses.documents', 'payments')
->withTrashed()
->firstOrFail();
$this->authorize('edit', $invoice);
$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)
@ -120,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);
}
@ -229,28 +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)
{
$this->authorizeCreate();
$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')){
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);
}
@ -267,9 +264,9 @@ class InvoiceController extends BaseController
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($invoice)
@ -395,17 +392,15 @@ class InvoiceController extends BaseController
*
* @return Response
*/
public function store(SaveInvoiceWithClientRequest $request)
public function store(CreateInvoiceRequest $request)
{
$data = $request->input();
$data['documents'] = $request->file('documents');
$this->authorizeUpdate($data);
$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}");
@ -434,25 +429,23 @@ class InvoiceController extends BaseController
* @param int $id
* @return Response
*/
public function update(SaveInvoiceWithClientRequest $request)
public function update(UpdateInvoiceRequest $request)
{
$data = $request->input();
$data['documents'] = $request->file('documents');
$this->authorizeUpdate($data);
$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'));
}
@ -521,7 +514,7 @@ class InvoiceController extends BaseController
{
Session::reflash();
return Redirect::to("invoices/{$publicId}/edit");
return Redirect::to("invoices/$publicId/edit");
}
/**
@ -549,23 +542,23 @@ 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 = $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);
@ -591,7 +584,7 @@ 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);
$invoice->features = [
$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),

View File

@ -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);
}
}

View File

@ -27,12 +27,13 @@ use App\Ninja\Mailers\ContactMailer;
use App\Ninja\Mailers\UserMailer;
use App\Services\PaymentService;
use App\Http\Requests\PaymentRequest;
use App\Http\Requests\CreatePaymentRequest;
use App\Http\Requests\UpdatePaymentRequest;
class PaymentController extends BaseController
{
protected $entity = ENTITY_PAYMENT;
protected $entityType = ENTITY_PAYMENT;
public function __construct(PaymentRepository $paymentRepo, InvoiceRepository $invoiceRepo, AccountRepository $accountRepo, ContactMailer $contactMailer, PaymentService $paymentService, UserMailer $userMailer)
{
@ -72,10 +73,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)
{
$this->authorizeCreate();
$invoices = Invoice::scope()
->where('is_recurring', '=', false)
->where('is_quote', '=', false)
@ -84,8 +83,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,
@ -99,12 +98,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();
$this->authorize('edit', $payment);
$payment = $request->entity();
$payment->payment_date = Utils::fromSqlDate($payment->payment_date);
$data = array(
@ -114,7 +111,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(), );
@ -386,9 +383,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;
}
}
@ -563,6 +569,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);
@ -637,7 +644,8 @@ class PaymentController extends BaseController
$payment = $this->paymentService->createPayment($invitation, $accountGateway, $token, $payerId);
Session::flash('message', trans('texts.applied_payment'));
} else {
Session::flash('error', Input::get('message'));
$message = Input::get('message') . ': ' . Input::get('invalid_fields');
Session::flash('error', $message);
}
return Redirect::to($invitation->getLink());
} elseif (method_exists($gateway, 'completePurchase')
@ -672,9 +680,7 @@ class PaymentController extends BaseController
public function store(CreatePaymentRequest $request)
{
$input = $request->input();
$this->authorizeUpdate($data);
$input['invoice_id'] = Invoice::getPrivateId($input['invoice']);
$input['client_id'] = Client::getPrivateId($input['client']);
$payment = $this->paymentRepo->save($input);
@ -691,11 +697,7 @@ class PaymentController extends BaseController
public function update(UpdatePaymentRequest $request)
{
$input = $request->input();
$this->authorizeUpdate($data);
$payment = $this->paymentRepo->save($input);
$payment = $this->paymentRepo->save($request->input(), $request->entity());
Session::flash('message', trans('texts.updated_payment'));

View File

@ -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);
}
}

View File

@ -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\InvoiceTransformer;
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 InvoiceTransformer(\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);
}
*/
}

View File

@ -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 $entity = ENTITY_INVOICE;
protected $entityType = ENTITY_INVOICE;
public function __construct(Mailer $mailer, InvoiceRepository $invoiceRepo, ClientRepository $clientRepo, InvoiceService $invoiceService)
{
@ -78,10 +79,8 @@ 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)
{
$this->authorizeCreate();
if (!Utils::hasFeature(FEATURE_QUOTES)) {
return Redirect::to('/invoices/create');
}

View File

@ -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);
}
/**

View File

@ -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 $entity = ENTITY_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,14 +87,13 @@ class TaskController extends BaseController
*
* @return Response
*/
public function create($clientPublicId = 0)
public function create(TaskRequest $request)
{
$this->authorizeCreate();
$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'),
@ -109,13 +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();
$this->authorize('edit', $task);
$task = $request->entity();
$actions = [];
if ($task->invoice) {
@ -143,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,
@ -163,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()
@ -180,20 +183,10 @@ class TaskController extends BaseController
{
$action = Input::get('action');
$this->authorizeUpdate(array('public_id'=>$publicId)/* Hacky, but works */);
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'));

View File

@ -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
}
}

View File

@ -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);

View File

@ -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)

View File

@ -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) {

View File

@ -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);
}
}

View File

@ -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 $entity = ENTITY_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,11 +76,7 @@ class VendorController extends BaseController
*/
public function store(CreateVendorRequest $request)
{
$data = $request->input();
$this->authorizeUpdate($data);
$vendor = $this->vendorService->save($data);
$vendor = $this->vendorService->save($request->input());
Session::flash('message', trans('texts.created_vendor'));
@ -94,12 +89,10 @@ 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();
$this->authorize('view', $vendor);
$vendor = $request->entity();
Utils::trackViewed($vendor->getDisplayName(), 'vendor');
$actionLinks = [
@ -125,10 +118,8 @@ class VendorController extends BaseController
*
* @return Response
*/
public function create()
public function create(VendorRequest $request)
{
$this->authorizeCreate();
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"]);
}
@ -151,16 +142,14 @@ 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();
$this->authorize('edit', $vendor)
$vendor = $request->entity();
$data = [
'vendor' => $vendor,
'method' => 'PUT',
'url' => 'vendors/'.$publicId,
'url' => 'vendors/'.$vendor->public_id,
'title' => trans('texts.edit_vendor'),
];
@ -193,11 +182,7 @@ class VendorController extends BaseController
*/
public function update(UpdateVendorRequest $request)
{
$data = $request->input();
$this->authorizeUpdate($data);
$vendor = $this->vendorService->save($data);
$vendor = $this->vendorService->save($request->input(), $request->entity());
Session::flash('message', trans('texts.updated_vendor'));

View File

@ -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 {

View File

@ -1,4 +1,4 @@
<?php namespace app\Http\Middleware;
<?php namespace App\Http\Middleware;
use Closure;

View File

@ -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,9 +141,11 @@ class StartupCheck
Session::flash('message', trans('texts.bought_designs'));
}
} elseif ($productId == PRODUCT_WHITE_LABEL) {
if ($data == 'valid') {
if ($data && $data != RESULT_FAILURE) {
$company = Auth::user()->account->company;
$company->plan_paid = date_create()->format('Y-m-d');
$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();

View 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;
}
}

View File

@ -1,4 +1,4 @@
<?php namespace app\Http\Requests;
<?php namespace App\Http\Requests;
use App\Http\Requests\Request;
use Illuminate\Validation\Factory;

View File

@ -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);
}
/**

View File

@ -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);
}
/**

View File

@ -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',
];
}
}

View File

@ -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);
}
/**

View 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;
}
}

View File

@ -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;
}
}

View 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;
}
}

View File

@ -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);
}
/**

View File

@ -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',
];
}
}

View 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',
];
}
}

View File

@ -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);
}
/**

View File

@ -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);
}
/**

View File

@ -0,0 +1,7 @@
<?php namespace App\Http\Requests;
class CreditRequest extends EntityRequest {
protected $entityType = ENTITY_CREDIT;
}

View File

@ -0,0 +1,7 @@
<?php namespace App\Http\Requests;
class DocumentRequest extends EntityRequest {
protected $entityType = ENTITY_DOCUMENT;
}

View 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 [];
}
}

View 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;
}
}

View 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;
}
}

View File

@ -0,0 +1,7 @@
<?php namespace App\Http\Requests;
class PaymentRequest extends EntityRequest {
protected $entityType = ENTITY_PAYMENT;
}

View File

@ -0,0 +1,6 @@
<?php namespace App\Http\Requests;
class ProductRequest extends EntityRequest {
protected $entityType = ENTITY_PRODUCT;
}

View File

@ -1,4 +1,4 @@
<?php namespace app\Http\Requests;
<?php namespace App\Http\Requests;
use Auth;
use App\Http\Requests\Request;

View File

@ -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;
}
}

View File

@ -0,0 +1,7 @@
<?php namespace App\Http\Requests;
class TaskRequest extends EntityRequest {
protected $entityType = ENTITY_TASK;
}

View File

@ -0,0 +1,7 @@
<?php namespace App\Http\Requests;
class TaxRateRequest extends EntityRequest {
protected $entityType = ENTITY_TAX_RATE;
}

View File

@ -1,4 +1,4 @@
<?php namespace app\Http\Requests;
<?php namespace App\Http\Requests;
use App\Http\Requests\Request;
use Illuminate\Validation\Factory;

View File

@ -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());
}
/**

View File

@ -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());
}
/**

View 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;
}
}

View File

@ -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;
}
}

View File

@ -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());
}
/**

View 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',
];
}
}

View 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',
];
}
}

View File

@ -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());
}
/**

View File

@ -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());
}
/**

View File

@ -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());
}
/**

View 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;
}
}

View File

@ -56,8 +56,8 @@ Route::group(['middleware' => 'auth:client'], function() {
Route::get('client/documents', 'PublicClientController@documentIndex');
Route::get('client/payments', 'PublicClientController@paymentIndex');
Route::get('client/dashboard', 'PublicClientController@dashboard');
Route::get('client/document/js/{public_id}/{filename}', 'PublicClientController@getDocumentVFSJS');
Route::get('client/document/{invitation_key}/{public_id}/{filename?}', 'PublicClientController@getDocument');
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'));
@ -121,9 +121,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'));
@ -145,20 +147,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('document/{public_id}/{filename?}', 'DocumentController@get');
Route::get('document/js/{public_id}/{filename}', 'DocumentController@getVFSJS');
Route::get('document/preview/{public_id}/{filename?}', 'DocumentController@getPreview');
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'));
@ -202,7 +204,6 @@ Route::group([
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');
@ -219,6 +220,7 @@ 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');
@ -230,11 +232,6 @@ Route::group([
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');
@ -257,15 +254,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');
@ -573,24 +570,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.1.3' . 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=');
@ -604,13 +603,12 @@ if (!defined('CONTACT_EMAIL')) {
define('INVOICE_DESIGNS_AFFILIATE_KEY', 'T3RS74');
define('SELF_HOST_AFFILIATE_KEY', '8S69AD');
define('PRO_PLAN_PRICE', 50);
define('PLAN_PRICE_PRO_MONTHLY', 5);
define('PLAN_PRICE_PRO_YEARLY', 50);
define('PLAN_PRICE_ENTERPRISE_MONTHLY', 10);
define('PLAN_PRICE_ENTERPRISE_YEARLY', 100);
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');
@ -619,9 +617,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);
@ -788,34 +788,10 @@ 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())
{
//ini_set('memory_limit','1024M');
//Auth::loginUsingId(1);
}
*/
*/

View File

@ -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
}
}
}

View File

@ -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();
@ -135,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()
@ -336,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;
@ -350,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) {
@ -669,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)

View File

@ -1,4 +1,4 @@
<?php namespace app\Listeners;
<?php namespace App\Listeners;
use App\Models\Invoice;
use App\Events\ClientWasCreated;

View 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);
}
}

View File

@ -1,4 +1,4 @@
<?php namespace app\Listeners;
<?php namespace App\Listeners;
use App\Events\PaymentFailed;
use Carbon;

View File

@ -1,4 +1,4 @@
<?php namespace app\Listeners;
<?php namespace App\Listeners;
use Carbon;
use App\Models\Expense;

View File

@ -1,4 +1,4 @@
<?php namespace app\Listeners;
<?php namespace App\Listeners;
use Utils;
use Auth;

View File

@ -1,4 +1,4 @@
<?php namespace app\Listeners;
<?php namespace App\Listeners;
use Utils;
use Auth;

View File

@ -1,4 +1,4 @@
<?php namespace app\Listeners;
<?php namespace App\Listeners;
use App\Ninja\Mailers\UserMailer;
use App\Ninja\Mailers\ContactMailer;

View File

@ -1,4 +1,4 @@
<?php namespace app\Listeners;
<?php namespace App\Listeners;
use Carbon;
use App\Events\QuoteWasEmailed;

View File

@ -1,4 +1,4 @@
<?php namespace app\Listeners;
<?php namespace App\Listeners;
use Auth;
use Utils;

View File

@ -1,4 +1,4 @@
<?php namespace app\Listeners;
<?php namespace App\Listeners;
use App\Models\Task;
use App\Events\InvoiceWasDeleted;

View File

@ -212,7 +212,9 @@ class Account extends Eloquent
public function isGatewayConfigured($gatewayId = 0)
{
$this->load('account_gateways');
if ( ! $this->relationLoaded('account_gateways')) {
$this->load('account_gateways');
}
if ($gatewayId) {
return $this->getGatewayConfig($gatewayId) != false;
@ -241,7 +243,7 @@ class Account extends Eloquent
return $this->name;
}
$this->load('users');
//$this->load('users');
$user = $this->users()->first();
return $user->getDisplayName();
@ -481,10 +483,17 @@ class Account extends Eloquent
return Document::getDirectFileUrl($this->logo, $this->getLogoDisk());
}
public function getToken($name)
public function getPrimaryUser()
{
return $this->users()
->orderBy('id')
->first();
}
public function getToken($userId, $name)
{
foreach ($this->account_tokens as $token) {
if ($token->name === $name) {
if ($token->user_id == $userId && $token->name === $name) {
return $token->token;
}
}
@ -809,6 +818,10 @@ class Account extends Eloquent
public function hasFeature($feature)
{
if (Utils::isNinjaDev()) {
return true;
}
$planDetails = $this->getPlanDetails();
$selfHost = !Utils::isNinjaProd();
@ -1176,13 +1189,18 @@ class Account extends Eloquent
return str_replace('/>', ' />', $template);
}
public function getTemplateView($view = '')
{
return $this->getEmailDesignId() == EMAIL_DESIGN_PLAIN ? $view : 'design' . $this->getEmailDesignId();
}
public function getEmailFooter()
{
if ($this->email_footer) {
// Add line breaks if HTML isn't already being used
return strip_tags($this->email_footer) == $this->email_footer ? nl2br($this->email_footer) : $this->email_footer;
} else {
return "<p>" . trans('texts.email_signature') . "\n<br>\$account</p>";
return "<p><div>" . trans('texts.email_signature') . "\n<br>\$account</div></p>";
}
}

View File

@ -16,4 +16,9 @@ class AccountToken extends EntityModel
{
return $this->belongsTo('App\Models\Account');
}
public function user()
{
return $this->belongsTo('App\Models\User');
}
}

View File

@ -199,6 +199,13 @@ class Client extends EntityModel
return $this->name;
}
public function getPrimaryContact()
{
return $this->contacts()
->whereIsPrimary(true)
->first();
}
public function getDisplayName()
{
if ($this->name) {
@ -254,14 +261,18 @@ class Client extends EntityModel
}
public function getGatewayToken(&$accountGateway = null)
public function getGatewayToken(&$accountGateway)
{
$this->account->load('account_gateways');
$account = $this->account;
if ( ! $account->relationLoaded('account_gateways')) {
$account->load('account_gateways');
}
if (!count($this->account->account_gateways)) {
if (!count($account->account_gateways)) {
return false;
}
$accountGateway = $this->account->getTokenGateway();
$accountGateway = $account->getTokenGateway();
if (!$accountGateway) {
return false;

View File

@ -173,11 +173,11 @@ class Document extends EntityModel
}
public function getUrl(){
return url('document/'.$this->public_id.'/'.$this->name);
return url('documents/'.$this->public_id.'/'.$this->name);
}
public function getClientUrl($invitation){
return url('client/document/'.$invitation->invitation_key.'/'.$this->public_id.'/'.$this->name);
return url('client/documents/'.$invitation->invitation_key.'/'.$this->public_id.'/'.$this->name);
}
public function isPDFEmbeddable(){
@ -186,16 +186,16 @@ class Document extends EntityModel
public function getVFSJSUrl(){
if(!$this->isPDFEmbeddable())return null;
return url('document/js/'.$this->public_id.'/'.$this->name.'.js');
return url('documents/js/'.$this->public_id.'/'.$this->name.'.js');
}
public function getClientVFSJSUrl(){
if(!$this->isPDFEmbeddable())return null;
return url('client/document/js/'.$this->public_id.'/'.$this->name.'.js');
return url('client/documents/js/'.$this->public_id.'/'.$this->name.'.js');
}
public function getPreviewUrl(){
return $this->preview?url('document/preview/'.$this->public_id.'/'.$this->name.'.'.pathinfo($this->preview, PATHINFO_EXTENSION)):null;
return $this->preview?url('documents/preview/'.$this->public_id.'/'.$this->name.'.'.pathinfo($this->preview, PATHINFO_EXTENSION)):null;
}
public function toArray()

View File

@ -101,6 +101,16 @@ class EntityModel extends Eloquent
return $this->getName();
}
public static function getClassName($entityType)
{
return 'App\\Models\\' . ucwords(Utils::toCamelCase($entityType));
}
public static function getTransformerName($entityType)
{
return 'App\\Ninja\\Transformers\\' . ucwords(Utils::toCamelCase($entityType)) . 'Transformer';
}
public function setNullValues()
{
foreach ($this->fillable as $field) {

View File

@ -228,6 +228,12 @@ class Invoice extends EntityModel implements BalanceAffecting
return $this->hasMany('App\Models\Expense','invoice_id','id')->withTrashed();
}
public function scopeInvoices($query)
{
return $query->where('is_quote', '=', false)
->where('is_recurring', '=', false);
}
public function markInvitationsSent($notify = false)
{
foreach ($this->invitations as $invitation) {
@ -436,6 +442,7 @@ class Invoice extends EntityModel implements BalanceAffecting
'contacts',
'country',
'currency_id',
'country_id',
'custom_value1',
'custom_value2',
]);
@ -792,7 +799,6 @@ class Invoice extends EntityModel implements BalanceAffecting
$invitation = $this->invitations[0];
$link = $invitation->getLink('view', true);
$key = env('PHANTOMJS_CLOUD_KEY');
$curl = curl_init();
if (Utils::isNinjaDev()) {
$link = env('TEST_LINK');

View File

@ -1,4 +1,4 @@
<?php namespace app\Models;
<?php namespace App\Models;
use Eloquent;
use Auth;

View File

@ -19,6 +19,11 @@ class InvoiceItem extends EntityModel
return $this->belongsTo('App\Models\Invoice');
}
public function user()
{
return $this->belongsTo('App\Models\User')->withTrashed();
}
public function product()
{
return $this->belongsTo('App\Models\Product');

View File

@ -8,6 +8,14 @@ class Product extends EntityModel
use SoftDeletes;
protected $dates = ['deleted_at'];
protected $fillable = [
'product_key',
'notes',
'cost',
'qty',
'default_tax_rate_id',
];
public function getEntityType()
{
return ENTITY_PRODUCT;
@ -18,6 +26,11 @@ class Product extends EntityModel
return Product::scope()->where('product_key', '=', $key)->first();
}
public function user()
{
return $this->belongsTo('App\Models\User')->withTrashed();
}
public function default_tax_rate()
{
return $this->belongsTo('App\Models\TaxRate');

View File

@ -17,4 +17,9 @@ class TaxRate extends EntityModel
{
return ENTITY_TAX_RATE;
}
public function user()
{
return $this->belongsTo('App\Models\User')->withTrashed();
}
}

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