Merging changes

This commit is contained in:
Hillel Coren 2016-02-22 15:20:38 +02:00
commit f26ab6fe5b
65 changed files with 724 additions and 503 deletions

View File

@ -8,8 +8,8 @@ DB_TYPE=mysql
DB_STRICT=false DB_STRICT=false
DB_HOST=localhost DB_HOST=localhost
DB_DATABASE=ninja DB_DATABASE=ninja
DB_USERNAME DB_USERNAME=ninja
DB_PASSWORD DB_PASSWORD=ninja
MAIL_DRIVER=smtp MAIL_DRIVER=smtp
MAIL_PORT=587 MAIL_PORT=587
@ -23,6 +23,7 @@ MAIL_PASSWORD
PHANTOMJS_CLOUD_KEY='a-demo-key-with-low-quota-per-ip-address' PHANTOMJS_CLOUD_KEY='a-demo-key-with-low-quota-per-ip-address'
LOG=single LOG=single
REQUIRE_HTTPS=false REQUIRE_HTTPS=false
API_SECRET=password
GOOGLE_CLIENT_ID GOOGLE_CLIENT_ID
GOOGLE_CLIENT_SECRET GOOGLE_CLIENT_SECRET

View File

@ -1,12 +1,12 @@
language: php language: php
sudo: false sudo: true
php: php:
- 5.5 - 5.5
- 5.6 # - 5.6
- 7.0 # - 7.0
- hhvm # - hhvm
addons: addons:
hosts: hosts:
@ -30,12 +30,22 @@ before_install:
install: install:
# install Composer dependencies # install Composer dependencies
- travis_retry composer update --prefer-dist; - rm composer.lock
# these providers require referencing git commit's which cause Travis to fail
- sed -i '/mollie/d' composer.json
- sed -i '/2checkout/d' composer.json
- travis_retry composer install --prefer-dist;
before_script: before_script:
# prevent MySQL went away error
- mysql -u root -e 'SET @@GLOBAL.wait_timeout=28800;'
# copy configuration files # copy configuration files
- cp .env.example .env
- cp tests/_bootstrap.php.default tests/_bootstrap.php - cp tests/_bootstrap.php.default tests/_bootstrap.php
- cp tests/.env.circleci .env - 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
# create the database and user # create the database and user
- mysql -u root -e "create database IF NOT EXISTS ninja;" - 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;" - mysql -u root -e "GRANT ALL PRIVILEGES ON ninja.* To 'ninja'@'localhost' IDENTIFIED BY 'ninja'; FLUSH PRIVILEGES;"
@ -53,7 +63,29 @@ before_script:
- curl -L http://ninja.dev:8000/update - curl -L http://ninja.dev:8000/update
script: script:
- php ./vendor/codeception/codeception/codecept run --html --debug - php ./vendor/codeception/codeception/codecept run --debug acceptance AllPagesCept.php
#- php ./vendor/codeception/codeception/codecept run --debug acceptance APICest.php
#- php ./vendor/codeception/codeception/codecept run --debug acceptance CheckBalanceCest.php
#- php ./vendor/codeception/codeception/codecept run --debug acceptance ClientCest.php
#- php ./vendor/codeception/codeception/codecept run --debug acceptance CreditCest.php
#- php ./vendor/codeception/codeception/codecept run --debug acceptance InvoiceCest.php
#- php ./vendor/codeception/codeception/codecept run --debug acceptance InvoiceDesignCest.php
#- php ./vendor/codeception/codeception/codecept run acceptance OnlinePaymentCest.php
#- php ./vendor/codeception/codeception/codecept run --debug acceptance PaymentCest.php
#- php ./vendor/codeception/codeception/codecept run --debug acceptance TaskCest.php
#- php ./vendor/codeception/codeception/codecept run --debug acceptance TaxRatesCest.php
#- sed -i 's/NINJA_DEV=true/NINJA_PROD=true/g' .env
#- php ./vendor/codeception/codeception/codecept run acceptance GoProCest.php
after_script:
- cat .env
- mysql -u root -e 'select * from accounts;' ninja
- mysql -u root -e 'select * from account_gateways;' ninja
- mysql -u root -e 'select * from clients;' ninja
- mysql -u root -e 'select * from invoices;' ninja
- mysql -u root -e 'select * from invoice_items;' ninja
- cat storage/logs/laravel.log
notifications: notifications:
email: email:

View File

@ -0,0 +1,68 @@
<?php namespace app\Console\Commands;
use File;
use Illuminate\Console\Command;
class GenerateResources extends Command
{
protected $name = 'ninja:generate-resources';
protected $description = 'Generate Resouces';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the command.
*
* @return void
*/
public function fire()
{
$langs = [
'da',
'de',
'en',
'es',
'es_ES',
'fr',
'fr_CA',
'it',
'lt',
'nb_NO',
'nl',
'pt_BR',
'sv'
];
$texts = File::getRequire(base_path() . '/resources/lang/en/texts.php');
foreach ($texts as $key => $value) {
if (is_array($value)) {
echo $key;
} else {
echo "$key => $value\n";
}
}
}
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

@ -18,6 +18,7 @@ class Kernel extends ConsoleKernel
'App\Console\Commands\SendRenewalInvoices', 'App\Console\Commands\SendRenewalInvoices',
'App\Console\Commands\SendReminders', 'App\Console\Commands\SendReminders',
'App\Console\Commands\TestOFX', 'App\Console\Commands\TestOFX',
'App\Console\Commands\GenerateResources',
]; ];
/** /**

View File

@ -71,6 +71,8 @@ class AccountApiController extends BaseAPIController
'invoices' => ['invoice_items', 'user', 'client', 'payments'], 'invoices' => ['invoice_items', 'user', 'client', 'payments'],
'products' => [], 'products' => [],
'tax_rates' => [], 'tax_rates' => [],
'expenses' => ['client', 'invoice', 'vendor'],
'payments' => ['invoice'],
]; ];
foreach ($map as $key => $values) { foreach ($map as $key => $values) {

View File

@ -117,13 +117,7 @@ class AccountController extends BaseController
{ {
Session::put("show_trash:{$entityType}", $visible == 'true'); Session::put("show_trash:{$entityType}", $visible == 'true');
if ($entityType == 'user') { return RESULT_SUCCESS;
return Redirect::to('settings/'.ACCOUNT_USER_MANAGEMENT);
} elseif ($entityType == 'token') {
return Redirect::to('settings/'.ACCOUNT_API_TOKENS);
} else {
return Redirect::to("{$entityType}s");
}
} }
public function getSearchData() public function getSearchData()
@ -958,7 +952,13 @@ class AccountController extends BaseController
'text' => $reason, 'text' => $reason,
]; ];
$this->userMailer->sendTo(CONTACT_EMAIL, $email, $name, 'Invoice Ninja Feedback [Canceled Account]', 'contact', $data); $subject = 'Invoice Ninja - Canceled Account';
if (Auth::user()->isPaidPro()) {
$subject .= ' [PRO]';
}
$this->userMailer->sendTo(CONTACT_EMAIL, $email, $name, $subject, 'contact', $data);
} }
$user = Auth::user(); $user = Auth::user();

View File

@ -200,7 +200,7 @@ class AccountGatewayController extends BaseController
if ($gatewayId == GATEWAY_DWOLLA) { if ($gatewayId == GATEWAY_DWOLLA) {
$optional = array_merge($optional, ['key', 'secret']); $optional = array_merge($optional, ['key', 'secret']);
} elseif ($gatewayId == GATEWAY_STRIPE) { } elseif ($gatewayId == GATEWAY_STRIPE) {
if (Utils::isNinjaDev() && Input::get('23_apiKey') == env('TEST_API_KEY')) { if (Utils::isNinjaDev()) {
// do nothing - we're unable to acceptance test with StripeJS // do nothing - we're unable to acceptance test with StripeJS
} else { } else {
$rules['publishable_key'] = 'required'; $rules['publishable_key'] = 'required';

View File

@ -136,11 +136,11 @@ class ClientApiController extends BaseAPIController
{ {
if ($request->action == ACTION_ARCHIVE) { if ($request->action == ACTION_ARCHIVE) {
try {
$client = Client::scope($publicId)->withTrashed()->firstOrFail(); $client = Client::scope($publicId)->withTrashed()->first();
} catch (ModelNotFoundException $e) {
if(!$client)
return $this->errorResponse(['message'=>'Record not found'], 400); return $this->errorResponse(['message'=>'Record not found'], 400);
}
$this->clientRepo->archive($client); $this->clientRepo->archive($client);
@ -154,7 +154,7 @@ class ClientApiController extends BaseAPIController
$client = Client::scope($publicId)->withTrashed()->first(); $client = Client::scope($publicId)->withTrashed()->first();
if(!$client) if(!$client)
return $this->errorResponse(['message'=>'Client not found.']); return $this->errorResponse(['message'=>'Client not found.'], 400);
$this->clientRepo->restore($client); $this->clientRepo->restore($client);
@ -173,7 +173,7 @@ class ClientApiController extends BaseAPIController
->first(); ->first();
if(!$client) if(!$client)
return $this->errorResponse(['message'=>'Client not found.']); return $this->errorResponse(['message'=>'Client not found.'],400);
$transformer = new ClientTransformer(Auth::user()->account, Input::get('serializer')); $transformer = new ClientTransformer(Auth::user()->account, Input::get('serializer'));
$data = $this->createItem($client, $transformer, ENTITY_CLIENT); $data = $this->createItem($client, $transformer, ENTITY_CLIENT);

View File

@ -0,0 +1,64 @@
<?php namespace App\Http\Controllers;
// vendor
use App\Models\Expense;
use app\Ninja\Repositories\ExpenseRepository;
use App\Ninja\Transformers\ExpenseTransformer;
use App\Services\ExpenseService;
use Utils;
use Response;
use Input;
use Auth;
class ExpenseApiController extends BaseAPIController
{
// Expenses
protected $expenseRepo;
protected $expenseService;
public function __construct(ExpenseRepository $expenseRepo, ExpenseService $expenseService)
{
parent::__construct();
$this->expenseRepo = $expenseRepo;
$this->expenseService = $expenseService;
}
public function index()
{
$expenses = Expense::scope()
->withTrashed()
->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);
}
public function update()
{
//stub
}
public function store()
{
//stub
}
public function destroy()
{
//stub
}
}

View File

@ -96,7 +96,7 @@ class ExpenseController extends BaseController
{ {
$expense = Expense::scope($publicId)->firstOrFail(); $expense = Expense::scope($publicId)->firstOrFail();
$expense->expense_date = Utils::fromSqlDate($expense->expense_date); $expense->expense_date = Utils::fromSqlDate($expense->expense_date);
$actions = []; $actions = [];
if ($expense->invoice) { if ($expense->invoice) {
$actions[] = ['url' => URL::to("invoices/{$expense->invoice->public_id}/edit"), 'label' => trans("texts.view_invoice")]; $actions[] = ['url' => URL::to("invoices/{$expense->invoice->public_id}/edit"), 'label' => trans("texts.view_invoice")];

View File

@ -1,6 +1,7 @@
<?php namespace App\Http\Controllers; <?php namespace App\Http\Controllers;
use Auth; use Auth;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Request; use Illuminate\Support\Facades\Request;
use Utils; use Utils;
use Response; use Response;
@ -19,18 +20,20 @@ use App\Http\Controllers\BaseAPIController;
use App\Ninja\Transformers\InvoiceTransformer; use App\Ninja\Transformers\InvoiceTransformer;
use App\Http\Requests\CreateInvoiceRequest; use App\Http\Requests\CreateInvoiceRequest;
use App\Http\Requests\UpdateInvoiceRequest; use App\Http\Requests\UpdateInvoiceRequest;
use App\Services\InvoiceService;
class InvoiceApiController extends BaseAPIController class InvoiceApiController extends BaseAPIController
{ {
protected $invoiceRepo; protected $invoiceRepo;
public function __construct(InvoiceRepository $invoiceRepo, ClientRepository $clientRepo, PaymentRepository $paymentRepo, Mailer $mailer) public function __construct(InvoiceService $invoiceService, InvoiceRepository $invoiceRepo, ClientRepository $clientRepo, PaymentRepository $paymentRepo, Mailer $mailer)
{ {
parent::__construct(); parent::__construct();
$this->invoiceRepo = $invoiceRepo; $this->invoiceRepo = $invoiceRepo;
$this->clientRepo = $clientRepo; $this->clientRepo = $clientRepo;
$this->paymentRepo = $paymentRepo; $this->paymentRepo = $paymentRepo;
$this->invoiceService = $invoiceService;
$this->mailer = $mailer; $this->mailer = $mailer;
} }
@ -84,6 +87,36 @@ class InvoiceApiController extends BaseAPIController
return $this->response($data); return $this->response($data);
} }
/**
* @SWG\Get(
* path="/invoices/{invoice_id}",
* summary="Individual Invoice",
* tags={"invoice"},
* @SWG\Response(
* response=200,
* description="A single invoice",
* @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/Invoice"))
* ),
* @SWG\Response(
* response="default",
* description="an ""unexpected"" error"
* )
* )
*/
public function show($publicId)
{
$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);
}
/** /**
* @SWG\Post( * @SWG\Post(
@ -156,7 +189,7 @@ class InvoiceApiController extends BaseAPIController
$data = self::prepareData($data, $client); $data = self::prepareData($data, $client);
$data['client_id'] = $client->id; $data['client_id'] = $client->id;
$invoice = $this->invoiceRepo->save($data); $invoice = $this->invoiceService->save($data);
$payment = false; $payment = false;
// Optionally create payment with invoice // Optionally create payment with invoice
@ -168,14 +201,6 @@ class InvoiceApiController extends BaseAPIController
]); ]);
} }
if (!isset($data['id'])) {
$invitation = Invitation::createNew();
$invitation->invoice_id = $invoice->id;
$invitation->contact_id = $client->contacts[0]->id;
$invitation->invitation_key = str_random(RANDOM_KEY_LENGTH);
$invitation->save();
}
if (isset($data['email_invoice']) && $data['email_invoice']) { if (isset($data['email_invoice']) && $data['email_invoice']) {
if ($payment) { if ($payment) {
$this->mailer->sendPaymentConfirmation($payment); $this->mailer->sendPaymentConfirmation($payment);
@ -249,7 +274,7 @@ class InvoiceApiController extends BaseAPIController
private function prepareItem($item) private function prepareItem($item)
{ {
// if only the product key is set we'll load the cost and notes // if only the product key is set we'll load the cost and notes
if ($item['product_key'] && empty($item['cost']) && empty($item['notes'])) { if (!empty($item['product_key']) && empty($item['cost']) && empty($item['notes'])) {
$product = Product::findProductByKey($item['product_key']); $product = Product::findProductByKey($item['product_key']);
if ($product) { if ($product) {
if (empty($item['cost'])) { if (empty($item['cost'])) {
@ -282,12 +307,17 @@ class InvoiceApiController extends BaseAPIController
$data = Input::all(); $data = Input::all();
$error = null; $error = null;
$invoice = Invoice::scope($data['id'])->firstOrFail(); $invoice = Invoice::scope($data['id'])->withTrashed()->first();
if(!$invoice)
return $this->errorResponse(['message'=>'Invoice does not exist.'], 400);
$this->mailer->sendInvoice($invoice, false, false);
$this->mailer->sendInvoice($invoice);
if($error) { if($error) {
$response['error'] = "There was an error sending the invoice"; return $this->errorResponse(['message'=>'There was an error sending the invoice'], 400);
} }
else { else {
$response = json_encode(RESULT_SUCCESS, JSON_PRETTY_PRINT); $response = json_encode(RESULT_SUCCESS, JSON_PRETTY_PRINT);
@ -351,7 +381,7 @@ class InvoiceApiController extends BaseAPIController
$data = $request->input(); $data = $request->input();
$data['public_id'] = $publicId; $data['public_id'] = $publicId;
$this->invoiceRepo->save($data); $this->invoiceService->save($data);
$invoice = Invoice::scope($publicId)->with('client', 'invoice_items', 'invitations')->firstOrFail(); $invoice = Invoice::scope($publicId)->with('client', 'invoice_items', 'invitations')->firstOrFail();
$transformer = new InvoiceTransformer(\Auth::user()->account, Input::get('serializer')); $transformer = new InvoiceTransformer(\Auth::user()->account, Input::get('serializer'));

View File

@ -58,8 +58,8 @@ class PaymentApiController extends BaseAPIController
$payments = $payments->orderBy('created_at', 'desc')->paginate(); $payments = $payments->orderBy('created_at', 'desc')->paginate();
$paginator = $paginator->paginate(); $paginator = $paginator->paginate();
$transformer = new PaymentTransformer(Auth::user()->account, Input::get('serializer')); $transformer = new PaymentTransformer(Auth::user()->account, Input::get('serializer'));
$data = $this->createCollection($payments, $transformer, 'payments', $paginator); $data = $this->createCollection($payments, $transformer, 'payments', $paginator);
return $this->response($data); return $this->response($data);
@ -98,11 +98,8 @@ class PaymentApiController extends BaseAPIController
$payment = Payment::scope($publicId)->withTrashed()->firstOrFail(); $payment = Payment::scope($publicId)->withTrashed()->firstOrFail();
$this->paymentRepo->archive($payment); $this->paymentRepo->archive($payment);
$invoice = Invoice::scope($data['invoice_id'])->with('client')->with(['payments' => function($query) { $transformer = new PaymentTransformer(\Auth::user()->account, Input::get('serializer'));
$query->withTrashed(); $data = $this->createItem($payment, $transformer, 'invoice');
}])->first();
$transformer = new InvoiceTransformer(\Auth::user()->account, Input::get('serializer'));
$data = $this->createItem($invoice, $transformer, 'invoice');
return $this->response($data); return $this->response($data);
} }
@ -113,12 +110,17 @@ class PaymentApiController extends BaseAPIController
return $error; return $error;
} }
/*
$invoice = Invoice::scope($data['invoice_id'])->with('client', 'invoice_items', 'invitations')->with(['payments' => function($query) { $invoice = Invoice::scope($data['invoice_id'])->with('client', 'invoice_items', 'invitations')->with(['payments' => function($query) {
$query->withTrashed(); $query->withTrashed();
}])->withTrashed()->first(); }])->withTrashed()->first();
$transformer = new InvoiceTransformer(\Auth::user()->account, Input::get('serializer')); */
$data = $this->createItem($invoice, $transformer, 'invoice');
$transformer = new PaymentTransformer(\Auth::user()->account, Input::get('serializer'));
$data = $this->createItem($payment, $transformer, 'invoice');
return $this->response($data); return $this->response($data);
} }
@ -175,13 +177,17 @@ class PaymentApiController extends BaseAPIController
$this->contactMailer->sendPaymentConfirmation($payment); $this->contactMailer->sendPaymentConfirmation($payment);
} }
/*
$invoice = Invoice::scope($invoice->public_id)->with('client', 'invoice_items', 'invitations')->with(['payments' => function($query) { $invoice = Invoice::scope($invoice->public_id)->with('client', 'invoice_items', 'invitations')->with(['payments' => function($query) {
$query->withTrashed(); $query->withTrashed();
}])->first(); }])->first();
$transformer = new InvoiceTransformer(\Auth::user()->account, Input::get('serializer')); */
$data = $this->createItem($invoice, $transformer, 'invoice');
$transformer = new PaymentTransformer(\Auth::user()->account, Input::get('serializer'));
$data = $this->createItem($payment, $transformer, 'invoice');
return $this->response($data); return $this->response($data);
} }
/** /**
@ -214,12 +220,13 @@ class PaymentApiController extends BaseAPIController
$this->paymentRepo->delete($payment); $this->paymentRepo->delete($payment);
/*
$invoice = Invoice::scope($invoiceId)->with('client', 'invoice_items', 'invitations')->with(['payments' => function($query) { $invoice = Invoice::scope($invoiceId)->with('client', 'invoice_items', 'invitations')->with(['payments' => function($query) {
$query->withTrashed(); $query->withTrashed();
}])->first(); }])->first();
*/
$transformer = new InvoiceTransformer(\Auth::user()->account, Input::get('serializer')); $transformer = new PaymentTransformer(\Auth::user()->account, Input::get('serializer'));
$data = $this->createItem($invoice, $transformer, 'invoice'); $data = $this->createItem($payment, $transformer, 'invoice');
return $this->response($data); return $this->response($data);
} }

View File

@ -162,6 +162,27 @@ class PublicClientController extends BaseController
return $paymentTypes; return $paymentTypes;
} }
public function download($invitationKey)
{
if (!$invitation = $this->invoiceRepo->findInvoiceByInvitation($invitationKey)) {
return response()->view('error', [
'error' => trans('texts.invoice_not_found'),
'hideHeader' => true,
]);
}
$invoice = $invitation->invoice;
$pdfString = $invoice->getPDFString();
header('Content-Type: application/pdf');
header('Content-Length: ' . strlen($pdfString));
header('Content-disposition: attachment; filename="' . $invoice->getFileName() . '"');
header('Cache-Control: public, must-revalidate, max-age=0');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
return $pdfString;
}
public function dashboard() public function dashboard()
{ {
if (!$invitation = $this->getInvitation()) { if (!$invitation = $this->getInvitation()) {

View File

@ -48,6 +48,7 @@ class VendorApiController extends BaseAPIController
{ {
$vendors = Vendor::scope() $vendors = Vendor::scope()
->with($this->getIncluded()) ->with($this->getIncluded())
->withTrashed()
->orderBy('created_at', 'desc') ->orderBy('created_at', 'desc')
->paginate(); ->paginate();

View File

@ -1,6 +1,5 @@
<?php <?php
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Application Routes | Application Routes
@ -37,6 +36,7 @@ Route::post('/get_started', 'AccountController@getStarted');
// Client visible pages // Client visible pages
Route::get('view/{invitation_key}', 'PublicClientController@view'); Route::get('view/{invitation_key}', 'PublicClientController@view');
Route::get('download/{invitation_key}', 'PublicClientController@download');
Route::get('view', 'HomeController@viewLogo'); Route::get('view', 'HomeController@viewLogo');
Route::get('approve/{invitation_key}', 'QuoteController@approve'); Route::get('approve/{invitation_key}', 'QuoteController@approve');
Route::get('payment/{invitation_key}/{payment_type?}', 'PaymentController@show_payment'); Route::get('payment/{invitation_key}/{payment_type?}', 'PaymentController@show_payment');
@ -188,9 +188,6 @@ Route::group(['middleware' => 'auth'], function() {
Route::get('api/payments/{client_id?}', array('as'=>'api.payments', 'uses'=>'PaymentController@getDatatable')); Route::get('api/payments/{client_id?}', array('as'=>'api.payments', 'uses'=>'PaymentController@getDatatable'));
Route::post('payments/bulk', 'PaymentController@bulk'); Route::post('payments/bulk', 'PaymentController@bulk');
Route::get('credits/{id}/edit', function() {
return View::make('header');
});
Route::resource('credits', 'CreditController'); Route::resource('credits', 'CreditController');
Route::get('credits/create/{client_id?}/{invoice_id?}', 'CreditController@create'); Route::get('credits/create/{client_id?}/{invoice_id?}', 'CreditController@create');
Route::get('api/credits/{client_id?}', array('as'=>'api.credits', 'uses'=>'CreditController@getDatatable')); Route::get('api/credits/{client_id?}', array('as'=>'api.credits', 'uses'=>'CreditController@getDatatable'));
@ -236,6 +233,7 @@ Route::group(['middleware' => 'api', 'prefix' => 'api/v1'], function()
Route::resource('products', 'ProductApiController'); Route::resource('products', 'ProductApiController');
Route::resource('tax_rates', 'TaxRateApiController'); Route::resource('tax_rates', 'TaxRateApiController');
Route::resource('users', 'UserApiController'); Route::resource('users', 'UserApiController');
Route::resource('expenses','ExpenseApiController');
// Vendor // Vendor
Route::resource('vendors', 'VendorApiController'); Route::resource('vendors', 'VendorApiController');
@ -245,6 +243,7 @@ Route::group(['middleware' => 'api', 'prefix' => 'api/v1'], function()
}); });
// Redirects for legacy links // Redirects for legacy links
/*
Route::get('/rocksteady', function() { Route::get('/rocksteady', function() {
return Redirect::to(NINJA_WEB_URL, 301); return Redirect::to(NINJA_WEB_URL, 301);
}); });
@ -272,6 +271,7 @@ Route::get('/compare-online-invoicing{sites?}', function() {
Route::get('/forgot_password', function() { Route::get('/forgot_password', function() {
return Redirect::to(NINJA_APP_URL.'/forgot', 301); return Redirect::to(NINJA_APP_URL.'/forgot', 301);
}); });
*/
if (!defined('CONTACT_EMAIL')) { if (!defined('CONTACT_EMAIL')) {
define('CONTACT_EMAIL', Config::get('mail.from.address')); define('CONTACT_EMAIL', Config::get('mail.from.address'));
@ -509,7 +509,7 @@ if (!defined('CONTACT_EMAIL')) {
define('NINJA_GATEWAY_CONFIG', 'NINJA_GATEWAY_CONFIG'); define('NINJA_GATEWAY_CONFIG', 'NINJA_GATEWAY_CONFIG');
define('NINJA_WEB_URL', 'https://www.invoiceninja.com'); define('NINJA_WEB_URL', 'https://www.invoiceninja.com');
define('NINJA_APP_URL', 'https://app.invoiceninja.com'); define('NINJA_APP_URL', 'https://app.invoiceninja.com');
define('NINJA_VERSION', '2.5.0.2'); define('NINJA_VERSION', '2.5.0.3');
define('NINJA_DATE', '2000-01-01'); define('NINJA_DATE', '2000-01-01');
define('SOCIAL_LINK_FACEBOOK', 'https://www.facebook.com/invoiceninja'); define('SOCIAL_LINK_FACEBOOK', 'https://www.facebook.com/invoiceninja');

View File

@ -62,17 +62,17 @@ class Utils
return true; return true;
} }
return isset($_ENV['NINJA_PROD']) && $_ENV['NINJA_PROD'] == 'true'; return env('NINJA_PROD') == 'true';
} }
public static function isNinjaDev() public static function isNinjaDev()
{ {
return isset($_ENV['NINJA_DEV']) && $_ENV['NINJA_DEV'] == 'true'; return env('NINJA_DEV') == 'true';
} }
public static function requireHTTPS() public static function requireHTTPS()
{ {
if (Request::root() === 'http://ninja.dev') { if (Request::root() === 'http://ninja.dev:8000') {
return false; return false;
} }

View File

@ -164,6 +164,15 @@ class Account extends Eloquent
return $this->belongsTo('App\Models\TaxRate'); return $this->belongsTo('App\Models\TaxRate');
} }
public function expenses()
{
return $this->hasMany('App\Models\Expense','account_id','id')->withTrashed();
}
public function payments()
{
return $this->hasMany('App\Models\Payment','account_id','id')->withTrashed();
}
public function setIndustryIdAttribute($value) public function setIndustryIdAttribute($value)
{ {

View File

@ -139,6 +139,10 @@ class Client extends EntityModel
return $this->hasMany('App\Models\Credit'); return $this->hasMany('App\Models\Credit');
} }
public function expenses()
{
return $this->hasMany('App\Models\Expense','client_id','id')->withTrashed();
}
public function addContact($data, $isPrimary = false) public function addContact($data, $isPrimary = false)
{ {

View File

@ -12,7 +12,7 @@ class Expense extends EntityModel
use SoftDeletes; use SoftDeletes;
use PresentableTrait; use PresentableTrait;
protected $dates = ['deleted_at','expense_date']; protected $dates = ['deleted_at'];
protected $presenter = 'App\Ninja\Presenters\ExpensePresenter'; protected $presenter = 'App\Ninja\Presenters\ExpensePresenter';
protected $fillable = [ protected $fillable = [
@ -76,19 +76,9 @@ class Expense extends EntityModel
return ENTITY_EXPENSE; return ENTITY_EXPENSE;
} }
public function apply($amount) public function isExchanged()
{ {
if ($amount > $this->balance) { return $this->invoice_currency_id != $this->expense_currency_id;
$applied = $this->balance;
$this->balance = 0;
} else {
$applied = $amount;
$this->balance = $this->balance - $amount;
}
$this->save();
return $applied;
} }
} }

View File

@ -197,6 +197,11 @@ class Invoice extends EntityModel implements BalanceAffecting
return $this->hasMany('App\Models\Invitation')->orderBy('invitations.contact_id'); return $this->hasMany('App\Models\Invitation')->orderBy('invitations.contact_id');
} }
public function expenses()
{
return $this->hasMany('App\Models\Expense','invoice_id','id')->withTrashed();
}
public function markInvitationsSent($notify = false) public function markInvitationsSent($notify = false)
{ {
foreach ($this->invitations as $invitation) { foreach ($this->invitations as $invitation) {
@ -728,42 +733,24 @@ class Invoice extends EntityModel implements BalanceAffecting
$invitation = $this->invitations[0]; $invitation = $this->invitations[0];
$link = $invitation->getLink(); $link = $invitation->getLink();
$key = env('PHANTOMJS_CLOUD_KEY');
$curl = curl_init(); $curl = curl_init();
$jsonEncodedData = json_encode([ if (Utils::isNinjaDev()) {
'url' => "{$link}?phantomjs=true", $link = env('TEST_LINK');
'renderType' => 'html',
'outputAsJson' => false,
'renderSettings' => [
'passThroughHeaders' => true,
],
// 'delayTime' => 1000,
]);
$opts = [
CURLOPT_URL => PHANTOMJS_CLOUD . env('PHANTOMJS_CLOUD_KEY') . '/',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => $jsonEncodedData,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Content-Length: '.strlen($jsonEncodedData)
],
];
curl_setopt_array($curl, $opts);
$response = curl_exec($curl);
curl_close($curl);
$encodedString = strip_tags($response);
$pdfString = Utils::decodePDF($encodedString);
if ( ! $pdfString || strlen($pdfString) < 200) {
Utils::logError("PhantomJSCloud - failed to create pdf: {$encodedString}");
} }
return $pdfString; $url = "http://api.phantomjscloud.com/api/browser/v2/{$key}/?request=%7Burl:%22{$link}?phantomjs=true%22,renderType:%22html%22%7D";
$pdfString = file_get_contents($url);
$pdfString = strip_tags($pdfString);
if ( ! $pdfString || strlen($pdfString) < 200) {
Utils::logError("PhantomJSCloud - failed to create pdf: {$pdfString}");
return false;
}
return Utils::decodePDF($pdfString);
} }
} }

View File

@ -107,6 +107,11 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
return $this->account->isPro(); return $this->account->isPro();
} }
public function isPaidPro()
{
return $this->isPro() && ! $this->isTrial();
}
public function isTrial() public function isTrial()
{ {
return $this->account->isTrial(); return $this->account->isTrial();

View File

@ -124,6 +124,11 @@ class Vendor extends EntityModel
return $this->belongsTo('App\Models\Industry'); return $this->belongsTo('App\Models\Industry');
} }
public function expenses()
{
return $this->hasMany('App\Models\Expense','vendor_id','id');
}
public function addVendorContact($data, $isPrimary = false) public function addVendorContact($data, $isPrimary = false)
{ {
$publicId = isset($data['public_id']) ? $data['public_id'] : false; $publicId = isset($data['public_id']) ? $data['public_id'] : false;

View File

@ -41,6 +41,8 @@ class ContactMailer extends Mailer
$client = $invoice->client; $client = $invoice->client;
$account = $invoice->account; $account = $invoice->account;
$response = null;
if ($client->trashed()) { if ($client->trashed()) {
return trans('texts.email_errors.inactive_client'); return trans('texts.email_errors.inactive_client');
} elseif ($invoice->trashed()) { } elseif ($invoice->trashed()) {

View File

@ -64,6 +64,7 @@ class ExpenseRepository extends BaseRepository
->orWhere('contacts.is_primary', '=', null); ->orWhere('contacts.is_primary', '=', null);
}) })
->select( ->select(
DB::raw('COALESCE(expenses.invoice_id, expenses.should_be_invoiced) expense_status_id'),
'expenses.account_id', 'expenses.account_id',
'expenses.amount', 'expenses.amount',
'expenses.deleted_at', 'expenses.deleted_at',

View File

@ -418,8 +418,7 @@ class InvoiceRepository extends BaseRepository
$expense->save(); $expense->save();
} }
if ($item['product_key']) { if ($productKey = trim($item['product_key'])) {
$productKey = trim($item['product_key']);
if (\Auth::user()->account->update_products && ! strtotime($productKey)) { if (\Auth::user()->account->update_products && ! strtotime($productKey)) {
$product = Product::findProductByKey($productKey); $product = Product::findProductByKey($productKey);
if (!$product) { if (!$product) {

View File

@ -12,10 +12,14 @@ class AccountTransformer extends EntityTransformer
{ {
protected $defaultIncludes = [ protected $defaultIncludes = [
'users', 'users',
// 'clients',
'invoices',
'products', 'products',
'taxRates' 'taxRates',
'payments'
];
protected $availableIncludes = [
'clients',
'invoices',
]; ];
public function includeUsers(Account $account) public function includeUsers(Account $account)
@ -48,6 +52,12 @@ class AccountTransformer extends EntityTransformer
return $this->includeCollection($account->tax_rates, $transformer, 'taxRates'); return $this->includeCollection($account->tax_rates, $transformer, 'taxRates');
} }
public function includePayments(Account $account)
{
$transformer = new PaymentTransformer($account, $this->serializer);
return $this->includeCollection($account->payments, $transformer, 'payments');
}
public function transform(Account $account) public function transform(Account $account)
{ {
return [ return [

View File

@ -47,6 +47,7 @@ class ClientTransformer extends EntityTransformer
protected $availableIncludes = [ protected $availableIncludes = [
'invoices', 'invoices',
'credits', 'credits',
'expenses',
]; ];
public function includeContacts(Client $client) public function includeContacts(Client $client)
@ -67,6 +68,13 @@ class ClientTransformer extends EntityTransformer
return $this->includeCollection($client->credits, $transformer, ENTITY_CREDIT); return $this->includeCollection($client->credits, $transformer, ENTITY_CREDIT);
} }
public function includeExpenses(Client $client)
{
$transformer = new ExpenseTransformer($this->account, $this->serializer);
return $this->includeCollection($client->expenses, $transformer, ENTITY_EXPENSE);
}
public function transform(Client $client) public function transform(Client $client)
{ {
return [ return [

View File

@ -0,0 +1,33 @@
<?php namespace App\Ninja\Transformers;
use App\Models\Account;
use App\Models\Expense;
use League\Fractal;
class ExpenseTransformer extends EntityTransformer
{
public function transform(Expense $expense)
{
return [
'id' => (int) $expense->public_id,
'private_notes' => $expense->private_notes,
'public_notes' => $expense->public_notes,
'should_be_invoiced' => (bool) $expense->should_be_invoiced,
'updated_at' => $this->getTimestamp($expense->updated_at),
'archived_at' => $this->getTimestamp($expense->deleted_at),
'transaction_id' => $expense->transaction_id,
'bank_id' => $expense->bank_id,
'expense_currency_id' => (int) $expense->expense_currency_id,
'account_key' => $this->account->account_key,
'amount' => (float) $expense->amount,
'expense_date' => $expense->expense_date,
'exchange_rate' => (float) $expense->exchange_rate,
'invoice_currency_id' => (int) $expense->invoice_currency_id,
'is_deleted' => (bool) $expense->is_deleted,
'client_id' => isset($expense->client->public_id) ? (int) $expense->client->public_id : null,
'invoice_id' => isset($expense->invoice->public_id) ? (int) $expense->invoice->public_id : null,
'vendor_id' => isset($expense->vendor->public_id) ? (int) $expense->vendor->public_id : null,
];
}
}

View File

@ -28,6 +28,7 @@ class InvoiceTransformer extends EntityTransformer
'invitations', 'invitations',
'payments', 'payments',
'client', 'client',
'expenses',
]; ];
public function includeInvoiceItems(Invoice $invoice) public function includeInvoiceItems(Invoice $invoice)
@ -51,9 +52,16 @@ class InvoiceTransformer extends EntityTransformer
public function includeClient(Invoice $invoice) public function includeClient(Invoice $invoice)
{ {
$transformer = new ClientTransformer($this->account, $this->serializer); $transformer = new ClientTransformer($this->account, $this->serializer);
return $this->includeItem($invoice->client, $transformer, 'client'); return $this->includeItem($invoice->client, $transformer, ENTITY_CLIENT);
} }
public function includeExpenses(Invoice $invoice)
{
$transformer = new ExpenseTransformer($this->account, $this->serializer);
return $this->includeCollection($invoice->expenses, $transformer, ENTITY_EXPENSE);
}
public function transform(Invoice $invoice) public function transform(Invoice $invoice)
{ {
return [ return [

View File

@ -57,6 +57,7 @@ class PaymentTransformer extends EntityTransformer
'archived_at' => $this->getTimestamp($payment->deleted_at), 'archived_at' => $this->getTimestamp($payment->deleted_at),
'is_deleted' => (bool) $payment->is_deleted, 'is_deleted' => (bool) $payment->is_deleted,
'payment_type_id' => (int) $payment->payment_type_id, 'payment_type_id' => (int) $payment->payment_type_id,
'invoice_id' => (int) $payment->invoice->public_id,
]; ];
} }
} }

View File

@ -17,7 +17,6 @@ class VendorContactTransformer extends EntityTransformer
'archived_at' => $this->getTimestamp($contact->deleted_at), 'archived_at' => $this->getTimestamp($contact->deleted_at),
'is_primary' => (bool) $contact->is_primary, 'is_primary' => (bool) $contact->is_primary,
'phone' => $contact->phone, 'phone' => $contact->phone,
'last_login' => $contact->last_login,
'account_key' => $this->account->account_key, 'account_key' => $this->account->account_key,
]; ];
} }

View File

@ -36,14 +36,15 @@ class VendorTransformer extends EntityTransformer
*/ */
protected $availableIncludes = [ protected $availableIncludes = [
'contacts', 'vendorContacts',
'invoices', 'invoices',
'expenses',
]; ];
public function includeContacts(Vendor $vendor) public function includeVendorContacts(Vendor $vendor)
{ {
$transformer = new ContactTransformer($this->account, $this->serializer); $transformer = new VendorContactTransformer($this->account, $this->serializer);
return $this->includeCollection($vendor->contacts, $transformer, ENTITY_CONTACT); return $this->includeCollection($vendor->vendorContacts, $transformer, ENTITY_CONTACT);
} }
public function includeInvoices(Vendor $vendor) public function includeInvoices(Vendor $vendor)
@ -52,6 +53,12 @@ class VendorTransformer extends EntityTransformer
return $this->includeCollection($vendor->invoices, $transformer, ENTITY_INVOICE); return $this->includeCollection($vendor->invoices, $transformer, ENTITY_INVOICE);
} }
public function includeExpenses(Vendor $vendor)
{
$transformer = new ExpenseTransformer($this->account, $this->serializer);
return $this->includeCollection($vendor->expenses, $transformer, ENTITY_EXPENSE);
}
public function transform(Vendor $vendor) public function transform(Vendor $vendor)
{ {
return [ return [

View File

@ -41,6 +41,7 @@ class DatatableService
private function createDropdown($entityType, $table, $actions) private function createDropdown($entityType, $table, $actions)
{ {
$table->addColumn('dropdown', function ($model) use ($entityType, $actions) { $table->addColumn('dropdown', function ($model) use ($entityType, $actions) {
$hasAction = false;
$str = '<center style="min-width:100px">'; $str = '<center style="min-width:100px">';
if (property_exists($model, 'is_deleted') && $model->is_deleted) { if (property_exists($model, 'is_deleted') && $model->is_deleted) {
@ -70,6 +71,7 @@ class DatatableService
if ($visible($model)) { if ($visible($model)) {
$str .= "<li><a href=\"{$url($model)}\">{$value}</a></li>"; $str .= "<li><a href=\"{$url($model)}\">{$value}</a></li>";
$lastIsDivider = false; $lastIsDivider = false;
$hasAction = true;
} }
} elseif ( ! $lastIsDivider) { } elseif ( ! $lastIsDivider) {
$str .= "<li class=\"divider\"></li>"; $str .= "<li class=\"divider\"></li>";
@ -77,6 +79,10 @@ class DatatableService
} }
} }
if ( ! $hasAction) {
return '';
}
if ( ! $lastIsDivider) { if ( ! $lastIsDivider) {
$str .= "<li class=\"divider\"></li>"; $str .= "<li class=\"divider\"></li>";
} }

View File

@ -106,7 +106,7 @@ class ExpenseService extends BaseService
} }
], ],
[ [
'invoice_id', 'expense_status_id',
function ($model) { function ($model) {
return self::getStatusLabel($model->invoice_id, $model->should_be_invoiced); return self::getStatusLabel($model->invoice_id, $model->should_be_invoiced);
} }

View File

@ -273,10 +273,13 @@ class PaymentService extends BaseService
// submit purchase/get response // submit purchase/get response
$response = $gateway->purchase($details)->send(); $response = $gateway->purchase($details)->send();
$ref = $response->getTransactionReference();
if ($response->isSuccessful()) {
// create payment record $ref = $response->getTransactionReference();
return $this->createPayment($invitation, $accountGateway, $ref); return $this->createPayment($invitation, $accountGateway, $ref);
} else {
return false;
}
} }
public function getDatatable($clientPublicId, $search) public function getDatatable($clientPublicId, $search)

View File

@ -19,7 +19,7 @@ extensions:
modules: modules:
config: config:
Db: Db:
dsn: 'mysql:dbname=ninja;host=localhost;' dsn: 'mysql:dbname=ninja;host=127.0.0.1;'
user: 'ninja' user: 'ninja'
password: 'ninja' password: 'ninja'
dump: tests/_data/dump.sql dump: tests/_data/dump.sql

View File

@ -36,7 +36,7 @@
"omnipay/bitpay": "dev-master", "omnipay/bitpay": "dev-master",
"guzzlehttp/guzzle": "~6.0", "guzzlehttp/guzzle": "~6.0",
"laravelcollective/html": "~5.0", "laravelcollective/html": "~5.0",
"wildbit/laravel-postmark-provider": "dev-master", "wildbit/laravel-postmark-provider": "2.0",
"Dwolla/omnipay-dwolla": "dev-master", "Dwolla/omnipay-dwolla": "dev-master",
"laravel/socialite": "~2.0", "laravel/socialite": "~2.0",
"simshaun/recurr": "dev-master", "simshaun/recurr": "dev-master",
@ -69,7 +69,7 @@
"require-dev": { "require-dev": {
"phpunit/phpunit": "~4.0", "phpunit/phpunit": "~4.0",
"phpspec/phpspec": "~2.1", "phpspec/phpspec": "~2.1",
"codeception/codeception": "2.1.2", "codeception/codeception": "*",
"codeception/c3": "~2.0", "codeception/c3": "~2.0",
"fzaninotto/faker": "^1.5" "fzaninotto/faker": "^1.5"
}, },

274
composer.lock generated
View File

@ -4,8 +4,8 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"hash": "6e219bb4f5ffaf8423177bd6fccc89f8", "hash": "fceb9a043eac244cb01d8e8378e6d66a",
"content-hash": "4778ab164bfb93c4af1bb51c4320ea4c", "content-hash": "f717dc8e67caa65002f0f0689d4a5478",
"packages": [ "packages": [
{ {
"name": "agmscode/omnipay-agms", "name": "agmscode/omnipay-agms",
@ -435,12 +435,12 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/barryvdh/laravel-ide-helper.git", "url": "https://github.com/barryvdh/laravel-ide-helper.git",
"reference": "aa8f772a46c35ecdcb7119f38772ac2ec952a941" "reference": "4b8ba85b346fc9962521661aa639911535b2bb3f"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/barryvdh/laravel-ide-helper/zipball/aa8f772a46c35ecdcb7119f38772ac2ec952a941", "url": "https://api.github.com/repos/barryvdh/laravel-ide-helper/zipball/4b8ba85b346fc9962521661aa639911535b2bb3f",
"reference": "aa8f772a46c35ecdcb7119f38772ac2ec952a941", "reference": "4b8ba85b346fc9962521661aa639911535b2bb3f",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -490,7 +490,7 @@
"phpstorm", "phpstorm",
"sublime" "sublime"
], ],
"time": "2016-01-22 13:33:15" "time": "2016-01-28 08:19:58"
}, },
{ {
"name": "cardgate/omnipay-cardgate", "name": "cardgate/omnipay-cardgate",
@ -2555,12 +2555,12 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/slampenny/Swaggervel.git", "url": "https://github.com/slampenny/Swaggervel.git",
"reference": "ea47fafde4984278e27a8044a1b1b0bcfd79130c" "reference": "e026d72cacec8b2db8b2510179d73042f5e87bb9"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/slampenny/Swaggervel/zipball/ea47fafde4984278e27a8044a1b1b0bcfd79130c", "url": "https://api.github.com/repos/slampenny/Swaggervel/zipball/e026d72cacec8b2db8b2510179d73042f5e87bb9",
"reference": "ea47fafde4984278e27a8044a1b1b0bcfd79130c", "reference": "e026d72cacec8b2db8b2510179d73042f5e87bb9",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2592,7 +2592,7 @@
"laravel", "laravel",
"swagger" "swagger"
], ],
"time": "2015-08-18 15:33:39" "time": "2016-01-25 15:38:17"
}, },
{ {
"name": "jsanc623/phpbenchtime", "name": "jsanc623/phpbenchtime",
@ -2786,16 +2786,16 @@
}, },
{ {
"name": "laravel/framework", "name": "laravel/framework",
"version": "v5.0.34", "version": "v5.0.35",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laravel/framework.git", "url": "https://github.com/laravel/framework.git",
"reference": "98dbaafe8e2781f86b1b858f8610be0d7318b153" "reference": "37151cf533f468e2227605e4b9ac596154f6b92b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/98dbaafe8e2781f86b1b858f8610be0d7318b153", "url": "https://api.github.com/repos/laravel/framework/zipball/37151cf533f468e2227605e4b9ac596154f6b92b",
"reference": "98dbaafe8e2781f86b1b858f8610be0d7318b153", "reference": "37151cf533f468e2227605e4b9ac596154f6b92b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2908,7 +2908,7 @@
"framework", "framework",
"laravel" "laravel"
], ],
"time": "2015-12-04 23:20:49" "time": "2016-02-02 14:55:52"
}, },
{ {
"name": "laravel/socialite", "name": "laravel/socialite",
@ -3284,12 +3284,12 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/lokielse/omnipay-alipay.git", "url": "https://github.com/lokielse/omnipay-alipay.git",
"reference": "f39ce21a5cbfe5c7cd4108d264b398dbd42be05b" "reference": "0b091a199f1ffce95582f5e11efcf4a8ffd90ec8"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/lokielse/omnipay-alipay/zipball/f39ce21a5cbfe5c7cd4108d264b398dbd42be05b", "url": "https://api.github.com/repos/lokielse/omnipay-alipay/zipball/0b091a199f1ffce95582f5e11efcf4a8ffd90ec8",
"reference": "f39ce21a5cbfe5c7cd4108d264b398dbd42be05b", "reference": "0b091a199f1ffce95582f5e11efcf4a8ffd90ec8",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3325,7 +3325,7 @@
"payment", "payment",
"purchase" "purchase"
], ],
"time": "2016-01-19 15:08:12" "time": "2016-01-27 17:06:44"
}, },
{ {
"name": "maatwebsite/excel", "name": "maatwebsite/excel",
@ -3701,23 +3701,23 @@
}, },
{ {
"name": "mtdowling/cron-expression", "name": "mtdowling/cron-expression",
"version": "v1.0.4", "version": "v1.1.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/mtdowling/cron-expression.git", "url": "https://github.com/mtdowling/cron-expression.git",
"reference": "fd92e883195e5dfa77720b1868cf084b08be4412" "reference": "c9ee7886f5a12902b225a1a12f36bb45f9ab89e5"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/mtdowling/cron-expression/zipball/fd92e883195e5dfa77720b1868cf084b08be4412", "url": "https://api.github.com/repos/mtdowling/cron-expression/zipball/c9ee7886f5a12902b225a1a12f36bb45f9ab89e5",
"reference": "fd92e883195e5dfa77720b1868cf084b08be4412", "reference": "c9ee7886f5a12902b225a1a12f36bb45f9ab89e5",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.3.2" "php": ">=5.3.2"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "4.*" "phpunit/phpunit": "~4.0|~5.0"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@ -3741,7 +3741,7 @@
"cron", "cron",
"schedule" "schedule"
], ],
"time": "2015-01-11 23:07:46" "time": "2016-01-26 21:23:30"
}, },
{ {
"name": "nesbot/carbon", "name": "nesbot/carbon",
@ -5279,16 +5279,16 @@
}, },
{ {
"name": "omnipay/sagepay", "name": "omnipay/sagepay",
"version": "2.3.0", "version": "2.3.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/thephpleague/omnipay-sagepay.git", "url": "https://github.com/thephpleague/omnipay-sagepay.git",
"reference": "4208d23b33b2f8a59176e44ad22d304c461ecb62" "reference": "ca992b28a0d7ec7dbf218852dab36ec309dee07e"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/thephpleague/omnipay-sagepay/zipball/4208d23b33b2f8a59176e44ad22d304c461ecb62", "url": "https://api.github.com/repos/thephpleague/omnipay-sagepay/zipball/ca992b28a0d7ec7dbf218852dab36ec309dee07e",
"reference": "4208d23b33b2f8a59176e44ad22d304c461ecb62", "reference": "ca992b28a0d7ec7dbf218852dab36ec309dee07e",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -5334,7 +5334,7 @@
"sage pay", "sage pay",
"sagepay" "sagepay"
], ],
"time": "2016-01-12 12:43:31" "time": "2016-02-07 13:25:23"
}, },
{ {
"name": "omnipay/securepay", "name": "omnipay/securepay",
@ -5509,16 +5509,16 @@
}, },
{ {
"name": "omnipay/worldpay", "name": "omnipay/worldpay",
"version": "v2.1.1", "version": "v2.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/thephpleague/omnipay-worldpay.git", "url": "https://github.com/thephpleague/omnipay-worldpay.git",
"reference": "5353f02b7f800b93d8aeae606d6df09afa538457" "reference": "26ead4ca2c6ec45c9a3b3dad0be8880e0b1df083"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/thephpleague/omnipay-worldpay/zipball/5353f02b7f800b93d8aeae606d6df09afa538457", "url": "https://api.github.com/repos/thephpleague/omnipay-worldpay/zipball/26ead4ca2c6ec45c9a3b3dad0be8880e0b1df083",
"reference": "5353f02b7f800b93d8aeae606d6df09afa538457", "reference": "26ead4ca2c6ec45c9a3b3dad0be8880e0b1df083",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -5562,20 +5562,20 @@
"payment", "payment",
"worldpay" "worldpay"
], ],
"time": "2014-09-17 00:37:18" "time": "2016-01-28 12:55:58"
}, },
{ {
"name": "paragonie/random_compat", "name": "paragonie/random_compat",
"version": "1.1.5", "version": "v1.2.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/paragonie/random_compat.git", "url": "https://github.com/paragonie/random_compat.git",
"reference": "dd8998b7c846f6909f4e7a5f67fabebfc412a4f7" "reference": "b0e69d10852716b2ccbdff69c75c477637220790"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/dd8998b7c846f6909f4e7a5f67fabebfc412a4f7", "url": "https://api.github.com/repos/paragonie/random_compat/zipball/b0e69d10852716b2ccbdff69c75c477637220790",
"reference": "dd8998b7c846f6909f4e7a5f67fabebfc412a4f7", "reference": "b0e69d10852716b2ccbdff69c75c477637220790",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -5610,7 +5610,7 @@
"pseudorandom", "pseudorandom",
"random" "random"
], ],
"time": "2016-01-06 13:31:20" "time": "2016-02-06 03:52:05"
}, },
{ {
"name": "patricktalmadge/bootstrapper", "name": "patricktalmadge/bootstrapper",
@ -6158,23 +6158,27 @@
}, },
{ {
"name": "symfony/class-loader", "name": "symfony/class-loader",
"version": "v3.0.1", "version": "v3.0.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/class-loader.git", "url": "https://github.com/symfony/class-loader.git",
"reference": "6294f616bb9888ba2e13c8bfdcc4d306c1c95da7" "reference": "92e7cf1af2bc1695daabb4ac972db169606e9030"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/class-loader/zipball/6294f616bb9888ba2e13c8bfdcc4d306c1c95da7", "url": "https://api.github.com/repos/symfony/class-loader/zipball/92e7cf1af2bc1695daabb4ac972db169606e9030",
"reference": "6294f616bb9888ba2e13c8bfdcc4d306c1c95da7", "reference": "92e7cf1af2bc1695daabb4ac972db169606e9030",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.5.9" "php": ">=5.5.9"
}, },
"require-dev": { "require-dev": {
"symfony/finder": "~2.8|~3.0" "symfony/finder": "~2.8|~3.0",
"symfony/polyfill-apcu": "~1.1"
},
"suggest": {
"symfony/polyfill-apcu": "For using ApcClassLoader on HHVM"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
@ -6206,7 +6210,7 @@
], ],
"description": "Symfony ClassLoader Component", "description": "Symfony ClassLoader Component",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"time": "2015-12-05 17:45:07" "time": "2016-02-03 09:33:23"
}, },
{ {
"name": "symfony/console", "name": "symfony/console",
@ -6268,25 +6272,25 @@
}, },
{ {
"name": "symfony/css-selector", "name": "symfony/css-selector",
"version": "v2.8.2", "version": "v3.0.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/css-selector.git", "url": "https://github.com/symfony/css-selector.git",
"reference": "ac06d8173bd80790536c0a4a634a7d705b91f54f" "reference": "6605602690578496091ac20ec7a5cbd160d4dff4"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/css-selector/zipball/ac06d8173bd80790536c0a4a634a7d705b91f54f", "url": "https://api.github.com/repos/symfony/css-selector/zipball/6605602690578496091ac20ec7a5cbd160d4dff4",
"reference": "ac06d8173bd80790536c0a4a634a7d705b91f54f", "reference": "6605602690578496091ac20ec7a5cbd160d4dff4",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.3.9" "php": ">=5.5.9"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "2.8-dev" "dev-master": "3.0-dev"
} }
}, },
"autoload": { "autoload": {
@ -6317,7 +6321,7 @@
], ],
"description": "Symfony CssSelector Component", "description": "Symfony CssSelector Component",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"time": "2016-01-03 15:33:41" "time": "2016-01-27 05:14:46"
}, },
{ {
"name": "symfony/debug", "name": "symfony/debug",
@ -6673,16 +6677,16 @@
}, },
{ {
"name": "symfony/polyfill-php56", "name": "symfony/polyfill-php56",
"version": "v1.0.1", "version": "v1.1.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-php56.git", "url": "https://github.com/symfony/polyfill-php56.git",
"reference": "e2e77609a9e2328eb370fbb0e0d8b2000ebb488f" "reference": "4d891fff050101a53a4caabb03277284942d1ad9"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/e2e77609a9e2328eb370fbb0e0d8b2000ebb488f", "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/4d891fff050101a53a4caabb03277284942d1ad9",
"reference": "e2e77609a9e2328eb370fbb0e0d8b2000ebb488f", "reference": "4d891fff050101a53a4caabb03277284942d1ad9",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -6692,7 +6696,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.0-dev" "dev-master": "1.1-dev"
} }
}, },
"autoload": { "autoload": {
@ -6725,20 +6729,20 @@
"portable", "portable",
"shim" "shim"
], ],
"time": "2015-12-18 15:10:25" "time": "2016-01-20 09:13:37"
}, },
{ {
"name": "symfony/polyfill-util", "name": "symfony/polyfill-util",
"version": "v1.0.1", "version": "v1.1.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-util.git", "url": "https://github.com/symfony/polyfill-util.git",
"reference": "4271c55cbc0a77b2641f861b978123e46b3da969" "reference": "8de62801aa12bc4dfcf85eef5d21981ae7bb3cc4"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-util/zipball/4271c55cbc0a77b2641f861b978123e46b3da969", "url": "https://api.github.com/repos/symfony/polyfill-util/zipball/8de62801aa12bc4dfcf85eef5d21981ae7bb3cc4",
"reference": "4271c55cbc0a77b2641f861b978123e46b3da969", "reference": "8de62801aa12bc4dfcf85eef5d21981ae7bb3cc4",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -6747,7 +6751,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.0-dev" "dev-master": "1.1-dev"
} }
}, },
"autoload": { "autoload": {
@ -6777,7 +6781,7 @@
"polyfill", "polyfill",
"shim" "shim"
], ],
"time": "2015-11-04 20:28:58" "time": "2016-01-20 09:13:37"
}, },
{ {
"name": "symfony/process", "name": "symfony/process",
@ -7374,7 +7378,7 @@
}, },
{ {
"name": "wildbit/laravel-postmark-provider", "name": "wildbit/laravel-postmark-provider",
"version": "dev-master", "version": "2.0.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/wildbit/laravel-postmark-provider.git", "url": "https://github.com/wildbit/laravel-postmark-provider.git",
@ -7448,16 +7452,16 @@
}, },
{ {
"name": "zircote/swagger-php", "name": "zircote/swagger-php",
"version": "2.0.5", "version": "2.0.6",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/zircote/swagger-php.git", "url": "https://github.com/zircote/swagger-php.git",
"reference": "c19af4edcc13c00e82fabeee926335b1fe1d92e9" "reference": "0dfc289d53bad4a2bd193adc8d4bd058029ab417"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/zircote/swagger-php/zipball/c19af4edcc13c00e82fabeee926335b1fe1d92e9", "url": "https://api.github.com/repos/zircote/swagger-php/zipball/0dfc289d53bad4a2bd193adc8d4bd058029ab417",
"reference": "c19af4edcc13c00e82fabeee926335b1fe1d92e9", "reference": "0dfc289d53bad4a2bd193adc8d4bd058029ab417",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -7466,6 +7470,7 @@
"symfony/finder": "*" "symfony/finder": "*"
}, },
"require-dev": { "require-dev": {
"squizlabs/php_codesniffer": "2.*",
"zendframework/zend-form": "*" "zendframework/zend-form": "*"
}, },
"bin": [ "bin": [
@ -7504,26 +7509,26 @@
"rest", "rest",
"service discovery" "service discovery"
], ],
"time": "2016-01-15 09:39:28" "time": "2016-02-13 15:39:11"
} }
], ],
"packages-dev": [ "packages-dev": [
{ {
"name": "codeception/c3", "name": "codeception/c3",
"version": "2.0.5", "version": "2.0.6",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/Codeception/c3.git", "url": "https://github.com/Codeception/c3.git",
"reference": "b866ca528474ddcf74147531cc4e50b80257a5f8" "reference": "dc4d39b36d585c2eda58129407e78855ea67b1ca"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/Codeception/c3/zipball/b866ca528474ddcf74147531cc4e50b80257a5f8", "url": "https://api.github.com/repos/Codeception/c3/zipball/dc4d39b36d585c2eda58129407e78855ea67b1ca",
"reference": "b866ca528474ddcf74147531cc4e50b80257a5f8", "reference": "dc4d39b36d585c2eda58129407e78855ea67b1ca",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"composer-plugin-api": "1.0.0", "composer-plugin-api": "^1.0",
"php": ">=5.4.0" "php": ">=5.4.0"
}, },
"type": "composer-plugin", "type": "composer-plugin",
@ -7556,37 +7561,37 @@
"code coverage", "code coverage",
"codecoverage" "codecoverage"
], ],
"time": "2015-11-28 10:17:10" "time": "2016-02-09 23:31:08"
}, },
{ {
"name": "codeception/codeception", "name": "codeception/codeception",
"version": "2.1.2", "version": "2.1.6",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/Codeception/Codeception.git", "url": "https://github.com/Codeception/Codeception.git",
"reference": "521adbb2ee34e9debdd8508a2c41ab2b5c2f042b" "reference": "b199941f5e59d1e7fd32d78296c8ab98db873d89"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/Codeception/Codeception/zipball/521adbb2ee34e9debdd8508a2c41ab2b5c2f042b", "url": "https://api.github.com/repos/Codeception/Codeception/zipball/b199941f5e59d1e7fd32d78296c8ab98db873d89",
"reference": "521adbb2ee34e9debdd8508a2c41ab2b5c2f042b", "reference": "b199941f5e59d1e7fd32d78296c8ab98db873d89",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-json": "*", "ext-json": "*",
"ext-mbstring": "*", "ext-mbstring": "*",
"facebook/webdriver": ">=1.0.1", "facebook/webdriver": ">=1.0.1",
"guzzlehttp/guzzle": ">=4.0|<7.0", "guzzlehttp/guzzle": ">=4.1.4 <7.0",
"guzzlehttp/psr7": "~1.0", "guzzlehttp/psr7": "~1.0",
"php": ">=5.4.0", "php": ">=5.4.0",
"phpunit/phpunit": "~4.8.0", "phpunit/phpunit": "~4.8.0",
"symfony/browser-kit": "~2.4", "symfony/browser-kit": ">=2.4|<3.1",
"symfony/console": "~2.4", "symfony/console": ">=2.4|<3.1",
"symfony/css-selector": "~2.4", "symfony/css-selector": ">=2.4|<3.1",
"symfony/dom-crawler": "~2.4,!=2.4.5", "symfony/dom-crawler": ">=2.4|<3.1",
"symfony/event-dispatcher": "~2.4", "symfony/event-dispatcher": ">=2.4|<3.1",
"symfony/finder": "~2.4", "symfony/finder": ">=2.4|<3.1",
"symfony/yaml": "~2.4" "symfony/yaml": ">=2.4|<3.1"
}, },
"require-dev": { "require-dev": {
"codeception/specify": "~0.3", "codeception/specify": "~0.3",
@ -7636,7 +7641,7 @@
"functional testing", "functional testing",
"unit testing" "unit testing"
], ],
"time": "2015-08-09 13:48:55" "time": "2016-02-09 22:27:48"
}, },
{ {
"name": "doctrine/instantiator", "name": "doctrine/instantiator",
@ -7901,22 +7906,24 @@
}, },
{ {
"name": "phpspec/prophecy", "name": "phpspec/prophecy",
"version": "v1.5.0", "version": "v1.6.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpspec/prophecy.git", "url": "https://github.com/phpspec/prophecy.git",
"reference": "4745ded9307786b730d7a60df5cb5a6c43cf95f7" "reference": "3c91bdf81797d725b14cb62906f9a4ce44235972"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/4745ded9307786b730d7a60df5cb5a6c43cf95f7", "url": "https://api.github.com/repos/phpspec/prophecy/zipball/3c91bdf81797d725b14cb62906f9a4ce44235972",
"reference": "4745ded9307786b730d7a60df5cb5a6c43cf95f7", "reference": "3c91bdf81797d725b14cb62906f9a4ce44235972",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"doctrine/instantiator": "^1.0.2", "doctrine/instantiator": "^1.0.2",
"php": "^5.3|^7.0",
"phpdocumentor/reflection-docblock": "~2.0", "phpdocumentor/reflection-docblock": "~2.0",
"sebastian/comparator": "~1.1" "sebastian/comparator": "~1.1",
"sebastian/recursion-context": "~1.0"
}, },
"require-dev": { "require-dev": {
"phpspec/phpspec": "~2.0" "phpspec/phpspec": "~2.0"
@ -7924,7 +7931,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.4.x-dev" "dev-master": "1.5.x-dev"
} }
}, },
"autoload": { "autoload": {
@ -7957,7 +7964,7 @@
"spy", "spy",
"stub" "stub"
], ],
"time": "2015-08-13 10:07:40" "time": "2016-02-15 07:46:21"
}, },
{ {
"name": "phpunit/php-code-coverage", "name": "phpunit/php-code-coverage",
@ -8201,16 +8208,16 @@
}, },
{ {
"name": "phpunit/phpunit", "name": "phpunit/phpunit",
"version": "4.8.21", "version": "4.8.23",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git", "url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "ea76b17bced0500a28098626b84eda12dbcf119c" "reference": "6e351261f9cd33daf205a131a1ba61c6d33bd483"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ea76b17bced0500a28098626b84eda12dbcf119c", "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/6e351261f9cd33daf205a131a1ba61c6d33bd483",
"reference": "ea76b17bced0500a28098626b84eda12dbcf119c", "reference": "6e351261f9cd33daf205a131a1ba61c6d33bd483",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -8269,7 +8276,7 @@
"testing", "testing",
"xunit" "xunit"
], ],
"time": "2015-12-12 07:45:58" "time": "2016-02-11 14:56:33"
}, },
{ {
"name": "phpunit/phpunit-mock-objects", "name": "phpunit/phpunit-mock-objects",
@ -8700,25 +8707,25 @@
}, },
{ {
"name": "symfony/browser-kit", "name": "symfony/browser-kit",
"version": "v2.8.2", "version": "v3.0.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/browser-kit.git", "url": "https://github.com/symfony/browser-kit.git",
"reference": "a93dffaf763182acad12a4c42c7efc372899891e" "reference": "dde849a0485b70a24b36f826ed3fb95b904d80c3"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/browser-kit/zipball/a93dffaf763182acad12a4c42c7efc372899891e", "url": "https://api.github.com/repos/symfony/browser-kit/zipball/dde849a0485b70a24b36f826ed3fb95b904d80c3",
"reference": "a93dffaf763182acad12a4c42c7efc372899891e", "reference": "dde849a0485b70a24b36f826ed3fb95b904d80c3",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.3.9", "php": ">=5.5.9",
"symfony/dom-crawler": "~2.0,>=2.0.5|~3.0.0" "symfony/dom-crawler": "~2.8|~3.0"
}, },
"require-dev": { "require-dev": {
"symfony/css-selector": "~2.0,>=2.0.5|~3.0.0", "symfony/css-selector": "~2.8|~3.0",
"symfony/process": "~2.3.34|~2.7,>=2.7.6|~3.0.0" "symfony/process": "~2.8|~3.0"
}, },
"suggest": { "suggest": {
"symfony/process": "" "symfony/process": ""
@ -8726,7 +8733,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "2.8-dev" "dev-master": "3.0-dev"
} }
}, },
"autoload": { "autoload": {
@ -8753,28 +8760,28 @@
], ],
"description": "Symfony BrowserKit Component", "description": "Symfony BrowserKit Component",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"time": "2016-01-12 17:46:01" "time": "2016-01-27 11:34:55"
}, },
{ {
"name": "symfony/dom-crawler", "name": "symfony/dom-crawler",
"version": "v2.8.2", "version": "v3.0.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/dom-crawler.git", "url": "https://github.com/symfony/dom-crawler.git",
"reference": "650d37aacb1fa0dcc24cced483169852b3a0594e" "reference": "b693a9650aa004576b593ff2e91ae749dc90123d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/650d37aacb1fa0dcc24cced483169852b3a0594e", "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/b693a9650aa004576b593ff2e91ae749dc90123d",
"reference": "650d37aacb1fa0dcc24cced483169852b3a0594e", "reference": "b693a9650aa004576b593ff2e91ae749dc90123d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.3.9", "php": ">=5.5.9",
"symfony/polyfill-mbstring": "~1.0" "symfony/polyfill-mbstring": "~1.0"
}, },
"require-dev": { "require-dev": {
"symfony/css-selector": "~2.8|~3.0.0" "symfony/css-selector": "~2.8|~3.0"
}, },
"suggest": { "suggest": {
"symfony/css-selector": "" "symfony/css-selector": ""
@ -8782,7 +8789,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "2.8-dev" "dev-master": "3.0-dev"
} }
}, },
"autoload": { "autoload": {
@ -8809,20 +8816,20 @@
], ],
"description": "Symfony DomCrawler Component", "description": "Symfony DomCrawler Component",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"time": "2016-01-03 15:33:41" "time": "2016-01-25 09:56:57"
}, },
{ {
"name": "symfony/polyfill-mbstring", "name": "symfony/polyfill-mbstring",
"version": "v1.0.1", "version": "v1.1.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git", "url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "49ff736bd5d41f45240cec77b44967d76e0c3d25" "reference": "1289d16209491b584839022f29257ad859b8532d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/49ff736bd5d41f45240cec77b44967d76e0c3d25", "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/1289d16209491b584839022f29257ad859b8532d",
"reference": "49ff736bd5d41f45240cec77b44967d76e0c3d25", "reference": "1289d16209491b584839022f29257ad859b8532d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -8834,7 +8841,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.0-dev" "dev-master": "1.1-dev"
} }
}, },
"autoload": { "autoload": {
@ -8868,29 +8875,29 @@
"portable", "portable",
"shim" "shim"
], ],
"time": "2015-11-20 09:19:13" "time": "2016-01-20 09:13:37"
}, },
{ {
"name": "symfony/yaml", "name": "symfony/yaml",
"version": "v2.8.2", "version": "v3.0.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/yaml.git", "url": "https://github.com/symfony/yaml.git",
"reference": "34c8a4b51e751e7ea869b8262f883d008a2b81b8" "reference": "3cf0709d7fe936e97bee9e954382e449003f1d9a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/34c8a4b51e751e7ea869b8262f883d008a2b81b8", "url": "https://api.github.com/repos/symfony/yaml/zipball/3cf0709d7fe936e97bee9e954382e449003f1d9a",
"reference": "34c8a4b51e751e7ea869b8262f883d008a2b81b8", "reference": "3cf0709d7fe936e97bee9e954382e449003f1d9a",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.3.9" "php": ">=5.5.9"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "2.8-dev" "dev-master": "3.0-dev"
} }
}, },
"autoload": { "autoload": {
@ -8917,7 +8924,7 @@
], ],
"description": "Symfony Yaml Component", "description": "Symfony Yaml Component",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"time": "2016-01-13 10:28:07" "time": "2016-02-02 13:44:19"
} }
], ],
"aliases": [], "aliases": [],
@ -8935,7 +8942,6 @@
"alfaproject/omnipay-neteller": 20, "alfaproject/omnipay-neteller": 20,
"alfaproject/omnipay-skrill": 20, "alfaproject/omnipay-skrill": 20,
"omnipay/bitpay": 20, "omnipay/bitpay": 20,
"wildbit/laravel-postmark-provider": 20,
"dwolla/omnipay-dwolla": 20, "dwolla/omnipay-dwolla": 20,
"simshaun/recurr": 20, "simshaun/recurr": 20,
"meebio/omnipay-creditcall": 20, "meebio/omnipay-creditcall": 20,

View File

@ -126,6 +126,7 @@ class PaymentLibrariesSeeder extends Seeder
['name' => 'Bulgarian Lev', 'code' => 'BGN', 'symbol' => '', 'precision' => '2', 'thousand_separator' => ' ', 'decimal_separator' => '.'], ['name' => 'Bulgarian Lev', 'code' => 'BGN', 'symbol' => '', 'precision' => '2', 'thousand_separator' => ' ', 'decimal_separator' => '.'],
['name' => 'Aruban Florin', 'code' => 'AWG', 'symbol' => 'Afl. ', 'precision' => '2', 'thousand_separator' => ' ', 'decimal_separator' => '.'], ['name' => 'Aruban Florin', 'code' => 'AWG', 'symbol' => 'Afl. ', 'precision' => '2', 'thousand_separator' => ' ', 'decimal_separator' => '.'],
['name' => 'Turkish Lira', 'code' => 'TRY', 'symbol' => 'TL ', 'precision' => '2', 'thousand_separator' => '.', 'decimal_separator' => ','], ['name' => 'Turkish Lira', 'code' => 'TRY', 'symbol' => 'TL ', 'precision' => '2', 'thousand_separator' => '.', 'decimal_separator' => ','],
['name' => 'Romanian New Leu', 'code' => 'RON', 'symbol' => '', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
]; ];
foreach ($currencies as $currency) { foreach ($currencies as $currency) {

View File

@ -12,4 +12,8 @@
RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L] RewriteRule ^ index.php [L]
# In case of running InvoiceNinja in a Subdomain like invoiceninja.example.com,
# you have to enablel the following line:
# RewriteBase /
</IfModule> </IfModule>

View File

@ -5,15 +5,12 @@
# Invoice Ninja # Invoice Ninja
### [https://www.invoiceninja.com](https://www.invoiceninja.com) ### [https://www.invoiceninja.com](https://www.invoiceninja.com)
[![Build Status](https://travis-ci.org/invoiceninja/invoiceninja.svg?branch=develop)](https://travis-ci.org/invoiceninja/invoiceninja)
[![Join the chat at https://gitter.im/hillelcoren/invoice-ninja](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/hillelcoren/invoice-ninja?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Join the chat at https://gitter.im/hillelcoren/invoice-ninja](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/hillelcoren/invoice-ninja?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
### Referral Program ### Affiliates Programs
* $100 per signup paid over 3 years - [Learn more](https://www.invoiceninja.com/referral-program/) * Referral program (we pay you): $100 per signup paid over 3 years - [Learn more](https://www.invoiceninja.com/referral-program/)
* White-label reseller (you pay us): 10% of revenue with a $100 sign up fee
### Reseller Program
There are two options:
* 10% of revenue
* $1,000 for a site limited to 1,000 users
### Installation Options ### Installation Options
* [Self-Host Zip](https://www.invoiceninja.com/knowledgebase/self-host/) - Free * [Self-Host Zip](https://www.invoiceninja.com/knowledgebase/self-host/) - Free
@ -26,6 +23,10 @@ There are two options:
* MCrypt PHP Extension * MCrypt PHP Extension
* MySQL * MySQL
### Recommended Providers
* [Stripe](https://stripe.com/)
* [Postmark](https://postmarkapp.com/)
### Features ### Features
* Built using Laravel 5 * Built using Laravel 5
* Live PDF generation using [pdfmake](http://pdfmake.org/) * Live PDF generation using [pdfmake](http://pdfmake.org/)
@ -41,10 +42,6 @@ There are two options:
* Custom email templates * Custom email templates
* [D3.js](http://d3js.org/) visualizations * [D3.js](http://d3js.org/) visualizations
### Recommended Providers
* [Stripe](https://stripe.com/)
* [Postmark](https://postmarkapp.com/)
### Documentation ### Documentation
* [Ubuntu and Apache](http://blog.technerdservices.com/index.php/2015/04/techpop-how-to-install-invoice-ninja-on-ubuntu-14-04/) * [Ubuntu and Apache](http://blog.technerdservices.com/index.php/2015/04/techpop-how-to-install-invoice-ninja-on-ubuntu-14-04/)
* [Debian and Nginx](https://www.rosehosting.com/blog/install-invoice-ninja-on-a-debian-7-vps/) * [Debian and Nginx](https://www.rosehosting.com/blog/install-invoice-ninja-on-a-debian-7-vps/)

View File

@ -1,8 +1,6 @@
<?php <?php
return array( $LANG = array(
// client
'organization' => 'Organization', 'organization' => 'Organization',
'name' => 'Name', 'name' => 'Name',
'website' => 'Website', 'website' => 'Website',
@ -25,8 +23,6 @@ return array(
'size_id' => 'Company Size', 'size_id' => 'Company Size',
'industry_id' => 'Industry', 'industry_id' => 'Industry',
'private_notes' => 'Private Notes', 'private_notes' => 'Private Notes',
// invoice
'invoice' => 'Invoice', 'invoice' => 'Invoice',
'client' => 'Client', 'client' => 'Client',
'invoice_date' => 'Invoice Date', 'invoice_date' => 'Invoice Date',
@ -50,7 +46,6 @@ return array(
'invoice_design_id' => 'Design', 'invoice_design_id' => 'Design',
'terms' => 'Terms', 'terms' => 'Terms',
'your_invoice' => 'Your Invoice', 'your_invoice' => 'Your Invoice',
'remove_contact' => 'Remove contact', 'remove_contact' => 'Remove contact',
'add_contact' => 'Add contact', 'add_contact' => 'Add contact',
'create_new_client' => 'Create new client', 'create_new_client' => 'Create new client',
@ -74,8 +69,6 @@ return array(
'settings' => 'Settings', 'settings' => 'Settings',
'enable_invoice_tax' => 'Enable specifying an <b>invoice tax</b>', 'enable_invoice_tax' => 'Enable specifying an <b>invoice tax</b>',
'enable_line_item_tax' => 'Enable specifying <b>line item taxes</b>', 'enable_line_item_tax' => 'Enable specifying <b>line item taxes</b>',
// navigation
'dashboard' => 'Dashboard', 'dashboard' => 'Dashboard',
'clients' => 'Clients', 'clients' => 'Clients',
'invoices' => 'Invoices', 'invoices' => 'Invoices',
@ -100,8 +93,6 @@ return array(
'provide_email' => 'Please provide a valid email address', 'provide_email' => 'Please provide a valid email address',
'powered_by' => 'Powered by', 'powered_by' => 'Powered by',
'no_items' => 'No items', 'no_items' => 'No items',
// recurring invoices
'recurring_invoices' => 'Recurring Invoices', 'recurring_invoices' => 'Recurring Invoices',
'recurring_help' => '<p>Automatically send clients the same invoices weekly, bi-monthly, monthly, quarterly or annually. </p> 'recurring_help' => '<p>Automatically send clients the same invoices weekly, bi-monthly, monthly, quarterly or annually. </p>
<p>Use :MONTH, :QUARTER or :YEAR for dynamic dates. Basic math works as well, for example :MONTH-1.</p> <p>Use :MONTH, :QUARTER or :YEAR for dynamic dates. Basic math works as well, for example :MONTH-1.</p>
@ -111,8 +102,6 @@ return array(
<li>":YEAR+1 yearly subscription" => "2015 Yearly Subscription"</li> <li>":YEAR+1 yearly subscription" => "2015 Yearly Subscription"</li>
<li>"Retainer payment for :QUARTER+1" => "Retainer payment for Q2"</li> <li>"Retainer payment for :QUARTER+1" => "Retainer payment for Q2"</li>
</ul>', </ul>',
// dashboard
'in_total_revenue' => 'in total revenue', 'in_total_revenue' => 'in total revenue',
'billed_client' => 'billed client', 'billed_client' => 'billed client',
'billed_clients' => 'billed clients', 'billed_clients' => 'billed clients',
@ -121,8 +110,6 @@ return array(
'invoices_past_due' => 'Invoices Past Due', 'invoices_past_due' => 'Invoices Past Due',
'upcoming_invoices' => 'Upcoming Invoices', 'upcoming_invoices' => 'Upcoming Invoices',
'average_invoice' => 'Average Invoice', 'average_invoice' => 'Average Invoice',
// list pages
'archive' => 'Archive', 'archive' => 'Archive',
'delete' => 'Delete', 'delete' => 'Delete',
'archive_client' => 'Archive Client', 'archive_client' => 'Archive Client',
@ -158,8 +145,6 @@ return array(
'select' => 'Select', 'select' => 'Select',
'edit_client' => 'Edit Client', 'edit_client' => 'Edit Client',
'edit_invoice' => 'Edit Invoice', 'edit_invoice' => 'Edit Invoice',
// client view page
'create_invoice' => 'Create Invoice', 'create_invoice' => 'Create Invoice',
'enter_credit' => 'Enter Credit', 'enter_credit' => 'Enter Credit',
'last_logged_in' => 'Last logged in', 'last_logged_in' => 'Last logged in',
@ -171,12 +156,8 @@ return array(
'message' => 'Message', 'message' => 'Message',
'adjustment' => 'Adjustment', 'adjustment' => 'Adjustment',
'are_you_sure' => 'Are you sure?', 'are_you_sure' => 'Are you sure?',
// payment pages
'payment_type_id' => 'Payment Type', 'payment_type_id' => 'Payment Type',
'amount' => 'Amount', 'amount' => 'Amount',
// account/company pages
'work_email' => 'Email', 'work_email' => 'Email',
'language_id' => 'Language', 'language_id' => 'Language',
'timezone_id' => 'Timezone', 'timezone_id' => 'Timezone',
@ -206,13 +187,9 @@ return array(
'client_view_styling' => 'Client View Styling', 'client_view_styling' => 'Client View Styling',
'pdf_email_attachment' => 'Attach PDFs', 'pdf_email_attachment' => 'Attach PDFs',
'custom_css' => 'Custom CSS', 'custom_css' => 'Custom CSS',
//import CSV data pages
'import_clients' => 'Import Client Data', 'import_clients' => 'Import Client Data',
'csv_file' => 'CSV file', 'csv_file' => 'CSV file',
'export_clients' => 'Export Client Data', 'export_clients' => 'Export Client Data',
// application messages
'created_client' => 'Successfully created client', 'created_client' => 'Successfully created client',
'created_clients' => 'Successfully created :count client(s)', 'created_clients' => 'Successfully created :count client(s)',
'updated_settings' => 'Successfully updated settings', 'updated_settings' => 'Successfully updated settings',
@ -223,14 +200,12 @@ return array(
'payment_error' => 'There was an error processing your payment. Please try again later.', 'payment_error' => 'There was an error processing your payment. Please try again later.',
'registration_required' => 'Please sign up to email an invoice', 'registration_required' => 'Please sign up to email an invoice',
'confirmation_required' => 'Please confirm your email address', 'confirmation_required' => 'Please confirm your email address',
'updated_client' => 'Successfully updated client', 'updated_client' => 'Successfully updated client',
'created_client' => 'Successfully created client', 'created_client' => 'Successfully created client',
'archived_client' => 'Successfully archived client', 'archived_client' => 'Successfully archived client',
'archived_clients' => 'Successfully archived :count clients', 'archived_clients' => 'Successfully archived :count clients',
'deleted_client' => 'Successfully deleted client', 'deleted_client' => 'Successfully deleted client',
'deleted_clients' => 'Successfully deleted :count clients', 'deleted_clients' => 'Successfully deleted :count clients',
'updated_invoice' => 'Successfully updated invoice', 'updated_invoice' => 'Successfully updated invoice',
'created_invoice' => 'Successfully created invoice', 'created_invoice' => 'Successfully created invoice',
'cloned_invoice' => 'Successfully cloned invoice', 'cloned_invoice' => 'Successfully cloned invoice',
@ -240,7 +215,6 @@ return array(
'archived_invoices' => 'Successfully archived :count invoices', 'archived_invoices' => 'Successfully archived :count invoices',
'deleted_invoice' => 'Successfully deleted invoice', 'deleted_invoice' => 'Successfully deleted invoice',
'deleted_invoices' => 'Successfully deleted :count invoices', 'deleted_invoices' => 'Successfully deleted :count invoices',
'created_payment' => 'Successfully created payment', 'created_payment' => 'Successfully created payment',
'created_payments' => 'Successfully created :count payment(s)', 'created_payments' => 'Successfully created :count payment(s)',
'archived_payment' => 'Successfully archived payment', 'archived_payment' => 'Successfully archived payment',
@ -248,22 +222,18 @@ return array(
'deleted_payment' => 'Successfully deleted payment', 'deleted_payment' => 'Successfully deleted payment',
'deleted_payments' => 'Successfully deleted :count payments', 'deleted_payments' => 'Successfully deleted :count payments',
'applied_payment' => 'Successfully applied payment', 'applied_payment' => 'Successfully applied payment',
'created_credit' => 'Successfully created credit', 'created_credit' => 'Successfully created credit',
'archived_credit' => 'Successfully archived credit', 'archived_credit' => 'Successfully archived credit',
'archived_credits' => 'Successfully archived :count credits', 'archived_credits' => 'Successfully archived :count credits',
'deleted_credit' => 'Successfully deleted credit', 'deleted_credit' => 'Successfully deleted credit',
'deleted_credits' => 'Successfully deleted :count credits', 'deleted_credits' => 'Successfully deleted :count credits',
'imported_file' => 'Successfully imported file', 'imported_file' => 'Successfully imported file',
'updated_vendor' => 'Successfully updated vendor', 'updated_vendor' => 'Successfully updated vendor',
'created_vendor' => 'Successfully created vendor', 'created_vendor' => 'Successfully created vendor',
'archived_vendor' => 'Successfully archived vendor', 'archived_vendor' => 'Successfully archived vendor',
'archived_vendors' => 'Successfully archived :count vendors', 'archived_vendors' => 'Successfully archived :count vendors',
'deleted_vendor' => 'Successfully deleted vendor', 'deleted_vendor' => 'Successfully deleted vendor',
'deleted_vendors' => 'Successfully deleted :count vendors', 'deleted_vendors' => 'Successfully deleted :count vendors',
// Emails
'confirmation_subject' => 'Invoice Ninja Account Confirmation', 'confirmation_subject' => 'Invoice Ninja Account Confirmation',
'confirmation_header' => 'Account Confirmation', 'confirmation_header' => 'Account Confirmation',
'confirmation_message' => 'Please access the link below to confirm your account.', 'confirmation_message' => 'Please access the link below to confirm your account.',
@ -274,7 +244,6 @@ return array(
'email_salutation' => 'Dear :name,', 'email_salutation' => 'Dear :name,',
'email_signature' => 'Regards,', 'email_signature' => 'Regards,',
'email_from' => 'The Invoice Ninja Team', 'email_from' => 'The Invoice Ninja Team',
'user_email_footer' => 'To adjust your email notification settings please visit '.SITE_URL.'/settings/notifications',
'invoice_link_message' => 'To view the invoice click the link below:', 'invoice_link_message' => 'To view the invoice click the link below:',
'notification_invoice_paid_subject' => 'Invoice :invoice was paid by :client', 'notification_invoice_paid_subject' => 'Invoice :invoice was paid by :client',
'notification_invoice_sent_subject' => 'Invoice :invoice was sent to :client', 'notification_invoice_sent_subject' => 'Invoice :invoice was sent to :client',
@ -283,32 +252,11 @@ return array(
'notification_invoice_sent' => 'The following client :client was emailed Invoice :invoice for :amount.', 'notification_invoice_sent' => 'The following client :client was emailed Invoice :invoice for :amount.',
'notification_invoice_viewed' => 'The following client :client viewed Invoice :invoice for :amount.', 'notification_invoice_viewed' => 'The following client :client viewed Invoice :invoice for :amount.',
'reset_password' => 'You can reset your account password by clicking the following button:', 'reset_password' => 'You can reset your account password by clicking the following button:',
'reset_password_footer' => 'If you did not request this password reset please email our support: '.CONTACT_EMAIL,
// Payment page
'secure_payment' => 'Secure Payment', 'secure_payment' => 'Secure Payment',
'card_number' => 'Card Number', 'card_number' => 'Card Number',
'expiration_month' => 'Expiration Month', 'expiration_month' => 'Expiration Month',
'expiration_year' => 'Expiration Year', 'expiration_year' => 'Expiration Year',
'cvv' => 'CVV', 'cvv' => 'CVV',
// Security alerts
'security' => [
'too_many_attempts' => 'Too many attempts. Try again in few minutes.',
'wrong_credentials' => 'Incorrect email or password.',
'confirmation' => 'Your account has been confirmed!',
'wrong_confirmation' => 'Wrong confirmation code.',
'password_forgot' => 'The information regarding password reset was sent to your email.',
'password_reset' => 'Your password has been changed successfully.',
'wrong_password_reset' => 'Invalid password. Try again',
],
// Pro Plan
'pro_plan' => [
'remove_logo' => ':link to remove the Invoice Ninja logo by joining the Pro Plan',
'remove_logo_link' => 'Click here',
],
'logout' => 'Log Out', 'logout' => 'Log Out',
'sign_up_to_save' => 'Sign up to save your work', 'sign_up_to_save' => 'Sign up to save your work',
'agree_to_terms' => 'I agree to the Invoice Ninja :terms', 'agree_to_terms' => 'I agree to the Invoice Ninja :terms',
@ -319,7 +267,6 @@ return array(
'success_message' => 'You have successfully registered! Please visit the link in the account confirmation email to verify your email address.', 'success_message' => 'You have successfully registered! Please visit the link in the account confirmation email to verify your email address.',
'erase_data' => 'This will permanently erase your data.', 'erase_data' => 'This will permanently erase your data.',
'password' => 'Password', 'password' => 'Password',
'pro_plan_product' => 'Pro Plan', 'pro_plan_product' => 'Pro Plan',
'pro_plan_description' => 'One year enrollment in the Invoice Ninja Pro Plan.', 'pro_plan_description' => 'One year enrollment in the Invoice Ninja Pro Plan.',
'pro_plan_success' => 'Thanks for choosing Invoice Ninja\'s Pro plan!<p/>&nbsp;<br/> 'pro_plan_success' => 'Thanks for choosing Invoice Ninja\'s Pro plan!<p/>&nbsp;<br/>
@ -329,7 +276,6 @@ return array(
for a year of Pro-level invoicing.<p/> for a year of Pro-level invoicing.<p/>
Can\'t find the invoice? Need further assistance? We\'re happy to help Can\'t find the invoice? Need further assistance? We\'re happy to help
-- email us at contact@invoiceninja.com', -- email us at contact@invoiceninja.com',
'unsaved_changes' => 'You have unsaved changes', 'unsaved_changes' => 'You have unsaved changes',
'custom_fields' => 'Custom Fields', 'custom_fields' => 'Custom Fields',
'company_fields' => 'Company Fields', 'company_fields' => 'Company Fields',
@ -339,8 +285,6 @@ return array(
'edit' => 'Edit', 'edit' => 'Edit',
'set_name' => 'Set your company name', 'set_name' => 'Set your company name',
'view_as_recipient' => 'View as recipient', 'view_as_recipient' => 'View as recipient',
// product management
'product_library' => 'Product Library', 'product_library' => 'Product Library',
'product' => 'Product', 'product' => 'Product',
'products' => 'Product Library', 'products' => 'Product Library',
@ -355,18 +299,14 @@ return array(
'created_product' => 'Successfully created product', 'created_product' => 'Successfully created product',
'archived_product' => 'Successfully archived product', 'archived_product' => 'Successfully archived product',
'pro_plan_custom_fields' => ':link to enable custom fields by joining the Pro Plan', 'pro_plan_custom_fields' => ':link to enable custom fields by joining the Pro Plan',
'advanced_settings' => 'Advanced Settings', 'advanced_settings' => 'Advanced Settings',
'pro_plan_advanced_settings' => ':link to enable the advanced settings by joining the Pro Plan', 'pro_plan_advanced_settings' => ':link to enable the advanced settings by joining the Pro Plan',
'invoice_design' => 'Invoice Design', 'invoice_design' => 'Invoice Design',
'specify_colors' => 'Specify colors', 'specify_colors' => 'Specify colors',
'specify_colors_label' => 'Select the colors used in the invoice', 'specify_colors_label' => 'Select the colors used in the invoice',
'chart_builder' => 'Chart Builder', 'chart_builder' => 'Chart Builder',
'ninja_email_footer' => 'Use :site to invoice your clients and get paid online for free!', 'ninja_email_footer' => 'Use :site to invoice your clients and get paid online for free!',
'go_pro' => 'Go Pro', 'go_pro' => 'Go Pro',
// Quotes
'quote' => 'Quote', 'quote' => 'Quote',
'quotes' => 'Quotes', 'quotes' => 'Quotes',
'quote_number' => 'Quote Number', 'quote_number' => 'Quote Number',
@ -376,7 +316,6 @@ return array(
'your_quote' => 'Your Quote', 'your_quote' => 'Your Quote',
'total' => 'Total', 'total' => 'Total',
'clone' => 'Clone', 'clone' => 'Clone',
'new_quote' => 'New Quote', 'new_quote' => 'New Quote',
'create_quote' => 'Create Quote', 'create_quote' => 'Create Quote',
'edit_quote' => 'Edit Quote', 'edit_quote' => 'Edit Quote',
@ -389,7 +328,6 @@ return array(
'view_invoice' => 'View Invoice', 'view_invoice' => 'View Invoice',
'view_client' => 'View Client', 'view_client' => 'View Client',
'view_quote' => 'View Quote', 'view_quote' => 'View Quote',
'updated_quote' => 'Successfully updated quote', 'updated_quote' => 'Successfully updated quote',
'created_quote' => 'Successfully created quote', 'created_quote' => 'Successfully created quote',
'cloned_quote' => 'Successfully cloned quote', 'cloned_quote' => 'Successfully cloned quote',
@ -399,7 +337,6 @@ return array(
'deleted_quote' => 'Successfully deleted quote', 'deleted_quote' => 'Successfully deleted quote',
'deleted_quotes' => 'Successfully deleted :count quotes', 'deleted_quotes' => 'Successfully deleted :count quotes',
'converted_to_invoice' => 'Successfully converted quote to invoice', 'converted_to_invoice' => 'Successfully converted quote to invoice',
'quote_subject' => 'New quote $quote from :account', 'quote_subject' => 'New quote $quote from :account',
'quote_message' => 'To view your quote for :amount, click the link below.', 'quote_message' => 'To view your quote for :amount, click the link below.',
'quote_link_message' => 'To view your client quote click the link below:', 'quote_link_message' => 'To view your client quote click the link below:',
@ -407,16 +344,13 @@ return array(
'notification_quote_viewed_subject' => 'Quote :invoice was viewed by :client', 'notification_quote_viewed_subject' => 'Quote :invoice was viewed by :client',
'notification_quote_sent' => 'The following client :client was emailed Quote :invoice for :amount.', 'notification_quote_sent' => 'The following client :client was emailed Quote :invoice for :amount.',
'notification_quote_viewed' => 'The following client :client viewed Quote :invoice for :amount.', 'notification_quote_viewed' => 'The following client :client viewed Quote :invoice for :amount.',
'session_expired' => 'Your session has expired.', 'session_expired' => 'Your session has expired.',
'invoice_fields' => 'Invoice Fields', 'invoice_fields' => 'Invoice Fields',
'invoice_options' => 'Invoice Options', 'invoice_options' => 'Invoice Options',
'hide_quantity' => 'Hide Quantity', 'hide_quantity' => 'Hide Quantity',
'hide_quantity_help' => 'If your line items quantities are always 1, then you can declutter invoices by no longer displaying this field.', 'hide_quantity_help' => 'If your line items quantities are always 1, then you can declutter invoices by no longer displaying this field.',
'hide_paid_to_date' => 'Hide Paid to Date', 'hide_paid_to_date' => 'Hide Paid to Date',
'hide_paid_to_date_help' => 'Only display the "Paid to Date" area on your invoices once a payment has been received.', 'hide_paid_to_date_help' => 'Only display the "Paid to Date" area on your invoices once a payment has been received.',
'charge_taxes' => 'Charge taxes', 'charge_taxes' => 'Charge taxes',
'user_management' => 'User Management', 'user_management' => 'User Management',
'add_user' => 'Add User', 'add_user' => 'Add User',
@ -431,21 +365,16 @@ return array(
'active' => 'Active', 'active' => 'Active',
'pending' => 'Pending', 'pending' => 'Pending',
'deleted_user' => 'Successfully deleted user', 'deleted_user' => 'Successfully deleted user',
'limit_users' => 'Sorry, this will exceed the limit of '.MAX_NUM_USERS.' users',
'confirm_email_invoice' => 'Are you sure you want to email this invoice?', 'confirm_email_invoice' => 'Are you sure you want to email this invoice?',
'confirm_email_quote' => 'Are you sure you want to email this quote?', 'confirm_email_quote' => 'Are you sure you want to email this quote?',
'confirm_recurring_email_invoice' => 'Are you sure you want this invoice emailed?', 'confirm_recurring_email_invoice' => 'Are you sure you want this invoice emailed?',
'cancel_account' => 'Cancel Account', 'cancel_account' => 'Cancel Account',
'cancel_account_message' => 'Warning: This will permanently erase all of your data, there is no undo.', 'cancel_account_message' => 'Warning: This will permanently erase all of your data, there is no undo.',
'go_back' => 'Go Back', 'go_back' => 'Go Back',
'data_visualizations' => 'Data Visualizations', 'data_visualizations' => 'Data Visualizations',
'sample_data' => 'Sample data shown', 'sample_data' => 'Sample data shown',
'hide' => 'Hide', 'hide' => 'Hide',
'new_version_available' => 'A new version of :releases_link is available. You\'re running v:user_version, the latest is v:latest_version', 'new_version_available' => 'A new version of :releases_link is available. You\'re running v:user_version, the latest is v:latest_version',
'invoice_settings' => 'Invoice Settings', 'invoice_settings' => 'Invoice Settings',
'invoice_number_prefix' => 'Invoice Number Prefix', 'invoice_number_prefix' => 'Invoice Number Prefix',
'invoice_number_counter' => 'Invoice Number Counter', 'invoice_number_counter' => 'Invoice Number Counter',
@ -455,59 +384,48 @@ return array(
'invoice_issued_to' => 'Invoice issued to', 'invoice_issued_to' => 'Invoice issued to',
'invalid_counter' => 'To prevent a possible conflict please set either an invoice or quote number prefix', 'invalid_counter' => 'To prevent a possible conflict please set either an invoice or quote number prefix',
'mark_sent' => 'Mark Sent', 'mark_sent' => 'Mark Sent',
'gateway_help_1' => ':link to sign up for Authorize.net.', 'gateway_help_1' => ':link to sign up for Authorize.net.',
'gateway_help_2' => ':link to sign up for Authorize.net.', 'gateway_help_2' => ':link to sign up for Authorize.net.',
'gateway_help_17' => ':link to get your PayPal API signature.', 'gateway_help_17' => ':link to get your PayPal API signature.',
'gateway_help_27' => ':link to sign up for TwoCheckout.', 'gateway_help_27' => ':link to sign up for TwoCheckout.',
'more_designs' => 'More designs', 'more_designs' => 'More designs',
'more_designs_title' => 'Additional Invoice Designs', 'more_designs_title' => 'Additional Invoice Designs',
'more_designs_cloud_header' => 'Go Pro for more invoice designs', 'more_designs_cloud_header' => 'Go Pro for more invoice designs',
'more_designs_cloud_text' => '', 'more_designs_cloud_text' => '',
'more_designs_self_host_header' => 'Get 6 more invoice designs for just $'.INVOICE_DESIGNS_PRICE,
'more_designs_self_host_text' => '', 'more_designs_self_host_text' => '',
'buy' => 'Buy', 'buy' => 'Buy',
'bought_designs' => 'Successfully added additional invoice designs', 'bought_designs' => 'Successfully added additional invoice designs',
'sent' => 'sent', 'sent' => 'sent',
'vat_number' => 'VAT Number', 'vat_number' => 'VAT Number',
'timesheets' => 'Timesheets', 'timesheets' => 'Timesheets',
'payment_title' => 'Enter Your Billing Address and Credit Card information', 'payment_title' => 'Enter Your Billing Address and Credit Card information',
'payment_cvv' => '*This is the 3-4 digit number onthe back of your card', 'payment_cvv' => '*This is the 3-4 digit number onthe back of your card',
'payment_footer1' => '*Billing address must match address associated with credit card.', 'payment_footer1' => '*Billing address must match address associated with credit card.',
'payment_footer2' => '*Please click "PAY NOW" only once - transaction may take up to 1 minute to process.', 'payment_footer2' => '*Please click "PAY NOW" only once - transaction may take up to 1 minute to process.',
'id_number' => 'ID Number', 'id_number' => 'ID Number',
'white_label_link' => 'White label', 'white_label_link' => 'White label',
'white_label_header' => 'White Label', 'white_label_header' => 'White Label',
'bought_white_label' => 'Successfully enabled white label license', 'bought_white_label' => 'Successfully enabled white label license',
'white_labeled' => 'White labeled', 'white_labeled' => 'White labeled',
'restore' => 'Restore', 'restore' => 'Restore',
'restore_invoice' => 'Restore Invoice', 'restore_invoice' => 'Restore Invoice',
'restore_quote' => 'Restore Quote', 'restore_quote' => 'Restore Quote',
'restore_client' => 'Restore Client', 'restore_client' => 'Restore Client',
'restore_credit' => 'Restore Credit', 'restore_credit' => 'Restore Credit',
'restore_payment' => 'Restore Payment', 'restore_payment' => 'Restore Payment',
'restored_invoice' => 'Successfully restored invoice', 'restored_invoice' => 'Successfully restored invoice',
'restored_quote' => 'Successfully restored quote', 'restored_quote' => 'Successfully restored quote',
'restored_client' => 'Successfully restored client', 'restored_client' => 'Successfully restored client',
'restored_payment' => 'Successfully restored payment', 'restored_payment' => 'Successfully restored payment',
'restored_credit' => 'Successfully restored credit', 'restored_credit' => 'Successfully restored credit',
'reason_for_canceling' => 'Help us improve our site by telling us why you\'re leaving.', 'reason_for_canceling' => 'Help us improve our site by telling us why you\'re leaving.',
'discount_percent' => 'Percent', 'discount_percent' => 'Percent',
'discount_amount' => 'Amount', 'discount_amount' => 'Amount',
'invoice_history' => 'Invoice History', 'invoice_history' => 'Invoice History',
'quote_history' => 'Quote History', 'quote_history' => 'Quote History',
'current_version' => 'Current version', 'current_version' => 'Current version',
'select_versiony' => 'Select version', 'select_versiony' => 'Select version',
'view_history' => 'View History', 'view_history' => 'View History',
'edit_payment' => 'Edit Payment', 'edit_payment' => 'Edit Payment',
'updated_payment' => 'Successfully updated payment', 'updated_payment' => 'Successfully updated payment',
'deleted' => 'Deleted', 'deleted' => 'Deleted',
@ -520,7 +438,6 @@ return array(
'quote_email' => 'Quote Email', 'quote_email' => 'Quote Email',
'reset_all' => 'Reset All', 'reset_all' => 'Reset All',
'approve' => 'Approve', 'approve' => 'Approve',
'token_billing_type_id' => 'Token Billing', 'token_billing_type_id' => 'Token Billing',
'token_billing_help' => 'Enables you to store credit cards with your gateway, and charge them at a later date.', 'token_billing_help' => 'Enables you to store credit cards with your gateway, and charge them at a later date.',
'token_billing_1' => 'Disabled', 'token_billing_1' => 'Disabled',
@ -533,7 +450,6 @@ return array(
'edit_payment_details' => 'Edit payment details', 'edit_payment_details' => 'Edit payment details',
'token_billing' => 'Save card details', 'token_billing' => 'Save card details',
'token_billing_secure' => 'The data is stored securely by :stripe_link', 'token_billing_secure' => 'The data is stored securely by :stripe_link',
'support' => 'Support', 'support' => 'Support',
'contact_information' => 'Contact Information', 'contact_information' => 'Contact Information',
'256_encryption' => '256-Bit Encryption', '256_encryption' => '256-Bit Encryption',
@ -543,10 +459,8 @@ return array(
'order_overview' => 'Order overview', 'order_overview' => 'Order overview',
'match_address' => '*Address must match address associated with credit card.', 'match_address' => '*Address must match address associated with credit card.',
'click_once' => '*Please click "PAY NOW" only once - transaction may take up to 1 minute to process.', 'click_once' => '*Please click "PAY NOW" only once - transaction may take up to 1 minute to process.',
'invoice_footer' => 'Invoice Footer', 'invoice_footer' => 'Invoice Footer',
'save_as_default_footer' => 'Save as default footer', 'save_as_default_footer' => 'Save as default footer',
'token_management' => 'Token Management', 'token_management' => 'Token Management',
'tokens' => 'Tokens', 'tokens' => 'Tokens',
'add_token' => 'Add Token', 'add_token' => 'Add Token',
@ -557,7 +471,6 @@ return array(
'edit_token' => 'Edit Token', 'edit_token' => 'Edit Token',
'delete_token' => 'Delete Token', 'delete_token' => 'Delete Token',
'token' => 'Token', 'token' => 'Token',
'add_gateway' => 'Add Gateway', 'add_gateway' => 'Add Gateway',
'delete_gateway' => 'Delete Gateway', 'delete_gateway' => 'Delete Gateway',
'edit_gateway' => 'Edit Gateway', 'edit_gateway' => 'Edit Gateway',
@ -566,7 +479,6 @@ return array(
'deleted_gateway' => 'Successfully deleted gateway', 'deleted_gateway' => 'Successfully deleted gateway',
'pay_with_paypal' => 'PayPal', 'pay_with_paypal' => 'PayPal',
'pay_with_card' => 'Credit Card', 'pay_with_card' => 'Credit Card',
'change_password' => 'Change password', 'change_password' => 'Change password',
'current_password' => 'Current password', 'current_password' => 'Current password',
'new_password' => 'New password', 'new_password' => 'New password',
@ -574,7 +486,6 @@ return array(
'password_error_incorrect' => 'The current password is incorrect.', 'password_error_incorrect' => 'The current password is incorrect.',
'password_error_invalid' => 'The new password is invalid.', 'password_error_invalid' => 'The new password is invalid.',
'updated_password' => 'Successfully updated password', 'updated_password' => 'Successfully updated password',
'api_tokens' => 'API Tokens', 'api_tokens' => 'API Tokens',
'users_and_tokens' => 'Users & Tokens', 'users_and_tokens' => 'Users & Tokens',
'account_login' => 'Account Login', 'account_login' => 'Account Login',
@ -582,18 +493,15 @@ return array(
'forgot_password' => 'Forgot your password?', 'forgot_password' => 'Forgot your password?',
'email_address' => 'Email address', 'email_address' => 'Email address',
'lets_go' => 'Let\'s go', 'lets_go' => 'Let\'s go',
//'lets_go' => 'Login',
'password_recovery' => 'Password Recovery', 'password_recovery' => 'Password Recovery',
'send_email' => 'Send email', 'send_email' => 'Send email',
'set_password' => 'Set Password', 'set_password' => 'Set Password',
'converted' => 'Converted', 'converted' => 'Converted',
'email_approved' => 'Email me when a quote is <b>approved</b>', 'email_approved' => 'Email me when a quote is <b>approved</b>',
'notification_quote_approved_subject' => 'Quote :invoice was approved by :client', 'notification_quote_approved_subject' => 'Quote :invoice was approved by :client',
'notification_quote_approved' => 'The following client :client approved Quote :invoice for :amount.', 'notification_quote_approved' => 'The following client :client approved Quote :invoice for :amount.',
'resend_confirmation' => 'Resend confirmation email', 'resend_confirmation' => 'Resend confirmation email',
'confirmation_resent' => 'The confirmation email was resent', 'confirmation_resent' => 'The confirmation email was resent',
'gateway_help_42' => ':link to sign up for BitPay.<br/>Note: use a Legacy API Key, not an API token.', 'gateway_help_42' => ':link to sign up for BitPay.<br/>Note: use a Legacy API Key, not an API token.',
'payment_type_credit_card' => 'Credit Card', 'payment_type_credit_card' => 'Credit Card',
'payment_type_paypal' => 'PayPal', 'payment_type_paypal' => 'PayPal',
@ -601,7 +509,6 @@ return array(
'knowledge_base' => 'Knowledge Base', 'knowledge_base' => 'Knowledge Base',
'partial' => 'Partial', 'partial' => 'Partial',
'partial_remaining' => ':partial of :balance', 'partial_remaining' => ':partial of :balance',
'more_fields' => 'More Fields', 'more_fields' => 'More Fields',
'less_fields' => 'Less Fields', 'less_fields' => 'Less Fields',
'client_name' => 'Client Name', 'client_name' => 'Client Name',
@ -612,7 +519,6 @@ return array(
'view_documentation' => 'View Documentation', 'view_documentation' => 'View Documentation',
'app_title' => 'Free Open-Source Online Invoicing', 'app_title' => 'Free Open-Source Online Invoicing',
'app_description' => 'Invoice Ninja is a free, open-source solution for invoicing and billing customers. With Invoice Ninja, you can easily build and send beautiful invoices from any device that has access to the web. Your clients can print your invoices, download them as pdf files, and even pay you online from within the system.', 'app_description' => 'Invoice Ninja is a free, open-source solution for invoicing and billing customers. With Invoice Ninja, you can easily build and send beautiful invoices from any device that has access to the web. Your clients can print your invoices, download them as pdf files, and even pay you online from within the system.',
'rows' => 'rows', 'rows' => 'rows',
'www' => 'www', 'www' => 'www',
'logo' => 'Logo', 'logo' => 'Logo',
@ -632,7 +538,6 @@ return array(
'zapier' => 'Zapier', 'zapier' => 'Zapier',
'recurring' => 'Recurring', 'recurring' => 'Recurring',
'last_invoice_sent' => 'Last invoice sent :date', 'last_invoice_sent' => 'Last invoice sent :date',
'processed_updates' => 'Successfully completed update', 'processed_updates' => 'Successfully completed update',
'tasks' => 'Tasks', 'tasks' => 'Tasks',
'new_task' => 'New Task', 'new_task' => 'New Task',
@ -678,12 +583,10 @@ return array(
'invoice_labels' => 'Invoice Labels', 'invoice_labels' => 'Invoice Labels',
'prefix' => 'Prefix', 'prefix' => 'Prefix',
'counter' => 'Counter', 'counter' => 'Counter',
'payment_type_dwolla' => 'Dwolla', 'payment_type_dwolla' => 'Dwolla',
'gateway_help_43' => ':link to sign up for Dwolla', 'gateway_help_43' => ':link to sign up for Dwolla',
'partial_value' => 'Must be greater than zero and less than the total', 'partial_value' => 'Must be greater than zero and less than the total',
'more_actions' => 'More Actions', 'more_actions' => 'More Actions',
'pro_plan_title' => 'NINJA PRO', 'pro_plan_title' => 'NINJA PRO',
'pro_plan_call_to_action' => 'Upgrade Now!', 'pro_plan_call_to_action' => 'Upgrade Now!',
'pro_plan_feature1' => 'Create Unlimited Clients', 'pro_plan_feature1' => 'Create Unlimited Clients',
@ -694,14 +597,12 @@ return array(
'pro_plan_feature6' => 'Create Quotes & Pro-forma Invoices', 'pro_plan_feature6' => 'Create Quotes & Pro-forma Invoices',
'pro_plan_feature7' => 'Customize Invoice Field Titles & Numbering', 'pro_plan_feature7' => 'Customize Invoice Field Titles & Numbering',
'pro_plan_feature8' => 'Option to Attach PDFs to Client Emails', 'pro_plan_feature8' => 'Option to Attach PDFs to Client Emails',
'resume' => 'Resume', 'resume' => 'Resume',
'break_duration' => 'Break', 'break_duration' => 'Break',
'edit_details' => 'Edit Details', 'edit_details' => 'Edit Details',
'work' => 'Work', 'work' => 'Work',
'timezone_unset' => 'Please :link to set your timezone', 'timezone_unset' => 'Please :link to set your timezone',
'click_here' => 'click here', 'click_here' => 'click here',
'email_receipt' => 'Email payment receipt to the client', 'email_receipt' => 'Email payment receipt to the client',
'created_payment_emailed_client' => 'Successfully created payment and emailed client', 'created_payment_emailed_client' => 'Successfully created payment and emailed client',
'add_company' => 'Add Company', 'add_company' => 'Add Company',
@ -711,10 +612,8 @@ return array(
'unlinked_account' => 'Successfully unlinked accounts', 'unlinked_account' => 'Successfully unlinked accounts',
'login' => 'Login', 'login' => 'Login',
'or' => 'or', 'or' => 'or',
'email_error' => 'There was a problem sending the email', 'email_error' => 'There was a problem sending the email',
'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.', 'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.',
'old_browser' => 'Please use a <a href="'.OUTDATE_BROWSER_URL.'" target="_blank">newer browser</a>',
'payment_terms_help' => 'Sets the default invoice due date', 'payment_terms_help' => 'Sets the default invoice due date',
'unlink_account' => 'Unlink Account', 'unlink_account' => 'Unlink Account',
'unlink' => 'Unlink', 'unlink' => 'Unlink',
@ -735,7 +634,6 @@ return array(
'primary_color' => 'Primary Color', 'primary_color' => 'Primary Color',
'secondary_color' => 'Secondary Color', 'secondary_color' => 'Secondary Color',
'customize_design' => 'Customize Design', 'customize_design' => 'Customize Design',
'content' => 'Content', 'content' => 'Content',
'styles' => 'Styles', 'styles' => 'Styles',
'defaults' => 'Defaults', 'defaults' => 'Defaults',
@ -749,7 +647,6 @@ return array(
'outstanding' => 'Outstanding', 'outstanding' => 'Outstanding',
'manage_companies' => 'Manage Companies', 'manage_companies' => 'Manage Companies',
'total_revenue' => 'Total Revenue', 'total_revenue' => 'Total Revenue',
'current_user' => 'Current User', 'current_user' => 'Current User',
'new_recurring_invoice' => 'New Recurring Invoice', 'new_recurring_invoice' => 'New Recurring Invoice',
'recurring_invoice' => 'Recurring Invoice', 'recurring_invoice' => 'Recurring Invoice',
@ -761,7 +658,6 @@ return array(
<p>You can access any invoice field by adding <code>Value</code> to the end. For example <code>$invoiceNumberValue</code> displays the invoice number.</p> <p>You can access any invoice field by adding <code>Value</code> to the end. For example <code>$invoiceNumberValue</code> displays the invoice number.</p>
<p>To access a child property using dot notation. For example to show the client name you could use <code>$client.nameValue</code>.</p> <p>To access a child property using dot notation. For example to show the client name you could use <code>$client.nameValue</code>.</p>
<p>If you need help figuring something out post a question to our <a href="https://www.invoiceninja.com/forums/forum/support/" target="_blank">support forum</a>.</p>', <p>If you need help figuring something out post a question to our <a href="https://www.invoiceninja.com/forums/forum/support/" target="_blank">support forum</a>.</p>',
'invoice_due_date' => 'Due Date', 'invoice_due_date' => 'Due Date',
'quote_due_date' => 'Valid Until', 'quote_due_date' => 'Valid Until',
'valid_until' => 'Valid Until', 'valid_until' => 'Valid Until',
@ -774,15 +670,12 @@ return array(
'status_partial' => 'Partial', 'status_partial' => 'Partial',
'status_paid' => 'Paid', 'status_paid' => 'Paid',
'show_line_item_tax' => 'Display <b>line item taxes inline</b>', 'show_line_item_tax' => 'Display <b>line item taxes inline</b>',
'iframe_url' => 'Website', 'iframe_url' => 'Website',
'iframe_url_help1' => 'Copy the following code to a page on your site.', 'iframe_url_help1' => 'Copy the following code to a page on your site.',
'iframe_url_help2' => 'You can test the feature by clicking \'View as recipient\' for an invoice.', 'iframe_url_help2' => 'You can test the feature by clicking \'View as recipient\' for an invoice.',
'auto_bill' => 'Auto Bill', 'auto_bill' => 'Auto Bill',
'military_time' => '24 Hour Time', 'military_time' => '24 Hour Time',
'last_sent' => 'Last Sent', 'last_sent' => 'Last Sent',
'reminder_emails' => 'Reminder Emails', 'reminder_emails' => 'Reminder Emails',
'templates_and_reminders' => 'Templates & Reminders', 'templates_and_reminders' => 'Templates & Reminders',
'subject' => 'Subject', 'subject' => 'Subject',
@ -794,15 +687,12 @@ return array(
'reminder_subject' => 'Reminder: Invoice :invoice from :account', 'reminder_subject' => 'Reminder: Invoice :invoice from :account',
'reset' => 'Reset', 'reset' => 'Reset',
'invoice_not_found' => 'The requested invoice is not available', 'invoice_not_found' => 'The requested invoice is not available',
'referral_program' => 'Referral Program', 'referral_program' => 'Referral Program',
'referral_code' => 'Referral URL', 'referral_code' => 'Referral URL',
'last_sent_on' => 'Sent Last: :date', 'last_sent_on' => 'Sent Last: :date',
'page_expire' => 'This page will expire soon, :click_here to keep working', 'page_expire' => 'This page will expire soon, :click_here to keep working',
'upcoming_quotes' => 'Upcoming Quotes', 'upcoming_quotes' => 'Upcoming Quotes',
'expired_quotes' => 'Expired Quotes', 'expired_quotes' => 'Expired Quotes',
'sign_up_using' => 'Sign up using', 'sign_up_using' => 'Sign up using',
'invalid_credentials' => 'These credentials do not match our records', 'invalid_credentials' => 'These credentials do not match our records',
'show_all_options' => 'Show all options', 'show_all_options' => 'Show all options',
@ -811,18 +701,10 @@ return array(
'disable' => 'Disable', 'disable' => 'Disable',
'invoice_quote_number' => 'Invoice and Quote Numbers', 'invoice_quote_number' => 'Invoice and Quote Numbers',
'invoice_charges' => 'Invoice Charges', 'invoice_charges' => 'Invoice Charges',
'invitation_status' => [
'sent' => 'Email Sent',
'opened' => 'Email Openend',
'viewed' => 'Invoice Viewed',
],
'notification_invoice_bounced' => 'We were unable to deliver Invoice :invoice to :contact.', 'notification_invoice_bounced' => 'We were unable to deliver Invoice :invoice to :contact.',
'notification_invoice_bounced_subject' => 'Unable to deliver Invoice :invoice', 'notification_invoice_bounced_subject' => 'Unable to deliver Invoice :invoice',
'notification_quote_bounced' => 'We were unable to deliver Quote :invoice to :contact.', 'notification_quote_bounced' => 'We were unable to deliver Quote :invoice to :contact.',
'notification_quote_bounced_subject' => 'Unable to deliver Quote :invoice', 'notification_quote_bounced_subject' => 'Unable to deliver Quote :invoice',
'custom_invoice_link' => 'Custom Invoice Link', 'custom_invoice_link' => 'Custom Invoice Link',
'total_invoiced' => 'Total Invoiced', 'total_invoiced' => 'Total Invoiced',
'open_balance' => 'Open Balance', 'open_balance' => 'Open Balance',
@ -830,15 +712,12 @@ return array(
'basic_settings' => 'Basic Settings', 'basic_settings' => 'Basic Settings',
'pro' => 'Pro', 'pro' => 'Pro',
'gateways' => 'Payment Gateways', 'gateways' => 'Payment Gateways',
'next_send_on' => 'Send Next: :date', 'next_send_on' => 'Send Next: :date',
'no_longer_running' => 'This invoice is not scheduled to run', 'no_longer_running' => 'This invoice is not scheduled to run',
'general_settings' => 'General Settings', 'general_settings' => 'General Settings',
'customize' => 'Customize', 'customize' => 'Customize',
'oneclick_login_help' => 'Connect an account to login without a password', 'oneclick_login_help' => 'Connect an account to login without a password',
'referral_code_help' => 'Earn money by sharing our app online', 'referral_code_help' => 'Earn money by sharing our app online',
'enable_with_stripe' => 'Enable | Requires Stripe', 'enable_with_stripe' => 'Enable | Requires Stripe',
'tax_settings' => 'Tax Settings', 'tax_settings' => 'Tax Settings',
'create_tax_rate' => 'Add Tax Rate', 'create_tax_rate' => 'Add Tax Rate',
@ -859,7 +738,6 @@ return array(
'invoice_counter' => 'Invoice Counter', 'invoice_counter' => 'Invoice Counter',
'quote_counter' => 'Quote Counter', 'quote_counter' => 'Quote Counter',
'type' => 'Type', 'type' => 'Type',
'activity_1' => ':user created client :client', 'activity_1' => ':user created client :client',
'activity_2' => ':user archived client :client', 'activity_2' => ':user archived client :client',
'activity_3' => ':user deleted client :client', 'activity_3' => ':user deleted client :client',
@ -897,7 +775,6 @@ return array(
'activity_35' => ':user created :vendor', 'activity_35' => ':user created :vendor',
'activity_36' => ':user created :vendor', 'activity_36' => ':user created :vendor',
'activity_37' => ':user created :vendor', 'activity_37' => ':user created :vendor',
'payment' => 'Payment', 'payment' => 'Payment',
'system' => 'System', 'system' => 'System',
'signature' => 'Email Signature', 'signature' => 'Email Signature',
@ -908,7 +785,6 @@ return array(
'default_invoice_footer' => 'Default Invoice Footer', 'default_invoice_footer' => 'Default Invoice Footer',
'quote_footer' => 'Quote Footer', 'quote_footer' => 'Quote Footer',
'free' => 'Free', 'free' => 'Free',
'quote_is_approved' => 'This quote is approved', 'quote_is_approved' => 'This quote is approved',
'apply_credit' => 'Apply Credit', 'apply_credit' => 'Apply Credit',
'system_settings' => 'System Settings', 'system_settings' => 'System Settings',
@ -926,7 +802,6 @@ return array(
'restored_recurring_invoice' => 'Successfully restored recurring invoice', 'restored_recurring_invoice' => 'Successfully restored recurring invoice',
'archived' => 'Archived', 'archived' => 'Archived',
'untitled_account' => 'Untitled Company', 'untitled_account' => 'Untitled Company',
'before' => 'Before', 'before' => 'Before',
'after' => 'After', 'after' => 'After',
'reset_terms_help' => 'Reset to the default account terms', 'reset_terms_help' => 'Reset to the default account terms',
@ -935,7 +810,6 @@ return array(
'user' => 'User', 'user' => 'User',
'country' => 'Country', 'country' => 'Country',
'include' => 'Include', 'include' => 'Include',
'logo_too_large' => 'Your logo is :size, for better PDF performance we suggest uploading an image file less than 200KB', 'logo_too_large' => 'Your logo is :size, for better PDF performance we suggest uploading an image file less than 200KB',
'import_freshbooks' => 'Import From FreshBooks', 'import_freshbooks' => 'Import From FreshBooks',
'import_data' => 'Import Data', 'import_data' => 'Import Data',
@ -946,16 +820,6 @@ return array(
'task_file' => 'Task File', 'task_file' => 'Task File',
'no_mapper' => 'No valid mapping for file', 'no_mapper' => 'No valid mapping for file',
'invalid_csv_header' => 'Invalid CSV Header', 'invalid_csv_header' => 'Invalid CSV Header',
'email_errors' => [
'inactive_client' => 'Emails can not be sent to inactive clients',
'inactive_contact' => 'Emails can not be sent to inactive contacts',
'inactive_invoice' => 'Emails can not be sent to inactive invoices',
'user_unregistered' => 'Please register your account to send emails',
'user_unconfirmed' => 'Please confirm your account to send emails',
'invalid_contact_email' => 'Invalid contact email',
],
'client_portal' => 'Client Portal', 'client_portal' => 'Client Portal',
'admin' => 'Admin', 'admin' => 'Admin',
'disabled' => 'Disabled', 'disabled' => 'Disabled',
@ -964,11 +828,9 @@ return array(
'invoice_will_create' => 'client will be created', 'invoice_will_create' => 'client will be created',
'invoices_will_create' => 'invoices will be created', 'invoices_will_create' => 'invoices will be created',
'failed_to_import' => 'The following records failed to import', 'failed_to_import' => 'The following records failed to import',
'publishable_key' => 'Publishable Key', 'publishable_key' => 'Publishable Key',
'secret_key' => 'Secret Key', 'secret_key' => 'Secret Key',
'missing_publishable_key' => 'Set your Stripe publishable key for an improved checkout process', 'missing_publishable_key' => 'Set your Stripe publishable key for an improved checkout process',
'email_design' => 'Email Design', 'email_design' => 'Email Design',
'due_by' => 'Due by :date', 'due_by' => 'Due by :date',
'enable_email_markup' => 'Enable Markup', 'enable_email_markup' => 'Enable Markup',
@ -980,7 +842,6 @@ return array(
'plain' => 'Plain', 'plain' => 'Plain',
'light' => 'Light', 'light' => 'Light',
'dark' => 'Dark', 'dark' => 'Dark',
'industry_help' => 'Used to provide comparisons against the averages of companies of similar size and industry.', 'industry_help' => 'Used to provide comparisons against the averages of companies of similar size and industry.',
'subdomain_help' => 'Customize the invoice link subdomain or display the invoice on your own website.', 'subdomain_help' => 'Customize the invoice link subdomain or display the invoice on your own website.',
'invoice_number_help' => 'Specify a prefix or use a custom pattern to dynamically set the invoice number.', 'invoice_number_help' => 'Specify a prefix or use a custom pattern to dynamically set the invoice number.',
@ -989,7 +850,6 @@ return array(
'custom_account_fields_helps' => 'Add a label and value to the company details section of the PDF.', 'custom_account_fields_helps' => 'Add a label and value to the company details section of the PDF.',
'custom_invoice_fields_helps' => 'Add a text input to the invoice create/edit page and display the label and value on the PDF.', 'custom_invoice_fields_helps' => 'Add a text input to the invoice create/edit page and display the label and value on the PDF.',
'custom_invoice_charges_helps' => 'Add a text input to the invoice create/edit page and include the charge in the invoice subtotals.', 'custom_invoice_charges_helps' => 'Add a text input to the invoice create/edit page and include the charge in the invoice subtotals.',
'token_expired' => 'Validation token was expired. Please try again.', 'token_expired' => 'Validation token was expired. Please try again.',
'invoice_link' => 'Invoice Link', 'invoice_link' => 'Invoice Link',
'button_confirmation_message' => 'Click to confirm your email address.', 'button_confirmation_message' => 'Click to confirm your email address.',
@ -998,7 +858,6 @@ return array(
'created_invoices' => 'Successfully created :count invoice(s)', 'created_invoices' => 'Successfully created :count invoice(s)',
'next_invoice_number' => 'The next invoice number is :number.', 'next_invoice_number' => 'The next invoice number is :number.',
'next_quote_number' => 'The next quote number is :number.', 'next_quote_number' => 'The next quote number is :number.',
'days_before' => 'days before', 'days_before' => 'days before',
'days_after' => 'days after', 'days_after' => 'days after',
'field_due_date' => 'due date', 'field_due_date' => 'due date',
@ -1006,11 +865,7 @@ return array(
'schedule' => 'Schedule', 'schedule' => 'Schedule',
'email_designs' => 'Email Designs', 'email_designs' => 'Email Designs',
'assigned_when_sent' => 'Assigned when sent', 'assigned_when_sent' => 'Assigned when sent',
'white_label_custom_css' => ':link for $'.WHITE_LABEL_PRICE.' to enable custom styling and help support our project.',
'white_label_purchase_link' => 'Purchase a white label license', 'white_label_purchase_link' => 'Purchase a white label license',
// Expense / vendor
'expense' => 'Expense', 'expense' => 'Expense',
'expenses' => 'Expenses', 'expenses' => 'Expenses',
'new_expense' => 'Enter Expense', 'new_expense' => 'Enter Expense',
@ -1027,8 +882,6 @@ return array(
'archived_expense' => 'Successfully archived expense', 'archived_expense' => 'Successfully archived expense',
'deleted_expenses' => 'Successfully deleted expenses', 'deleted_expenses' => 'Successfully deleted expenses',
'archived_expenses' => 'Successfully archived expenses', 'archived_expenses' => 'Successfully archived expenses',
// Expenses
'expense_amount' => 'Expense Amount', 'expense_amount' => 'Expense Amount',
'expense_balance' => 'Expense Balance', 'expense_balance' => 'Expense Balance',
'expense_date' => 'Expense Date', 'expense_date' => 'Expense Date',
@ -1053,15 +906,11 @@ return array(
'expense_error_multiple_clients' => 'The expenses can\'t belong to different clients', 'expense_error_multiple_clients' => 'The expenses can\'t belong to different clients',
'expense_error_invoiced' => 'Expense has already been invoiced', 'expense_error_invoiced' => 'Expense has already been invoiced',
'convert_currency' => 'Convert currency', 'convert_currency' => 'Convert currency',
// Payment terms
'num_days' => 'Number of days', 'num_days' => 'Number of days',
'create_payment_term' => 'Create Payment Term', 'create_payment_term' => 'Create Payment Term',
'edit_payment_terms' => 'Edit Payment Term', 'edit_payment_terms' => 'Edit Payment Term',
'edit_payment_term' => 'Edit Payment Term', 'edit_payment_term' => 'Edit Payment Term',
'archive_payment_term' => 'Archive Payment Term', 'archive_payment_term' => 'Archive Payment Term',
// recurring due dates
'recurring_due_dates' => 'Recurring Invoice Due Dates', 'recurring_due_dates' => 'Recurring Invoice Due Dates',
'recurring_due_date_help' => '<p>Automatically sets a due date for the invoice.</p> 'recurring_due_date_help' => '<p>Automatically sets a due date for the invoice.</p>
<p>Invoices on a monthly or yearly cycle set to be due on or before the day they are created will be due the next month. Invoices set to be due on the 29th or 30th in months that don\'t have that day will be due the last day of the month.</p> <p>Invoices on a monthly or yearly cycle set to be due on or before the day they are created will be due the next month. Invoices set to be due on the 29th or 30th in months that don\'t have that day will be due the last day of the month.</p>
@ -1089,15 +938,11 @@ return array(
'thursday' => 'Thursday', 'thursday' => 'Thursday',
'friday' => 'Friday', 'friday' => 'Friday',
'saturday' => 'Saturday', 'saturday' => 'Saturday',
// Fonts
'header_font_id' => 'Header Font', 'header_font_id' => 'Header Font',
'body_font_id' => 'Body Font', 'body_font_id' => 'Body Font',
'color_font_help' => 'Note: the primary color and fonts are also used in the client portal and custom email designs.', 'color_font_help' => 'Note: the primary color and fonts are also used in the client portal and custom email designs.',
'live_preview' => 'Live Preview', 'live_preview' => 'Live Preview',
'invalid_mail_config' => 'Unable to send email, please check that the mail settings are correct.', 'invalid_mail_config' => 'Unable to send email, please check that the mail settings are correct.',
'invoice_message_button' => 'To view your invoice for :amount, click the button below.', 'invoice_message_button' => 'To view your invoice for :amount, click the button below.',
'quote_message_button' => 'To view your quote for :amount, click the button below.', 'quote_message_button' => 'To view your quote for :amount, click the button below.',
'payment_message_button' => 'Thank you for your payment of :amount.', 'payment_message_button' => 'Thank you for your payment of :amount.',
@ -1114,7 +959,6 @@ return array(
'archived_bank_account' => 'Successfully archived bank account', 'archived_bank_account' => 'Successfully archived bank account',
'created_bank_account' => 'Successfully created bank account', 'created_bank_account' => 'Successfully created bank account',
'validate_bank_account' => 'Validate Bank Account', 'validate_bank_account' => 'Validate Bank Account',
'bank_accounts_help' => 'Connect a bank account to automatically import expenses and create vendors. Supports American Express and <a href="'.OFX_HOME_URL.'" target="_blank">400+ US banks.</a>',
'bank_password_help' => 'Note: your password is transmitted securely and never stored on our servers.', 'bank_password_help' => 'Note: your password is transmitted securely and never stored on our servers.',
'bank_password_warning' => 'Warning: your password may be transmitted in plain text, consider enabling HTTPS.', 'bank_password_warning' => 'Warning: your password may be transmitted in plain text, consider enabling HTTPS.',
'username' => 'Username', 'username' => 'Username',
@ -1128,7 +972,6 @@ return array(
'validate' => 'Validate', 'validate' => 'Validate',
'info' => 'Info', 'info' => 'Info',
'imported_expenses' => 'Successfully created :count_vendors vendor(s) and :count_expenses expense(s)', 'imported_expenses' => 'Successfully created :count_vendors vendor(s) and :count_expenses expense(s)',
'iframe_url_help3' => 'Note: if you plan on accepting credit cards details we strongly recommend enabling HTTPS on your site.', 'iframe_url_help3' => 'Note: if you plan on accepting credit cards details we strongly recommend enabling HTTPS on your site.',
'expense_error_multiple_currencies' => 'The expenses can\'t have different currencies.', 'expense_error_multiple_currencies' => 'The expenses can\'t have different currencies.',
'expense_error_mismatch_currencies' => 'The client\'s currency does not match the expense currency.', 'expense_error_mismatch_currencies' => 'The client\'s currency does not match the expense currency.',
@ -1149,6 +992,44 @@ return array(
'trial_call_to_action' => 'Start Free Trial', 'trial_call_to_action' => 'Start Free Trial',
'trial_success' => 'Successfully enabled two week free pro plan trial', 'trial_success' => 'Successfully enabled two week free pro plan trial',
'overdue' => 'Overdue', 'overdue' => 'Overdue',
'white_label_text' => 'Purchase a ONE YEAR white label license for $'.WHITE_LABEL_PRICE.' to remove the Invoice Ninja branding from the client portal and help support our project.', 'white_label_text' => 'Purchase a ONE YEAR white label license for $'.WHITE_LABEL_PRICE.' to remove the Invoice Ninja branding from the client portal and help support our project.',
'user_email_footer' => 'To adjust your email notification settings please visit '.SITE_URL.'/settings/notifications',
'reset_password_footer' => 'If you did not request this password reset please email our support: '.CONTACT_EMAIL,
'limit_users' => 'Sorry, this will exceed the limit of '.MAX_NUM_USERS.' users',
'more_designs_self_host_header' => 'Get 6 more invoice designs for just $'.INVOICE_DESIGNS_PRICE,
'old_browser' => 'Please use a <a href="'.OUTDATE_BROWSER_URL.'" target="_blank">newer browser</a>',
'white_label_custom_css' => ':link for $'.WHITE_LABEL_PRICE.' to enable custom styling and help support our project.',
'bank_accounts_help' => 'Connect a bank account to automatically import expenses and create vendors. Supports American Express and <a href="'.OFX_HOME_URL.'" target="_blank">400+ US banks.</a>',
'security' => [
'too_many_attempts' => 'Too many attempts. Try again in few minutes.',
'wrong_credentials' => 'Incorrect email or password.',
'confirmation' => 'Your account has been confirmed!',
'wrong_confirmation' => 'Wrong confirmation code.',
'password_forgot' => 'The information regarding password reset was sent to your email.',
'password_reset' => 'Your password has been changed successfully.',
'wrong_password_reset' => 'Invalid password. Try again',
],
'pro_plan' => [
'remove_logo' => ':link to remove the Invoice Ninja logo by joining the Pro Plan',
'remove_logo_link' => 'Click here',
],
'invitation_status' => [
'sent' => 'Email Sent',
'opened' => 'Email Openend',
'viewed' => 'Invoice Viewed',
],
'email_errors' => [
'inactive_client' => 'Emails can not be sent to inactive clients',
'inactive_contact' => 'Emails can not be sent to inactive contacts',
'inactive_invoice' => 'Emails can not be sent to inactive invoices',
'user_unregistered' => 'Please register your account to send emails',
'user_unconfirmed' => 'Please confirm your account to send emails',
'invalid_contact_email' => 'Invalid contact email',
],
); );
return $LANG;
?>.

View File

@ -42,9 +42,13 @@
function setTrashVisible() { function setTrashVisible() {
var checked = $('#trashed').is(':checked'); var checked = $('#trashed').is(':checked');
window.location = '{!! URL::to('view_archive/token') !!}' + (checked ? '/true' : '/false'); var url = '{{ URL::to('view_archive/token') }}' + (checked ? '/true' : '/false');
$.get(url, function(data) {
refreshDatatable();
})
} }
</script> </script>
@stop @stop

View File

@ -39,7 +39,11 @@
function setTrashVisible() { function setTrashVisible() {
var checked = $('#trashed').is(':checked'); var checked = $('#trashed').is(':checked');
window.location = '{!! URL::to('view_archive/user') !!}' + (checked ? '/true' : '/false'); var url = '{{ URL::to('view_archive/user') }}' + (checked ? '/true' : '/false');
$.get(url, function(data) {
refreshDatatable();
})
} }
</script> </script>

View File

@ -22,7 +22,7 @@
@section('content') @section('content')
<div class="row"> <div class="row">
<div class="col-md-8"> <div class="col-md-7">
<div> <div>
<span style="font-size:28px">{{ $client->getDisplayName() }}</span> <span style="font-size:28px">{{ $client->getDisplayName() }}</span>
@if ($client->trashed()) @if ($client->trashed())
@ -30,7 +30,7 @@
@endif @endif
</div> </div>
</div> </div>
<div class="col-md-4"> <div class="col-md-5">
<div class="pull-right"> <div class="pull-right">
{!! Former::open('clients/bulk')->addClass('mainForm') !!} {!! Former::open('clients/bulk')->addClass('mainForm') !!}
<div style="display:none"> <div style="display:none">

View File

@ -42,8 +42,12 @@
}); });
@endif @endif
function refreshDatatable() {
window.dataTable.api().ajax.reload();
}
function load_{{ $class }}() { function load_{{ $class }}() {
jQuery('.{{ $class }}').dataTable({ window.dataTable = jQuery('.{{ $class }}').dataTable({
"fnRowCallback": function(row, data) { "fnRowCallback": function(row, data) {
if (data[0].indexOf('ENTITY_DELETED') > 0) { if (data[0].indexOf('ENTITY_DELETED') > 0) {
$(row).addClass('entityDeleted'); $(row).addClass('entityDeleted');

View File

@ -59,40 +59,50 @@
->data_bind('combobox: client_id') ->data_bind('combobox: client_id')
->addGroupClass('client-select') !!} ->addGroupClass('client-select') !!}
@if (!$expense || ($expense && !$expense->invoice_id)) @if (!$expense || ($expense && !$expense->invoice_id && !$expense->client_id))
{!! Former::checkbox('should_be_invoiced') {!! Former::checkbox('should_be_invoiced')
->text(trans('texts.should_be_invoiced')) ->text(trans('texts.should_be_invoiced'))
->data_bind('checked: should_be_invoiced() || client_id(), enable: !client_id()') ->data_bind('checked: should_be_invoiced() || client_id(), enable: !client_id()')
->label(' ') !!}<br/> ->label(' ') !!}
@endif @endif
<span style="display:none" data-bind="visible: !client_id()"> @if (!$expense || ($expense && ! $expense->isExchanged()))
{!! Former::select('invoice_currency_id')->addOption('','') {!! Former::checkbox('convert_currency')
->label(trans('texts.invoice_currency')) ->text(trans('texts.convert_currency'))
->data_placeholder(Utils::getFromCache($account->getCurrencyId(), 'currencies')->name) ->data_bind('checked: convert_currency')
->data_bind('combobox: invoice_currency_id, disable: true') ->label(' ') !!}
->fromQuery($currencies, 'name', 'id') !!} @endif
</span> <br/>
<span style="display:none;" data-bind="visible: client_id">
{!! Former::plaintext('test')
->value('<span data-bind="html: invoiceCurrencyName"></span>')
->style('min-height:46px')
->label(trans('texts.invoice_currency')) !!}
</span>
{!! Former::text('exchange_rate') <div style="display:none" data-bind="visible: enableExchangeRate">
->data_bind("value: exchange_rate, enable: enableExchangeRate, valueUpdate: 'afterkeydown'") !!} <span style="display:none" data-bind="visible: !client_id()">
{!! Former::select('invoice_currency_id')->addOption('','')
->label(trans('texts.invoice_currency'))
->data_placeholder(Utils::getFromCache($account->getCurrencyId(), 'currencies')->name)
->data_bind('combobox: invoice_currency_id, disable: true')
->fromQuery($currencies, 'name', 'id') !!}
</span>
<span style="display:none;" data-bind="visible: client_id">
{!! Former::plaintext('test')
->value('<span data-bind="html: invoiceCurrencyName"></span>')
->style('min-height:46px')
->label(trans('texts.invoice_currency')) !!}
</span>
{!! Former::text('invoice_amount') {!! Former::text('exchange_rate')
->addGroupClass('converted-amount') ->data_bind("value: exchange_rate, enable: enableExchangeRate, valueUpdate: 'afterkeydown'") !!}
->data_bind("value: convertedAmount, enable: enableExchangeRate")
->append('<span data-bind="html: invoiceCurrencyCode"></span>') !!}
{!! Former::text('invoice_amount')
->addGroupClass('converted-amount')
->data_bind("value: convertedAmount, enable: enableExchangeRate")
->append('<span data-bind="html: invoiceCurrencyCode"></span>') !!}
</div>
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
{!! Former::textarea('public_notes')->style('height:255px') !!} {!! Former::textarea('public_notes')->rows(8) !!}
{!! Former::textarea('private_notes')->style('height:255px') !!} {!! Former::textarea('private_notes')->rows(8) !!}
</div> </div>
</div> </div>
</div> </div>
@ -150,7 +160,7 @@
} }
$vendorSelect.combobox(); $vendorSelect.combobox();
$('#expense_date').datepicker('update', new Date()); $('#expense_date').datepicker('update', '{{ $expense ? $expense->expense_date : 'new Date()' }}');
$('.expense_date .input-group-addon').click(function() { $('.expense_date .input-group-addon').click(function() {
toggleDatePicker('expense_date'); toggleDatePicker('expense_date');
@ -194,6 +204,7 @@
self.amount = ko.observable(); self.amount = ko.observable();
self.exchange_rate = ko.observable(1); self.exchange_rate = ko.observable(1);
self.should_be_invoiced = ko.observable(); self.should_be_invoiced = ko.observable();
self.convert_currency = ko.observable(false);
if (data) { if (data) {
ko.mapping.fromJS(data, {}, this); ko.mapping.fromJS(data, {}, this);
@ -230,9 +241,14 @@
}); });
self.enableExchangeRate = ko.computed(function() { self.enableExchangeRate = ko.computed(function() {
if (self.convert_currency()) {
return true;
}
var expenseCurrencyId = self.expense_currency_id() || self.account_currency_id(); var expenseCurrencyId = self.expense_currency_id() || self.account_currency_id();
var invoiceCurrencyId = self.invoice_currency_id() || self.account_currency_id(); var invoiceCurrencyId = self.invoice_currency_id() || self.account_currency_id();
return expenseCurrencyId != invoiceCurrencyId; return expenseCurrencyId != invoiceCurrencyId
|| invoiceCurrencyId != self.account_currency_id()
|| expenseCurrencyId != self.account_currency_id();
}) })
}; };

View File

@ -259,8 +259,10 @@
} }
function showSearch() { function showSearch() {
$('#search-form').show(); $('#search').typeahead('setQuery', '');
$('#navbar-options').hide(); $('#navbar-options').hide();
$('#search-form').show();
if (window.hasOwnProperty('searchData')) { if (window.hasOwnProperty('searchData')) {
$('#search').focus(); $('#search').focus();
} else { } else {
@ -289,7 +291,6 @@
} }
function hideSearch() { function hideSearch() {
$('#search').typeahead('setQuery', '');
$('#search-form').hide(); $('#search-form').hide();
$('#navbar-options').show(); $('#navbar-options').show();
} }
@ -299,7 +300,7 @@
$(".alert-hide").fadeOut(); $(".alert-hide").fadeOut();
}, 3000); }, 3000);
$('#search').blur(function(){ $('#search').blur(function(event){
hideSearch(); hideSearch();
}); });
@ -331,7 +332,7 @@
showSignUp(); showSignUp();
@endif @endif
$('ul.navbar-settings, ul.navbar-history').hover(function () { $('ul.navbar-settings, ul.navbar-search').hover(function () {
if ($('.user-accounts').css('display') == 'block') { if ($('.user-accounts').css('display') == 'block') {
$('.user-accounts').dropdown('toggle'); $('.user-accounts').dropdown('toggle');
} }
@ -351,6 +352,14 @@
}); });
@endif @endif
// Focus the search input if the user clicks forward slash
$('body').keypress(function(event) {
if (event.which == 47) {
event.preventDefault();
showSearch();
}
});
}); });
</script> </script>
@ -396,7 +405,7 @@
<div class="btn-group user-dropdown"> <div class="btn-group user-dropdown">
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown"> <button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown">
<div id="myAccountButton" class="ellipsis" style="max-width:{{ Utils::isPro() && ! Utils::isTrial() ? '100' : '70' }}px"> <div id="myAccountButton" class="ellipsis" style="max-width:{{ Utils::isPro() && ! Utils::isTrial() ? '130' : '100' }}px">
@if (session(SESSION_USER_ACCOUNTS) && count(session(SESSION_USER_ACCOUNTS))) @if (session(SESSION_USER_ACCOUNTS) && count(session(SESSION_USER_ACCOUNTS)))
{{ Auth::user()->account->getDisplayName() }} {{ Auth::user()->account->getDisplayName() }}
@else @else
@ -466,10 +475,10 @@
</ul> </ul>
<ul class="nav navbar-nav navbar-right navbar-history"> <ul class="nav navbar-nav navbar-right navbar-search">
<li class="dropdown"> <li class="dropdown">
<a href="{{ Utils::getLastURL() }}" class="dropdown-toggle"> <a href="#" onclick="showSearch()">
<span class="glyphicon glyphicon-time" title="{{ trans('texts.history') }}"/> <span class="glyphicon glyphicon-search" title="{{ trans('texts.search') }}"/>
</a> </a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
@if (count(Session::get(RECENTLY_VIEWED)) == 0) @if (count(Session::get(RECENTLY_VIEWED)) == 0)
@ -484,19 +493,11 @@
</ul> </ul>
</li> </li>
</ul> </ul>
<ul class="nav navbar-nav navbar-right navbar-settings">
<li class="dropdown">
<a href="#" onclick="showSearch()">
<span class="glyphicon glyphicon-search" title="{{ trans('texts.search') }}"/>
</a>
</li>
</ul>
</div> </div>
<form id="search-form" class="navbar-form navbar-right" role="search" style="display:none"> <form id="search-form" class="navbar-form navbar-right" role="search" style="display:none">
<div class="form-group"> <div class="form-group">
<input type="text" id="search" style="width: 300px;padding-top:0px;padding-bottom:0px" <input type="text" id="search" style="width: 240px;padding-top:0px;padding-bottom:0px"
class="form-control" placeholder="{{ trans('texts.search') }}"> class="form-control" placeholder="{{ trans('texts.search') }}">
</div> </div>
</form> </form>

View File

@ -101,7 +101,11 @@
function setTrashVisible() { function setTrashVisible() {
var checked = $('#trashed').is(':checked'); var checked = $('#trashed').is(':checked');
window.location = '{{ URL::to('view_archive/' . $entityType) }}' + (checked ? '/true' : '/false'); var url = '{{ URL::to('view_archive/' . $entityType) }}' + (checked ? '/true' : '/false');
$.get(url, function(data) {
refreshDatatable();
})
} }
$(function() { $(function() {

View File

@ -127,17 +127,16 @@
//console.log(JSON.stringify(products)); //console.log(JSON.stringify(products));
var arc = d3.svg.arc() var arc = d3.svg.arc()
.innerRadius(function(d) { return d.r - 2 }) .innerRadius(function(d) { return d.r })
.outerRadius(function(d) { return d.r - 8 }) .outerRadius(function(d) { return d.r - 5 })
.startAngle(0); .startAngle(0);
var fullArc = d3.svg.arc() var fullArc = d3.svg.arc()
.innerRadius(function(d) { return d.r - 3 }) .innerRadius(function(d) { return d.r })
.outerRadius(function(d) { return d.r - 7 }) .outerRadius(function(d) { return d.r - 5 })
.startAngle(0) .startAngle(0)
.endAngle(2 * Math.PI); .endAngle(2 * Math.PI);
var diameter = 800, var diameter = 800,
format = d3.format(",d"); format = d3.format(",d");
//color = d3.scale.category10(); //color = d3.scale.category10();
@ -233,7 +232,7 @@
.attr("class", "no-pointer-events") .attr("class", "no-pointer-events")
.attr("class", "animate-grow") .attr("class", "animate-grow")
.attr("d", arc) .attr("d", arc)
.style("fill", function(d, i) { return 'grey'; }); .style("fill", function(d, i) { return '#2e9e49'; });
d3.selectAll("path.animate-grow") d3.selectAll("path.animate-grow")
.transition() .transition()
@ -245,7 +244,7 @@
.transition() .transition()
.duration(1000) .duration(1000)
.style("fill", function(d, i) { .style("fill", function(d, i) {
return d.displayAge == -1 ? 'grey' : color(d.displayAge); return d.displayAge == -1 ? 'white' : 'red';
}); });
selection.exit().remove(); selection.exit().remove();

View File

@ -2,7 +2,10 @@
// This is global bootstrap for autoloading // This is global bootstrap for autoloading
use Codeception\Util\Fixtures; use Codeception\Util\Fixtures;
Fixtures::add('url', 'http://ninja.dev:8000');
Fixtures::add('username', 'user@example.com'); Fixtures::add('username', 'user@example.com');
Fixtures::add('password', 'password'); Fixtures::add('password', 'password');
Fixtures::add('gateway_key', ''); Fixtures::add('api_secret', 'password');
Fixtures::add('stripe_secret_key', '');
Fixtures::add('stripe_publishable_key', '');

View File

@ -29,6 +29,7 @@ class AcceptanceTester extends \Codeception\Actor
//if ($I->loadSessionSnapshot('login')) return; //if ($I->loadSessionSnapshot('login')) return;
$I->amOnPage('/login'); $I->amOnPage('/login');
$I->see('Login');
$I->fillField(['name' => 'email'], Fixtures::get('username')); $I->fillField(['name' => 'email'], Fixtures::get('username'));
$I->fillField(['name' => 'password'], Fixtures::get('password')); $I->fillField(['name' => 'password'], Fixtures::get('password'));
$I->click('Login'); $I->click('Login');

View File

@ -8,16 +8,15 @@ class_name: AcceptanceTester
modules: modules:
enabled: enabled:
- WebDriver: - WebDriver:
url: 'http://ninja.dev/' url: 'http://ninja.dev:8000/'
host: 127.0.0.1
window_size: 1024x768 window_size: 1024x768
wait: 5 wait: 5
browser: phantomjs browser: firefox
capabilities: capabilities:
unexpectedAlertBehaviour: 'accept' unexpectedAlertBehaviour: 'accept'
webStorageEnabled: true webStorageEnabled: true
- Db: - Db:
dsn: 'mysql:dbname=ninja;host=localhost;' dsn: 'mysql:dbname=ninja;host=127.0.0.1;'
user: 'ninja' user: 'ninja'
password: 'ninja' password: 'ninja'
dump: tests/_data/dump.sql dump: tests/_data/dump.sql

View File

@ -117,6 +117,8 @@ class APICest
$response = curl_exec($curl); $response = curl_exec($curl);
curl_close($curl); curl_close($curl);
//Debug::debug('Response: ' . $response);
return json_decode($response); return json_decode($response);
} }
} }

View File

@ -1,7 +1,6 @@
<?php <?php
use Codeception\Util\Fixtures; use Codeception\Util\Fixtures;
use \AcceptanceTester;
use Faker\Factory; use Faker\Factory;
class CheckBalanceCest class CheckBalanceCest

View File

@ -1,6 +1,5 @@
<?php <?php
use \AcceptanceTester;
use Faker\Factory; use Faker\Factory;
use Codeception\Util\Fixtures; use Codeception\Util\Fixtures;

View File

@ -1,6 +1,5 @@
<?php <?php
use \AcceptanceTester;
use App\Models\Credit; use App\Models\Credit;
use Faker\Factory; use Faker\Factory;
use Codeception\Util\Fixtures; use Codeception\Util\Fixtures;

View File

@ -1,7 +1,6 @@
<?php <?php
use Codeception\Util\Fixtures; use Codeception\Util\Fixtures;
use \AcceptanceTester;
use Faker\Factory; use Faker\Factory;
class GoProCest class GoProCest

View File

@ -1,6 +1,5 @@
<?php <?php
use \AcceptanceTester;
use Faker\Factory; use Faker\Factory;
class InvoiceCest class InvoiceCest

View File

@ -1,6 +1,5 @@
<?php <?php
use \AcceptanceTester;
use Faker\Factory; use Faker\Factory;
class InvoiceDesignCest class InvoiceDesignCest

View File

@ -1,7 +1,6 @@
/<?php /<?php
use Codeception\Util\Fixtures; use Codeception\Util\Fixtures;
use \AcceptanceTester;
use Faker\Factory; use Faker\Factory;
class OnlinePaymentCest class OnlinePaymentCest
@ -27,9 +26,9 @@ class OnlinePaymentCest
$I->amOnPage('/settings/online_payments'); $I->amOnPage('/settings/online_payments');
if (strpos($I->grabFromCurrentUrl(), 'create') !== false) { if (strpos($I->grabFromCurrentUrl(), 'create') !== false) {
$I->fillField(['name' =>'23_apiKey'], Fixtures::get('secret_key')); $I->fillField(['name' =>'23_apiKey'], env('stripe_secret_key') ?: Fixtures::get('stripe_secret_key'));
// Fails to load StripeJS causing "ReferenceError: Can't find variable: Stripe" // Fails to load StripeJS causing "ReferenceError: Can't find variable: Stripe"
//$I->fillField(['name' =>'publishable_key'], Fixtures::get('publishable_key')); //$I->fillField(['name' =>'stripe_publishable_key'], env('stripe_secret_key') ?: Fixtures::get('stripe_publishable_key'));
$I->selectOption('#token_billing_type_id', 4); $I->selectOption('#token_billing_type_id', 4);
$I->click('Save'); $I->click('Save');
$I->see('Successfully created gateway'); $I->see('Successfully created gateway');

View File

@ -1,6 +1,5 @@
<?php <?php
use \AcceptanceTester;
use App\Models\Payment; use App\Models\Payment;
use Faker\Factory; use Faker\Factory;

View File

@ -1,6 +1,5 @@
<?php <?php
use \AcceptanceTester;
use Faker\Factory; use Faker\Factory;
class TaskCest class TaskCest

View File

@ -1,7 +1,6 @@
/<?php /<?php
use Codeception\Util\Fixtures; use Codeception\Util\Fixtures;
use \AcceptanceTester;
use Faker\Factory; use Faker\Factory;
class TaxRatesCest class TaxRatesCest
@ -75,6 +74,7 @@ class TaxRatesCest
// check total is right before saving // check total is right before saving
$I->see("\${$total}"); $I->see("\${$total}");
$I->click('Save'); $I->click('Save');
$I->wait(1);
$I->see($clientEmail); $I->see($clientEmail);
// check total is right after saving // check total is right after saving

View File

@ -9,7 +9,7 @@ modules:
enabled: enabled:
- \Helper\Functional - \Helper\Functional
- PhpBrowser: - PhpBrowser:
url: 'http://ninja.dev' url: 'http://ninja.dev:8000'
curl: curl:
CURLOPT_RETURNTRANSFER: true CURLOPT_RETURNTRANSFER: true
- Laravel5: - Laravel5: