diff --git a/.env.example b/.env.example
index 1dc6d99bd419..20c977c663e9 100644
--- a/.env.example
+++ b/.env.example
@@ -8,8 +8,8 @@ DB_TYPE=mysql
DB_STRICT=false
DB_HOST=localhost
DB_DATABASE=ninja
-DB_USERNAME
-DB_PASSWORD
+DB_USERNAME=ninja
+DB_PASSWORD=ninja
MAIL_DRIVER=smtp
MAIL_PORT=587
@@ -23,6 +23,7 @@ MAIL_PASSWORD
PHANTOMJS_CLOUD_KEY='a-demo-key-with-low-quota-per-ip-address'
LOG=single
REQUIRE_HTTPS=false
+API_SECRET=password
GOOGLE_CLIENT_ID
GOOGLE_CLIENT_SECRET
diff --git a/.travis.yml b/.travis.yml
index 5c303f42917a..8005afdb85da 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,9 +4,15 @@ sudo: false
php:
- 5.5
+<<<<<<< HEAD
- 5.6
- 7.0
- hhvm
+=======
+# - 5.6
+# - 7.0
+# - hhvm
+>>>>>>> upstream/develop
addons:
hosts:
@@ -30,12 +36,28 @@ before_install:
install:
# install Composer dependencies
+<<<<<<< HEAD
- travis_retry composer update --prefer-dist;
before_script:
# copy configuration files
- cp tests/_bootstrap.php.default tests/_bootstrap.php
- cp tests/.env.circleci .env
+=======
+ - 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:
+ # copy configuration files
+ - cp .env.example .env
+ - cp tests/_bootstrap.php.default tests/_bootstrap.php
+ - 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
+>>>>>>> upstream/develop
# create the database and user
- mysql -u root -e "create database IF NOT EXISTS ninja;"
- mysql -u root -e "GRANT ALL PRIVILEGES ON ninja.* To 'ninja'@'localhost' IDENTIFIED BY 'ninja'; FLUSH PRIVILEGES;"
@@ -55,6 +77,13 @@ before_script:
script:
- php ./vendor/codeception/codeception/codecept run --html --debug
+<<<<<<< HEAD
+=======
+after_script:
+ - cat storage/logs/laravel.log
+
+
+>>>>>>> upstream/develop
notifications:
email:
on_success: never
diff --git a/app/Http/Controllers/AccountController.php b/app/Http/Controllers/AccountController.php
index 56a7d1a82b43..4b12b6802e90 100644
--- a/app/Http/Controllers/AccountController.php
+++ b/app/Http/Controllers/AccountController.php
@@ -958,7 +958,13 @@ class AccountController extends BaseController
'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();
diff --git a/app/Http/Controllers/InvoiceApiController.php b/app/Http/Controllers/InvoiceApiController.php
index 8c4344f608b6..2ba39cd77651 100644
--- a/app/Http/Controllers/InvoiceApiController.php
+++ b/app/Http/Controllers/InvoiceApiController.php
@@ -280,7 +280,7 @@ class InvoiceApiController extends BaseAPIController
private function prepareItem($item)
{
// 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']);
if ($product) {
if (empty($item['cost'])) {
diff --git a/app/Http/Controllers/PublicClientController.php b/app/Http/Controllers/PublicClientController.php
index 834a89beac59..9d806061d88c 100644
--- a/app/Http/Controllers/PublicClientController.php
+++ b/app/Http/Controllers/PublicClientController.php
@@ -162,6 +162,27 @@ class PublicClientController extends BaseController
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()
{
if (!$invitation = $this->getInvitation()) {
diff --git a/app/Http/routes.php b/app/Http/routes.php
index 848d22bcdd05..566f4aa15ae6 100644
--- a/app/Http/routes.php
+++ b/app/Http/routes.php
@@ -1,6 +1,5 @@
$this->balance) {
- $applied = $this->balance;
- $this->balance = 0;
- } else {
- $applied = $amount;
- $this->balance = $this->balance - $amount;
- }
-
- $this->save();
-
- return $applied;
+ return $this->invoice_currency_id != $this->expense_currency_id;
}
}
diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php
index 626f4db6475d..4e15934efeb3 100644
--- a/app/Models/Invoice.php
+++ b/app/Models/Invoice.php
@@ -733,42 +733,24 @@ class Invoice extends EntityModel implements BalanceAffecting
$invitation = $this->invitations[0];
$link = $invitation->getLink();
+ $key = env('PHANTOMJS_CLOUD_KEY');
$curl = curl_init();
- $jsonEncodedData = json_encode([
- 'url' => "{$link}?phantomjs=true",
- '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}");
+ if (Utils::isNinjaDev()) {
+ $link = env('TEST_LINK');
}
- 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);
}
}
diff --git a/app/Models/User.php b/app/Models/User.php
index f62e4a5846c6..9f66f0d2af8f 100644
--- a/app/Models/User.php
+++ b/app/Models/User.php
@@ -107,6 +107,11 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
return $this->account->isPro();
}
+ public function isPaidPro()
+ {
+ return $this->isPro() && ! $this->isTrial();
+ }
+
public function isTrial()
{
return $this->account->isTrial();
diff --git a/app/Ninja/Repositories/ExpenseRepository.php b/app/Ninja/Repositories/ExpenseRepository.php
index 442df6ef2979..cfd312622ad3 100644
--- a/app/Ninja/Repositories/ExpenseRepository.php
+++ b/app/Ninja/Repositories/ExpenseRepository.php
@@ -64,6 +64,7 @@ class ExpenseRepository extends BaseRepository
->orWhere('contacts.is_primary', '=', null);
})
->select(
+ DB::raw('COALESCE(expenses.invoice_id, expenses.should_be_invoiced) expense_status_id'),
'expenses.account_id',
'expenses.amount',
'expenses.deleted_at',
diff --git a/app/Services/DatatableService.php b/app/Services/DatatableService.php
index 5a1fd279aebb..63fe47005bab 100644
--- a/app/Services/DatatableService.php
+++ b/app/Services/DatatableService.php
@@ -41,6 +41,7 @@ class DatatableService
private function createDropdown($entityType, $table, $actions)
{
$table->addColumn('dropdown', function ($model) use ($entityType, $actions) {
+ $hasAction = false;
$str = '
';
if (property_exists($model, 'is_deleted') && $model->is_deleted) {
@@ -70,6 +71,7 @@ class DatatableService
if ($visible($model)) {
$str .= "{$value}";
$lastIsDivider = false;
+ $hasAction = true;
}
} elseif ( ! $lastIsDivider) {
$str .= "";
@@ -77,6 +79,10 @@ class DatatableService
}
}
+ if ( ! $hasAction) {
+ return '';
+ }
+
if ( ! $lastIsDivider) {
$str .= "";
}
diff --git a/app/Services/ExpenseService.php b/app/Services/ExpenseService.php
index 491c0e7957d8..e8f4d591d75d 100644
--- a/app/Services/ExpenseService.php
+++ b/app/Services/ExpenseService.php
@@ -106,7 +106,7 @@ class ExpenseService extends BaseService
}
],
[
- 'invoice_id',
+ 'expense_status_id',
function ($model) {
return self::getStatusLabel($model->invoice_id, $model->should_be_invoiced);
}
diff --git a/codeception.yml b/codeception.yml
index dfbb0d47bbb3..87ecbd1fc806 100644
--- a/codeception.yml
+++ b/codeception.yml
@@ -19,7 +19,7 @@ extensions:
modules:
config:
Db:
- dsn: 'mysql:dbname=ninja;host=localhost;'
+ dsn: 'mysql:dbname=ninja;host=127.0.0.1;'
user: 'ninja'
password: 'ninja'
dump: tests/_data/dump.sql
diff --git a/composer.json b/composer.json
index a338165ea034..740e501771d0 100644
--- a/composer.json
+++ b/composer.json
@@ -36,7 +36,7 @@
"omnipay/bitpay": "dev-master",
"guzzlehttp/guzzle": "~6.0",
"laravelcollective/html": "~5.0",
- "wildbit/laravel-postmark-provider": "dev-master",
+ "wildbit/laravel-postmark-provider": "2.0",
"Dwolla/omnipay-dwolla": "dev-master",
"laravel/socialite": "~2.0",
"simshaun/recurr": "dev-master",
diff --git a/composer.lock b/composer.lock
index 28ae475dee18..7157dd51188c 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,8 +4,8 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
- "hash": "6e219bb4f5ffaf8423177bd6fccc89f8",
- "content-hash": "4778ab164bfb93c4af1bb51c4320ea4c",
+ "hash": "cfae9eb02e70e68bef3b7a573b771cd1",
+ "content-hash": "9725ebe501b47a2dd80af2554009e32a",
"packages": [
{
"name": "agmscode/omnipay-agms",
@@ -435,12 +435,12 @@
"source": {
"type": "git",
"url": "https://github.com/barryvdh/laravel-ide-helper.git",
- "reference": "aa8f772a46c35ecdcb7119f38772ac2ec952a941"
+ "reference": "4b8ba85b346fc9962521661aa639911535b2bb3f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/barryvdh/laravel-ide-helper/zipball/aa8f772a46c35ecdcb7119f38772ac2ec952a941",
- "reference": "aa8f772a46c35ecdcb7119f38772ac2ec952a941",
+ "url": "https://api.github.com/repos/barryvdh/laravel-ide-helper/zipball/4b8ba85b346fc9962521661aa639911535b2bb3f",
+ "reference": "4b8ba85b346fc9962521661aa639911535b2bb3f",
"shasum": ""
},
"require": {
@@ -490,7 +490,7 @@
"phpstorm",
"sublime"
],
- "time": "2016-01-22 13:33:15"
+ "time": "2016-01-28 08:19:58"
},
{
"name": "cardgate/omnipay-cardgate",
@@ -2555,12 +2555,12 @@
"source": {
"type": "git",
"url": "https://github.com/slampenny/Swaggervel.git",
- "reference": "ea47fafde4984278e27a8044a1b1b0bcfd79130c"
+ "reference": "e026d72cacec8b2db8b2510179d73042f5e87bb9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/slampenny/Swaggervel/zipball/ea47fafde4984278e27a8044a1b1b0bcfd79130c",
- "reference": "ea47fafde4984278e27a8044a1b1b0bcfd79130c",
+ "url": "https://api.github.com/repos/slampenny/Swaggervel/zipball/e026d72cacec8b2db8b2510179d73042f5e87bb9",
+ "reference": "e026d72cacec8b2db8b2510179d73042f5e87bb9",
"shasum": ""
},
"require": {
@@ -2592,7 +2592,7 @@
"laravel",
"swagger"
],
- "time": "2015-08-18 15:33:39"
+ "time": "2016-01-25 15:38:17"
},
{
"name": "jsanc623/phpbenchtime",
@@ -2786,16 +2786,16 @@
},
{
"name": "laravel/framework",
- "version": "v5.0.34",
+ "version": "v5.0.35",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
- "reference": "98dbaafe8e2781f86b1b858f8610be0d7318b153"
+ "reference": "37151cf533f468e2227605e4b9ac596154f6b92b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/framework/zipball/98dbaafe8e2781f86b1b858f8610be0d7318b153",
- "reference": "98dbaafe8e2781f86b1b858f8610be0d7318b153",
+ "url": "https://api.github.com/repos/laravel/framework/zipball/37151cf533f468e2227605e4b9ac596154f6b92b",
+ "reference": "37151cf533f468e2227605e4b9ac596154f6b92b",
"shasum": ""
},
"require": {
@@ -2908,7 +2908,7 @@
"framework",
"laravel"
],
- "time": "2015-12-04 23:20:49"
+ "time": "2016-02-02 14:55:52"
},
{
"name": "laravel/socialite",
@@ -3284,12 +3284,12 @@
"source": {
"type": "git",
"url": "https://github.com/lokielse/omnipay-alipay.git",
- "reference": "f39ce21a5cbfe5c7cd4108d264b398dbd42be05b"
+ "reference": "0b091a199f1ffce95582f5e11efcf4a8ffd90ec8"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/lokielse/omnipay-alipay/zipball/f39ce21a5cbfe5c7cd4108d264b398dbd42be05b",
- "reference": "f39ce21a5cbfe5c7cd4108d264b398dbd42be05b",
+ "url": "https://api.github.com/repos/lokielse/omnipay-alipay/zipball/0b091a199f1ffce95582f5e11efcf4a8ffd90ec8",
+ "reference": "0b091a199f1ffce95582f5e11efcf4a8ffd90ec8",
"shasum": ""
},
"require": {
@@ -3325,7 +3325,7 @@
"payment",
"purchase"
],
- "time": "2016-01-19 15:08:12"
+ "time": "2016-01-27 17:06:44"
},
{
"name": "maatwebsite/excel",
@@ -3701,23 +3701,23 @@
},
{
"name": "mtdowling/cron-expression",
- "version": "v1.0.4",
+ "version": "v1.1.0",
"source": {
"type": "git",
"url": "https://github.com/mtdowling/cron-expression.git",
- "reference": "fd92e883195e5dfa77720b1868cf084b08be4412"
+ "reference": "c9ee7886f5a12902b225a1a12f36bb45f9ab89e5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/mtdowling/cron-expression/zipball/fd92e883195e5dfa77720b1868cf084b08be4412",
- "reference": "fd92e883195e5dfa77720b1868cf084b08be4412",
+ "url": "https://api.github.com/repos/mtdowling/cron-expression/zipball/c9ee7886f5a12902b225a1a12f36bb45f9ab89e5",
+ "reference": "c9ee7886f5a12902b225a1a12f36bb45f9ab89e5",
"shasum": ""
},
"require": {
"php": ">=5.3.2"
},
"require-dev": {
- "phpunit/phpunit": "4.*"
+ "phpunit/phpunit": "~4.0|~5.0"
},
"type": "library",
"autoload": {
@@ -3741,7 +3741,7 @@
"cron",
"schedule"
],
- "time": "2015-01-11 23:07:46"
+ "time": "2016-01-26 21:23:30"
},
{
"name": "nesbot/carbon",
@@ -5279,16 +5279,16 @@
},
{
"name": "omnipay/sagepay",
- "version": "2.3.0",
+ "version": "2.3.1",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/omnipay-sagepay.git",
- "reference": "4208d23b33b2f8a59176e44ad22d304c461ecb62"
+ "reference": "ca992b28a0d7ec7dbf218852dab36ec309dee07e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/thephpleague/omnipay-sagepay/zipball/4208d23b33b2f8a59176e44ad22d304c461ecb62",
- "reference": "4208d23b33b2f8a59176e44ad22d304c461ecb62",
+ "url": "https://api.github.com/repos/thephpleague/omnipay-sagepay/zipball/ca992b28a0d7ec7dbf218852dab36ec309dee07e",
+ "reference": "ca992b28a0d7ec7dbf218852dab36ec309dee07e",
"shasum": ""
},
"require": {
@@ -5334,7 +5334,7 @@
"sage pay",
"sagepay"
],
- "time": "2016-01-12 12:43:31"
+ "time": "2016-02-07 13:25:23"
},
{
"name": "omnipay/securepay",
@@ -5509,16 +5509,16 @@
},
{
"name": "omnipay/worldpay",
- "version": "v2.1.1",
+ "version": "v2.2",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/omnipay-worldpay.git",
- "reference": "5353f02b7f800b93d8aeae606d6df09afa538457"
+ "reference": "26ead4ca2c6ec45c9a3b3dad0be8880e0b1df083"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/thephpleague/omnipay-worldpay/zipball/5353f02b7f800b93d8aeae606d6df09afa538457",
- "reference": "5353f02b7f800b93d8aeae606d6df09afa538457",
+ "url": "https://api.github.com/repos/thephpleague/omnipay-worldpay/zipball/26ead4ca2c6ec45c9a3b3dad0be8880e0b1df083",
+ "reference": "26ead4ca2c6ec45c9a3b3dad0be8880e0b1df083",
"shasum": ""
},
"require": {
@@ -5562,20 +5562,20 @@
"payment",
"worldpay"
],
- "time": "2014-09-17 00:37:18"
+ "time": "2016-01-28 12:55:58"
},
{
"name": "paragonie/random_compat",
- "version": "1.1.5",
+ "version": "v1.2.0",
"source": {
"type": "git",
"url": "https://github.com/paragonie/random_compat.git",
- "reference": "dd8998b7c846f6909f4e7a5f67fabebfc412a4f7"
+ "reference": "b0e69d10852716b2ccbdff69c75c477637220790"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/paragonie/random_compat/zipball/dd8998b7c846f6909f4e7a5f67fabebfc412a4f7",
- "reference": "dd8998b7c846f6909f4e7a5f67fabebfc412a4f7",
+ "url": "https://api.github.com/repos/paragonie/random_compat/zipball/b0e69d10852716b2ccbdff69c75c477637220790",
+ "reference": "b0e69d10852716b2ccbdff69c75c477637220790",
"shasum": ""
},
"require": {
@@ -5610,7 +5610,7 @@
"pseudorandom",
"random"
],
- "time": "2016-01-06 13:31:20"
+ "time": "2016-02-06 03:52:05"
},
{
"name": "patricktalmadge/bootstrapper",
@@ -6158,23 +6158,27 @@
},
{
"name": "symfony/class-loader",
- "version": "v3.0.1",
+ "version": "v3.0.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/class-loader.git",
- "reference": "6294f616bb9888ba2e13c8bfdcc4d306c1c95da7"
+ "reference": "92e7cf1af2bc1695daabb4ac972db169606e9030"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/class-loader/zipball/6294f616bb9888ba2e13c8bfdcc4d306c1c95da7",
- "reference": "6294f616bb9888ba2e13c8bfdcc4d306c1c95da7",
+ "url": "https://api.github.com/repos/symfony/class-loader/zipball/92e7cf1af2bc1695daabb4ac972db169606e9030",
+ "reference": "92e7cf1af2bc1695daabb4ac972db169606e9030",
"shasum": ""
},
"require": {
"php": ">=5.5.9"
},
"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",
"extra": {
@@ -6206,7 +6210,7 @@
],
"description": "Symfony ClassLoader Component",
"homepage": "https://symfony.com",
- "time": "2015-12-05 17:45:07"
+ "time": "2016-02-03 09:33:23"
},
{
"name": "symfony/console",
@@ -6673,16 +6677,16 @@
},
{
"name": "symfony/polyfill-php56",
- "version": "v1.0.1",
+ "version": "v1.1.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php56.git",
- "reference": "e2e77609a9e2328eb370fbb0e0d8b2000ebb488f"
+ "reference": "4d891fff050101a53a4caabb03277284942d1ad9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/e2e77609a9e2328eb370fbb0e0d8b2000ebb488f",
- "reference": "e2e77609a9e2328eb370fbb0e0d8b2000ebb488f",
+ "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/4d891fff050101a53a4caabb03277284942d1ad9",
+ "reference": "4d891fff050101a53a4caabb03277284942d1ad9",
"shasum": ""
},
"require": {
@@ -6692,7 +6696,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.0-dev"
+ "dev-master": "1.1-dev"
}
},
"autoload": {
@@ -6725,20 +6729,20 @@
"portable",
"shim"
],
- "time": "2015-12-18 15:10:25"
+ "time": "2016-01-20 09:13:37"
},
{
"name": "symfony/polyfill-util",
- "version": "v1.0.1",
+ "version": "v1.1.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-util.git",
- "reference": "4271c55cbc0a77b2641f861b978123e46b3da969"
+ "reference": "8de62801aa12bc4dfcf85eef5d21981ae7bb3cc4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-util/zipball/4271c55cbc0a77b2641f861b978123e46b3da969",
- "reference": "4271c55cbc0a77b2641f861b978123e46b3da969",
+ "url": "https://api.github.com/repos/symfony/polyfill-util/zipball/8de62801aa12bc4dfcf85eef5d21981ae7bb3cc4",
+ "reference": "8de62801aa12bc4dfcf85eef5d21981ae7bb3cc4",
"shasum": ""
},
"require": {
@@ -6747,7 +6751,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.0-dev"
+ "dev-master": "1.1-dev"
}
},
"autoload": {
@@ -6777,7 +6781,7 @@
"polyfill",
"shim"
],
- "time": "2015-11-04 20:28:58"
+ "time": "2016-01-20 09:13:37"
},
{
"name": "symfony/process",
@@ -7374,7 +7378,7 @@
},
{
"name": "wildbit/laravel-postmark-provider",
- "version": "dev-master",
+ "version": "2.0.0",
"source": {
"type": "git",
"url": "https://github.com/wildbit/laravel-postmark-provider.git",
@@ -7448,16 +7452,16 @@
},
{
"name": "zircote/swagger-php",
- "version": "2.0.5",
+ "version": "2.0.6",
"source": {
"type": "git",
"url": "https://github.com/zircote/swagger-php.git",
- "reference": "c19af4edcc13c00e82fabeee926335b1fe1d92e9"
+ "reference": "0dfc289d53bad4a2bd193adc8d4bd058029ab417"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/zircote/swagger-php/zipball/c19af4edcc13c00e82fabeee926335b1fe1d92e9",
- "reference": "c19af4edcc13c00e82fabeee926335b1fe1d92e9",
+ "url": "https://api.github.com/repos/zircote/swagger-php/zipball/0dfc289d53bad4a2bd193adc8d4bd058029ab417",
+ "reference": "0dfc289d53bad4a2bd193adc8d4bd058029ab417",
"shasum": ""
},
"require": {
@@ -7466,6 +7470,7 @@
"symfony/finder": "*"
},
"require-dev": {
+ "squizlabs/php_codesniffer": "2.*",
"zendframework/zend-form": "*"
},
"bin": [
@@ -7504,26 +7509,26 @@
"rest",
"service discovery"
],
- "time": "2016-01-15 09:39:28"
+ "time": "2016-02-13 15:39:11"
}
],
"packages-dev": [
{
"name": "codeception/c3",
- "version": "2.0.5",
+ "version": "2.0.6",
"source": {
"type": "git",
"url": "https://github.com/Codeception/c3.git",
- "reference": "b866ca528474ddcf74147531cc4e50b80257a5f8"
+ "reference": "dc4d39b36d585c2eda58129407e78855ea67b1ca"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Codeception/c3/zipball/b866ca528474ddcf74147531cc4e50b80257a5f8",
- "reference": "b866ca528474ddcf74147531cc4e50b80257a5f8",
+ "url": "https://api.github.com/repos/Codeception/c3/zipball/dc4d39b36d585c2eda58129407e78855ea67b1ca",
+ "reference": "dc4d39b36d585c2eda58129407e78855ea67b1ca",
"shasum": ""
},
"require": {
- "composer-plugin-api": "1.0.0",
+ "composer-plugin-api": "^1.0",
"php": ">=5.4.0"
},
"type": "composer-plugin",
@@ -7556,7 +7561,7 @@
"code coverage",
"codecoverage"
],
- "time": "2015-11-28 10:17:10"
+ "time": "2016-02-09 23:31:08"
},
{
"name": "codeception/codeception",
@@ -7901,22 +7906,24 @@
},
{
"name": "phpspec/prophecy",
- "version": "v1.5.0",
+ "version": "v1.6.0",
"source": {
"type": "git",
"url": "https://github.com/phpspec/prophecy.git",
- "reference": "4745ded9307786b730d7a60df5cb5a6c43cf95f7"
+ "reference": "3c91bdf81797d725b14cb62906f9a4ce44235972"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4745ded9307786b730d7a60df5cb5a6c43cf95f7",
- "reference": "4745ded9307786b730d7a60df5cb5a6c43cf95f7",
+ "url": "https://api.github.com/repos/phpspec/prophecy/zipball/3c91bdf81797d725b14cb62906f9a4ce44235972",
+ "reference": "3c91bdf81797d725b14cb62906f9a4ce44235972",
"shasum": ""
},
"require": {
"doctrine/instantiator": "^1.0.2",
+ "php": "^5.3|^7.0",
"phpdocumentor/reflection-docblock": "~2.0",
- "sebastian/comparator": "~1.1"
+ "sebastian/comparator": "~1.1",
+ "sebastian/recursion-context": "~1.0"
},
"require-dev": {
"phpspec/phpspec": "~2.0"
@@ -7924,7 +7931,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.4.x-dev"
+ "dev-master": "1.5.x-dev"
}
},
"autoload": {
@@ -7957,7 +7964,7 @@
"spy",
"stub"
],
- "time": "2015-08-13 10:07:40"
+ "time": "2016-02-15 07:46:21"
},
{
"name": "phpunit/php-code-coverage",
@@ -8201,16 +8208,16 @@
},
{
"name": "phpunit/phpunit",
- "version": "4.8.21",
+ "version": "4.8.23",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "ea76b17bced0500a28098626b84eda12dbcf119c"
+ "reference": "6e351261f9cd33daf205a131a1ba61c6d33bd483"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ea76b17bced0500a28098626b84eda12dbcf119c",
- "reference": "ea76b17bced0500a28098626b84eda12dbcf119c",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/6e351261f9cd33daf205a131a1ba61c6d33bd483",
+ "reference": "6e351261f9cd33daf205a131a1ba61c6d33bd483",
"shasum": ""
},
"require": {
@@ -8269,7 +8276,7 @@
"testing",
"xunit"
],
- "time": "2015-12-12 07:45:58"
+ "time": "2016-02-11 14:56:33"
},
{
"name": "phpunit/phpunit-mock-objects",
@@ -8813,16 +8820,16 @@
},
{
"name": "symfony/polyfill-mbstring",
- "version": "v1.0.1",
+ "version": "v1.1.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
- "reference": "49ff736bd5d41f45240cec77b44967d76e0c3d25"
+ "reference": "1289d16209491b584839022f29257ad859b8532d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/49ff736bd5d41f45240cec77b44967d76e0c3d25",
- "reference": "49ff736bd5d41f45240cec77b44967d76e0c3d25",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/1289d16209491b584839022f29257ad859b8532d",
+ "reference": "1289d16209491b584839022f29257ad859b8532d",
"shasum": ""
},
"require": {
@@ -8834,7 +8841,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.0-dev"
+ "dev-master": "1.1-dev"
}
},
"autoload": {
@@ -8868,7 +8875,7 @@
"portable",
"shim"
],
- "time": "2015-11-20 09:19:13"
+ "time": "2016-01-20 09:13:37"
},
{
"name": "symfony/yaml",
@@ -8935,7 +8942,6 @@
"alfaproject/omnipay-neteller": 20,
"alfaproject/omnipay-skrill": 20,
"omnipay/bitpay": 20,
- "wildbit/laravel-postmark-provider": 20,
"dwolla/omnipay-dwolla": 20,
"simshaun/recurr": 20,
"meebio/omnipay-creditcall": 20,
diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php
index 114022662c69..63ac704fe8e1 100644
--- a/resources/lang/en/texts.php
+++ b/resources/lang/en/texts.php
@@ -1150,5 +1150,6 @@ return array(
'trial_success' => 'Successfully enabled two week free pro plan trial',
'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.',
-
+
+ 'convert_currency' => 'Convert currency',
);
diff --git a/resources/views/expenses/edit.blade.php b/resources/views/expenses/edit.blade.php
index 8d413e16b69c..c2e00ab6af79 100644
--- a/resources/views/expenses/edit.blade.php
+++ b/resources/views/expenses/edit.blade.php
@@ -59,40 +59,50 @@
->data_bind('combobox: client_id')
->addGroupClass('client-select') !!}
- @if (!$expense || ($expense && !$expense->invoice_id))
+ @if (!$expense || ($expense && !$expense->invoice_id && !$expense->client_id))
{!! Former::checkbox('should_be_invoiced')
->text(trans('texts.should_be_invoiced'))
->data_bind('checked: should_be_invoiced() || client_id(), enable: !client_id()')
- ->label(' ') !!}
+ ->label(' ') !!}
@endif
-
- {!! 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') !!}
-
-
- {!! Former::plaintext('test')
- ->value('')
- ->style('min-height:46px')
- ->label(trans('texts.invoice_currency')) !!}
-
+ @if (!$expense || ($expense && ! $expense->isExchanged()))
+ {!! Former::checkbox('convert_currency')
+ ->text(trans('texts.convert_currency'))
+ ->data_bind('checked: convert_currency')
+ ->label(' ') !!}
+ @endif
+
- {!! Former::text('exchange_rate')
- ->data_bind("value: exchange_rate, enable: enableExchangeRate, valueUpdate: 'afterkeydown'") !!}
+
+
+ {!! 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') !!}
+
+
+ {!! Former::plaintext('test')
+ ->value('')
+ ->style('min-height:46px')
+ ->label(trans('texts.invoice_currency')) !!}
+
- {!! Former::text('invoice_amount')
- ->addGroupClass('converted-amount')
- ->data_bind("value: convertedAmount, enable: enableExchangeRate")
- ->append('') !!}
+ {!! Former::text('exchange_rate')
+ ->data_bind("value: exchange_rate, enable: enableExchangeRate, valueUpdate: 'afterkeydown'") !!}
+ {!! Former::text('invoice_amount')
+ ->addGroupClass('converted-amount')
+ ->data_bind("value: convertedAmount, enable: enableExchangeRate")
+ ->append('') !!}
+
- {!! Former::textarea('public_notes')->style('height:255px') !!}
- {!! Former::textarea('private_notes')->style('height:255px') !!}
+ {!! Former::textarea('public_notes')->rows(8) !!}
+ {!! Former::textarea('private_notes')->rows(8) !!}
+
@@ -194,6 +204,7 @@
self.amount = ko.observable();
self.exchange_rate = ko.observable(1);
self.should_be_invoiced = ko.observable();
+ self.convert_currency = ko.observable(false);
if (data) {
ko.mapping.fromJS(data, {}, this);
@@ -230,9 +241,14 @@
});
self.enableExchangeRate = ko.computed(function() {
+ if (self.convert_currency()) {
+ return true;
+ }
var expenseCurrencyId = self.expense_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();
})
};
diff --git a/resources/views/header.blade.php b/resources/views/header.blade.php
index a007d34328df..e2c6b92c38e4 100644
--- a/resources/views/header.blade.php
+++ b/resources/views/header.blade.php
@@ -259,6 +259,7 @@
}
function showSearch() {
+ $('#search').typeahead('setQuery', '');
$('#search-form').show();
$('#navbar-options').hide();
if (window.hasOwnProperty('searchData')) {
@@ -289,7 +290,6 @@
}
function hideSearch() {
- $('#search').typeahead('setQuery', '');
$('#search-form').hide();
$('#navbar-options').show();
}
@@ -331,7 +331,7 @@
showSignUp();
@endif
- $('ul.navbar-settings, ul.navbar-history').hover(function () {
+ $('ul.navbar-settings, ul.navbar-search').hover(function () {
if ($('.user-accounts').css('display') == 'block') {
$('.user-accounts').dropdown('toggle');
}
@@ -351,6 +351,13 @@
});
@endif
+ // Focus the search input if the user clicks forward slash
+ $('body').keypress(function(event) {
+ if (event.which == 47) {
+ showSearch();
+ }
+ });
+
});
@@ -396,7 +403,7 @@