diff --git a/.env.example b/.env.example index 41ce2039f7..fc27ba048e 100644 --- a/.env.example +++ b/.env.example @@ -1,7 +1,6 @@ APP_ENV=production APP_DEBUG=false APP_URL=http://ninja.dev -APP_CIPHER=rijndael-128 APP_KEY=SomeRandomString DB_TYPE=mysql @@ -20,6 +19,9 @@ MAIL_FROM_ADDRESS MAIL_FROM_NAME MAIL_PASSWORD +MAILGUN_DOMAIN= +MAILGUN_SECRET= + #POSTMARK_API_TOKEN= PHANTOMJS_CLOUD_KEY='a-demo-key-with-low-quota-per-ip-address' @@ -60,11 +62,21 @@ API_SECRET=password # If this is set to anything, the URL secret will be set the next # time a file is downloaded through the client portal. # Only set this temporarily, as it slows things down. -#RACKSPACE_TEMP_URL_SECRET_SET= +#RACKSPACE_TEMP_URL_SECRET_SET= #DOCUMENT_FILESYSTEM= #MAX_DOCUMENT_SIZE # KB #MAX_EMAIL_DOCUMENTS_SIZE # Total KB #MAX_ZIP_DOCUMENTS_SIZE # Total KB (uncompressed) -#DOCUMENT_PREVIEW_SIZE # Pixels \ No newline at end of file +#DOCUMENT_PREVIEW_SIZE # Pixels + +WEPAY_CLIENT_ID= +WEPAY_CLIENT_SECRET= +WEPAY_ENVIRONMENT=production # production or stage +WEPAY_AUTO_UPDATE=true # Requires permission from WePay +WEPAY_ENABLE_CANADA=true +WEPAY_FEE_PAYER=payee +WEPAY_APP_FEE_MULTIPLIER=0.002 +WEPAY_APP_FEE_FIXED=0 +WEPAY_THEME='{"name":"Invoice Ninja","primary_color":"0b4d78","secondary_color":"0b4d78","background_color":"f8f8f8","button_color":"33b753"}' # See https://www.wepay.com/developer/reference/structures#theme diff --git a/.gitignore b/.gitignore index 5a86589d7a..09e1dfee7b 100644 --- a/.gitignore +++ b/.gitignore @@ -35,4 +35,4 @@ tests/_bootstrap.php # composer stuff /c3.php -_ide_helper.php \ No newline at end of file +_ide_helper.php diff --git a/.styleci.yml b/.styleci.yml new file mode 100644 index 0000000000..6a307ad3c9 --- /dev/null +++ b/.styleci.yml @@ -0,0 +1,18 @@ +preset: laravel + +risky: false + +enabled: + - no_useless_else + - phpdoc_align + - phpdoc_no_empty_return + - phpdoc_order + - phpdoc_separation + +finder: + exclude: + - "resources" + - "storage" + - "tests" + not-path: + - "bootstrap/cache" diff --git a/.travis.yml b/.travis.yml index b27c9d02af..21fb9cb965 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,9 +3,10 @@ language: php sudo: true php: - - 5.5.9 +# - 5.5.9 # - 5.6 -# - 7.0 +# - 5.6 + - 7.0 # - hhvm addons: @@ -27,13 +28,14 @@ before_install: # set GitHub token and update composer - if [ -n "$GH_TOKEN" ]; then composer config github-oauth.github.com ${GH_TOKEN}; fi; - composer self-update && composer -V +# - export USE_ZEND_ALLOC=0 install: # install Composer dependencies - - rm composer.lock + # - 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 + # - sed -i '/mollie/d' composer.json + # - sed -i '/2checkout/d' composer.json - travis_retry composer install --prefer-dist; before_script: @@ -66,17 +68,17 @@ before_script: script: - php ./vendor/codeception/codeception/codecept run --debug acceptance AllPagesCept.php - php ./vendor/codeception/codeception/codecept run --debug acceptance APICest.php - #- php ./vendor/codeception/codeception/codecept run --debug acceptance CheckBalanceCest.php - #- php ./vendor/codeception/codeception/codecept run --debug acceptance ClientCest.php - #- php ./vendor/codeception/codeception/codecept run --debug acceptance ExpenseCest.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 QuoteCest.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 + - php ./vendor/codeception/codeception/codecept run --debug acceptance TaxRatesCest.php + - php ./vendor/codeception/codeception/codecept run --debug acceptance CheckBalanceCest.php + - php ./vendor/codeception/codeception/codecept run --debug acceptance ClientCest.php + - php ./vendor/codeception/codeception/codecept run --debug acceptance ExpenseCest.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 QuoteCest.php + - php ./vendor/codeception/codeception/codecept run --debug acceptance InvoiceDesignCest.php + - php ./vendor/codeception/codeception/codecept run --debug acceptance OnlinePaymentCest.php + - php ./vendor/codeception/codeception/codecept run --debug acceptance PaymentCest.php + - php ./vendor/codeception/codeception/codecept run --debug acceptance TaskCest.php #- sed -i 's/NINJA_DEV=true/NINJA_PROD=true/g' .env #- php ./vendor/codeception/codeception/codecept run acceptance GoProCest.php @@ -90,6 +92,7 @@ after_script: - mysql -u root -e 'select * from invoice_items;' ninja - mysql -u root -e 'select * from payments;' ninja - mysql -u root -e 'select * from credits;' ninja + - mysql -u root -e 'select * from expenses;' ninja - cat storage/logs/laravel-error.log - cat storage/logs/laravel-info.log - FILES=$(find tests/_output -type f -name '*.png') diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000000..50c1739ad6 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,19 @@ +# Changelog +All notable changes to this project will be documented in this file. +This project adheres to [Semantic Versioning](http://semver.org/). + +## [2.6] - 2016-07-08 + +### Added +- Configuration for first day of the week #950 +- StyleCI configuration #929 +- Added expense category + +### Changed +- Removed `invoiceninja.komodoproject` from Git #932 +- `APP_CIPHER` changed from `rinjdael-128` to `AES-256-CBC` #898 +- Improved options when exporting data + +### Fixed +- "Manual entry" untranslatable #562 +- Using a database table prefix breaks the dashboard #203 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1e26492d5d..c7bc7ddd71 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,9 +1,45 @@ # Contributing to Invoice Ninja -We welcome contributions! We'll improve this guide over time... +Thanks for your contributions! -*Please note: although our application is open-source we run a for-profit hosted service at [invoiceninja.com](https://www.invoiceninja.com).* +## Submit bug reports or feature requests -Guidelines -- Please try to follow [PSR-2 guidlines](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) -- Add translations in our [Transifex](https://www.transifex.com/invoice-ninja/) project +### Submit pull requests + * [Fork](https://github.com/invoiceninja/invoiceninja#fork-destination-box) the [Invoice Ninja repository](https://github.com/invoiceninja/invoiceninja) + * Create a new branch with the name `#issue_number-Short-description` + * _Example:_ `#100-Add-GoogleAnalytics` + * Make your changes and commit + * Check if your branch is still in sync with the repositorys **`develop`** branch + * _Read:_ [Syncing a fork](https://help.github.com/articles/syncing-a-fork/) + * _Also read:_ [How to rebase a pull request](https://github.com/edx/edx-platform/wiki/How-to-Rebase-a-Pull-Request) + * Push your branch and create a PR against the Invoice Ninja **`develop`** branch + * Update the [Changelog](CHANGELOG.md) + +### Some rules +To make the contribution process nice and easy for anyone, please follow some rules: + * Each contribution(bug or feature) should have an [issue on Github](https://github.com/invoiceninja/invoiceninja/issues) +to give a more detailed explanation. + * Only one feature/bugfix per issue. If you want to submit more, create multiple issues. + * Only one feature/bugfix per PR(pull request). Split more changes into multiple PRs. + +#### Coding Style +Try to follow the [PSR-2 guidlines](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) + +_Example styling:_ +```php +/** + * Gets a preview of the email + * + * @param TemplateService $templateService + * + * @return \Illuminate\Http\Response + */ +public function previewEmail(TemplateService $templateService) +{ + // +} +``` + + +## Translations +For helping us with translating Invoice Ninja, please use [Transifex](https://www.transifex.com/invoice-ninja/invoice-ninja/). diff --git a/README.md b/README.md index 240cc58403..d6adf78804 100644 --- a/README.md +++ b/README.md @@ -3,14 +3,15 @@

# Invoice Ninja -### [http://www.invoiceninja.org](http://www.invoiceninja.org) [![Build Status](https://travis-ci.org/invoiceninja/invoiceninja.svg?branch=master)](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) -We're often asked to recommend PHP developers to help setup our app and make small adjustments, email us at contact@invoiceninja.com if you're interested in taking on the work. +## [Hosted](https://www.invoiceninja.com) | [Self-hosted](https://invoiceninja.org) -### Affiliates Programs +We're often asked to recommend Laravel/PHP developers to help setup our app and make small adjustments, email us at contact@invoiceninja.com if you're interested in taking on the work. + +## Affiliates Programs * 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 $500 sign up fee @@ -20,23 +21,24 @@ We're often asked to recommend PHP developers to help setup our app and make sma * [Bitnami](https://bitnami.com/stack/invoice-ninja) - Free * [Softaculous](https://www.softaculous.com/apps/ecommerce/Invoice_Ninja) - $30 -### Requirements +## Requirements * PHP >= 5.5.9 * MCrypt PHP Extension * MySQL -### Recommended Providers +## Recommended Providers * [Stripe](https://stripe.com/) * [Postmark](https://postmarkapp.com/) -### Features +## Features * Built using Laravel 5.2 * Live PDF generation using [pdfmake](http://pdfmake.org/) -* Integrates with 50+ payment providers with [OmniPay](https://github.com/thephpleague/omnipay) +* Integrates with 50+ payment providers with [Omnipay](https://github.com/thephpleague/omnipay) * Recurring invoices with auto-billing * Expenses and vendors * Tasks with time-tracking +* File Attachments * Multi-user/multi-company support * Tax rates and payment terms * Reminder emails @@ -45,7 +47,7 @@ We're often asked to recommend PHP developers to help setup our app and make sma * Custom email templates * [D3.js](http://d3js.org/) visualizations -### Documentation +## Documentation * [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/) * [User Guide](https://www.invoiceninja.com/app-user-guide/) @@ -54,51 +56,22 @@ We're often asked to recommend PHP developers to help setup our app and make sma * [Support Forum](https://www.invoiceninja.com/forums/forum/support/) * [Feature Roadmap](https://trello.com/b/63BbiVVe/) -### Pull Requests -We're using the [Git-Flow](http://nvie.com/posts/a-successful-git-branching-model/) model of branching and releasing, **please create pull requests against the develop branch**. +## Contributing +All contributors are welcome! +For information on how contribute to Invoice Ninja, please see our [contributing guide](CONTRIBUTING.md). -### Contributors +## Credits +* [Hillel Coren](https://github.com/hillelcoren) +* [All contributors](https://github.com/invoiceninja/invoiceninja/graphs/contributors) + +**Special thanks to:** * [Troels Liebe Bentsen](https://github.com/tlbdk) * [Jeramy Simpson](https://github.com/JeramyMywork) - [MyWork](https://www.mywork.com.au) * [Sigitas Limontas](https://lt.linkedin.com/in/sigitaslimontas) * [Joshua Dwire](https://github.com/joshuadwire) - [Some Techie](https://www.sometechie.com) +* [Holger Lösken](https://github.com/codedge) - [codedge](http://codedge.de/) -### Frameworks/Libraries -* [laravel/laravel](https://github.com/laravel/laravel) - A PHP Framework For Web Artisans -* [twbs/bootstrap](https://github.com/twbs/bootstrap) - Sleek, intuitive, and powerful front-end framework for faster and easier web development. -* [jquery/jquery](https://github.com/jquery/jquery) - jQuery JavaScript Library -* [jquery/jquery-ui](https://github.com/jquery/jquery-ui) - The official jQuery user interface library -* [patricktalmadge/bootstrapper](https://github.com/patricktalmadge/bootstrapper) - Laravel Twitter Bootstrap Bundle -* [danielfarrell/bootstrap-combobox](https://github.com/danielfarrell/bootstrap-combobox) - A combobox plugin -* [eternicode/bootstrap-datepicker](https://github.com/eternicode/bootstrap-datepicker) - A datepicker for @twitter bootstrap -* [twitter/typeahead.js](https://github.com/twitter/typeahead.js) - a fast and fully-featured autocomplete library -* [krisk/Fuse](https://github.com/krisk/Fuse) - Lightweight fuzzy-search, in JavaScript -* [knockout/knockout](https://github.com/knockout/knockout) - Knockout makes it easier to create rich, responsive UIs with JavaScript -* [rniemeyer/knockout-sortable](https://github.com/rniemeyer/knockout-sortable) - A Knockout.js binding to connect observableArrays with jQuery UI sortable functionality -* [bpampuch/pdfmake](https://github.com/bpampuch/pdfmake) - Client/server side PDF printing in pure JavaScript -* [FortAwesome/Font-Awesome](https://github.com/FortAwesome/Font-Awesome) - The iconic font designed for Bootstrap that works with twitter bootstrap -* [Anahkiasen/former](https://github.com/Anahkiasen/former) - A powerful form builder, for Laravel and other frameworks (stand-alone too) -* [barryvdh/laravel-debugbar](https://github.com/barryvdh/laravel-debugbar) - Laravel debugbar -* [DataTables/DataTables](https://github.com/DataTables/DataTables) - Tables plug-in for jQuery -* [Chumper/Datatable](https://github.com/Chumper/Datatable) - This is a laravel 4 package for the server and client side of datatables -* [omnipay/omnipay](https://github.com/omnipay/omnipay) - A framework agnostic, multi-gateway payment processing library for PHP 5.3+ -* [Intervention/image](https://github.com/Intervention/image) - PHP Image Manipulation -* [webpatser/laravel-countries](https://github.com/webpatser/laravel-countries) - Almost ISO 3166_2, 3166_3, currency, Capital and more for all countries -* [briannesbitt/Carbon](https://github.com/briannesbitt/Carbon) - A simple API extension for DateTime with PHP 5.3+ -* [thomaspark/bootswatch](https://github.com/thomaspark/bootswatch) - Themes for Bootstrap -* [mozilla/pdf.js](https://github.com/mozilla/pdf.js) - PDF Reader in JavaScript -* [nnnick/Chart.js](https://github.com/nnnick/Chart.js) - Simple HTML5 Charts using the canvas tag -* [josscrowcroft/accounting.js](https://github.com/josscrowcroft/accounting.js) - A lightweight JavaScript library for number, money and currency formatting -* [jashkenas/underscore](https://github.com/jashkenas/underscore) - JavaScript's utility _ belt -* [caouecs/Laravel4-long](https://github.com/caouecs/Laravel4-lang) - List of languages ​​for Laravel4 -* [bgrins/spectrum](https://github.com/bgrins/spectrum) - The No Hassle JavaScript Colorpicker -* [lokesh/lightbox2](https://github.com/lokesh/lightbox2/) - The original lightbox script -* [josdejong/jsoneditor](https://github.com/josdejong/jsoneditor/) - A web-based tool to view, edit and format JSON -* [simshaun/recurr](https://github.com/simshaun/recurr) - PHP library for working with recurrence rules -* [quilljs/quill](https://github.com/quilljs/quill/) - A cross browser rich text editor with an API -* [Maatwebsite/Laravel-Excel](https://github.com/Maatwebsite/Laravel-Excel) - An eloquent way of importing and exporting Excel and CSV files for Laravel -* [thephpleague/fractal](https://github.com/thephpleague/fractal) - Output complex, flexible, AJAX/RESTful data structures -* [ezyang/htmlpurifier](https://github.com/ezyang/htmlpurifier) - Standards compliant HTML filter written in PHP -* [cerdic/css-tidy](https://github.com/Cerdic/CSSTidy) - CSSTidy is a CSS minifier -* [asgrim/ofxparser](https://github.com/asgrim/ofxparser) - OFX File Parser -* [stacktracejs/stacktrace.js](https://github.com/stacktracejs/stacktrace.js) - Framework-agnostic, micro-library for getting stack traces in all web browsers + +## License +Invoice Ninja is released under the Attribution Assurance License. +See [LICENSE](LICENSE) for details. diff --git a/app/Console/Commands/ChargeRenewalInvoices.php b/app/Console/Commands/ChargeRenewalInvoices.php index 39d63ee44c..4773f53c43 100644 --- a/app/Console/Commands/ChargeRenewalInvoices.php +++ b/app/Console/Commands/ChargeRenewalInvoices.php @@ -1,22 +1,47 @@ info('Done'); } + /** + * @return array + */ protected function getArguments() { - return array( - //array('example', InputArgument::REQUIRED, 'An example argument.'), - ); + return []; } + /** + * @return array + */ protected function getOptions() { - return array( - //array('example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null), - ); + return []; } } diff --git a/app/Console/Commands/CheckData.php b/app/Console/Commands/CheckData.php index 5c644c5b4b..567c697248 100644 --- a/app/Console/Commands/CheckData.php +++ b/app/Console/Commands/CheckData.php @@ -1,11 +1,9 @@ where("{$table}.account_id", '!=', DB::raw("{$entityType}s.account_id")) - ->get(["{$table}.id", "clients.account_id", "clients.user_id"]); + ->get(["{$table}.id", 'clients.account_id', 'clients.user_id']); if (count($records)) { $this->info(count($records) . " {$table} records with incorrect {$entityType} account id"); @@ -154,7 +162,7 @@ class CheckData extends Command { $clients->where('clients.id', '=', $this->option('client_id')); } else { $clients->where('invoices.is_deleted', '=', 0) - ->where('invoices.is_quote', '=', 0) + ->where('invoices.invoice_type_id', '=', INVOICE_TYPE_STANDARD) ->where('invoices.is_recurring', '=', 0) ->havingRaw('abs(clients.balance - sum(invoices.balance)) > .01 and clients.balance != 999999999.9999'); } @@ -184,7 +192,7 @@ class CheckData extends Command { if ($activity->invoice_id) { $invoice = DB::table('invoices') ->where('id', '=', $activity->invoice_id) - ->first(['invoices.amount', 'invoices.is_recurring', 'invoices.is_quote', 'invoices.deleted_at', 'invoices.id', 'invoices.is_deleted']); + ->first(['invoices.amount', 'invoices.is_recurring', 'invoices.invoice_type_id', 'invoices.deleted_at', 'invoices.id', 'invoices.is_deleted']); // Check if this invoice was once set as recurring invoice if ($invoice && !$invoice->is_recurring && DB::table('invoices') @@ -221,14 +229,14 @@ class CheckData extends Command { && $invoice->amount > 0; // **Fix for allowing converting a recurring invoice to a normal one without updating the balance** - if ($noAdjustment && !$invoice->is_quote && !$invoice->is_recurring) { - $this->info("No adjustment for new invoice:{$activity->invoice_id} amount:{$invoice->amount} isQuote:{$invoice->is_quote} isRecurring:{$invoice->is_recurring}"); + if ($noAdjustment && $invoice->invoice_type_id == INVOICE_TYPE_STANDARD && !$invoice->is_recurring) { + $this->info("No adjustment for new invoice:{$activity->invoice_id} amount:{$invoice->amount} invoiceTypeId:{$invoice->invoice_type_id} isRecurring:{$invoice->is_recurring}"); $foundProblem = true; $clientFix += $invoice->amount; $activityFix = $invoice->amount; // **Fix for updating balance when creating a quote or recurring invoice** - } elseif ($activity->adjustment != 0 && ($invoice->is_quote || $invoice->is_recurring)) { - $this->info("Incorrect adjustment for new invoice:{$activity->invoice_id} adjustment:{$activity->adjustment} isQuote:{$invoice->is_quote} isRecurring:{$invoice->is_recurring}"); + } elseif ($activity->adjustment != 0 && ($invoice->invoice_type_id == INVOICE_TYPE_QUOTE || $invoice->is_recurring)) { + $this->info("Incorrect adjustment for new invoice:{$activity->invoice_id} adjustment:{$activity->adjustment} invoiceTypeId:{$invoice->invoice_type_id} isRecurring:{$invoice->is_recurring}"); $foundProblem = true; $clientFix -= $activity->adjustment; $activityFix = 0; @@ -327,19 +335,23 @@ class CheckData extends Command { } } + /** + * @return array + */ protected function getArguments() { - return array( - //array('example', InputArgument::REQUIRED, 'An example argument.'), - ); + return []; } + /** + * @return array + */ protected function getOptions() { - return array( - array('fix', null, InputOption::VALUE_OPTIONAL, 'Fix data', null), - array('client_id', null, InputOption::VALUE_OPTIONAL, 'Client id', null), - ); + return [ + ['fix', null, InputOption::VALUE_OPTIONAL, 'Fix data', null], + ['client_id', null, InputOption::VALUE_OPTIONAL, 'Client id', null], + ]; } } \ No newline at end of file diff --git a/app/Console/Commands/CreateTestData.php b/app/Console/Commands/CreateTestData.php index 6a0643e46c..a75922635f 100644 --- a/app/Console/Commands/CreateTestData.php +++ b/app/Console/Commands/CreateTestData.php @@ -1,28 +1,43 @@ expenseRepo = $expenseRepo; } + /** + * @return bool + */ public function fire() { if (Utils::isNinjaProd()) { @@ -83,6 +101,9 @@ class CreateTestData extends Command } } + /** + * @param $client + */ private function createInvoices($client) { for ($i=0; $i<$this->count; $i++) { @@ -102,7 +123,11 @@ class CreateTestData extends Command $this->createPayment($client, $invoice); } } - + + /** + * @param $client + * @param $invoice + */ private function createPayment($client, $invoice) { $data = [ @@ -115,7 +140,7 @@ class CreateTestData extends Command $this->info('Payment: ' . $payment->amount); } - + private function createVendors() { for ($i=0; $i<$this->count; $i++) { @@ -140,7 +165,10 @@ class CreateTestData extends Command $this->createExpense($vendor); } } - + + /** + * @param $vendor + */ private function createExpense($vendor) { for ($i=0; $i<$this->count; $i++) { @@ -156,17 +184,19 @@ class CreateTestData extends Command } } + /** + * @return array + */ protected function getArguments() { - return array( - //array('example', InputArgument::REQUIRED, 'An example argument.'), - ); + return []; } + /** + * @return array + */ protected function getOptions() { - return array( - //array('example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null), - ); + return []; } } diff --git a/app/Console/Commands/GenerateResources.php b/app/Console/Commands/GenerateResources.php index e7139c85be..9826f3c70b 100644 --- a/app/Console/Commands/GenerateResources.php +++ b/app/Console/Commands/GenerateResources.php @@ -3,15 +3,22 @@ use File; use Illuminate\Console\Command; +/** + * Class GenerateResources + */ class GenerateResources extends Command { + /** + * @var string + */ protected $name = 'ninja:generate-resources'; + /** + * @var string + */ protected $description = 'Generate Resouces'; /** * Create a new command instance. - * - * @return void */ public function __construct() { @@ -25,22 +32,6 @@ class GenerateResources extends Command */ 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) { @@ -52,17 +43,19 @@ class GenerateResources extends Command } } + /** + * @return array + */ protected function getArguments() { - return array( - //array('example', InputArgument::REQUIRED, 'An example argument.'), - ); + return []; } + /** + * @return array + */ protected function getOptions() { - return array( - //array('example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null), - ); + return []; } } diff --git a/app/Console/Commands/Inspire.php b/app/Console/Commands/Inspire.php index 65c265a258..8909799ec7 100644 --- a/app/Console/Commands/Inspire.php +++ b/app/Console/Commands/Inspire.php @@ -3,6 +3,9 @@ use Illuminate\Console\Command; use Illuminate\Foundation\Inspiring; +/** + * Class Inspire + */ class Inspire extends Command { /** diff --git a/app/Console/Commands/PruneData.php b/app/Console/Commands/PruneData.php index 8970376424..1c04e1ab5f 100644 --- a/app/Console/Commands/PruneData.php +++ b/app/Console/Commands/PruneData.php @@ -3,9 +3,19 @@ use DB; use Illuminate\Console\Command; +/** + * Class PruneData + */ class PruneData extends Command { + /** + * @var string + */ protected $name = 'ninja:prune-data'; + + /** + * @var string + */ protected $description = 'Delete inactive accounts'; public function fire() @@ -41,17 +51,19 @@ class PruneData extends Command $this->info('Done'); } + /** + * @return array + */ protected function getArguments() { - return array( - //array('example', InputArgument::REQUIRED, 'An example argument.'), - ); + return []; } + /** + * @return array + */ protected function getOptions() { - return array( - //array('example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null), - ); + return []; } } diff --git a/app/Console/Commands/RemoveOrphanedDocuments.php b/app/Console/Commands/RemoveOrphanedDocuments.php index 3c7fe1bb53..edcb864564 100644 --- a/app/Console/Commands/RemoveOrphanedDocuments.php +++ b/app/Console/Commands/RemoveOrphanedDocuments.php @@ -4,16 +4,25 @@ use DateTime; use App\Models\Document; use Illuminate\Console\Command; +/** + * Class RemoveOrphanedDocuments + */ class RemoveOrphanedDocuments extends Command { + /** + * @var string + */ protected $name = 'ninja:remove-orphaned-documents'; + /** + * @var string + */ protected $description = 'Removes old documents not associated with an expense or invoice'; public function fire() { $this->info(date('Y-m-d').' Running RemoveOrphanedDocuments...'); - $documents = Document::whereRaw('invoice_id IS NULL AND expense_id IS NULL AND updated_at <= ?', array(new DateTime('-1 hour'))) + $documents = Document::whereRaw('invoice_id IS NULL AND expense_id IS NULL AND updated_at <= ?', [new DateTime('-1 hour')]) ->get(); $this->info(count($documents).' orphaned document(s) found'); @@ -25,17 +34,19 @@ class RemoveOrphanedDocuments extends Command $this->info('Done'); } + /** + * @return array + */ protected function getArguments() { - return array( - //array('example', InputArgument::REQUIRED, 'An example argument.'), - ); + return []; } + /** + * @return array + */ protected function getOptions() { - return array( - //array('example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null), - ); + return []; } } diff --git a/app/Console/Commands/ResetData.php b/app/Console/Commands/ResetData.php index a027600347..2ab706fa1d 100644 --- a/app/Console/Commands/ResetData.php +++ b/app/Console/Commands/ResetData.php @@ -1,24 +1,35 @@ info(date('Y-m-d') . ' Running ResetData...'); + public function fire() + { + $this->info(date('Y-m-d') . ' Running ResetData...'); - if (!Utils::isNinjaDev()) { - return; + if (!Utils::isNinjaDev()) { + return; + } + + Artisan::call('migrate:reset'); + Artisan::call('migrate'); + Artisan::call('db:seed'); } - - Artisan::call('migrate:reset'); - Artisan::call('migrate'); - Artisan::call('db:seed'); - } } \ No newline at end of file diff --git a/app/Console/Commands/SendRecurringInvoices.php b/app/Console/Commands/SendRecurringInvoices.php index abf493d1ca..38f8b1afdc 100644 --- a/app/Console/Commands/SendRecurringInvoices.php +++ b/app/Console/Commands/SendRecurringInvoices.php @@ -1,30 +1,55 @@ mailer = $mailer; $this->invoiceRepo = $invoiceRepo; + $this->paymentService = $paymentService; } public function fire() @@ -33,18 +58,20 @@ class SendRecurringInvoices extends Command $today = new DateTime(); $invoices = Invoice::with('account.timezone', 'invoice_items', 'client', 'user') - ->whereRaw('is_deleted IS FALSE AND deleted_at IS NULL AND is_recurring IS TRUE AND frequency_id > 0 AND start_date <= ? AND (end_date IS NULL OR end_date >= ?)', array($today, $today)) + ->whereRaw('is_deleted IS FALSE AND deleted_at IS NULL AND is_recurring IS TRUE AND frequency_id > 0 AND start_date <= ? AND (end_date IS NULL OR end_date >= ?)', [$today, $today]) ->orderBy('id', 'asc') ->get(); $this->info(count($invoices).' recurring invoice(s) found'); foreach ($invoices as $recurInvoice) { - if (!$recurInvoice->user->confirmed) { + $shouldSendToday = $recurInvoice->shouldSendToday(); + $this->info('Processing Invoice '.$recurInvoice->id.' - Should send '.($shouldSendToday ? 'YES' : 'NO')); + + if ( ! $shouldSendToday) { continue; } - + $recurInvoice->account->loadLocalizationSettings($recurInvoice->client); - $this->info('Processing Invoice '.$recurInvoice->id.' - Should send '.($recurInvoice->shouldSendToday() ? 'YES' : 'NO')); $invoice = $this->invoiceRepo->createRecurringInvoice($recurInvoice); if ($invoice && !$invoice->isPaid()) { @@ -53,20 +80,42 @@ class SendRecurringInvoices extends Command } } + $delayedAutoBillInvoices = Invoice::with('account.timezone', 'recurring_invoice', 'invoice_items', 'client', 'user') + ->whereRaw('is_deleted IS FALSE AND deleted_at IS NULL AND is_recurring IS FALSE + AND balance > 0 AND due_date = ? AND recurring_invoice_id IS NOT NULL', + [$today->format('Y-m-d')]) + ->orderBy('invoices.id', 'asc') + ->get(); + $this->info(count($delayedAutoBillInvoices).' due recurring invoice instance(s) found'); + + /** @var Invoice $invoice */ + foreach ($delayedAutoBillInvoices as $invoice) { + if ($invoice->isPaid()) { + continue; + } + + if ($invoice->getAutoBillEnabled() && $invoice->client->autoBillLater()) { + $this->info('Processing Invoice '.$invoice->id.' - Should bill '.($billNow ? 'YES' : 'NO')); + $this->paymentService->autoBillInvoice($invoice); + } + } + $this->info('Done'); } + /** + * @return array + */ protected function getArguments() { - return array( - //array('example', InputArgument::REQUIRED, 'An example argument.'), - ); + return []; } + /** + * @return array + */ protected function getOptions() { - return array( - //array('example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null), - ); + return []; } } diff --git a/app/Console/Commands/SendReminders.php b/app/Console/Commands/SendReminders.php index 58c38a7d81..bdb239deff 100644 --- a/app/Console/Commands/SendReminders.php +++ b/app/Console/Commands/SendReminders.php @@ -1,23 +1,47 @@ info(date('Y-m-d').' Running SendReminders...'); - $today = new DateTime(); + $this->info(date('Y-m-d') . ' Running SendReminders...'); $accounts = $this->accountRepo->findWithReminders(); - $this->info(count($accounts).' accounts found'); + $this->info(count($accounts) . ' accounts found'); + /** @var \App\Models\Account $account */ foreach ($accounts as $account) { if (!$account->hasFeature(FEATURE_EMAIL_TEMPLATES_REMINDERS)) { continue; } $invoices = $this->invoiceRepo->findNeedingReminding($account); - $this->info($account->name . ': ' . count($invoices).' invoices found'); + $this->info($account->name . ': ' . count($invoices) . ' invoices found'); + /** @var Invoice $invoice */ foreach ($invoices as $invoice) { if ($reminder = $account->getInvoiceReminder($invoice)) { $this->info('Send to ' . $invoice->id); @@ -54,17 +79,19 @@ class SendReminders extends Command $this->info('Done'); } + /** + * @return array + */ protected function getArguments() { - return array( - //array('example', InputArgument::REQUIRED, 'An example argument.'), - ); + return []; } + /** + * @return array + */ protected function getOptions() { - return array( - //array('example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null), - ); + return []; } } diff --git a/app/Console/Commands/SendRenewalInvoices.php b/app/Console/Commands/SendRenewalInvoices.php index 87a840aed2..1c46f50680 100644 --- a/app/Console/Commands/SendRenewalInvoices.php +++ b/app/Console/Commands/SendRenewalInvoices.php @@ -1,21 +1,42 @@ info(date('Y-m-d').' Running SendRenewalInvoices...'); - $today = new DateTime(); - $sentTo = []; // get all accounts with plans expiring in 10 days $companies = Company::whereRaw('datediff(plan_expires, curdate()) = 10') @@ -40,28 +59,36 @@ class SendRenewalInvoices extends Command if (!count($company->accounts)) { continue; } - + $account = $company->accounts->sortBy('id')->first(); - $plan = $company->plan; - $term = $company->plan_term; - + $plan = []; + $plan['plan'] = $company->plan; + $plan['term'] = $company->plan_term; + $plan['num_users'] = $company->num_users; + $plan['price'] = min($company->plan_price, Utils::getPlanPrice($plan)); + if ($company->pending_plan) { - $plan = $company->pending_plan; - $term = $company->pending_term; + $plan['plan'] = $company->pending_plan; + $plan['term'] = $company->pending_term; + $plan['num_users'] = $company->pending_num_users; + $plan['price'] = min($company->pending_plan_price, Utils::getPlanPrice($plan)); } - - if ($plan == PLAN_FREE || !$plan || !$term ){ + + if ($plan['plan'] == PLAN_FREE || !$plan['plan'] || !$plan['term'] || !$plan['price']){ continue; } - + $client = $this->accountRepo->getNinjaClient($account); - $invitation = $this->accountRepo->createNinjaInvoice($client, $account, $plan, $term); + $invitation = $this->accountRepo->createNinjaInvoice($client, $account, $plan, 0, false); // set the due date to 10 days from now $invoice = $invitation->invoice; $invoice->due_date = date('Y-m-d', strtotime('+ 10 days')); $invoice->save(); + $term = $plan['term']; + $plan = $plan['plan']; + if ($term == PLAN_TERM_YEARLY) { $this->mailer->sendInvoice($invoice); $this->info("Sent {$term}ly {$plan} invoice to {$client->getDisplayName()}"); @@ -73,17 +100,19 @@ class SendRenewalInvoices extends Command $this->info('Done'); } + /** + * @return array + */ protected function getArguments() { - return array( - //array('example', InputArgument::REQUIRED, 'An example argument.'), - ); + return []; } + /** + * @return array + */ protected function getOptions() { - return array( - //array('example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null), - ); + return []; } } diff --git a/app/Console/Commands/TestOFX.php b/app/Console/Commands/TestOFX.php index f7eb2b748b..d21518cba7 100644 --- a/app/Console/Commands/TestOFX.php +++ b/app/Console/Commands/TestOFX.php @@ -3,11 +3,31 @@ use Illuminate\Console\Command; use App\Services\BankAccountService; +/** + * Class TestOFX + */ class TestOFX extends Command { + /** + * @var string + */ protected $name = 'ninja:test-ofx'; + + /** + * @var string + */ protected $description = 'Test OFX'; + /** + * @var BankAccountService + */ + protected $bankAccountService; + + /** + * TestOFX constructor. + * + * @param BankAccountService $bankAccountService + */ public function __construct(BankAccountService $bankAccountService) { parent::__construct(); @@ -18,15 +38,5 @@ class TestOFX extends Command public function fire() { $this->info(date('Y-m-d').' Running TestOFX...'); - - /* - $bankId = env('TEST_BANK_ID'); - $username = env('TEST_BANK_USERNAME'); - $password = env('TEST_BANK_PASSWORD'); - - $data = $this->bankAccountService->loadBankAccounts($bankId, $username, $password, false); - - echo json_encode($data); - */ } } \ No newline at end of file diff --git a/app/Events/ClientWasArchived.php b/app/Events/ClientWasArchived.php index 03ebdc09cd..176376d2b6 100644 --- a/app/Events/ClientWasArchived.php +++ b/app/Events/ClientWasArchived.php @@ -1,20 +1,26 @@ client = $client; } diff --git a/app/Events/ClientWasCreated.php b/app/Events/ClientWasCreated.php index 5c2d370017..eed24343fb 100644 --- a/app/Events/ClientWasCreated.php +++ b/app/Events/ClientWasCreated.php @@ -1,20 +1,26 @@ client = $client; } diff --git a/app/Events/ClientWasDeleted.php b/app/Events/ClientWasDeleted.php index b87063c497..f6d27b92d9 100644 --- a/app/Events/ClientWasDeleted.php +++ b/app/Events/ClientWasDeleted.php @@ -1,20 +1,26 @@ client = $client; } diff --git a/app/Events/ClientWasRestored.php b/app/Events/ClientWasRestored.php index 385a0472ab..16fb6b9616 100644 --- a/app/Events/ClientWasRestored.php +++ b/app/Events/ClientWasRestored.php @@ -1,20 +1,26 @@ client = $client; } diff --git a/app/Events/ClientWasUpdated.php b/app/Events/ClientWasUpdated.php index 7e4790da68..1f863d6c01 100644 --- a/app/Events/ClientWasUpdated.php +++ b/app/Events/ClientWasUpdated.php @@ -1,20 +1,26 @@ client = $client; } diff --git a/app/Events/CreditWasArchived.php b/app/Events/CreditWasArchived.php index 2c680905b3..b9dd495ddd 100644 --- a/app/Events/CreditWasArchived.php +++ b/app/Events/CreditWasArchived.php @@ -1,23 +1,30 @@ credit = $credit; - } + /** + * Create a new event instance. + * + * @param Client $credit + */ + public function __construct(Client $credit) + { + $this->credit = $credit; + } } diff --git a/app/Events/CreditWasCreated.php b/app/Events/CreditWasCreated.php index bc20b312dc..81ba63c450 100644 --- a/app/Events/CreditWasCreated.php +++ b/app/Events/CreditWasCreated.php @@ -1,21 +1,24 @@ credit = $credit; } diff --git a/app/Events/CreditWasDeleted.php b/app/Events/CreditWasDeleted.php index e26a5d3ab0..c5f585fcf3 100644 --- a/app/Events/CreditWasDeleted.php +++ b/app/Events/CreditWasDeleted.php @@ -1,21 +1,26 @@ credit = $credit; } diff --git a/app/Events/CreditWasRestored.php b/app/Events/CreditWasRestored.php index 8d17d961e7..a80c9e729b 100644 --- a/app/Events/CreditWasRestored.php +++ b/app/Events/CreditWasRestored.php @@ -1,21 +1,27 @@ credit = $credit; } diff --git a/app/Events/Event.php b/app/Events/Event.php index d59f7690f8..76e730a4b8 100644 --- a/app/Events/Event.php +++ b/app/Events/Event.php @@ -1,7 +1,5 @@ expense = $expense; - } + /** + * Create a new event instance. + * + * @param Expense $expense + */ + public function __construct(Expense $expense) + { + $this->expense = $expense; + } } diff --git a/app/Events/ExpenseWasCreated.php b/app/Events/ExpenseWasCreated.php index ab462fe602..edaca9c00a 100644 --- a/app/Events/ExpenseWasCreated.php +++ b/app/Events/ExpenseWasCreated.php @@ -1,20 +1,26 @@ expense = $expense; } diff --git a/app/Events/ExpenseWasDeleted.php b/app/Events/ExpenseWasDeleted.php index 1549b483b4..bb2b6e4dbd 100644 --- a/app/Events/ExpenseWasDeleted.php +++ b/app/Events/ExpenseWasDeleted.php @@ -1,21 +1,26 @@ expense = $expense; } diff --git a/app/Events/ExpenseWasRestored.php b/app/Events/ExpenseWasRestored.php index b52a2d119a..142f41d7e9 100644 --- a/app/Events/ExpenseWasRestored.php +++ b/app/Events/ExpenseWasRestored.php @@ -1,21 +1,27 @@ expense = $expense; } diff --git a/app/Events/ExpenseWasUpdated.php b/app/Events/ExpenseWasUpdated.php index 1066d90de4..469a258ba1 100644 --- a/app/Events/ExpenseWasUpdated.php +++ b/app/Events/ExpenseWasUpdated.php @@ -1,20 +1,26 @@ expense = $expense; } diff --git a/app/Events/InvoiceInvitationWasEmailed.php b/app/Events/InvoiceInvitationWasEmailed.php index da00312492..b51e8af0c1 100644 --- a/app/Events/InvoiceInvitationWasEmailed.php +++ b/app/Events/InvoiceInvitationWasEmailed.php @@ -1,21 +1,28 @@ invitation = $invitation; } diff --git a/app/Events/InvoiceInvitationWasViewed.php b/app/Events/InvoiceInvitationWasViewed.php index bbf7e23c33..0897895a7a 100644 --- a/app/Events/InvoiceInvitationWasViewed.php +++ b/app/Events/InvoiceInvitationWasViewed.php @@ -1,25 +1,35 @@ invoice = $invoice; $this->invitation = $invitation; } - } diff --git a/app/Events/InvoiceWasArchived.php b/app/Events/InvoiceWasArchived.php index 7587c071a6..0de212661a 100644 --- a/app/Events/InvoiceWasArchived.php +++ b/app/Events/InvoiceWasArchived.php @@ -1,20 +1,26 @@ invoice = $invoice; } diff --git a/app/Events/InvoiceWasCreated.php b/app/Events/InvoiceWasCreated.php index cfd943bcff..b78d7f769f 100644 --- a/app/Events/InvoiceWasCreated.php +++ b/app/Events/InvoiceWasCreated.php @@ -1,20 +1,26 @@ invoice = $invoice; } diff --git a/app/Events/InvoiceWasDeleted.php b/app/Events/InvoiceWasDeleted.php index 316b1b5c50..792e693eb4 100644 --- a/app/Events/InvoiceWasDeleted.php +++ b/app/Events/InvoiceWasDeleted.php @@ -1,22 +1,27 @@ invoice = $invoice; } - } diff --git a/app/Events/InvoiceWasEmailed.php b/app/Events/InvoiceWasEmailed.php index dc30f6a558..a83035818c 100644 --- a/app/Events/InvoiceWasEmailed.php +++ b/app/Events/InvoiceWasEmailed.php @@ -1,22 +1,27 @@ invoice = $invoice; } - } diff --git a/app/Events/InvoiceWasRestored.php b/app/Events/InvoiceWasRestored.php index 5d75b4b246..e935f5b9e8 100644 --- a/app/Events/InvoiceWasRestored.php +++ b/app/Events/InvoiceWasRestored.php @@ -1,22 +1,30 @@ invoice = $invoice; $this->fromDeleted = $fromDeleted; diff --git a/app/Events/InvoiceWasUpdated.php b/app/Events/InvoiceWasUpdated.php index 87a0f8f201..f929b3d5be 100644 --- a/app/Events/InvoiceWasUpdated.php +++ b/app/Events/InvoiceWasUpdated.php @@ -1,22 +1,27 @@ invoice = $invoice; - } - + /** + * Create a new event instance. + * + * @param Invoice $invoice + */ + public function __construct(Invoice $invoice) + { + $this->invoice = $invoice; + } } diff --git a/app/Events/PaymentCompleted.php b/app/Events/PaymentCompleted.php new file mode 100644 index 0000000000..4d78fb923e --- /dev/null +++ b/app/Events/PaymentCompleted.php @@ -0,0 +1,28 @@ +payment = $payment; + } + +} diff --git a/app/Events/PaymentFailed.php b/app/Events/PaymentFailed.php new file mode 100644 index 0000000000..445b8ba5be --- /dev/null +++ b/app/Events/PaymentFailed.php @@ -0,0 +1,27 @@ +payment = $payment; + } +} diff --git a/app/Events/PaymentWasArchived.php b/app/Events/PaymentWasArchived.php index b8bb693dfc..4bf7eb8ff7 100644 --- a/app/Events/PaymentWasArchived.php +++ b/app/Events/PaymentWasArchived.php @@ -1,22 +1,28 @@ payment = $payment; - } + /** + * Create a new event instance. + * + * @param Payment $payment + */ + public function __construct(Payment $payment) + { + $this->payment = $payment; + } } diff --git a/app/Events/PaymentWasCreated.php b/app/Events/PaymentWasCreated.php index 619d33e958..98e95ae43a 100644 --- a/app/Events/PaymentWasCreated.php +++ b/app/Events/PaymentWasCreated.php @@ -1,22 +1,27 @@ payment = $payment; } - } diff --git a/app/Events/PaymentWasDeleted.php b/app/Events/PaymentWasDeleted.php index e12647c860..e7b62fe74c 100644 --- a/app/Events/PaymentWasDeleted.php +++ b/app/Events/PaymentWasDeleted.php @@ -1,22 +1,29 @@ -payment = $payment; } - } diff --git a/app/Events/PaymentWasRefunded.php b/app/Events/PaymentWasRefunded.php new file mode 100644 index 0000000000..55ca280ba8 --- /dev/null +++ b/app/Events/PaymentWasRefunded.php @@ -0,0 +1,31 @@ +payment = $payment; + $this->refundAmount = $refundAmount; + } +} diff --git a/app/Events/PaymentWasRestored.php b/app/Events/PaymentWasRestored.php index 711bdbb67f..1179d1896e 100644 --- a/app/Events/PaymentWasRestored.php +++ b/app/Events/PaymentWasRestored.php @@ -1,25 +1,30 @@ payment = $payment; $this->fromDeleted = $fromDeleted; } - } diff --git a/app/Events/PaymentWasVoided.php b/app/Events/PaymentWasVoided.php new file mode 100644 index 0000000000..e2d4f50133 --- /dev/null +++ b/app/Events/PaymentWasVoided.php @@ -0,0 +1,27 @@ +payment = $payment; + } +} diff --git a/app/Events/QuoteInvitationWasApproved.php b/app/Events/QuoteInvitationWasApproved.php index 5e69fe9c78..e5532352e1 100644 --- a/app/Events/QuoteInvitationWasApproved.php +++ b/app/Events/QuoteInvitationWasApproved.php @@ -1,27 +1,37 @@ quote = $quote; $this->invoice = $invoice; $this->invitation = $invitation; } - } diff --git a/app/Events/QuoteInvitationWasEmailed.php b/app/Events/QuoteInvitationWasEmailed.php index 5ce1c68602..54481ab9e7 100644 --- a/app/Events/QuoteInvitationWasEmailed.php +++ b/app/Events/QuoteInvitationWasEmailed.php @@ -1,21 +1,26 @@ invitation = $invitation; } diff --git a/app/Events/QuoteInvitationWasViewed.php b/app/Events/QuoteInvitationWasViewed.php index 3cd84b0e11..87f5da2a0b 100644 --- a/app/Events/QuoteInvitationWasViewed.php +++ b/app/Events/QuoteInvitationWasViewed.php @@ -1,25 +1,31 @@ quote = $quote; $this->invitation = $invitation; } - } diff --git a/app/Events/QuoteWasArchived.php b/app/Events/QuoteWasArchived.php index 285a61250c..4e78026b24 100644 --- a/app/Events/QuoteWasArchived.php +++ b/app/Events/QuoteWasArchived.php @@ -1,22 +1,20 @@ quote = $quote; - } + /** + * Create a new event instance. + * + * @param $quote + */ + public function __construct($quote) + { + $this->quote = $quote; + } } diff --git a/app/Events/QuoteWasCreated.php b/app/Events/QuoteWasCreated.php index d17ef9c131..8077ea6716 100644 --- a/app/Events/QuoteWasCreated.php +++ b/app/Events/QuoteWasCreated.php @@ -1,22 +1,22 @@ quote = $quote; } - } diff --git a/app/Events/QuoteWasDeleted.php b/app/Events/QuoteWasDeleted.php index ce3685d7a2..c338042e8d 100644 --- a/app/Events/QuoteWasDeleted.php +++ b/app/Events/QuoteWasDeleted.php @@ -1,22 +1,22 @@ quote = $quote; } - } diff --git a/app/Events/QuoteWasEmailed.php b/app/Events/QuoteWasEmailed.php index 19b1ec12d6..e41cfebb2c 100644 --- a/app/Events/QuoteWasEmailed.php +++ b/app/Events/QuoteWasEmailed.php @@ -1,22 +1,22 @@ quote = $quote; } - } diff --git a/app/Events/QuoteWasRestored.php b/app/Events/QuoteWasRestored.php index 0f13a65b43..4733991f69 100644 --- a/app/Events/QuoteWasRestored.php +++ b/app/Events/QuoteWasRestored.php @@ -1,22 +1,22 @@ quote = $quote; } - } diff --git a/app/Events/QuoteWasUpdated.php b/app/Events/QuoteWasUpdated.php index f01b982260..b3559a85b1 100644 --- a/app/Events/QuoteWasUpdated.php +++ b/app/Events/QuoteWasUpdated.php @@ -1,22 +1,23 @@ quote = $quote; - } + /** + * Create a new event instance. + * + * @param $quote + */ + public function __construct($quote) + { + $this->quote = $quote; + } } diff --git a/app/Events/TaskWasCreated.php b/app/Events/TaskWasCreated.php new file mode 100644 index 0000000000..af1fc5c27d --- /dev/null +++ b/app/Events/TaskWasCreated.php @@ -0,0 +1,28 @@ +task = $task; + } +} diff --git a/app/Events/TaskWasUpdated.php b/app/Events/TaskWasUpdated.php new file mode 100644 index 0000000000..608f57ea7c --- /dev/null +++ b/app/Events/TaskWasUpdated.php @@ -0,0 +1,28 @@ +task = $task; + } +} diff --git a/app/Events/UserLoggedIn.php b/app/Events/UserLoggedIn.php index 1f4af5e86a..3127d38247 100644 --- a/app/Events/UserLoggedIn.php +++ b/app/Events/UserLoggedIn.php @@ -1,21 +1,18 @@ user = $user; - } - + } } diff --git a/app/Events/UserSignedUp.php b/app/Events/UserSignedUp.php index 99e8b22456..fcef6296cd 100644 --- a/app/Events/UserSignedUp.php +++ b/app/Events/UserSignedUp.php @@ -1,21 +1,18 @@ vendor = $vendor; } diff --git a/app/Events/VendorWasCreated.php b/app/Events/VendorWasCreated.php index b2d7e81c93..dcd86a1548 100644 --- a/app/Events/VendorWasCreated.php +++ b/app/Events/VendorWasCreated.php @@ -1,21 +1,26 @@ vendor = $vendor; } diff --git a/app/Events/VendorWasDeleted.php b/app/Events/VendorWasDeleted.php index 553bece3cc..c53a8c2123 100644 --- a/app/Events/VendorWasDeleted.php +++ b/app/Events/VendorWasDeleted.php @@ -1,21 +1,26 @@ vendor = $vendor; } diff --git a/app/Events/VendorWasRestored.php b/app/Events/VendorWasRestored.php index 88c24693e6..0b62f5a27e 100644 --- a/app/Events/VendorWasRestored.php +++ b/app/Events/VendorWasRestored.php @@ -1,21 +1,26 @@ vendor = $vendor; } diff --git a/app/Events/VendorWasUpdated.php b/app/Events/VendorWasUpdated.php index eb90a68f46..17f4a56c7f 100644 --- a/app/Events/VendorWasUpdated.php +++ b/app/Events/VendorWasUpdated.php @@ -1,20 +1,26 @@ vendor = $vendor; } diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index 2a8b0d3052..0eecaba698 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -4,13 +4,17 @@ use Redirect; use Utils; use Exception; use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; -use Illuminate\Http\Exception\HttpResponseException; +use Illuminate\Http\Exception\HttpResponseException; use Illuminate\Auth\Access\AuthorizationException; use Illuminate\Database\Eloquent\ModelNotFoundException; use Symfony\Component\HttpKernel\Exception\HttpException; -use Illuminate\Foundation\Validation\ValidationException; +use Illuminate\Validation\ValidationException; -class Handler extends ExceptionHandler { +/** + * Class Handler + */ +class Handler extends ExceptionHandler +{ /** * A list of the exception types that should not be reported. @@ -24,14 +28,14 @@ class Handler extends ExceptionHandler { ValidationException::class, ]; - /** - * Report or log an exception. - * - * This is a great spot to send exceptions to Sentry, Bugsnag, etc. - * - * @param \Exception $e - * @return void - */ + /** + * Report or log an exception. + * + * This is a great spot to send exceptions to Sentry, Bugsnag, etc. + * + * @param \Exception $e + * @return bool|void + */ public function report(Exception $e) { // don't show these errors in the logs diff --git a/app/Http/Controllers/AccountApiController.php b/app/Http/Controllers/AccountApiController.php index 65175cdd5b..1034bdf254 100644 --- a/app/Http/Controllers/AccountApiController.php +++ b/app/Http/Controllers/AccountApiController.php @@ -3,22 +3,12 @@ use Auth; use Utils; use Response; -use Input; -use Validator; use Cache; -use App\Models\Client; use App\Models\Account; -use App\Models\AccountToken; use App\Ninja\Repositories\AccountRepository; use Illuminate\Http\Request; -use League\Fractal; -use League\Fractal\Manager; -use App\Ninja\Serializers\ArraySerializer; use App\Ninja\Transformers\AccountTransformer; use App\Ninja\Transformers\UserAccountTransformer; -use App\Http\Controllers\BaseAPIController; -use Swagger\Annotations as SWG; - use App\Events\UserSignedUp; use App\Http\Requests\RegisterRequest; use App\Http\Requests\UpdateAccountRequest; @@ -183,8 +173,6 @@ class AccountApiController extends BaseAPIController 'notify_paid' => $request->notify_paid, ]; - //unset($devices[$x]); - $devices[$x] = $newDevice; $account->devices = json_encode($devices); $account->save(); diff --git a/app/Http/Controllers/AccountController.php b/app/Http/Controllers/AccountController.php index 57f581e3df..dac7c171b2 100644 --- a/app/Http/Controllers/AccountController.php +++ b/app/Http/Controllers/AccountController.php @@ -1,5 +1,7 @@ accountRepo = $accountRepo; $this->userMailer = $userMailer; $this->contactMailer = $contactMailer; @@ -54,6 +90,9 @@ class AccountController extends BaseController $this->paymentService = $paymentService; } + /** + * @return \Illuminate\Http\RedirectResponse + */ public function demo() { $demoAccountId = Utils::getDemoAccountId(); @@ -70,6 +109,9 @@ class AccountController extends BaseController return Redirect::to('invoices/create'); } + /** + * @return \Illuminate\Http\RedirectResponse + */ public function getStarted() { $user = false; @@ -112,17 +154,9 @@ class AccountController extends BaseController return Redirect::to($redirectTo)->with('sign_up', Input::get('sign_up')); } - public function enableProPlan() - { - if (Auth::user()->isPro() && ! Auth::user()->isTrial()) { - return false; - } - - $invitation = $this->accountRepo->enablePlan(); - - return $invitation->invitation_key; - } - + /** + * @return \Illuminate\Http\RedirectResponse + */ public function changePlan() { $user = Auth::user(); $account = $user->account; @@ -142,22 +176,23 @@ class AccountController extends BaseController $term = PLAN_TERM_YEARLY; } - $new_plan = array( + $new_plan = [ 'plan' => PLAN_ENTERPRISE, 'term' => $term, - ); + ]; } elseif ($planDetails['plan'] == $plan) { // Term switch if ($planDetails['term'] == PLAN_TERM_YEARLY && $term == PLAN_TERM_MONTHLY) { - $pending_change = array( + $pending_change = [ 'plan' => $plan, 'term' => $term - ); - } elseif ($planDetails['term'] == PLAN_TERM_MONTHLY && $term == PLAN_TERM_YEARLY) { - $new_plan = array( + ]; + } elseif ($planDetails['term'] == PLAN_TERM_MONTHLY && $term == PLAN_TERM_YEARLY + || $planDetails['num_users'] != Input::get('num_users')) { + $new_plan = [ 'plan' => $plan, 'term' => $term, - ); + ]; } else { // Cancel the pending change $account->company->pending_plan = null; @@ -180,16 +215,10 @@ class AccountController extends BaseController $account->company->pending_plan = null; $account->company->pending_term = null; - if ($account->company->payment) { - $payment = $account->company->payment; - - $gateway = $this->paymentService->createGateway($payment->account_gateway); - $refund = $gateway->refund(array( - 'transactionReference' => $payment->transaction_reference, - 'amount' => $payment->amount - )); - $refund->send(); - $payment->delete(); + if ($payment = $account->company->payment) { + $ninjaAccount = $this->accountRepo->getNinjaAccount(); + $paymentDriver = $ninjaAccount->paymentDriver(); + $paymentDriver->refundPayment($payment); Session::flash('message', trans('texts.plan_refunded')); \Log::info("Refunded Plan Payment: {$account->name} - {$user->email}"); } else { @@ -199,10 +228,10 @@ class AccountController extends BaseController $account->company->save(); } else { - $pending_change = array( + $pending_change = [ 'plan' => $plan, 'term' => $plan == PLAN_FREE ? null : $term, - ); + ]; } } @@ -218,32 +247,44 @@ class AccountController extends BaseController $days_total = $planDetails['paid']->diff($planDetails['expires'])->days; $percent_used = $days_used / $days_total; - $old_plan_price = Account::$plan_prices[$planDetails['plan']][$planDetails['term']]; - $credit = $old_plan_price * (1 - $percent_used); + $credit = $planDetails['plan_price'] * (1 - $percent_used); } } else { - $new_plan = array( + $new_plan = [ 'plan' => $plan, 'term' => $term, - ); + ]; } if (!empty($pending_change) && empty($new_plan)) { + $pending_change['num_users'] = Input::get('num_users'); $account->company->pending_plan = $pending_change['plan']; $account->company->pending_term = $pending_change['term']; + $account->company->pending_num_users = $pending_change['num_users']; + $account->company->pending_plan_price = Utils::getPlanPrice($pending_change); $account->company->save(); Session::flash('message', trans('texts.updated_plan')); } - if (!empty($new_plan)) { - $invitation = $this->accountRepo->enablePlan($new_plan['plan'], $new_plan['term'], $credit, !empty($pending_monthly)); + if (!empty($new_plan) && $new_plan['plan'] != PLAN_FREE) { + $new_plan['num_users'] = 1; + if ($new_plan['plan'] == PLAN_ENTERPRISE) { + $new_plan['num_users'] = Input::get('num_users'); + } + $new_plan['price'] = Utils::getPlanPrice($new_plan); + $invitation = $this->accountRepo->enablePlan($new_plan, $credit, !empty($pending_monthly)); return Redirect::to('view/'.$invitation->invitation_key); } return Redirect::to('/settings/'.ACCOUNT_MANAGEMENT, 301); } + /** + * @param $entityType + * @param $visible + * @return mixed + */ public function setTrashVisible($entityType, $visible) { Session::put("show_trash:{$entityType}", $visible == 'true'); @@ -251,6 +292,9 @@ class AccountController extends BaseController return RESULT_SUCCESS; } + /** + * @return \Illuminate\Http\JsonResponse + */ public function getSearchData() { $data = $this->accountRepo->getSearchData(Auth::user()); @@ -258,6 +302,10 @@ class AccountController extends BaseController return Response::json($data); } + /** + * @param bool $section + * @return \Illuminate\Contracts\View\View|\Illuminate\Http\RedirectResponse + */ public function showSection($section = false) { if (!$section) { @@ -303,6 +351,9 @@ class AccountController extends BaseController } } + /** + * @return \Illuminate\Contracts\View\View|\Illuminate\Http\RedirectResponse + */ private function showSystemSettings() { if (Utils::isNinjaProd()) { @@ -311,13 +362,16 @@ class AccountController extends BaseController $data = [ 'account' => Account::with('users')->findOrFail(Auth::user()->account_id), - 'title' => trans("texts.system_settings"), + 'title' => trans('texts.system_settings'), 'section' => ACCOUNT_SYSTEM_SETTINGS, ]; - return View::make("accounts.system_settings", $data); + return View::make('accounts.system_settings', $data); } + /** + * @return \Illuminate\Contracts\View\View + */ private function showInvoiceSettings() { $account = Auth::user()->account; @@ -334,14 +388,17 @@ class AccountController extends BaseController $data = [ 'account' => Account::with('users')->findOrFail(Auth::user()->account_id), - 'title' => trans("texts.invoice_settings"), + 'title' => trans('texts.invoice_settings'), 'section' => ACCOUNT_INVOICE_SETTINGS, 'recurringHours' => $recurringHours, ]; - return View::make("accounts.invoice_settings", $data); + return View::make('accounts.invoice_settings', $data); } + /** + * @return \Illuminate\Contracts\View\View + */ private function showCompanyDetails() { // check that logo is less than the max file size @@ -352,15 +409,16 @@ class AccountController extends BaseController $data = [ 'account' => Account::with('users')->findOrFail(Auth::user()->account_id), - 'countries' => Cache::get('countries'), 'sizes' => Cache::get('sizes'), - 'industries' => Cache::get('industries'), 'title' => trans('texts.company_details'), ]; return View::make('accounts.details', $data); } + /** + * @return \Illuminate\Contracts\View\View + */ private function showAccountManagement() { $account = Auth::user()->account; @@ -373,6 +431,9 @@ class AccountController extends BaseController return View::make('accounts.management', $data); } + /** + * @return \Illuminate\Contracts\View\View + */ public function showUserDetails() { $oauthLoginUrls = []; @@ -392,6 +453,9 @@ class AccountController extends BaseController return View::make('accounts.user_details', $data); } + /** + * @return \Illuminate\Contracts\View\View + */ private function showLocalization() { $data = [ @@ -400,33 +464,33 @@ class AccountController extends BaseController 'dateFormats' => Cache::get('dateFormats'), 'datetimeFormats' => Cache::get('datetimeFormats'), 'currencies' => Cache::get('currencies'), - 'languages' => Cache::get('languages'), 'title' => trans('texts.localization'), + 'weekdays' => Utils::getTranslatedWeekdayNames(), ]; return View::make('accounts.localization', $data); } + /** + * @return \Illuminate\Contracts\View\View + */ private function showBankAccounts() { - $account = Auth::user()->account; - $account->load('bank_accounts'); - $count = count($account->bank_accounts); - - if ($count == 0) { - return Redirect::to('bank_accounts/create'); - } else { - return View::make('accounts.banks', [ - 'title' => trans('texts.bank_accounts') - ]); - } + return View::make('accounts.banks', [ + 'title' => trans('texts.bank_accounts'), + 'advanced' => ! Auth::user()->hasFeature(FEATURE_EXPENSES), + ]); } + /** + * @return \Illuminate\Contracts\View\View|\Illuminate\Http\RedirectResponse + */ private function showOnlinePayments() { $account = Auth::user()->account; $account->load('account_gateways'); $count = count($account->account_gateways); + $trashedCount = AccountGateway::scope($account->id)->withTrashed()->count(); if ($accountGateway = $account->getGatewayConfig(GATEWAY_STRIPE)) { if (! $accountGateway->getPublishableStripeKey()) { @@ -434,16 +498,26 @@ class AccountController extends BaseController } } - if ($count == 0) { + if ($trashedCount == 0) { return Redirect::to('gateways/create'); } else { + $tokenBillingOptions = []; + for ($i=1; $i<=4; $i++) { + $tokenBillingOptions[$i] = trans("texts.token_billing_{$i}"); + } + return View::make('accounts.payments', [ - 'showAdd' => $count < count(Gateway::$paymentTypes), - 'title' => trans('texts.online_payments') + 'showAdd' => $count < count(Gateway::$alternate) + 1, + 'title' => trans('texts.online_payments'), + 'tokenBillingOptions' => $tokenBillingOptions, + 'account' => $account, ]); } } + /** + * @return \Illuminate\Contracts\View\View + */ private function showProducts() { $columns = ['product', 'description', 'unit_cost']; @@ -461,6 +535,9 @@ class AccountController extends BaseController return View::make('accounts.products', $data); } + /** + * @return \Illuminate\Contracts\View\View + */ private function showTaxRates() { $data = [ @@ -472,6 +549,9 @@ class AccountController extends BaseController return View::make('accounts.tax_rates', $data); } + /** + * @return \Illuminate\Contracts\View\View + */ private function showPaymentTerms() { $data = [ @@ -483,6 +563,10 @@ class AccountController extends BaseController return View::make('accounts.payment_terms', $data); } + /** + * @param $section + * @return \Illuminate\Contracts\View\View + */ private function showInvoiceDesign($section) { $account = Auth::user()->account->load('country'); @@ -596,8 +680,8 @@ class AccountController extends BaseController // sample invoice to help determine variables $invoice = Invoice::scope() + ->invoiceType(INVOICE_TYPE_STANDARD) ->with('client', 'account') - ->where('is_quote', '=', false) ->where('is_recurring', '=', false) ->first(); @@ -613,6 +697,9 @@ class AccountController extends BaseController return View::make("accounts.{$section}", $data); } + /** + * @return \Illuminate\Contracts\View\View + */ private function showClientPortal() { $account = Auth::user()->account->load('country'); @@ -621,8 +708,8 @@ class AccountController extends BaseController if (Utils::isNinja() && $css) { // Unescape the CSS for display purposes $css = str_replace( - array('\3C ', '\3E ', '\26 '), - array('<', '>', '&'), + ['\3C ', '\3E ', '\26 '], + ['<', '>', '&'], $css ); } @@ -631,14 +718,17 @@ class AccountController extends BaseController 'client_view_css' => $css, 'enable_portal_password' => $account->enable_portal_password, 'send_portal_password' => $account->send_portal_password, - 'title' => trans("texts.client_portal"), + 'title' => trans('texts.client_portal'), 'section' => ACCOUNT_CLIENT_PORTAL, 'account' => $account, ]; - return View::make("accounts.client_portal", $data); + return View::make('accounts.client_portal', $data); } + /** + * @return \Illuminate\Contracts\View\View + */ private function showTemplates() { $account = Auth::user()->account->load('country'); @@ -661,12 +751,18 @@ class AccountController extends BaseController return View::make('accounts.templates_and_reminders', $data); } + /** + * @param $section + * @return \Illuminate\Http\RedirectResponse + */ public function doSection($section = ACCOUNT_COMPANY_DETAILS) { if ($section === ACCOUNT_COMPANY_DETAILS) { return AccountController::saveDetails(); } elseif ($section === ACCOUNT_LOCALIZATION) { return AccountController::saveLocalization(); + } elseif ($section == ACCOUNT_PAYMENTS) { + return self::saveOnlinePayments(); } elseif ($section === ACCOUNT_NOTIFICATIONS) { return AccountController::saveNotifications(); } elseif ($section === ACCOUNT_EXPORT) { @@ -692,6 +788,9 @@ class AccountController extends BaseController } } + /** + * @return \Illuminate\Http\RedirectResponse + */ private function saveCustomizeDesign() { if (Auth::user()->account->hasFeature(FEATURE_CUSTOMIZE_INVOICE_DESIGN)) { @@ -706,6 +805,9 @@ class AccountController extends BaseController return Redirect::to('settings/'.ACCOUNT_CUSTOMIZE_DESIGN); } + /** + * @return \Illuminate\Http\RedirectResponse + */ private function saveClientPortal() { $account = Auth::user()->account; @@ -759,6 +861,9 @@ class AccountController extends BaseController return Redirect::to('settings/'.ACCOUNT_CLIENT_PORTAL); } + /** + * @return \Illuminate\Http\RedirectResponse + */ private function saveEmailTemplates() { if (Auth::user()->account->hasFeature(FEATURE_EMAIL_TEMPLATES_REMINDERS)) { @@ -793,14 +898,13 @@ class AccountController extends BaseController return Redirect::to('settings/'.ACCOUNT_TEMPLATES_AND_REMINDERS); } + /** + * @return \Illuminate\Http\RedirectResponse + */ private function saveTaxRates() { $account = Auth::user()->account; - - $account->invoice_taxes = Input::get('invoice_taxes') ? true : false; - $account->invoice_item_taxes = Input::get('invoice_item_taxes') ? true : false; - $account->show_item_taxes = Input::get('show_item_taxes') ? true : false; - $account->default_tax_rate_id = Input::get('default_tax_rate_id'); + $account->fill(Input::all()); $account->save(); Session::flash('message', trans('texts.updated_settings')); @@ -808,6 +912,9 @@ class AccountController extends BaseController return Redirect::to('settings/'.ACCOUNT_TAX_RATES); } + /** + * @return \Illuminate\Http\RedirectResponse + */ private function saveProducts() { $account = Auth::user()->account; @@ -821,21 +928,24 @@ class AccountController extends BaseController return Redirect::to('settings/'.ACCOUNT_PRODUCTS); } + /** + * @return $this|\Illuminate\Http\RedirectResponse + */ private function saveEmailSettings() { if (Auth::user()->account->hasFeature(FEATURE_CUSTOM_EMAILS)) { - $rules = []; $user = Auth::user(); - $iframeURL = preg_replace('/[^a-zA-Z0-9_\-\:\/\.]/', '', substr(strtolower(Input::get('iframe_url')), 0, MAX_IFRAME_URL_LENGTH)); - $iframeURL = rtrim($iframeURL, "/"); + $subdomain = null; + $iframeURL = null; + $rules = []; - $subdomain = preg_replace('/[^a-zA-Z0-9_\-\.]/', '', substr(strtolower(Input::get('subdomain')), 0, MAX_SUBDOMAIN_LENGTH)); - if ($iframeURL) { - $subdomain = null; - } - if ($subdomain) { + if (Input::get('custom_link') == 'subdomain') { + $subdomain = preg_replace('/[^a-zA-Z0-9_\-\.]/', '', substr(strtolower(Input::get('subdomain')), 0, MAX_SUBDOMAIN_LENGTH)); $exclude = ['www', 'app', 'mail', 'admin', 'blog', 'user', 'contact', 'payment', 'payments', 'billing', 'invoice', 'business', 'owner', 'info', 'ninja']; $rules['subdomain'] = "unique:accounts,subdomain,{$user->account_id},id|not_in:" . implode(',', $exclude); + } else { + $iframeURL = preg_replace('/[^a-zA-Z0-9_\-\:\/\.]/', '', substr(strtolower(Input::get('iframe_url')), 0, MAX_IFRAME_URL_LENGTH)); + $iframeURL = rtrim($iframeURL, '/'); } $validator = Validator::make(Input::all(), $rules); @@ -864,6 +974,9 @@ class AccountController extends BaseController return Redirect::to('settings/'.ACCOUNT_EMAIL_SETTINGS); } + /** + * @return $this|\Illuminate\Http\RedirectResponse + */ private function saveInvoiceSettings() { if (Auth::user()->account->hasFeature(FEATURE_INVOICE_SETTINGS)) { @@ -945,6 +1058,9 @@ class AccountController extends BaseController return Redirect::to('settings/'.ACCOUNT_INVOICE_SETTINGS); } + /** + * @return \Illuminate\Http\RedirectResponse + */ private function saveInvoiceDesign() { if (Auth::user()->account->hasFeature(FEATURE_CUSTOMIZE_INVOICE_DESIGN)) { @@ -976,7 +1092,7 @@ class AccountController extends BaseController } $labels = []; - foreach (['item', 'description', 'unit_cost', 'quantity', 'line_total', 'terms', 'balance_due', 'partial_due'] as $field) { + foreach (['item', 'description', 'unit_cost', 'quantity', 'line_total', 'terms', 'balance_due', 'partial_due', 'subtotal', 'paid_to_date', 'discount'] as $field) { $labels[$field] = Input::get("labels_{$field}"); } $account->invoice_labels = json_encode($labels); @@ -989,6 +1105,9 @@ class AccountController extends BaseController return Redirect::to('settings/'.ACCOUNT_INVOICE_DESIGN); } + /** + * @return \Illuminate\Http\RedirectResponse + */ private function saveNotifications() { $user = Auth::user(); @@ -1003,6 +1122,10 @@ class AccountController extends BaseController return Redirect::to('settings/'.ACCOUNT_NOTIFICATIONS); } + /** + * @param UpdateAccountRequest $request + * @return \Illuminate\Http\RedirectResponse + */ public function updateDetails(UpdateAccountRequest $request) { $account = Auth::user()->account; @@ -1025,7 +1148,7 @@ class AccountController extends BaseController $documentType = $extension; } - if(!in_array($documentType, array('jpeg', 'png', 'gif'))){ + if(!in_array($documentType, ['jpeg', 'png', 'gif'])){ Session::flash('warning', 'Unsupported file type'); } else { $documentTypeData = Document::$types[$documentType]; @@ -1089,8 +1212,12 @@ class AccountController extends BaseController return Redirect::to('settings/'.ACCOUNT_COMPANY_DETAILS); } + /** + * @return $this|\Illuminate\Http\RedirectResponse + */ public function saveUserDetails() { + /** @var \App\Models\User $user */ $user = Auth::user(); $rules = ['email' => 'email|required|unique:users,email,'.$user->id.',id']; $validator = Validator::make(Input::all(), $rules); @@ -1124,9 +1251,14 @@ class AccountController extends BaseController } } + /** + * @return \Illuminate\Http\RedirectResponse + */ private function saveLocalization() { + /** @var \App\Models\Account $account */ $account = Auth::user()->account; + $account->timezone_id = Input::get('timezone_id') ? Input::get('timezone_id') : null; $account->date_format_id = Input::get('date_format_id') ? Input::get('date_format_id') : null; $account->datetime_format_id = Input::get('datetime_format_id') ? Input::get('datetime_format_id') : null; @@ -1134,6 +1266,7 @@ class AccountController extends BaseController $account->language_id = Input::get('language_id') ? Input::get('language_id') : 1; // English $account->military_time = Input::get('military_time') ? true : false; $account->show_currency_code = Input::get('show_currency_code') ? true : false; + $account->start_of_week = Input::get('start_of_week') ? Input::get('start_of_week') : 0; $account->save(); event(new UserSettingsChanged()); @@ -1143,6 +1276,26 @@ class AccountController extends BaseController return Redirect::to('settings/'.ACCOUNT_LOCALIZATION); } + /** + * @return \Illuminate\Http\RedirectResponse + */ + private function saveOnlinePayments() + { + $account = Auth::user()->account; + $account->token_billing_type_id = Input::get('token_billing_type_id'); + $account->auto_bill_on_due_date = boolval(Input::get('auto_bill_on_due_date')); + $account->save(); + + event(new UserSettingsChanged()); + + Session::flash('message', trans('texts.updated_settings')); + + return Redirect::to('settings/'.ACCOUNT_PAYMENTS); + } + + /** + * @return \Illuminate\Http\RedirectResponse + */ public function removeLogo() { $account = Auth::user()->account; @@ -1161,25 +1314,33 @@ class AccountController extends BaseController return Redirect::to('settings/'.ACCOUNT_COMPANY_DETAILS); } + /** + * @return string + */ public function checkEmail() { - $email = User::withTrashed()->where('email', '=', Input::get('email'))->where('id', '<>', Auth::user()->id)->first(); + $email = User::withTrashed()->where('email', '=', Input::get('email')) + ->where('id', '<>', Auth::user()->id) + ->first(); if ($email) { - return "taken"; + return 'taken'; } else { - return "available"; + return 'available'; } } + /** + * @return string + */ public function submitSignup() { - $rules = array( + $rules = [ 'new_first_name' => 'required', 'new_last_name' => 'required', 'new_password' => 'required|min:6', 'new_email' => 'email|required|unique:users,email,'.Auth::user()->id.',id', - ); + ]; $validator = Validator::make(Input::all(), $rules); @@ -1187,6 +1348,7 @@ class AccountController extends BaseController return ''; } + /** @var \App\Models\User $user */ $user = Auth::user(); $user->first_name = trim(Input::get('new_first_name')); $user->last_name = trim(Input::get('new_last_name')); @@ -1205,6 +1367,9 @@ class AccountController extends BaseController return "{$user->first_name} {$user->last_name}"; } + /** + * @return mixed + */ public function doRegister() { $affiliate = Affiliate::where('affiliate_key', '=', SELF_HOST_AFFILIATE_KEY)->first(); @@ -1228,6 +1393,9 @@ class AccountController extends BaseController return RESULT_SUCCESS; } + /** + * @return \Illuminate\Http\RedirectResponse + */ public function cancelAccount() { if ($reason = trim(Input::get('reason'))) { @@ -1268,16 +1436,25 @@ class AccountController extends BaseController return Redirect::to('/')->with('clearGuestKey', true); } + /** + * @return \Illuminate\Http\RedirectResponse + */ public function resendConfirmation() { + /** @var \App\Models\User $user */ $user = Auth::user(); $this->userMailer->sendConfirmation($user); return Redirect::to('/settings/'.ACCOUNT_USER_DETAILS)->with('message', trans('texts.confirmation_resent')); } + /** + * @param $plan + * @return \Illuminate\Http\RedirectResponse + */ public function startTrial($plan) { + /** @var \App\Models\User $user */ $user = Auth::user(); if ($user->isEligibleForTrial($plan)) { @@ -1287,6 +1464,11 @@ class AccountController extends BaseController return Redirect::back()->with('message', trans('texts.trial_success')); } + /** + * @param $section + * @param bool $subSection + * @return \Illuminate\Http\RedirectResponse + */ public function redirectLegacy($section, $subSection = false) { if ($section === 'details') { @@ -1307,7 +1489,11 @@ class AccountController extends BaseController return Redirect::to("/settings/$section/", 301); } - public function previewEmail(\App\Services\TemplateService $templateService) + /** + * @param TemplateService $templateService + * @return \Illuminate\Http\Response + */ + public function previewEmail(TemplateService $templateService) { $template = Input::get('template'); $invoice = Invoice::scope() diff --git a/app/Http/Controllers/AccountGatewayController.php b/app/Http/Controllers/AccountGatewayController.php index 968fac50e6..fc6af8a66e 100644 --- a/app/Http/Controllers/AccountGatewayController.php +++ b/app/Http/Controllers/AccountGatewayController.php @@ -1,8 +1,6 @@ gateway->name; $data['config'] = $config; $data['hiddenFields'] = Gateway::$hiddenFields; - $data['paymentTypeId'] = $accountGateway->getPaymentType(); $data['selectGateways'] = Gateway::where('id', '=', $accountGateway->gateway_id)->get(); - return View::make('accounts.account_gateway', $data); } @@ -84,43 +79,40 @@ class AccountGatewayController extends BaseController */ public function create() { - $data = self::getViewModel(); - $data['url'] = 'gateways'; - $data['method'] = 'POST'; - $data['title'] = trans('texts.add_gateway'); - $data['selectGateways'] = Gateway::where('payment_library_id', '=', 1) - ->where('id', '!=', GATEWAY_PAYPAL_EXPRESS) - ->where('id', '!=', GATEWAY_BITPAY) - ->where('id', '!=', GATEWAY_GOCARDLESS) - ->where('id', '!=', GATEWAY_DWOLLA) - ->orderBy('name')->get(); - $data['hiddenFields'] = Gateway::$hiddenFields; - if ( ! \Request::secure() && ! Utils::isNinjaDev()) { Session::flash('warning', trans('texts.enable_https')); } - return View::make('accounts.account_gateway', $data); + $account = Auth::user()->account; + $accountGatewaysIds = $account->gatewayIds(); + $otherProviders = Input::get('other_providers'); + + if ( ! Utils::isNinja() || Gateway::hasStandardGateway($accountGatewaysIds)) { + $otherProviders = true; + } + + $data = self::getViewModel(); + $data['url'] = 'gateways'; + $data['method'] = 'POST'; + $data['title'] = trans('texts.add_gateway'); + + if ($otherProviders) { + $availableGatewaysIds = $account->availableGatewaysIds(); + $data['primaryGateways'] = Gateway::primary($availableGatewaysIds)->orderBy('name', 'desc')->get(); + $data['secondaryGateways'] = Gateway::secondary($availableGatewaysIds)->orderBy('name')->get(); + $data['hiddenFields'] = Gateway::$hiddenFields; + + return View::make('accounts.account_gateway', $data); + } else { + return View::make('accounts.account_gateway_wepay', $data); + } } private function getViewModel($accountGateway = false) { $selectedCards = $accountGateway ? $accountGateway->accepted_credit_cards : 0; - $account = Auth::user()->account; - - $paymentTypes = []; - foreach (Gateway::$paymentTypes as $type) { - if ($accountGateway || !$account->getGatewayByType($type)) { - $paymentTypes[$type] = trans('texts.'.strtolower($type)); - - if ($type == PAYMENT_TYPE_BITCOIN) { - $paymentTypes[$type] .= ' - BitPay'; - } - if ($type == PAYMENT_TYPE_DIRECT_DEBIT) { - $paymentTypes[$type] .= ' - GoCardless'; - } - } - } + $user = Auth::user(); + $account =$user->account; $creditCardsArray = unserialize(CREDIT_CARDS); $creditCards = []; @@ -139,25 +131,19 @@ class AccountGatewayController extends BaseController foreach ($gateways as $gateway) { $fields = $gateway->getFields(); asort($fields); - $gateway->fields = $fields; + $gateway->fields = $gateway->id == GATEWAY_WEPAY ? [] : $fields; if ($accountGateway && $accountGateway->gateway_id == $gateway->id) { $accountGateway->fields = $gateway->fields; } } - $tokenBillingOptions = []; - for ($i=1; $i<=4; $i++) { - $tokenBillingOptions[$i] = trans("texts.token_billing_{$i}"); - } - return [ - 'paymentTypes' => $paymentTypes, 'account' => $account, + 'user' => $user, 'accountGateway' => $accountGateway, 'config' => false, 'gateways' => $gateways, 'creditCardTypes' => $creditCards, - 'tokenBillingOptions' => $tokenBillingOptions, 'countGateways' => count($currentGateways) ]; } @@ -169,7 +155,7 @@ class AccountGatewayController extends BaseController $ids = Input::get('bulk_public_id'); $count = $this->accountGatewayService->bulk($ids, $action); - Session::flash('message', trans('texts.archived_account_gateway')); + Session::flash('message', trans("texts.{$action}d_account_gateway")); return Redirect::to('settings/' . ACCOUNT_PAYMENTS); } @@ -180,27 +166,10 @@ class AccountGatewayController extends BaseController */ public function save($accountGatewayPublicId = false) { - $rules = array(); - $paymentType = Input::get('payment_type_id'); - $gatewayId = Input::get('gateway_id'); - - if ($paymentType == PAYMENT_TYPE_PAYPAL) { - $gatewayId = GATEWAY_PAYPAL_EXPRESS; - } elseif ($paymentType == PAYMENT_TYPE_BITCOIN) { - $gatewayId = GATEWAY_BITPAY; - } elseif ($paymentType == PAYMENT_TYPE_DIRECT_DEBIT) { - $gatewayId = GATEWAY_GOCARDLESS; - } elseif ($paymentType == PAYMENT_TYPE_DWOLLA) { - $gatewayId = GATEWAY_DWOLLA; - } - - if (!$gatewayId) { - Session::flash('error', trans('validation.required', ['attribute' => 'gateway'])); - return Redirect::to('gateways/create') - ->withInput(); - } - + $gatewayId = Input::get('primary_gateway_id') ?: Input::get('secondary_gateway_id'); $gateway = Gateway::findOrFail($gatewayId); + + $rules = []; $fields = $gateway->getFields(); $optional = array_merge(Gateway::$hiddenFields, Gateway::$optionalFields); @@ -211,17 +180,20 @@ class AccountGatewayController extends BaseController // do nothing - we're unable to acceptance test with StripeJS } else { $rules['publishable_key'] = 'required'; + $rules['enable_ach'] = 'boolean'; } } - foreach ($fields as $field => $details) { - if (!in_array($field, $optional)) { - if (strtolower($gateway->name) == 'beanstream') { - if (in_array($field, ['merchant_id', 'passCode'])) { - $rules[$gateway->id.'_'.$field] = 'required'; + if ($gatewayId != GATEWAY_WEPAY) { + foreach ($fields as $field => $details) { + if (!in_array($field, $optional)) { + if (strtolower($gateway->name) == 'beanstream') { + if (in_array($field, ['merchant_id', 'passCode'])) { + $rules[$gateway->id . '_' . $field] = 'required'; + } + } else { + $rules[$gateway->id . '_' . $field] = 'required'; } - } else { - $rules[$gateway->id.'_'.$field] = 'required'; } } } @@ -241,22 +213,44 @@ class AccountGatewayController extends BaseController $accountGateway = AccountGateway::scope($accountGatewayPublicId)->firstOrFail(); $oldConfig = $accountGateway->getConfig(); } else { + // check they don't already have an active gateway for this provider + // TODO complete this + $accountGateway = AccountGateway::scope() + ->whereGatewayId($gatewayId) + ->first(); + if ($accountGateway) { + Session::flash('error', trans('texts.gateway_exists')); + return Redirect::to("gateways/{$accountGateway->public_id}/edit"); + } + $accountGateway = AccountGateway::createNew(); $accountGateway->gateway_id = $gatewayId; + + if ($gatewayId == GATEWAY_WEPAY) { + if(!$this->setupWePay($accountGateway, $wepayResponse)) { + return $wepayResponse; + } + $oldConfig = $accountGateway->getConfig(); + } } $config = new stdClass(); - foreach ($fields as $field => $details) { - $value = trim(Input::get($gateway->id.'_'.$field)); - // if the new value is masked use the original value - if ($oldConfig && $value && $value === str_repeat('*', strlen($value))) { - $value = $oldConfig->$field; - } - if (!$value && ($field == 'testMode' || $field == 'developerMode')) { - // do nothing - } else { - $config->$field = $value; + + if ($gatewayId != GATEWAY_WEPAY) { + foreach ($fields as $field => $details) { + $value = trim(Input::get($gateway->id . '_' . $field)); + // if the new value is masked use the original value + if ($oldConfig && $value && $value === str_repeat('*', strlen($value))) { + $value = $oldConfig->$field; + } + if (!$value && ($field == 'testMode' || $field == 'developerMode')) { + // do nothing + } else { + $config->$field = $value; + } } + } elseif($oldConfig) { + $config = clone $oldConfig; } $publishableKey = Input::get('publishable_key'); @@ -266,6 +260,35 @@ class AccountGatewayController extends BaseController $config->publishableKey = $oldConfig->publishableKey; } + $plaidClientId = Input::get('plaid_client_id'); + if ($plaidClientId = str_replace('*', '', $plaidClientId)) { + $config->plaidClientId = $plaidClientId; + } elseif ($oldConfig && property_exists($oldConfig, 'plaidClientId')) { + $config->plaidClientId = $oldConfig->plaidClientId; + } + + $plaidSecret = Input::get('plaid_secret'); + if ($plaidSecret = str_replace('*', '', $plaidSecret)) { + $config->plaidSecret = $plaidSecret; + } elseif ($oldConfig && property_exists($oldConfig, 'plaidSecret')) { + $config->plaidSecret = $oldConfig->plaidSecret; + } + + $plaidPublicKey = Input::get('plaid_public_key'); + if ($plaidPublicKey = str_replace('*', '', $plaidPublicKey)) { + $config->plaidPublicKey = $plaidPublicKey; + } elseif ($oldConfig && property_exists($oldConfig, 'plaidPublicKey')) { + $config->plaidPublicKey = $oldConfig->plaidPublicKey; + } + + if ($gatewayId == GATEWAY_STRIPE || $gatewayId == GATEWAY_WEPAY) { + $config->enableAch = boolval(Input::get('enable_ach')); + } + + if ($gatewayId == GATEWAY_BRAINTREE) { + $config->enablePayPal = boolval(Input::get('enable_paypal')); + } + $cardCount = 0; if ($creditcards) { foreach ($creditcards as $card => $value) { @@ -284,21 +307,167 @@ class AccountGatewayController extends BaseController $account->account_gateways()->save($accountGateway); } - if (Input::get('token_billing_type_id')) { - $account->token_billing_type_id = Input::get('token_billing_type_id'); - $account->save(); - } - - if ($accountGatewayPublicId) { - $message = trans('texts.updated_gateway'); + if(isset($wepayResponse)) { + return $wepayResponse; } else { - $message = trans('texts.created_gateway'); + if ($accountGatewayPublicId) { + $message = trans('texts.updated_gateway'); + } else { + $message = trans('texts.created_gateway'); + } + + Session::flash('message', $message); + return Redirect::to("gateways/{$accountGateway->public_id}/edit"); } - - Session::flash('message', $message); - - return Redirect::to("gateways/{$accountGateway->public_id}/edit"); } } + protected function getWePayUpdateUri($accountGateway) + { + if ($accountGateway->gateway_id != GATEWAY_WEPAY) { + return null; + } + + $wepay = Utils::setupWePay($accountGateway); + + $update_uri_data = $wepay->request('account/get_update_uri', [ + 'account_id' => $accountGateway->getConfig()->accountId, + 'mode' => 'iframe', + 'redirect_uri' => URL::to('/gateways'), + ]); + + return $update_uri_data->uri; + } + + protected function setupWePay($accountGateway, &$response) + { + $user = Auth::user(); + $account = $user->account; + + $rules = [ + 'company_name' => 'required', + 'description' => 'required', + 'tos_agree' => 'required', + 'first_name' => 'required', + 'last_name' => 'required', + 'email' => 'required', + ]; + + if (WEPAY_ENABLE_CANADA) { + $rules['country'] = 'required|in:US,CA'; + } + + $validator = Validator::make(Input::all(), $rules); + + if ($validator->fails()) { + return Redirect::to('gateways/create') + ->withErrors($validator) + ->withInput(); + } + + try{ + $wepay = Utils::setupWePay(); + + $userDetails = [ + 'client_id' => WEPAY_CLIENT_ID, + 'client_secret' => WEPAY_CLIENT_SECRET, + 'email' => Input::get('email'), + 'first_name' => Input::get('first_name'), + 'last_name' => Input::get('last_name'), + 'original_ip' => \Request::getClientIp(true), + 'original_device' => \Request::server('HTTP_USER_AGENT'), + 'tos_acceptance_time' => time(), + 'redirect_uri' => URL::to('gateways'), + 'scope' => 'manage_accounts,collect_payments,view_user,preapprove_payments,send_money', + ]; + + $wepayUser = $wepay->request('user/register/', $userDetails); + + $accessToken = $wepayUser->access_token; + $accessTokenExpires = $wepayUser->expires_in ? (time() + $wepayUser->expires_in) : null; + + $wepay = new WePay($accessToken); + + $accountDetails = [ + 'name' => Input::get('company_name'), + 'description' => Input::get('description'), + 'theme_object' => json_decode(WEPAY_THEME), + 'callback_uri' => $accountGateway->getWebhookUrl(), + ]; + + if (WEPAY_ENABLE_CANADA) { + $accountDetails['country'] = Input::get('country'); + + if (Input::get('country') == 'CA') { + $accountDetails['currencies'] = ['CAD']; + $accountDetails['country_options'] = ['debit_opt_in' => boolval(Input::get('debit_cards'))]; + } + } + + $wepayAccount = $wepay->request('account/create/', $accountDetails); + + try { + $wepay->request('user/send_confirmation/', []); + $confirmationRequired = true; + } catch(\WePayException $ex){ + if ($ex->getMessage() == 'This access_token is already approved.') { + $confirmationRequired = false; + } else { + throw $ex; + } + } + + $accountGateway->gateway_id = GATEWAY_WEPAY; + $accountGateway->setConfig([ + 'userId' => $wepayUser->user_id, + 'accessToken' => $accessToken, + 'tokenType' => $wepayUser->token_type, + 'tokenExpires' => $accessTokenExpires, + 'accountId' => $wepayAccount->account_id, + 'state' => $wepayAccount->state, + 'testMode' => WEPAY_ENVIRONMENT == WEPAY_STAGE, + 'country' => WEPAY_ENABLE_CANADA ? Input::get('country') : 'US', + ]); + + if ($confirmationRequired) { + Session::flash('message', trans('texts.created_wepay_confirmation_required')); + } else { + $updateUri = $wepay->request('/account/get_update_uri', [ + 'account_id' => $wepayAccount->account_id, + 'redirect_uri' => URL::to('gateways'), + ]); + + $response = Redirect::to($updateUri->uri); + return true; + } + + $response = Redirect::to("gateways/{$accountGateway->public_id}/edit"); + return true; + } catch (\WePayException $e) { + Session::flash('error', $e->getMessage()); + $response = Redirect::to('gateways/create') + ->withInput(); + return false; + } + } + + + public function resendConfirmation($publicId = false) + { + $accountGateway = AccountGateway::scope($publicId)->firstOrFail(); + + if ($accountGateway->gateway_id == GATEWAY_WEPAY) { + try { + $wepay = Utils::setupWePay($accountGateway); + $wepay->request('user/send_confirmation', []); + + Session::flash('message', trans('texts.resent_confirmation_email')); + } catch (\WePayException $e) { + Session::flash('error', $e->getMessage()); + } + } + + return Redirect::to("gateways/{$accountGateway->public_id}/edit"); + } + } diff --git a/app/Http/Controllers/ActivityController.php b/app/Http/Controllers/ActivityController.php index 897e1d2a97..bd84d3ff9a 100644 --- a/app/Http/Controllers/ActivityController.php +++ b/app/Http/Controllers/ActivityController.php @@ -1,12 +1,5 @@ $val) { @@ -114,18 +114,18 @@ class AppController extends BaseController // Write Config Settings - $fp = fopen(base_path()."/.env", 'w'); + $fp = fopen(base_path().'/.env', 'w'); fwrite($fp, $config); fclose($fp); // == DB Migrate & Seed == // // Artisan::call('migrate:rollback', array('--force' => true)); // Debug Purposes - Artisan::call('migrate', array('--force' => true)); + Artisan::call('migrate', ['--force' => true]); if (Industry::count() == 0) { - Artisan::call('db:seed', array('--force' => true)); + Artisan::call('db:seed', ['--force' => true]); } Cache::flush(); - Artisan::call('optimize', array('--force' => true)); + Artisan::call('optimize', ['--force' => true]); $firstName = trim(Input::get('first_name')); $lastName = trim(Input::get('last_name')); @@ -147,7 +147,7 @@ class AppController extends BaseController return Redirect::to('/'); } - if ( ! $canUpdateEnv = @fopen(base_path()."/.env", 'w')) { + if ( ! $canUpdateEnv = @fopen(base_path().'/.env', 'w')) { Session::flash('error', 'Warning: Permission denied to write to .env config file, try running sudo chown www-data:www-data /path/to/ninja/.env'); return Redirect::to('/settings/system_settings'); } @@ -174,6 +174,8 @@ class AppController extends BaseController $_ENV['MAIL_FROM_NAME'] = $mail['from']['name']; $_ENV['MAIL_PASSWORD'] = $mail['password']; $_ENV['MAIL_FROM_ADDRESS'] = $mail['username']; + $_ENV['MAILGUN_DOMAIN'] = $mail['mailgun_domain']; + $_ENV['MAILGUN_SECRET'] = $mail['mailgun_secret']; } $config = ''; @@ -187,7 +189,7 @@ class AppController extends BaseController $config .= "{$key}={$val}\n"; } - $fp = fopen(base_path()."/.env", 'w'); + $fp = fopen(base_path().'/.env', 'w'); fwrite($fp, $config); fclose($fp); @@ -243,11 +245,11 @@ class AppController extends BaseController if (!Utils::isNinjaProd() && !Utils::isDatabaseSetup()) { try { set_time_limit(60 * 5); // shouldn't take this long but just in case - Artisan::call('migrate', array('--force' => true)); + Artisan::call('migrate', ['--force' => true]); if (Industry::count() == 0) { - Artisan::call('db:seed', array('--force' => true)); + Artisan::call('db:seed', ['--force' => true]); } - Artisan::call('optimize', array('--force' => true)); + Artisan::call('optimize', ['--force' => true]); } catch (Exception $e) { Utils::logError($e); return Response::make($e->getMessage(), 500); @@ -268,13 +270,18 @@ class AppController extends BaseController Artisan::call('route:clear'); Artisan::call('view:clear'); Artisan::call('config:clear'); - Artisan::call('optimize', array('--force' => true)); + Artisan::call('optimize', ['--force' => true]); Cache::flush(); Session::flush(); - Artisan::call('migrate', array('--force' => true)); - Artisan::call('db:seed', array('--force' => true, '--class' => "UpdateSeeder")); + Artisan::call('migrate', ['--force' => true]); + Artisan::call('db:seed', ['--force' => true, '--class' => 'UpdateSeeder']); Event::fire(new UserSettingsChanged()); - Session::flash('message', trans('texts.processed_updates')); + + // show message with link to Trello board + $message = trans('texts.see_whats_new', ['version' => NINJA_VERSION]); + $message = link_to(RELEASES_URL, $message, ['target' => '_blank']); + $message = sprintf('%s - %s', trans('texts.processed_updates'), $message); + Session::flash('warning', $message); } catch (Exception $e) { Utils::logError($e); return Response::make($e->getMessage(), 500); diff --git a/app/Http/Controllers/Auth/AuthController.php b/app/Http/Controllers/Auth/AuthController.php index e599890c6a..0824f4d44e 100644 --- a/app/Http/Controllers/Auth/AuthController.php +++ b/app/Http/Controllers/Auth/AuthController.php @@ -12,40 +12,55 @@ use App\Ninja\Repositories\AccountRepository; use App\Services\AuthService; use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers; -class AuthController extends Controller { +class AuthController extends Controller +{ - /* - |-------------------------------------------------------------------------- - | Registration & Login Controller - |-------------------------------------------------------------------------- - | - | This controller handles the registration of new users, as well as the - | authentication of existing users. By default, this controller uses - | a simple trait to add these behaviors. Why don't you explore it? - | - */ + /* + |-------------------------------------------------------------------------- + | Registration & Login Controller + |-------------------------------------------------------------------------- + | + | This controller handles the registration of new users, as well as the + | authentication of existing users. By default, this controller uses + | a simple trait to add these behaviors. Why don't you explore it? + | + */ - use AuthenticatesAndRegistersUsers; + use AuthenticatesAndRegistersUsers; + /** + * @var string + */ protected $redirectTo = '/dashboard'; + + /** + * @var AuthService + */ protected $authService; + + /** + * @var AccountRepository + */ protected $accountRepo; - /** - * Create a new authentication controller instance. - * - * @param \Illuminate\Contracts\Auth\Guard $auth - * @param \Illuminate\Contracts\Auth\Registrar $registrar - * @return void - */ - public function __construct(AccountRepository $repo, AuthService $authService) - { + /** + * Create a new authentication controller instance. + * + * @param AccountRepository $repo + * @param AuthService $authService + * @internal param \Illuminate\Contracts\Auth\Guard $auth + * @internal param \Illuminate\Contracts\Auth\Registrar $registrar + */ + public function __construct(AccountRepository $repo, AuthService $authService) + { $this->accountRepo = $repo; $this->authService = $authService; + } - //$this->middleware('guest', ['except' => 'getLogout']); - } - + /** + * @param array $data + * @return mixed + */ public function validator(array $data) { return Validator::make($data, [ @@ -58,7 +73,8 @@ class AuthController extends Controller { /** * Create a new user instance after a valid registration. * - * @param array $data + * @param array $data + * * @return User */ public function create(array $data) @@ -70,11 +86,20 @@ class AuthController extends Controller { ]); } + /** + * @param $provider + * @param Request $request + * + * @return \Illuminate\Http\RedirectResponse + */ public function authLogin($provider, Request $request) { return $this->authService->execute($provider, $request->has('code')); } + /** + * @return \Illuminate\Http\RedirectResponse + */ public function authUnlink() { $this->accountRepo->unlinkUserFromOauth(Auth::user()); @@ -83,6 +108,9 @@ class AuthController extends Controller { return redirect()->to('/settings/' . ACCOUNT_USER_DETAILS); } + /** + * @return \Illuminate\Http\Response + */ public function getLoginWrapper() { if (!Utils::isNinja() && !User::count()) { @@ -92,6 +120,11 @@ class AuthController extends Controller { return self::getLogin(); } + /** + * @param Request $request + * + * @return \Illuminate\Http\Response + */ public function postLoginWrapper(Request $request) { @@ -113,7 +146,7 @@ class AuthController extends Controller { if ($request->link_accounts && $userId && Auth::user()->id != $userId) { $users = $this->accountRepo->associateAccounts($userId, Auth::user()->id); Session::flash('message', trans('texts.associated_accounts')); - // check if other accounts are linked + // check if other accounts are linked } else { $users = $this->accountRepo->loadAccounts(Auth::user()->id); } @@ -127,14 +160,16 @@ class AuthController extends Controller { return $response; } - + /** + * @return \Illuminate\Http\Response + */ public function getLogoutWrapper() { if (Auth::check() && !Auth::user()->registered) { $account = Auth::user()->account; $this->accountRepo->unlinkAccount($account); if ($account->company->accounts->count() == 1) { - $account->company->forceDelete(); + $account->company->forceDelete(); } $account->forceDelete(); } diff --git a/app/Http/Controllers/Auth/PasswordController.php b/app/Http/Controllers/Auth/PasswordController.php index bd7d0bb0ef..e26ca7bc1f 100644 --- a/app/Http/Controllers/Auth/PasswordController.php +++ b/app/Http/Controllers/Auth/PasswordController.php @@ -3,33 +3,36 @@ use App\Http\Controllers\Controller; use Illuminate\Foundation\Auth\ResetsPasswords; -class PasswordController extends Controller { +class PasswordController extends Controller +{ - /* - |-------------------------------------------------------------------------- - | Password Reset Controller - |-------------------------------------------------------------------------- - | - | This controller is responsible for handling password reset requests - | and uses a simple trait to include this behavior. You're free to - | explore this trait and override any methods you wish to tweak. - | - */ + /* + |-------------------------------------------------------------------------- + | Password Reset Controller + |-------------------------------------------------------------------------- + | + | This controller is responsible for handling password reset requests + | and uses a simple trait to include this behavior. You're free to + | explore this trait and override any methods you wish to tweak. + | + */ - use ResetsPasswords; + use ResetsPasswords; + /** + * @var string + */ protected $redirectTo = '/dashboard'; - - /** - * Create a new password controller instance. - * - * @param \Illuminate\Contracts\Auth\Guard $auth - * @param \Illuminate\Contracts\Auth\PasswordBroker $passwords - * @return void - */ - public function __construct() - { - $this->middleware('guest'); - } + + /** + * Create a new password controller instance. + * + * @internal param \Illuminate\Contracts\Auth\Guard $auth + * @internal param \Illuminate\Contracts\Auth\PasswordBroker $passwords + */ + public function __construct() + { + $this->middleware('guest'); + } } diff --git a/app/Http/Controllers/BankAccountController.php b/app/Http/Controllers/BankAccountController.php index bce86bce42..338894c692 100644 --- a/app/Http/Controllers/BankAccountController.php +++ b/app/Http/Controllers/BankAccountController.php @@ -2,23 +2,18 @@ use Cache; use Auth; -use Datatable; -use DB; use Input; use Redirect; use Session; use View; -use Validator; -use stdClass; use Crypt; -use URL; -use Utils; -use App\Models\Gateway; +use File; use App\Models\Account; use App\Models\BankAccount; use App\Ninja\Repositories\BankAccountRepository; use App\Services\BankAccountService; use App\Http\Requests\CreateBankAccountRequest; +use Illuminate\Http\Request; class BankAccountController extends BaseController { @@ -122,4 +117,28 @@ class BankAccountController extends BaseController return $this->bankAccountService->importExpenses($bankId, Input::all()); } + public function showImportOFX() + { + return view('accounts.import_ofx'); + } + + public function doImportOFX(Request $request) + { + $file = File::get($request->file('ofx_file')); + + try { + $data = $this->bankAccountService->parseOFX($file); + } catch (\Exception $e) { + Session::flash('error', trans('texts.ofx_parse_failed')); + return view('accounts.import_ofx'); + } + + $data = [ + 'banks' => null, + 'bankAccount' => null, + 'transactions' => json_encode([$data]) + ]; + + return View::make('accounts.bank_account', $data); + } } diff --git a/app/Http/Controllers/BaseAPIController.php b/app/Http/Controllers/BaseAPIController.php index 4531afc252..2561a1c57b 100644 --- a/app/Http/Controllers/BaseAPIController.php +++ b/app/Http/Controllers/BaseAPIController.php @@ -1,13 +1,10 @@ first(); - if ($invitation && !$invitation->is_deleted) { - $invoice = $invitation->invoice; - $client = $invoice->client; - $account = $client->account; - - $data['hideLogo'] = $account->hasFeature(FEATURE_WHITE_LABEL); - $data['clientViewCSS'] = $account->clientViewCSS(); + $contactKey = session('contact_key'); + if ($contactKey) { + $contact = Contact::where('contact_key', '=', $contactKey)->first(); + if ($contact && !$contact->is_deleted) { + $account = $contact->account; + + $data['account'] = $account; $data['clientFontUrl'] = $account->getFontsUrl(); } } - - return view('clientauth.login')->with($data); - } - /** + return view('clientauth.login')->with($data); + } + + /** * Get the needed authorization credentials from the request. * - * @param \Illuminate\Http\Request $request + * @param \Illuminate\Http\Request $request + * * @return array */ protected function getCredentials(Request $request) { $credentials = $request->only('password'); $credentials['id'] = null; - - $invitation_key = session('invitation_key'); - if($invitation_key){ - $invitation = Invitation::where('invitation_key', '=', $invitation_key)->first(); - if ($invitation && !$invitation->is_deleted) { - $credentials['id'] = $invitation->contact_id; + + $contactKey = session('contact_key'); + if ($contactKey) { + $contact = Contact::where('contact_key', '=', $contactKey)->first(); + if ($contact && !$contact->is_deleted) { + $credentials['id'] = $contact->id; } } - + return $credentials; } - - /** + + /** * Validate the user login request. * - * @param \Illuminate\Http\Request $request + * @param \Illuminate\Http\Request $request + * * @return void */ protected function validateLogin(Request $request) @@ -76,4 +78,12 @@ class AuthController extends Controller { 'password' => 'required', ]); } + + /** + * @return mixed + */ + public function getSessionExpired() + { + return view('clientauth.sessionexpired'); + } } diff --git a/app/Http/Controllers/ClientAuth/PasswordController.php b/app/Http/Controllers/ClientAuth/PasswordController.php index 35576b47ae..a7957cacf5 100644 --- a/app/Http/Controllers/ClientAuth/PasswordController.php +++ b/app/Http/Controllers/ClientAuth/PasswordController.php @@ -6,79 +6,84 @@ use Illuminate\Foundation\Auth\ResetsPasswords; use Illuminate\Http\Request; use Illuminate\Mail\Message; use Illuminate\Support\Facades\Password; +use App\Models\Contact; use App\Models\Invitation; +class PasswordController extends Controller +{ -class PasswordController extends Controller { + /* + |-------------------------------------------------------------------------- + | Password Reset Controller + |-------------------------------------------------------------------------- + | + | This controller is responsible for handling password reset requests + | and uses a simple trait to include this behavior. You're free to + | explore this trait and override any methods you wish to tweak. + | + */ - /* - |-------------------------------------------------------------------------- - | Password Reset Controller - |-------------------------------------------------------------------------- - | - | This controller is responsible for handling password reset requests - | and uses a simple trait to include this behavior. You're free to - | explore this trait and override any methods you wish to tweak. - | - */ - - use ResetsPasswords; + use ResetsPasswords; + /** + * @var string + */ protected $redirectTo = '/client/dashboard'; - - /** - * Create a new password controller instance. - * - * @param \Illuminate\Contracts\Auth\Guard $auth - * @param \Illuminate\Contracts\Auth\PasswordBroker $passwords - * @return void - */ - public function __construct() - { - $this->middleware('guest'); - Config::set("auth.defaults.passwords","client"); - } - public function showLinkRequestForm() - { - $data = array(); - $invitation_key = session('invitation_key'); - if($invitation_key){ - $invitation = Invitation::where('invitation_key', '=', $invitation_key)->first(); - if ($invitation && !$invitation->is_deleted) { - $invoice = $invitation->invoice; - $client = $invoice->client; - $account = $client->account; - - $data['hideLogo'] = $account->hasFeature(FEATURE_WHITE_LABEL); - $data['clientViewCSS'] = $account->clientViewCSS(); + /** + * Create a new password controller instance. + * + * @internal param \Illuminate\Contracts\Auth\Guard $auth + * @internal param \Illuminate\Contracts\Auth\PasswordBroker $passwords + */ + public function __construct() + { + $this->middleware('guest'); + Config::set('auth.defaults.passwords', 'client'); + } + + /** + * @return \Illuminate\Http\RedirectResponse + */ + public function showLinkRequestForm() + { + $data = []; + $contactKey = session('contact_key'); + if ($contactKey) { + $contact = Contact::where('contact_key', '=', $contactKey)->first(); + if ($contact && !$contact->is_deleted) { + $account = $contact->account; + $data['account'] = $account; $data['clientFontUrl'] = $account->getFontsUrl(); } + } else { + return \Redirect::to('/client/sessionexpired'); } - - return view('clientauth.password')->with($data); - } - - /** + + return view('clientauth.password')->with($data); + } + + /** * Send a reset link to the given user. * - * @param \Illuminate\Http\Request $request + * @param \Illuminate\Http\Request $request + * * @return \Illuminate\Http\Response */ public function sendResetLinkEmail(Request $request) { $broker = $this->getBroker(); - $contact_id = null; - $invitation_key = session('invitation_key'); - if($invitation_key){ - $invitation = Invitation::where('invitation_key', '=', $invitation_key)->first(); - if ($invitation && !$invitation->is_deleted) { - $contact_id = $invitation->contact_id; + $contactId = null; + $contactKey = session('contact_key'); + if ($contactKey) { + $contact = Contact::where('contact_key', '=', $contactKey)->first(); + if ($contact && !$contact->is_deleted) { + $contactId = $contact->id; } } - - $response = Password::broker($broker)->sendResetLink(array('id'=>$contact_id), function (Message $message) { + + $response = Password::broker($broker)->sendResetLink(['id' => $contactId], function (Message $message) { $message->subject($this->getEmailSubject()); }); @@ -91,62 +96,69 @@ class PasswordController extends Controller { return $this->getSendResetLinkEmailFailureResponse($response); } } - + /** * Display the password reset view for the given token. * * If no token is present, display the link request form. * - * @param \Illuminate\Http\Request $request - * @param string|null $invitation_key - * @param string|null $token + * @param \Illuminate\Http\Request $request + * @param string|null $key + * @param string|null $token * @return \Illuminate\Http\Response */ - public function showResetForm(Request $request, $invitation_key = null, $token = null) + public function showResetForm(Request $request, $key = null, $token = null) { if (is_null($token)) { return $this->getEmail(); } - - $data = compact('token', 'invitation_key'); - $invitation_key = session('invitation_key'); - if($invitation_key){ - $invitation = Invitation::where('invitation_key', '=', $invitation_key)->first(); - if ($invitation && !$invitation->is_deleted) { - $invoice = $invitation->invoice; - $client = $invoice->client; - $account = $client->account; - - $data['hideLogo'] = $account->hasFeature(FEATURE_WHITE_LABEL); - $data['clientViewCSS'] = $account->clientViewCSS(); + + $data = compact('token'); + if ($key) { + $contact = Contact::where('contact_key', '=', $key)->first(); + if ($contact && !$contact->is_deleted) { + $account = $contact->account; + $data['contact_key'] = $contact->contact_key; + } else { + // Maybe it's an invitation key + $invitation = Invitation::where('invitation_key', '=', $key)->first(); + if ($invitation && !$invitation->is_deleted) { + $account = $invitation->account; + $data['contact_key'] = $invitation->contact->contact_key; + } + } + + if (!empty($account)) { + $data['account'] = $account; $data['clientFontUrl'] = $account->getFontsUrl(); + } else { + return \Redirect::to('/client/sessionexpired'); } } return view('clientauth.reset')->with($data); } - - + /** * Display the password reset view for the given token. * * If no token is present, display the link request form. * - * @param \Illuminate\Http\Request $request - * @param string|null $invitation_key - * @param string|null $token + * @param \Illuminate\Http\Request $request + * @param string|null $key + * @param string|null $token * @return \Illuminate\Http\Response */ - public function getReset(Request $request, $invitation_key = null, $token = null) + public function getReset(Request $request, $key = null, $token = null) { - return $this->showResetForm($request, $invitation_key, $token); + return $this->showResetForm($request, $key, $token); } - + /** * Reset the given user's password. * - * @param \Illuminate\Http\Request $request + * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function reset(Request $request) @@ -156,14 +168,14 @@ class PasswordController extends Controller { $credentials = $request->only( 'password', 'password_confirmation', 'token' ); - + $credentials['id'] = null; - - $invitation_key = $request->input('invitation_key'); - if($invitation_key){ - $invitation = Invitation::where('invitation_key', '=', $invitation_key)->first(); - if ($invitation && !$invitation->is_deleted) { - $credentials['id'] = $invitation->contact_id; + + $contactKey = session('contact_key'); + if ($contactKey) { + $contact = Contact::where('contact_key', '=', $contactKey)->first(); + if ($contact && !$contact->is_deleted) { + $credentials['id'] = $contact->id; } } @@ -181,7 +193,7 @@ class PasswordController extends Controller { return $this->getResetFailureResponse($request, $response); } } - + /** * Get the password reset validation rules. * diff --git a/app/Http/Controllers/ClientController.php b/app/Http/Controllers/ClientController.php index 90aedfb897..79e309c76d 100644 --- a/app/Http/Controllers/ClientController.php +++ b/app/Http/Controllers/ClientController.php @@ -1,33 +1,21 @@ ENTITY_CLIENT, 'title' => trans('texts.clients'), 'sortCol' => '4', @@ -67,12 +55,15 @@ class ClientController extends BaseController 'balance', '' ]), - )); + ]); } public function getDatatable() { - return $this->clientService->getDatatable(Input::get('sSearch')); + $search = Input::get('sSearch'); + $userId = Auth::user()->filterId(); + + return $this->clientService->getDatatable($search, $userId); } /** @@ -97,8 +88,8 @@ class ClientController extends BaseController */ public function show(ClientRequest $request) { - $client = $request->entity(); - + $client = $request->entity(); + $user = Auth::user(); Utils::trackViewed($client->getDisplayName(), ENTITY_CLIENT); @@ -109,34 +100,37 @@ class ClientController extends BaseController if (Utils::hasFeature(FEATURE_QUOTES) && $user->can('create', ENTITY_INVOICE)) { $actionLinks[] = ['label' => trans('texts.new_quote'), 'url' => URL::to('/quotes/create/'.$client->public_id)]; } - + if(!empty($actionLinks)){ $actionLinks[] = \DropdownButton::DIVIDER; } - + if($user->can('create', ENTITY_PAYMENT)){ $actionLinks[] = ['label' => trans('texts.enter_payment'), 'url' => URL::to('/payments/create/'.$client->public_id)]; } - + if($user->can('create', ENTITY_CREDIT)){ $actionLinks[] = ['label' => trans('texts.enter_credit'), 'url' => URL::to('/credits/create/'.$client->public_id)]; } - + if($user->can('create', ENTITY_EXPENSE)){ $actionLinks[] = ['label' => trans('texts.enter_expense'), 'url' => URL::to('/expenses/create/0/'.$client->public_id)]; } - $data = array( + $token = $client->getGatewayToken(); + + $data = [ 'actionLinks' => $actionLinks, 'showBreadcrumbs' => false, 'client' => $client, 'credit' => $client->getTotalCredit(), 'title' => trans('texts.view_client'), 'hasRecurringInvoices' => Invoice::scope()->where('is_recurring', '=', true)->whereClientId($client->id)->count() > 0, - 'hasQuotes' => Invoice::scope()->where('is_quote', '=', true)->whereClientId($client->id)->count() > 0, + 'hasQuotes' => Invoice::scope()->invoiceType(INVOICE_TYPE_QUOTE)->whereClientId($client->id)->count() > 0, 'hasTasks' => Task::scope()->whereClientId($client->id)->count() > 0, - 'gatewayLink' => $client->getGatewayLink(), - ); + 'gatewayLink' => $token ? $token->gatewayLink() : false, + 'gatewayName' => $token ? $token->gatewayName() : false, + ]; return View::make('clients.show', $data); } @@ -149,7 +143,7 @@ class ClientController extends BaseController public function create(ClientRequest $request) { if (Client::scope()->withTrashed()->count() > Auth::user()->getMaxNumClients()) { - return View::make('error', ['hideHeader' => true, 'error' => "Sorry, you've exceeded the limit of ".Auth::user()->getMaxNumClients()." clients"]); + return View::make('error', ['hideHeader' => true, 'error' => "Sorry, you've exceeded the limit of ".Auth::user()->getMaxNumClients().' clients']); } $data = [ @@ -173,7 +167,7 @@ class ClientController extends BaseController public function edit(ClientRequest $request) { $client = $request->entity(); - + $data = [ 'client' => $client, 'method' => 'PUT', @@ -199,10 +193,7 @@ class ClientController extends BaseController 'account' => Auth::user()->account, 'sizes' => Cache::get('sizes'), 'paymentTerms' => Cache::get('paymentTerms'), - 'industries' => Cache::get('industries'), 'currencies' => Cache::get('currencies'), - 'languages' => Cache::get('languages'), - 'countries' => Cache::get('countries'), 'customLabel1' => Auth::user()->account->custom_client_label1, 'customLabel2' => Auth::user()->account->custom_client_label2, ]; diff --git a/app/Http/Controllers/PublicClientController.php b/app/Http/Controllers/ClientPortalController.php similarity index 53% rename from app/Http/Controllers/PublicClientController.php rename to app/Http/Controllers/ClientPortalController.php index 32d6d53c38..fa396a6824 100644 --- a/app/Http/Controllers/PublicClientController.php +++ b/app/Http/Controllers/ClientPortalController.php @@ -2,7 +2,6 @@ use Auth; use View; -use DB; use URL; use Input; use Utils; @@ -10,9 +9,15 @@ use Request; use Response; use Session; use Datatable; +use Validator; +use Cache; +use Redirect; +use Exception; use App\Models\Gateway; use App\Models\Invitation; use App\Models\Document; +use App\Models\PaymentMethod; +use App\Models\Contact; use App\Ninja\Repositories\InvoiceRepository; use App\Ninja\Repositories\PaymentRepository; use App\Ninja\Repositories\ActivityRepository; @@ -22,7 +27,7 @@ use App\Events\QuoteInvitationWasViewed; use App\Services\PaymentService; use Barracuda\ArchiveStream\ZipArchive; -class PublicClientController extends BaseController +class ClientPortalController extends BaseController { private $invoiceRepo; private $paymentRepo; @@ -56,9 +61,9 @@ class PublicClientController extends BaseController ]); } - if (!Input::has('phantomjs') && !Input::has('silent') && !Session::has($invitationKey) + if (!Input::has('phantomjs') && !Input::has('silent') && !Session::has($invitationKey) && (!Auth::check() || Auth::user()->account_id != $invoice->account_id)) { - if ($invoice->is_quote) { + if ($invoice->isType(INVOICE_TYPE_QUOTE)) { event(new QuoteInvitationWasViewed($invoice, $invitation)); } else { event(new InvoiceInvitationWasViewed($invoice, $invitation)); @@ -66,10 +71,10 @@ class PublicClientController extends BaseController } Session::put($invitationKey, true); // track this invitation has been seen - Session::put('invitation_key', $invitationKey); // track current invitation + Session::put('contact_key', $invitation->contact->contact_key);// track current contact $account->loadLocalizationSettings($client); - + $invoice->invoice_date = Utils::fromSqlDate($invoice->invoice_date); $invoice->due_date = Utils::fromSqlDate($invoice->due_date); $invoice->features = [ @@ -78,7 +83,7 @@ class PublicClientController extends BaseController 'invoice_settings' => $account->hasFeature(FEATURE_INVOICE_SETTINGS), ]; $invoice->invoice_fonts = $account->getFontsData(); - + if ($invoice->invoice_design_id == CUSTOM_DESIGN) { $invoice->invoice_design->javascript = $account->custom_design; } else { @@ -92,15 +97,20 @@ class PublicClientController extends BaseController 'phone', ]); - $paymentTypes = $this->getPaymentTypes($client, $invitation); + $data = []; + $paymentTypes = $this->getPaymentTypes($account, $client, $invitation); $paymentURL = ''; - if (count($paymentTypes)) { + if (count($paymentTypes) == 1) { $paymentURL = $paymentTypes[0]['url']; if (!$account->isGatewayConfigured(GATEWAY_PAYPAL_EXPRESS)) { $paymentURL = URL::to($paymentURL); } } + if ($wepayGateway = $account->getGatewayConfig(GATEWAY_WEPAY)){ + $data['enableWePayACH'] = $wepayGateway->getAchEnabled(); + } + $showApprove = $invoice->quote_invoice_id ? false : true; if ($invoice->due_date) { $showApprove = time() < strtotime($invoice->due_date); @@ -109,28 +119,10 @@ class PublicClientController extends BaseController $showApprove = false; } - // Checkout.com requires first getting a payment token - $checkoutComToken = false; - $checkoutComKey = false; - $checkoutComDebug = false; - if ($accountGateway = $account->getGatewayConfig(GATEWAY_CHECKOUT_COM)) { - $checkoutComDebug = $accountGateway->getConfigField('testMode'); - if ($checkoutComToken = $this->paymentService->getCheckoutComToken($invitation)) { - $checkoutComKey = $accountGateway->getConfigField('publicApiKey'); - $invitation->transaction_reference = $checkoutComToken; - $invitation->save(); - } - } - - $data = array( + $data += [ 'account' => $account, 'showApprove' => $showApprove, 'showBreadcrumbs' => false, - 'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL), - 'hideHeader' => $account->isNinjaAccount() || !$account->enable_client_portal, - 'hideDashboard' => !$account->enable_client_portal_dashboard, - 'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS), - 'clientViewCSS' => $account->clientViewCSS(), 'clientFontUrl' => $account->getFontsUrl(), 'invoice' => $invoice->hidePrivateFields(), 'invitation' => $invitation, @@ -138,15 +130,22 @@ class PublicClientController extends BaseController 'contact' => $contact, 'paymentTypes' => $paymentTypes, 'paymentURL' => $paymentURL, - 'checkoutComToken' => $checkoutComToken, - 'checkoutComKey' => $checkoutComKey, - 'checkoutComDebug' => $checkoutComDebug, 'phantomjs' => Input::has('phantomjs'), - ); - + ]; + + if ($paymentDriver = $account->paymentDriver($invitation, GATEWAY_TYPE_CREDIT_CARD)) { + $data += [ + 'transactionToken' => $paymentDriver->createTransactionToken(), + 'partialView' => $paymentDriver->partialView(), + 'accountGateway' => $paymentDriver->accountGateway, + ]; + } + + + if($account->hasFeature(FEATURE_DOCUMENTS) && $this->canCreateZip()){ $zipDocs = $this->getInvoiceZipDocuments($invoice, $size); - + if(count($zipDocs) > 1){ $data['documentsZipURL'] = URL::to("client/documents/{$invitation->invitation_key}"); $data['documentsZipSize'] = $size; @@ -156,32 +155,29 @@ class PublicClientController extends BaseController return View::make('invoices.view', $data); } - private function getPaymentTypes($client, $invitation) + public function contactIndex($contactKey) { + if (!$contact = Contact::where('contact_key', '=', $contactKey)->first()) { + return $this->returnError(); + } + + $client = $contact->client; + + Session::put('contact_key', $contactKey);// track current contact + + return redirect()->to($client->account->enable_client_portal_dashboard?'/client/dashboard':'/client/invoices/'); + } + + private function getPaymentTypes($account, $client, $invitation) { - $paymentTypes = []; - $account = $client->account; + $links = []; - if ($client->getGatewayToken()) { - $paymentTypes[] = [ - 'url' => URL::to("payment/{$invitation->invitation_key}/token"), 'label' => trans('texts.use_card_on_file') - ]; - } - foreach(Gateway::$paymentTypes as $type) { - if ($account->getGatewayByType($type)) { - $typeLink = strtolower(str_replace('PAYMENT_TYPE_', '', $type)); - $url = URL::to("/payment/{$invitation->invitation_key}/{$typeLink}"); - - // PayPal doesn't allow being run in an iframe so we need to open in new tab - if ($type === PAYMENT_TYPE_PAYPAL && $account->iframe_url) { - $url = 'javascript:window.open("'.$url.'", "_blank")'; - } - $paymentTypes[] = [ - 'url' => $url, 'label' => trans('texts.'.strtolower($type)) - ]; - } + foreach ($account->account_gateways as $accountGateway) { + $paymentDriver = $accountGateway->paymentDriver($invitation); + $links = array_merge($links, $paymentDriver->tokenLinks()); + $links = array_merge($links, $paymentDriver->paymentLinks()); } - return $paymentTypes; + return $links; } public function download($invitationKey) @@ -207,40 +203,46 @@ class PublicClientController extends BaseController public function dashboard() { - if (!$invitation = $this->getInvitation()) { + if (!$contact = $this->getContact()) { return $this->returnError(); } - $account = $invitation->account; - $invoice = $invitation->invoice; - $client = $invoice->client; + $client = $contact->client; + $account = $client->account; $color = $account->primary_color ? $account->primary_color : '#0b4d78'; + $customer = false; if (!$account->enable_client_portal || !$account->enable_client_portal_dashboard) { return $this->returnError(); } + if ($paymentDriver = $account->paymentDriver(false, GATEWAY_TYPE_TOKEN)) { + $customer = $paymentDriver->customer($client->id); + } + $data = [ 'color' => $color, + 'contact' => $contact, 'account' => $account, 'client' => $client, - 'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL), - 'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS), - 'clientViewCSS' => $account->clientViewCSS(), 'clientFontUrl' => $account->getFontsUrl(), + 'gateway' => $account->getTokenGateway(), + 'paymentMethods' => $customer ? $customer->payment_methods : false, + 'transactionToken' => $paymentDriver ? $paymentDriver->createTransactionToken() : false, ]; - + return response()->view('invited.dashboard', $data); } public function activityDatatable() { - if (!$invitation = $this->getInvitation()) { - return false; + if (!$contact = $this->getContact()) { + return $this->returnError(); } - $invoice = $invitation->invoice; - $query = $this->activityRepo->findByClientId($invoice->client_id); + $client = $contact->client; + + $query = $this->activityRepo->findByClientId($client->id); $query->where('activities.adjustment', '!=', 0); return Datatable::query($query) @@ -248,10 +250,13 @@ class PublicClientController extends BaseController ->addColumn('activity_type_id', function ($model) { $data = [ 'client' => Utils::getClientDisplayName($model), - 'user' => $model->is_system ? ('' . trans('texts.system') . '') : ($model->user_first_name . ' ' . $model->user_last_name), - 'invoice' => trans('texts.invoice') . ' ' . $model->invoice, + 'user' => $model->is_system ? ('' . trans('texts.system') . '') : ($model->account_name), + 'invoice' => $model->invoice, 'contact' => Utils::getClientDisplayName($model), - 'payment' => trans('texts.payment') . ($model->payment ? ' ' . $model->payment : ''), + 'payment' => $model->payment ? ' ' . $model->payment : '', + 'credit' => $model->payment_amount ? Utils::formatMoney($model->credit, $model->currency_id, $model->country_id) : '', + 'payment_amount' => $model->payment_amount ? Utils::formatMoney($model->payment_amount, $model->currency_id, $model->country_id) : null, + 'adjustment' => $model->adjustment ? Utils::formatMoney($model->adjustment, $model->currency_id, $model->country_id) : null, ]; return trans("texts.activity_{$model->activity_type_id}", $data); @@ -261,26 +266,51 @@ class PublicClientController extends BaseController ->make(); } - public function invoiceIndex() + public function recurringInvoiceIndex() { - if (!$invitation = $this->getInvitation()) { + if (!$contact = $this->getContact()) { return $this->returnError(); } - $account = $invitation->account; + $account = $contact->account; if (!$account->enable_client_portal) { return $this->returnError(); } $color = $account->primary_color ? $account->primary_color : '#0b4d78'; - + $data = [ 'color' => $color, - 'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL), - 'hideDashboard' => !$account->enable_client_portal_dashboard, - 'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS), - 'clientViewCSS' => $account->clientViewCSS(), + 'account' => $account, + 'client' => $contact->client, + 'clientFontUrl' => $account->getFontsUrl(), + 'title' => trans('texts.recurring_invoices'), + 'entityType' => ENTITY_RECURRING_INVOICE, + 'columns' => Utils::trans(['frequency', 'start_date', 'end_date', 'invoice_total', 'auto_bill']), + ]; + + return response()->view('public_list', $data); + } + + public function invoiceIndex() + { + if (!$contact = $this->getContact()) { + return $this->returnError(); + } + + $account = $contact->account; + + if (!$account->enable_client_portal) { + return $this->returnError(); + } + + $color = $account->primary_color ? $account->primary_color : '#0b4d78'; + + $data = [ + 'color' => $color, + 'account' => $account, + 'client' => $contact->client, 'clientFontUrl' => $account->getFontsUrl(), 'title' => trans('texts.invoices'), 'entityType' => ENTITY_INVOICE, @@ -292,36 +322,43 @@ class PublicClientController extends BaseController public function invoiceDatatable() { - if (!$invitation = $this->getInvitation()) { + if (!$contact = $this->getContact()) { return ''; } - return $this->invoiceRepo->getClientDatatable($invitation->contact_id, ENTITY_INVOICE, Input::get('sSearch')); + return $this->invoiceRepo->getClientDatatable($contact->id, ENTITY_INVOICE, Input::get('sSearch')); + } + + public function recurringInvoiceDatatable() + { + if (!$contact = $this->getContact()) { + return ''; + } + + return $this->invoiceRepo->getClientRecurringDatatable($contact->id); } public function paymentIndex() { - if (!$invitation = $this->getInvitation()) { + if (!$contact = $this->getContact()) { return $this->returnError(); } - $account = $invitation->account; + + $account = $contact->account; if (!$account->enable_client_portal) { return $this->returnError(); } - $color = $account->primary_color ? $account->primary_color : '#0b4d78'; + $color = $account->primary_color ? $account->primary_color : '#0b4d78'; $data = [ 'color' => $color, - 'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL), - 'hideDashboard' => !$account->enable_client_portal_dashboard, - 'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS), - 'clientViewCSS' => $account->clientViewCSS(), + 'account' => $account, 'clientFontUrl' => $account->getFontsUrl(), 'entityType' => ENTITY_PAYMENT, 'title' => trans('texts.payments'), - 'columns' => Utils::trans(['invoice', 'transaction_reference', 'method', 'payment_amount', 'payment_date']) + 'columns' => Utils::trans(['invoice', 'transaction_reference', 'method', 'payment_amount', 'payment_date', 'status']) ]; return response()->view('public_list', $data); @@ -329,27 +366,56 @@ class PublicClientController extends BaseController public function paymentDatatable() { - if (!$invitation = $this->getInvitation()) { - return false; + if (!$contact = $this->getContact()) { + return $this->returnError(); } - $payments = $this->paymentRepo->findForContact($invitation->contact->id, Input::get('sSearch')); + $payments = $this->paymentRepo->findForContact($contact->id, Input::get('sSearch')); return Datatable::query($payments) ->addColumn('invoice_number', function ($model) { return $model->invitation_key ? link_to('/view/'.$model->invitation_key, $model->invoice_number)->toHtml() : $model->invoice_number; }) - ->addColumn('transaction_reference', function ($model) { return $model->transaction_reference ? $model->transaction_reference : 'Manual entry'; }) - ->addColumn('payment_type', function ($model) { return $model->payment_type ? $model->payment_type : ($model->account_gateway_id ? 'Online payment' : ''); }) + ->addColumn('transaction_reference', function ($model) { return $model->transaction_reference ? $model->transaction_reference : ''.trans('texts.manual_entry').''; }) + ->addColumn('payment_type', function ($model) { return ($model->payment_type && !$model->last4) ? $model->payment_type : ($model->account_gateway_id ? 'Online payment' : ''); }) ->addColumn('amount', function ($model) { return Utils::formatMoney($model->amount, $model->currency_id, $model->country_id); }) ->addColumn('payment_date', function ($model) { return Utils::dateToString($model->payment_date); }) + ->addColumn('status', function ($model) { return $this->getPaymentStatusLabel($model); }) + ->orderColumns( 'invoice_number', 'transaction_reference', 'payment_type', 'amount', 'payment_date') ->make(); } + private function getPaymentStatusLabel($model) + { + $label = trans('texts.status_' . strtolower($model->payment_status_name)); + $class = 'default'; + switch ($model->payment_status_id) { + case PAYMENT_STATUS_PENDING: + $class = 'info'; + break; + case PAYMENT_STATUS_COMPLETED: + $class = 'success'; + break; + case PAYMENT_STATUS_FAILED: + $class = 'danger'; + break; + case PAYMENT_STATUS_PARTIALLY_REFUNDED: + $label = trans('texts.status_partially_refunded_amount', [ + 'amount' => Utils::formatMoney($model->refunded, $model->currency_id, $model->country_id), + ]); + $class = 'primary'; + break; + case PAYMENT_STATUS_REFUNDED: + $class = 'default'; + break; + } + return "

$label

"; + } + public function quoteIndex() { - if (!$invitation = $this->getInvitation()) { + if (!$contact = $this->getContact()) { return $this->returnError(); } - $account = $invitation->account; + $account = $contact->account; if (!$account->enable_client_portal) { return $this->returnError(); @@ -358,10 +424,7 @@ class PublicClientController extends BaseController $color = $account->primary_color ? $account->primary_color : '#0b4d78'; $data = [ 'color' => $color, - 'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL), - 'hideDashboard' => !$account->enable_client_portal_dashboard, - 'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS), - 'clientViewCSS' => $account->clientViewCSS(), + 'account' => $account, 'clientFontUrl' => $account->getFontsUrl(), 'title' => trans('texts.quotes'), 'entityType' => ENTITY_QUOTE, @@ -374,32 +437,29 @@ class PublicClientController extends BaseController public function quoteDatatable() { - if (!$invitation = $this->getInvitation()) { + if (!$contact = $this->getContact()) { return false; } - return $this->invoiceRepo->getClientDatatable($invitation->contact_id, ENTITY_QUOTE, Input::get('sSearch')); + return $this->invoiceRepo->getClientDatatable($contact->id, ENTITY_QUOTE, Input::get('sSearch')); } public function documentIndex() { - if (!$invitation = $this->getInvitation()) { + if (!$contact = $this->getContact()) { return $this->returnError(); } - $account = $invitation->account; + $account = $contact->account; if (!$account->enable_client_portal) { return $this->returnError(); } - $color = $account->primary_color ? $account->primary_color : '#0b4d78'; + $color = $account->primary_color ? $account->primary_color : '#0b4d78'; $data = [ 'color' => $color, - 'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL), - 'hideDashboard' => !$account->enable_client_portal_dashboard, - 'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS), - 'clientViewCSS' => $account->clientViewCSS(), + 'account' => $account, 'clientFontUrl' => $account->getFontsUrl(), 'title' => trans('texts.documents'), 'entityType' => ENTITY_DOCUMENT, @@ -412,11 +472,11 @@ class PublicClientController extends BaseController public function documentDatatable() { - if (!$invitation = $this->getInvitation()) { + if (!$contact = $this->getContact()) { return false; } - return $this->documentRepo->getClientDatatable($invitation->contact_id, ENTITY_DOCUMENT, Input::get('sSearch')); + return $this->documentRepo->getClientDatatable($contact->id, ENTITY_DOCUMENT, Input::get('sSearch')); } private function returnError($error = false) @@ -424,97 +484,90 @@ class PublicClientController extends BaseController return response()->view('error', [ 'error' => $error ?: trans('texts.invoice_not_found'), 'hideHeader' => true, + 'account' => $this->getContact()->account, ]); } - private function getInvitation() - { - $invitationKey = session('invitation_key'); + private function getContact() { + $contactKey = session('contact_key'); - if (!$invitationKey) { + if (!$contactKey) { return false; } - $invitation = Invitation::where('invitation_key', '=', $invitationKey)->first(); + $contact = Contact::where('contact_key', '=', $contactKey)->first(); - if (!$invitation || $invitation->is_deleted) { + if (!$contact || $contact->is_deleted) { return false; } - $invoice = $invitation->invoice; - - if (!$invoice || $invoice->is_deleted) { - return false; - } - - return $invitation; + return $contact; } - + public function getDocumentVFSJS($publicId, $name){ - if (!$invitation = $this->getInvitation()) { + if (!$contact = $this->getContact()) { return $this->returnError(); } - - $clientId = $invitation->invoice->client_id; - $document = Document::scope($publicId, $invitation->account_id)->first(); - - + + $document = Document::scope($publicId, $contact->account_id)->first(); + + if(!$document->isPDFEmbeddable()){ - return Response::view('error', array('error'=>'Image does not exist!'), 404); + return Response::view('error', ['error'=>'Image does not exist!'], 404); } - + $authorized = false; - if($document->expense && $document->expense->client_id == $invitation->invoice->client_id){ + if($document->expense && $document->expense->client_id == $contact->client_id){ $authorized = true; - } else if($document->invoice && $document->invoice->client_id == $invitation->invoice->client_id){ + } else if($document->invoice && $document->invoice->client_id ==$contact->client_id){ $authorized = true; } - + if(!$authorized){ - return Response::view('error', array('error'=>'Not authorized'), 403); - } - + return Response::view('error', ['error'=>'Not authorized'], 403); + } + if(substr($name, -3)=='.js'){ $name = substr($name, 0, -3); } - + $content = $document->preview?$document->getRawPreview():$document->getRaw(); $content = 'ninjaAddVFSDoc('.json_encode(intval($publicId).'/'.strval($name)).',"'.base64_encode($content).'")'; $response = Response::make($content, 200); $response->header('content-type', 'text/javascript'); $response->header('cache-control', 'max-age=31536000'); - + return $response; } - + protected function canCreateZip(){ return function_exists('gmp_init'); } - + protected function getInvoiceZipDocuments($invoice, &$size=0){ $documents = $invoice->documents; - + foreach($invoice->expenses as $expense){ $documents = $documents->merge($expense->documents); } - + $documents = $documents->sortBy('size'); $size = 0; $maxSize = MAX_ZIP_DOCUMENTS_SIZE * 1000; - $toZip = array(); + $toZip = []; foreach($documents as $document){ if($size + $document->size > $maxSize)break; - + if(!empty($toZip[$document->name])){ // This name is taken if($toZip[$document->name]->hash != $document->hash){ // 2 different files with the same name $nameInfo = pathinfo($document->name); - + for($i = 1;; $i++){ $name = $nameInfo['filename'].' ('.$i.').'.$nameInfo['extension']; - + if(empty($toZip[$name])){ $toZip[$name] = $document; $size += $document->size; @@ -524,7 +577,7 @@ class PublicClientController extends BaseController break; } } - + } } else{ @@ -532,31 +585,31 @@ class PublicClientController extends BaseController $size += $document->size; } } - + return $toZip; } - + public function getInvoiceDocumentsZip($invitationKey){ if (!$invitation = $this->invoiceRepo->findInvoiceByInvitation($invitationKey)) { return $this->returnError(); } - - Session::put('invitation_key', $invitationKey); // track current invitation - + + Session::put('contact_key', $invitation->contact->contact_key);// track current contact + $invoice = $invitation->invoice; - + $toZip = $this->getInvoiceZipDocuments($invoice); - + if(!count($toZip)){ - return Response::view('error', array('error'=>'No documents small enough'), 404); + return Response::view('error', ['error'=>'No documents small enough'], 404); } - + $zip = new ZipArchive($invitation->account->name.' Invoice '.$invoice->invoice_number.'.zip'); return Response::stream(function() use ($toZip, $zip) { foreach($toZip as $name=>$document){ $fileStream = $document->getStream(); if($fileStream){ - $zip->init_file_stream_transfer($name, $document->size, array('time'=>$document->created_at->timestamp)); + $zip->init_file_stream_transfer($name, $document->size, ['time'=>$document->created_at->timestamp]); while ($buffer = fread($fileStream, 256000))$zip->stream_file_part($buffer); fclose($fileStream); $zip->complete_file_stream(); @@ -568,29 +621,169 @@ class PublicClientController extends BaseController $zip->finish(); }, 200); } - + public function getDocument($invitationKey, $publicId){ if (!$invitation = $this->invoiceRepo->findInvoiceByInvitation($invitationKey)) { return $this->returnError(); } - - Session::put('invitation_key', $invitationKey); // track current invitation - + + Session::put('contact_key', $invitation->contact->contact_key);// track current contact + $clientId = $invitation->invoice->client_id; $document = Document::scope($publicId, $invitation->account_id)->firstOrFail(); - + $authorized = false; if($document->expense && $document->expense->client_id == $invitation->invoice->client_id){ $authorized = true; } else if($document->invoice && $document->invoice->client_id == $invitation->invoice->client_id){ $authorized = true; } - + if(!$authorized){ - return Response::view('error', array('error'=>'Not authorized'), 403); - } - + return Response::view('error', ['error'=>'Not authorized'], 403); + } + return DocumentController::getDownloadResponse($document); } + public function paymentMethods() + { + if (!$contact = $this->getContact()) { + return $this->returnError(); + } + + $client = $contact->client; + $account = $client->account; + + $paymentDriver = $account->paymentDriver(false, GATEWAY_TYPE_TOKEN); + $customer = $paymentDriver->customer($client->id); + + $data = [ + 'account' => $account, + 'contact' => $contact, + 'color' => $account->primary_color ? $account->primary_color : '#0b4d78', + 'client' => $client, + 'clientViewCSS' => $account->clientViewCSS(), + 'clientFontUrl' => $account->getFontsUrl(), + 'paymentMethods' => $customer ? $customer->payment_methods : false, + 'gateway' => $account->getTokenGateway(), + 'title' => trans('texts.payment_methods'), + 'transactionToken' => $paymentDriver->createTransactionToken(), + ]; + + return response()->view('payments.paymentmethods', $data); + } + + public function verifyPaymentMethod() + { + $publicId = Input::get('source_id'); + $amount1 = Input::get('verification1'); + $amount2 = Input::get('verification2'); + + if (!$contact = $this->getContact()) { + return $this->returnError(); + } + + $client = $contact->client; + $account = $client->account; + + $paymentDriver = $account->paymentDriver(null, GATEWAY_TYPE_BANK_TRANSFER); + $result = $paymentDriver->verifyBankAccount($client, $publicId, $amount1, $amount2); + + if (is_string($result)) { + Session::flash('error', $result); + } else { + Session::flash('message', trans('texts.payment_method_verified')); + } + + return redirect()->to($account->enable_client_portal_dashboard?'/client/dashboard':'/client/payment_methods/'); + } + + public function removePaymentMethod($publicId) + { + if (!$contact = $this->getContact()) { + return $this->returnError(); + } + + $client = $contact->client; + $account = $contact->account; + + $paymentDriver = $account->paymentDriver(false, GATEWAY_TYPE_TOKEN); + $paymentMethod = PaymentMethod::clientId($client->id) + ->wherePublicId($publicId) + ->firstOrFail(); + + try { + $paymentDriver->removePaymentMethod($paymentMethod); + Session::flash('message', trans('texts.payment_method_removed')); + } catch (Exception $exception) { + Session::flash('error', $exception->getMessage()); + } + + return redirect()->to($client->account->enable_client_portal_dashboard?'/client/dashboard':'/client/payment_methods/'); + } + + public function setDefaultPaymentMethod(){ + if (!$contact = $this->getContact()) { + return $this->returnError(); + } + + $client = $contact->client; + $account = $client->account; + + $validator = Validator::make(Input::all(), ['source' => 'required']); + if ($validator->fails()) { + return Redirect::to($client->account->enable_client_portal_dashboard?'/client/dashboard':'/client/payment_methods/'); + } + + $paymentDriver = $account->paymentDriver(false, GATEWAY_TYPE_TOKEN); + $paymentMethod = PaymentMethod::clientId($client->id) + ->wherePublicId(Input::get('source')) + ->firstOrFail(); + + $customer = $paymentDriver->customer($client->id); + $customer->default_payment_method_id = $paymentMethod->id; + $customer->save(); + + Session::flash('message', trans('texts.payment_method_set_as_default')); + + return redirect()->to($client->account->enable_client_portal_dashboard?'/client/dashboard':'/client/payment_methods/'); + } + + private function paymentMethodError($type, $error, $accountGateway = false, $exception = false) + { + $message = ''; + if ($accountGateway && $accountGateway->gateway) { + $message = $accountGateway->gateway->name . ': '; + } + $message .= $error ?: trans('texts.payment_method_error'); + + Session::flash('error', $message); + Utils::logError("Payment Method Error [{$type}]: " . ($exception ? Utils::getErrorString($exception) : $message), 'PHP', true); + } + + public function setAutoBill(){ + if (!$contact = $this->getContact()) { + return $this->returnError(); + } + + $client = $contact->client; + + $validator = Validator::make(Input::all(), ['public_id' => 'required']); + + if ($validator->fails()) { + return Redirect::to('client/invoices/recurring'); + } + + $publicId = Input::get('public_id'); + $enable = Input::get('enable'); + $invoice = $client->invoices()->where('public_id', intval($publicId))->first(); + + if ($invoice && $invoice->is_recurring && ($invoice->auto_bill == AUTO_BILL_OPT_IN || $invoice->auto_bill == AUTO_BILL_OPT_OUT)) { + $invoice->client_enable_auto_bill = $enable ? true : false; + $invoice->save(); + } + + return Redirect::to('client/invoices/recurring'); + } } diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index b3a6ac7b1f..b0c144732f 100644 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -4,8 +4,10 @@ use Illuminate\Foundation\Bus\DispatchesJobs; use Illuminate\Routing\Controller as BaseController; use Illuminate\Foundation\Validation\ValidatesRequests; -abstract class Controller extends BaseController { - - use DispatchesJobs, ValidatesRequests; - +/** + * Class Controller + */ +abstract class Controller extends BaseController +{ + use DispatchesJobs, ValidatesRequests; } diff --git a/app/Http/Controllers/CreditController.php b/app/Http/Controllers/CreditController.php index ff1257d445..5d432881d2 100644 --- a/app/Http/Controllers/CreditController.php +++ b/app/Http/Controllers/CreditController.php @@ -1,13 +1,11 @@ ENTITY_CREDIT, 'title' => trans('texts.credits'), 'sortCol' => '4', @@ -48,7 +46,7 @@ class CreditController extends BaseController 'private_notes', '' ]), - )); + ]); } public function getDatatable($clientPublicId = null) @@ -58,14 +56,14 @@ class CreditController extends BaseController public function create(CreditRequest $request) { - $data = array( + $data = [ 'clientPublicId' => Input::old('client') ? Input::old('client') : ($request->client_id ?: 0), 'credit' => null, 'method' => 'POST', 'url' => 'credits', 'title' => trans('texts.new_credit'), - 'clients' => Client::scope()->viewable()->with('contacts')->orderBy('name')->get(), - ); + 'clients' => Client::scope()->with('contacts')->orderBy('name')->get(), + ]; return View::make('credits.edit', $data); } diff --git a/app/Http/Controllers/DashboardApiController.php b/app/Http/Controllers/DashboardApiController.php index 06393e3ddc..c97f1408b0 100644 --- a/app/Http/Controllers/DashboardApiController.php +++ b/app/Http/Controllers/DashboardApiController.php @@ -2,14 +2,12 @@ use Auth; use DB; -use View; -use App\Models\Activity; class DashboardApiController extends BaseAPIController { public function index() { - $view_all = !Auth::user()->hasPermission('view_all'); + $view_all = Auth::user()->hasPermission('view_all'); $user_id = Auth::user()->id; // total_income, billed_clients, invoice_sent and active_clients @@ -24,7 +22,7 @@ class DashboardApiController extends BaseAPIController ->where('clients.is_deleted', '=', false) ->where('invoices.is_deleted', '=', false) ->where('invoices.is_recurring', '=', false) - ->where('invoices.is_quote', '=', false); + ->where('invoices.invoice_type_id', '=', false); if(!$view_all){ $metrics = $metrics->where(function($query) use($user_id){ @@ -62,7 +60,7 @@ class DashboardApiController extends BaseAPIController ->where('accounts.id', '=', Auth::user()->account_id) ->where('clients.is_deleted', '=', false) ->where('invoices.is_deleted', '=', false) - ->where('invoices.is_quote', '=', false) + ->where('invoices.invoice_type_id', '=', INVOICE_TYPE_STANDARD) ->where('invoices.is_recurring', '=', false); if(!$view_all){ @@ -80,8 +78,13 @@ class DashboardApiController extends BaseAPIController ->where('accounts.id', '=', Auth::user()->account_id) ->where('clients.is_deleted', '=', false) ->groupBy('accounts.id') - ->groupBy(DB::raw('CASE WHEN clients.currency_id IS NULL THEN CASE WHEN accounts.currency_id IS NULL THEN 1 ELSE accounts.currency_id END ELSE clients.currency_id END')) - ->get(); + ->groupBy(DB::raw('CASE WHEN clients.currency_id IS NULL THEN CASE WHEN accounts.currency_id IS NULL THEN 1 ELSE accounts.currency_id END ELSE clients.currency_id END')); + + if (!$view_all) { + $balances->where('clients.user_id', '=', $user_id); + } + + $balances = $balances->get(); $pastDue = DB::table('invoices') ->leftJoin('clients', 'clients.id', '=', 'invoices.client_id') @@ -101,7 +104,7 @@ class DashboardApiController extends BaseAPIController $pastDue = $pastDue->where('invoices.user_id', '=', $user_id); } - $pastDue = $pastDue->select(['invoices.due_date', 'invoices.balance', 'invoices.public_id', 'invoices.invoice_number', 'clients.name as client_name', 'contacts.email', 'contacts.first_name', 'contacts.last_name', 'clients.currency_id', 'clients.public_id as client_public_id', 'clients.user_id as client_user_id', 'is_quote']) + $pastDue = $pastDue->select(['invoices.due_date', 'invoices.balance', 'invoices.public_id', 'invoices.invoice_number', 'clients.name as client_name', 'contacts.email', 'contacts.first_name', 'contacts.last_name', 'clients.currency_id', 'clients.public_id as client_public_id', 'clients.user_id as client_user_id', 'invoice_type_id']) ->orderBy('invoices.due_date', 'asc') ->take(50) ->get(); @@ -126,7 +129,7 @@ class DashboardApiController extends BaseAPIController } $upcoming = $upcoming->take(50) - ->select(['invoices.due_date', 'invoices.balance', 'invoices.public_id', 'invoices.invoice_number', 'clients.name as client_name', 'contacts.email', 'contacts.first_name', 'contacts.last_name', 'clients.currency_id', 'clients.public_id as client_public_id', 'clients.user_id as client_user_id', 'is_quote']) + ->select(['invoices.due_date', 'invoices.balance', 'invoices.public_id', 'invoices.invoice_number', 'clients.name as client_name', 'contacts.email', 'contacts.first_name', 'contacts.last_name', 'clients.currency_id', 'clients.public_id as client_public_id', 'clients.user_id as client_user_id', 'invoice_type_id']) ->get(); $payments = DB::table('payments') @@ -152,21 +155,20 @@ class DashboardApiController extends BaseAPIController $hasQuotes = false; foreach ([$upcoming, $pastDue] as $data) { foreach ($data as $invoice) { - if ($invoice->is_quote) { + if ($invoice->invoice_type_id == INVOICE_TYPE_QUOTE) { $hasQuotes = true; } } } - - + $data = [ 'id' => 1, - 'paidToDate' => $paidToDate[0]->value, - 'paidToDateCurrency' => $paidToDate[0]->currency_id, - 'balances' => $balances[0]->value, - 'balancesCurrency' => $balances[0]->currency_id, - 'averageInvoice' => $averageInvoice[0]->invoice_avg, - 'averageInvoiceCurrency' => $averageInvoice[0]->currency_id, + 'paidToDate' => $paidToDate[0]->value ? $paidToDate[0]->value : 0, + 'paidToDateCurrency' => $paidToDate[0]->currency_id ? $paidToDate[0]->currency_id : 0, + 'balances' => $balances[0]->value ? $balances[0]->value : 0, + 'balancesCurrency' => $balances[0]->currency_id ? $balances[0]->currency_id : 0, + 'averageInvoice' => $averageInvoice[0]->invoice_avg ? $averageInvoice[0]->invoice_avg : 0, + 'averageInvoiceCurrency' => $averageInvoice[0]->currency_id ? $averageInvoice[0]->currency_id : 0, 'invoicesSent' => $metrics ? $metrics->invoices_sent : 0, 'activeClients' => $metrics ? $metrics->active_clients : 0, ]; diff --git a/app/Http/Controllers/DashboardController.php b/app/Http/Controllers/DashboardController.php index 718d73c67d..209e88b0c0 100644 --- a/app/Http/Controllers/DashboardController.php +++ b/app/Http/Controllers/DashboardController.php @@ -7,17 +7,25 @@ use App\Models\Activity; use App\Models\Invoice; use App\Models\Payment; +/** + * Class DashboardController + */ class DashboardController extends BaseController { + /** + * @return \Illuminate\Contracts\View\View + */ public function index() { $view_all = Auth::user()->hasPermission('view_all'); $user_id = Auth::user()->id; // total_income, billed_clients, invoice_sent and active_clients - $select = DB::raw('COUNT(DISTINCT CASE WHEN invoices.id IS NOT NULL THEN clients.id ELSE null END) billed_clients, - SUM(CASE WHEN invoices.invoice_status_id >= '.INVOICE_STATUS_SENT.' THEN 1 ELSE 0 END) invoices_sent, - COUNT(DISTINCT clients.id) active_clients'); + $select = DB::raw( + 'COUNT(DISTINCT CASE WHEN '.DB::getQueryGrammar()->wrap('invoices.id', true).' IS NOT NULL THEN '.DB::getQueryGrammar()->wrap('clients.id', true).' ELSE null END) billed_clients, + SUM(CASE WHEN '.DB::getQueryGrammar()->wrap('invoices.invoice_status_id', true).' >= '.INVOICE_STATUS_SENT.' THEN 1 ELSE 0 END) invoices_sent, + COUNT(DISTINCT '.DB::getQueryGrammar()->wrap('clients.id', true).') active_clients' + ); $metrics = DB::table('accounts') ->select($select) ->leftJoin('clients', 'accounts.id', '=', 'clients.account_id') @@ -26,7 +34,7 @@ class DashboardController extends BaseController ->where('clients.is_deleted', '=', false) ->where('invoices.is_deleted', '=', false) ->where('invoices.is_recurring', '=', false) - ->where('invoices.is_quote', '=', false); + ->where('invoices.invoice_type_id', '=', INVOICE_TYPE_STANDARD); if(!$view_all){ $metrics = $metrics->where(function($query) use($user_id){ @@ -41,7 +49,10 @@ class DashboardController extends BaseController $metrics = $metrics->groupBy('accounts.id') ->first(); - $select = DB::raw('SUM(clients.paid_to_date) as value, clients.currency_id as currency_id'); + $select = DB::raw( + 'SUM('.DB::getQueryGrammar()->wrap('clients.paid_to_date', true).') as value,' + .DB::getQueryGrammar()->wrap('clients.currency_id', true).' as currency_id' + ); $paidToDate = DB::table('accounts') ->select($select) ->leftJoin('clients', 'accounts.id', '=', 'clients.account_id') @@ -53,10 +64,13 @@ class DashboardController extends BaseController } $paidToDate = $paidToDate->groupBy('accounts.id') - ->groupBy(DB::raw('CASE WHEN clients.currency_id IS NULL THEN CASE WHEN accounts.currency_id IS NULL THEN 1 ELSE accounts.currency_id END ELSE clients.currency_id END')) + ->groupBy(DB::raw('CASE WHEN '.DB::getQueryGrammar()->wrap('clients.currency_id', true).' IS NULL THEN CASE WHEN '.DB::getQueryGrammar()->wrap('accounts.currency_id', true).' IS NULL THEN 1 ELSE '.DB::getQueryGrammar()->wrap('accounts.currency_id', true).' END ELSE '.DB::getQueryGrammar()->wrap('clients.currency_id', true).' END')) ->get(); - $select = DB::raw('AVG(invoices.amount) as invoice_avg, clients.currency_id as currency_id'); + $select = DB::raw( + 'AVG('.DB::getQueryGrammar()->wrap('invoices.amount', true).') as invoice_avg, ' + .DB::getQueryGrammar()->wrap('clients.currency_id', true).' as currency_id' + ); $averageInvoice = DB::table('accounts') ->select($select) ->leftJoin('clients', 'accounts.id', '=', 'clients.account_id') @@ -64,7 +78,7 @@ class DashboardController extends BaseController ->where('accounts.id', '=', Auth::user()->account_id) ->where('clients.is_deleted', '=', false) ->where('invoices.is_deleted', '=', false) - ->where('invoices.is_quote', '=', false) + ->where('invoices.invoice_type_id', '=', INVOICE_TYPE_STANDARD) ->where('invoices.is_recurring', '=', false); if(!$view_all){ @@ -72,17 +86,20 @@ class DashboardController extends BaseController } $averageInvoice = $averageInvoice->groupBy('accounts.id') - ->groupBy(DB::raw('CASE WHEN clients.currency_id IS NULL THEN CASE WHEN accounts.currency_id IS NULL THEN 1 ELSE accounts.currency_id END ELSE clients.currency_id END')) + ->groupBy(DB::raw('CASE WHEN '.DB::getQueryGrammar()->wrap('clients.currency_id', true).' IS NULL THEN CASE WHEN '.DB::getQueryGrammar()->wrap('accounts.currency_id', true).' IS NULL THEN 1 ELSE '.DB::getQueryGrammar()->wrap('accounts.currency_id', true).' END ELSE '.DB::getQueryGrammar()->wrap('clients.currency_id', true).' END')) ->get(); - $select = DB::raw('SUM(clients.balance) as value, clients.currency_id as currency_id'); + $select = DB::raw( + 'SUM('.DB::getQueryGrammar()->wrap('clients.balance', true).') as value, ' + .DB::getQueryGrammar()->wrap('clients.currency_id', true).' as currency_id' + ); $balances = DB::table('accounts') ->select($select) ->leftJoin('clients', 'accounts.id', '=', 'clients.account_id') ->where('accounts.id', '=', Auth::user()->account_id) ->where('clients.is_deleted', '=', false) ->groupBy('accounts.id') - ->groupBy(DB::raw('CASE WHEN clients.currency_id IS NULL THEN CASE WHEN accounts.currency_id IS NULL THEN 1 ELSE accounts.currency_id END ELSE clients.currency_id END')); + ->groupBy(DB::raw('CASE WHEN '.DB::getQueryGrammar()->wrap('clients.currency_id', true).' IS NULL THEN CASE WHEN '.DB::getQueryGrammar()->wrap('accounts.currency_id', true).' IS NULL THEN 1 ELSE '.DB::getQueryGrammar()->wrap('accounts.currency_id', true).' END ELSE '.DB::getQueryGrammar()->wrap('clients.currency_id', true).' END')); if (!$view_all) { $balances->where('clients.user_id', '=', $user_id); @@ -121,7 +138,7 @@ class DashboardController extends BaseController $pastDue = $pastDue->where('invoices.user_id', '=', $user_id); } - $pastDue = $pastDue->select(['invoices.due_date', 'invoices.balance', 'invoices.public_id', 'invoices.invoice_number', 'clients.name as client_name', 'contacts.email', 'contacts.first_name', 'contacts.last_name', 'clients.currency_id', 'clients.public_id as client_public_id', 'clients.user_id as client_user_id', 'is_quote']) + $pastDue = $pastDue->select(['invoices.due_date', 'invoices.balance', 'invoices.public_id', 'invoices.invoice_number', 'clients.name as client_name', 'contacts.email', 'contacts.first_name', 'contacts.last_name', 'clients.currency_id', 'clients.public_id as client_public_id', 'clients.user_id as client_user_id', 'invoice_type_id']) ->orderBy('invoices.due_date', 'asc') ->take(50) ->get(); @@ -147,7 +164,7 @@ class DashboardController extends BaseController } $upcoming = $upcoming->take(50) - ->select(['invoices.due_date', 'invoices.balance', 'invoices.public_id', 'invoices.invoice_number', 'clients.name as client_name', 'contacts.email', 'contacts.first_name', 'contacts.last_name', 'clients.currency_id', 'clients.public_id as client_public_id', 'clients.user_id as client_user_id', 'is_quote']) + ->select(['invoices.due_date', 'invoices.balance', 'invoices.public_id', 'invoices.invoice_number', 'clients.name as client_name', 'contacts.email', 'contacts.first_name', 'contacts.last_name', 'clients.currency_id', 'clients.public_id as client_public_id', 'clients.user_id as client_user_id', 'invoice_type_id']) ->get(); $payments = DB::table('payments') @@ -173,7 +190,7 @@ class DashboardController extends BaseController $hasQuotes = false; foreach ([$upcoming, $pastDue] as $data) { foreach ($data as $invoice) { - if ($invoice->is_quote) { + if ($invoice->invoice_type_id == INVOICE_TYPE_QUOTE) { $hasQuotes = true; } } diff --git a/app/Http/Controllers/DocumentAPIController.php b/app/Http/Controllers/DocumentAPIController.php new file mode 100644 index 0000000000..01a05a17e2 --- /dev/null +++ b/app/Http/Controllers/DocumentAPIController.php @@ -0,0 +1,70 @@ +documentRepo = $documentRepo; + } + + /** + * @return \Illuminate\Http\Response + */ + public function index() + { + $documents = Document::scope(); + + return $this->listResponse($documents); + + } + + /** + * @param DocumentRequest $request + * + * @return \Illuminate\Http\Response|\Redirect|\Symfony\Component\HttpFoundation\StreamedResponse + */ + public function show(DocumentRequest $request) + { + $document = $request->entity(); + + return DocumentController::getDownloadResponse($document); + } + + /** + * @param CreateDocumentRequest $request + * + * @return \Illuminate\Http\Response + */ + public function store(CreateDocumentRequest $request) + { + + $document = $this->documentRepo->upload($request->all()); + + return $this->itemResponse($document); + } +} diff --git a/app/Http/Controllers/DocumentController.php b/app/Http/Controllers/DocumentController.php index e4ea605d57..e6f1d8fb8c 100644 --- a/app/Http/Controllers/DocumentController.php +++ b/app/Http/Controllers/DocumentController.php @@ -1,17 +1,10 @@ entity(); if(empty($document->preview)){ - return Response::view('error', array('error'=>'Preview does not exist!'), 404); + return Response::view('error', ['error'=>'Preview does not exist!'], 404); } $direct_url = $document->getDirectPreviewUrl(); @@ -88,7 +81,7 @@ class DocumentController extends BaseController } if(!$document->isPDFEmbeddable()){ - return Response::view('error', array('error'=>'Image does not exist!'), 404); + return Response::view('error', ['error'=>'Image does not exist!'], 404); } $content = $document->preview?$document->getRawPreview():$document->getRaw(); @@ -106,7 +99,7 @@ class DocumentController extends BaseController return; } - $result = $this->documentRepo->upload(Input::all()['file'], $doc_array); + $result = $this->documentRepo->upload($request->all(), $doc_array); if(is_string($result)){ return Response::json([ diff --git a/app/Http/Controllers/ExpenseApiController.php b/app/Http/Controllers/ExpenseApiController.php index 725067aa1f..ea4425df86 100644 --- a/app/Http/Controllers/ExpenseApiController.php +++ b/app/Http/Controllers/ExpenseApiController.php @@ -1,14 +1,8 @@ categoryRepo = $categoryRepo; + $this->categoryService = $categoryService; + } + + /** + * Display a listing of the resource. + * + * @return Response + */ + public function index() + { + return View::make('list', [ + 'entityType' => ENTITY_EXPENSE_CATEGORY, + 'title' => trans('texts.expense_categories'), + 'sortCol' => '1', + 'columns' => Utils::trans([ + 'checkbox', + 'name', + '' + ]), + ]); + } + + public function getDatatable($expensePublicId = null) + { + return $this->categoryService->getDatatable(Input::get('sSearch')); + } + + public function create(ExpenseCategoryRequest $request) + { + $data = [ + 'category' => null, + 'method' => 'POST', + 'url' => 'expense_categories', + 'title' => trans('texts.new_category'), + ]; + + return View::make('expense_categories.edit', $data); + } + + public function edit(ExpenseCategoryRequest $request) + { + $category = $request->entity(); + + $data = [ + 'category' => $category, + 'method' => 'PUT', + 'url' => 'expense_categories/' . $category->public_id, + 'title' => trans('texts.edit_category'), + ]; + + return View::make('expense_categories.edit', $data); + } + + public function store(CreateExpenseCategoryRequest $request) + { + $category = $this->categoryRepo->save($request->input()); + + Session::flash('message', trans('texts.created_expense_category')); + + return redirect()->to($category->getRoute()); + } + + public function update(UpdateExpenseCategoryRequest $request) + { + $category = $this->categoryRepo->save($request->input(), $request->entity()); + + Session::flash('message', trans('texts.updated_expense_category')); + + return redirect()->to($category->getRoute()); + } + + public function bulk() + { + $action = Input::get('action'); + $ids = Input::get('public_id') ? Input::get('public_id') : Input::get('ids'); + $count = $this->categoryService->bulk($ids, $action); + + if ($count > 0) { + $field = $count == 1 ? "{$action}d_expense_category" : "{$action}d_expense_categories"; + $message = trans("texts.$field", ['count' => $count]); + Session::flash('message', $message); + } + + return redirect()->to('/expense_categories'); + } + +} diff --git a/app/Http/Controllers/ExpenseController.php b/app/Http/Controllers/ExpenseController.php index d4184abf3f..425b5d4b8c 100644 --- a/app/Http/Controllers/ExpenseController.php +++ b/app/Http/Controllers/ExpenseController.php @@ -1,23 +1,20 @@ ENTITY_EXPENSE, 'title' => trans('texts.expenses'), 'sortCol' => '3', @@ -54,11 +51,12 @@ class ExpenseController extends BaseController 'client', 'expense_date', 'amount', + 'category', 'public_notes', 'status', '' ]), - )); + ]); } public function getDatatable($expensePublicId = null) @@ -78,8 +76,8 @@ class ExpenseController extends BaseController } else { $vendor = null; } - - $data = array( + + $data = [ 'vendorPublicId' => Input::old('vendor') ? Input::old('vendor') : $request->vendor_id, 'expense' => null, 'method' => 'POST', @@ -89,7 +87,8 @@ class ExpenseController extends BaseController 'vendor' => $vendor, 'clients' => Client::scope()->with('contacts')->orderBy('name')->get(), 'clientPublicId' => $request->client_id, - ); + 'categoryPublicId' => $request->category_id, + ]; $data = array_merge($data, self::getViewModel()); @@ -99,14 +98,14 @@ class ExpenseController extends BaseController public function edit(ExpenseRequest $request) { $expense = $request->entity(); - + $expense->expense_date = Utils::fromSqlDate($expense->expense_date); - + $actions = []; 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')]; } else { - $actions[] = ['url' => 'javascript:submitAction("invoice")', 'label' => trans("texts.invoice_expense")]; + $actions[] = ['url' => 'javascript:submitAction("invoice")', 'label' => trans('texts.invoice_expense')]; } $actions[] = \DropdownButton::DIVIDER; @@ -117,7 +116,7 @@ class ExpenseController extends BaseController $actions[] = ['url' => 'javascript:submitAction("restore")', 'label' => trans('texts.restore_expense')]; } - $data = array( + $data = [ 'vendor' => null, 'expense' => $expense, 'method' => 'PUT', @@ -128,7 +127,8 @@ class ExpenseController extends BaseController 'vendorPublicId' => $expense->vendor ? $expense->vendor->public_id : null, 'clients' => Client::scope()->with('contacts')->orderBy('name')->get(), 'clientPublicId' => $expense->client ? $expense->client->public_id : null, - ); + 'categoryPublicId' => $expense->expense_category ? $expense->expense_category->public_id : null, + ]; $data = array_merge($data, self::getViewModel()); @@ -145,7 +145,7 @@ class ExpenseController extends BaseController { $data = $request->input(); $data['documents'] = $request->file('documents'); - + $expense = $this->expenseService->save($data, $request->entity()); Session::flash('message', trans('texts.updated_expense')); @@ -162,7 +162,7 @@ class ExpenseController extends BaseController { $data = $request->input(); $data['documents'] = $request->file('documents'); - + $expense = $this->expenseService->save($data); Session::flash('message', trans('texts.created_expense')); @@ -181,7 +181,7 @@ class ExpenseController extends BaseController $expenses = Expense::scope($ids)->with('client')->get(); $clientPublicId = null; $currencyId = null; - + // Validate that either all expenses do not have a client or if there is a client, it is the same client foreach ($expenses as $expense) { @@ -237,6 +237,8 @@ class ExpenseController extends BaseController 'countries' => Cache::get('countries'), 'customLabel1' => Auth::user()->account->custom_vendor_label1, 'customLabel2' => Auth::user()->account->custom_vendor_label2, + 'categories' => ExpenseCategory::whereAccountId(Auth::user()->account_id)->orderBy('name')->get(), + 'taxRates' => TaxRate::scope()->orderBy('name')->get(), ]; } diff --git a/app/Http/Controllers/ExportController.php b/app/Http/Controllers/ExportController.php index ebaaa1f6c3..c4467b4ac3 100644 --- a/app/Http/Controllers/ExportController.php +++ b/app/Http/Controllers/ExportController.php @@ -16,8 +16,16 @@ use App\Models\Payment; use App\Models\Vendor; use App\Models\VendorContact; +/** + * Class ExportController + */ class ExportController extends BaseController { + /** + * @param Request $request + * + * @return \Illuminate\Http\JsonResponse + */ public function doExport(Request $request) { $format = $request->input('format'); @@ -33,6 +41,12 @@ class ExportController extends BaseController } } + /** + * @param $request + * @param $fileName + * + * @return \Illuminate\Http\JsonResponse + */ private function returnJSON($request, $fileName) { $output = fopen('php://output', 'w') or Utils::fatalError(); @@ -42,16 +56,32 @@ class ExportController extends BaseController $manager = new Manager(); $manager->setSerializer(new ArraySerializer()); + // eager load data, include archived but exclude deleted $account = Auth::user()->account; - $account->loadAllData(); + $account->load(['clients' => function($query) { + $query->withArchived() + ->with(['contacts', 'invoices' => function($query) { + $query->withArchived() + ->with(['invoice_items', 'payments' => function($query) { + $query->withArchived(); + }]); + }]); + }]); $resource = new Item($account, new AccountTransformer); - $data = $manager->createData($resource)->toArray(); + $data = $manager->parseIncludes('clients.invoices.payments') + ->createData($resource) + ->toArray(); return response()->json($data); } - + /** + * @param $request + * @param $fileName + * + * @return mixed + */ private function returnCSV($request, $fileName) { $data = $this->getData($request); @@ -63,6 +93,12 @@ class ExportController extends BaseController })->download('csv'); } + /** + * @param $request + * @param $fileName + * + * @return mixed + */ private function returnXLS($request, $fileName) { $user = Auth::user(); @@ -84,13 +120,14 @@ class ExportController extends BaseController if ($key === 'account' || $key === 'title' || $key === 'multiUser') { continue; } + if ($key === 'recurringInvoices') { + $key = 'recurring_invoices'; + } $label = trans("texts.{$key}"); $excel->sheet($label, function($sheet) use ($key, $data) { if ($key === 'quotes') { $key = 'invoices'; $data['entityType'] = ENTITY_QUOTE; - } elseif ($key === 'recurringInvoices') { - $key = 'recurring_invoices'; } $sheet->loadView("export.{$key}", $data); }); @@ -98,6 +135,11 @@ class ExportController extends BaseController })->download('xls'); } + /** + * @param $request + * + * @return array + */ private function getData($request) { $account = Auth::user()->account; @@ -107,79 +149,82 @@ class ExportController extends BaseController 'title' => 'Invoice Ninja v' . NINJA_VERSION . ' - ' . $account->formatDateTime($account->getDateTime()), 'multiUser' => $account->users->count() > 1 ]; - - if ($request->input(ENTITY_CLIENT)) { + + if ($request->input('include') === 'all' || $request->input('clients')) { $data['clients'] = Client::scope() ->with('user', 'contacts', 'country') ->withArchived() ->get(); + } + if ($request->input('include') === 'all' || $request->input('contacts')) { $data['contacts'] = Contact::scope() ->with('user', 'client.contacts') ->withTrashed() ->get(); + } + if ($request->input('include') === 'all' || $request->input('credits')) { $data['credits'] = Credit::scope() ->with('user', 'client.contacts') ->get(); } - - if ($request->input(ENTITY_TASK)) { + + if ($request->input('include') === 'all' || $request->input('tasks')) { $data['tasks'] = Task::scope() ->with('user', 'client.contacts') ->withArchived() ->get(); } - - if ($request->input(ENTITY_INVOICE)) { - $data['invoices'] = Invoice::scope() - ->with('user', 'client.contacts', 'invoice_status') - ->withArchived() - ->where('is_quote', '=', false) - ->where('is_recurring', '=', false) - ->get(); - - $data['quotes'] = Invoice::scope() - ->with('user', 'client.contacts', 'invoice_status') - ->withArchived() - ->where('is_quote', '=', true) - ->where('is_recurring', '=', false) - ->get(); + if ($request->input('include') === 'all' || $request->input('invoices')) { + $data['invoices'] = Invoice::scope() + ->invoiceType(INVOICE_TYPE_STANDARD) + ->with('user', 'client.contacts', 'invoice_status') + ->withArchived() + ->where('is_recurring', '=', false) + ->get(); + } + + if ($request->input('include') === 'all' || $request->input('quotes')) { + $data['quotes'] = Invoice::scope() + ->invoiceType(INVOICE_TYPE_QUOTE) + ->with('user', 'client.contacts', 'invoice_status') + ->withArchived() + ->where('is_recurring', '=', false) + ->get(); + } + + if ($request->input('include') === 'all' || $request->input('recurring')) { $data['recurringInvoices'] = Invoice::scope() + ->invoiceType(INVOICE_TYPE_STANDARD) ->with('user', 'client.contacts', 'invoice_status', 'frequency') ->withArchived() - ->where('is_quote', '=', false) ->where('is_recurring', '=', true) ->get(); } - - if ($request->input(ENTITY_PAYMENT)) { + + if ($request->input('include') === 'all' || $request->input('payments')) { $data['payments'] = Payment::scope() ->withArchived() ->with('user', 'client.contacts', 'payment_type', 'invoice', 'account_gateway.gateway') ->get(); } - - if ($request->input(ENTITY_VENDOR)) { - $data['clients'] = Vendor::scope() + if ($request->input('include') === 'all' || $request->input('vendors')) { + $data['vendors'] = Vendor::scope() ->with('user', 'vendor_contacts', 'country') ->withArchived() ->get(); + } + if ($request->input('include') === 'all' || $request->input('vendor_contacts')) { $data['vendor_contacts'] = VendorContact::scope() ->with('user', 'vendor.vendor_contacts') ->withTrashed() ->get(); - - /* - $data['expenses'] = Credit::scope() - ->with('user', 'client.contacts') - ->get(); - */ } - + return $data; } -} \ No newline at end of file +} diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php index f01c4a6f13..395d4a0f24 100644 --- a/app/Http/Controllers/HomeController.php +++ b/app/Http/Controllers/HomeController.php @@ -9,12 +9,22 @@ use Session; use App\Models\Account; use App\Libraries\Utils; use App\Ninja\Mailers\Mailer; -use Symfony\Component\Security\Core\Util\StringUtils; +/** + * Class HomeController + */ class HomeController extends BaseController { + /** + * @var Mailer + */ protected $mailer; + /** + * HomeController constructor. + * + * @param Mailer $mailer + */ public function __construct(Mailer $mailer) { //parent::__construct(); @@ -22,6 +32,9 @@ class HomeController extends BaseController $this->mailer = $mailer; } + /** + * @return \Illuminate\Http\RedirectResponse + */ public function showIndex() { Session::reflash(); @@ -35,16 +48,25 @@ class HomeController extends BaseController } } + /** + * @return \Illuminate\Contracts\View\View + */ public function showTerms() { return View::make('public.terms', ['hideHeader' => true]); } + /** + * @return \Illuminate\Contracts\View\View + */ public function viewLogo() { return View::make('public.logo'); } - + + /** + * @return \Illuminate\Contracts\View\View|\Illuminate\Http\RedirectResponse + */ public function invoiceNow() { if (Auth::check() && Input::get('new_company')) { @@ -68,6 +90,11 @@ class HomeController extends BaseController } } + /** + * @param $userType + * @param $version + * @return \Illuminate\Http\JsonResponse + */ public function newsFeed($userType, $version) { $response = Utils::getNewsFeedResponse($userType); @@ -75,6 +102,9 @@ class HomeController extends BaseController return Response::json($response); } + /** + * @return string + */ public function hideMessage() { if (Auth::check() && Session::has('news_feed_id')) { @@ -91,11 +121,17 @@ class HomeController extends BaseController return 'success'; } + /** + * @return string + */ public function logError() { return Utils::logError(Input::get('error'), 'JavaScript'); } + /** + * @return mixed + */ public function keepAlive() { return RESULT_SUCCESS; diff --git a/app/Http/Controllers/ImportController.php b/app/Http/Controllers/ImportController.php index fe006332ca..3e893d57b5 100644 --- a/app/Http/Controllers/ImportController.php +++ b/app/Http/Controllers/ImportController.php @@ -7,7 +7,6 @@ use Input; use Session; use Redirect; use App\Services\ImportService; -use App\Http\Controllers\BaseController; class ImportController extends BaseController { @@ -36,8 +35,11 @@ class ImportController extends BaseController if ($source === IMPORT_CSV) { $data = $this->importService->mapCSV($files); return View::make('accounts.import_map', ['data' => $data]); + } elseif ($source === IMPORT_JSON) { + $results = $this->importService->importJSON($files[IMPORT_JSON]); + return $this->showResult($results); } else { - $results = $this->importService->import($source, $files); + $results = $this->importService->importFiles($source, $files); return $this->showResult($results); } } catch (Exception $exception) { diff --git a/app/Http/Controllers/IntegrationController.php b/app/Http/Controllers/IntegrationController.php index 740c91e361..a55498db8f 100644 --- a/app/Http/Controllers/IntegrationController.php +++ b/app/Http/Controllers/IntegrationController.php @@ -6,8 +6,14 @@ use Auth; use Input; use App\Models\Subscription; +/** + * Class IntegrationController + */ class IntegrationController extends Controller { + /** + * @return \Illuminate\Http\JsonResponse + */ public function subscribe() { $eventId = Utils::lookupEventId(trim(Input::get('event'))); diff --git a/app/Http/Controllers/InvoiceApiController.php b/app/Http/Controllers/InvoiceApiController.php index cdaea65af9..ce95ef83d1 100644 --- a/app/Http/Controllers/InvoiceApiController.php +++ b/app/Http/Controllers/InvoiceApiController.php @@ -1,8 +1,6 @@ clientRepo = $clientRepo; $this->invoiceService = $invoiceService; $this->recurringInvoiceService = $recurringInvoiceService; + $this->paymentService = $paymentService; } public function index() @@ -95,9 +94,9 @@ class InvoiceController extends BaseController { $account = Auth::user()->account; $invoice = $request->entity()->load('invitations', 'account.country', 'client.contacts', 'client.country', 'invoice_items', 'documents', 'expenses', 'expenses.documents', 'payments'); - + $entityType = $invoice->getEntityType(); - + $contactIds = DB::table('invitations') ->join('contacts', 'contacts.id', '=', 'invitations.contact_id') ->where('invitations.invoice_id', '=', $invoice->id) @@ -136,34 +135,34 @@ class InvoiceController extends BaseController $actions = [ ['url' => 'javascript:onCloneClick()', 'label' => trans("texts.clone_{$entityType}")], - ['url' => URL::to("{$entityType}s/{$entityType}_history/{$invoice->public_id}"), 'label' => trans("texts.view_history")], + ['url' => URL::to("{$entityType}s/{$entityType}_history/{$invoice->public_id}"), 'label' => trans('texts.view_history')], DropdownButton::DIVIDER ]; if ($invoice->invoice_status_id < INVOICE_STATUS_SENT && !$invoice->is_recurring) { - $actions[] = ['url' => 'javascript:onMarkClick()', 'label' => trans("texts.mark_sent")]; + $actions[] = ['url' => 'javascript:onMarkClick()', 'label' => trans('texts.mark_sent')]; } if ($entityType == ENTITY_QUOTE) { if ($invoice->quote_invoice_id) { - $actions[] = ['url' => URL::to("invoices/{$invoice->quote_invoice_id}/edit"), 'label' => trans("texts.view_invoice")]; + $actions[] = ['url' => URL::to("invoices/{$invoice->quote_invoice_id}/edit"), 'label' => trans('texts.view_invoice')]; } else { - $actions[] = ['url' => 'javascript:onConvertClick()', 'label' => trans("texts.convert_to_invoice")]; + $actions[] = ['url' => 'javascript:onConvertClick()', 'label' => trans('texts.convert_to_invoice')]; } } elseif ($entityType == ENTITY_INVOICE) { if ($invoice->quote_id) { - $actions[] = ['url' => URL::to("quotes/{$invoice->quote_id}/edit"), 'label' => trans("texts.view_quote")]; + $actions[] = ['url' => URL::to("quotes/{$invoice->quote_id}/edit"), 'label' => trans('texts.view_quote')]; } if (!$invoice->is_recurring && $invoice->balance > 0) { $actions[] = ['url' => 'javascript:onPaymentClick()', 'label' => trans('texts.enter_payment')]; } - + foreach ($invoice->payments as $payment) { - $label = trans("texts.view_payment"); + $label = trans('texts.view_payment'); if (count($invoice->payments) > 1) { - $label .= ' - ' . $account->formatMoney($payment->amount, $invoice->client); - } + $label .= ' - ' . $account->formatMoney($payment->amount, $invoice->client); + } $actions[] = ['url' => $payment->present()->url, 'label' => $label]; } } @@ -180,8 +179,8 @@ class InvoiceController extends BaseController if(!Auth::user()->hasPermission('view_all')){ $clients = $clients->where('clients.user_id', '=', Auth::user()->id); } - - $data = array( + + $data = [ 'clients' => $clients->get(), 'entityType' => $entityType, 'showBreadcrumbs' => $clone, @@ -193,9 +192,13 @@ class InvoiceController extends BaseController 'client' => $invoice->client, 'isRecurring' => $invoice->is_recurring, 'actions' => $actions, - 'lastSent' => $lastSent); + 'lastSent' => $lastSent]; $data = array_merge($data, self::getViewModel($invoice)); + if ($invoice->isSent() && $invoice->getAutoBillEnabled() && !$invoice->isPaid()) { + $data['autoBillChangeWarning'] = $invoice->client->autoBillLater(); + } + if ($clone) { $data['formIsChanged'] = true; } @@ -230,7 +233,7 @@ class InvoiceController extends BaseController public function create(InvoiceRequest $request, $clientPublicId = 0, $isRecurring = false) { $account = Auth::user()->account; - + $entityType = $isRecurring ? ENTITY_RECURRING_INVOICE : ENTITY_INVOICE; $clientId = null; @@ -240,17 +243,17 @@ class InvoiceController extends BaseController $invoice = $account->createInvoice($entityType, $clientId); $invoice->public_id = 0; - + if (Session::get('expenses')) { - $invoice->expenses = Expense::scope(Session::get('expenses'))->with('documents')->get(); + $invoice->expenses = Expense::scope(Session::get('expenses'))->with('documents', 'expense_category')->get(); } - + $clients = Client::scope()->with('contacts', 'country')->orderBy('name'); if (!Auth::user()->hasPermission('view_all')) { $clients = $clients->where('clients.user_id', '=', Auth::user()->id); } - + $data = [ 'clients' => $clients->get(), 'entityType' => $invoice->getEntityType(), @@ -273,7 +276,7 @@ class InvoiceController extends BaseController { $recurringHelp = ''; foreach (preg_split("/((\r?\n)|(\r\n?))/", trans('texts.recurring_help')) as $line) { - $parts = explode("=>", $line); + $parts = explode('=>', $line); if (count($parts) > 1) { $line = $parts[0].' => '.Utils::processVariables($parts[0]); $recurringHelp .= '
  • '.strip_tags($line).'
  • '; @@ -284,7 +287,7 @@ class InvoiceController extends BaseController $recurringDueDateHelp = ''; foreach (preg_split("/((\r?\n)|(\r\n?))/", trans('texts.recurring_due_date_help')) as $line) { - $parts = explode("=>", $line); + $parts = explode('=>', $line); if (count($parts) > 1) { $line = $parts[0].' => '.Utils::processVariables($parts[0]); $recurringDueDateHelp .= '
  • '.strip_tags($line).'
  • '; @@ -294,24 +297,24 @@ class InvoiceController extends BaseController } // Create due date options - $recurringDueDates = array( - trans('texts.use_client_terms') => array('value' => '', 'class' => 'monthly weekly'), - ); + $recurringDueDates = [ + trans('texts.use_client_terms') => ['value' => '', 'class' => 'monthly weekly'], + ]; - $ends = array('th','st','nd','rd','th','th','th','th','th','th'); + $ends = ['th','st','nd','rd','th','th','th','th','th','th']; for($i = 1; $i < 31; $i++){ if ($i >= 11 && $i <= 13) $ordinal = $i. 'th'; else $ordinal = $i . $ends[$i % 10]; $dayStr = str_pad($i, 2, '0', STR_PAD_LEFT); - $str = trans('texts.day_of_month', array('ordinal'=>$ordinal)); + $str = trans('texts.day_of_month', ['ordinal'=>$ordinal]); - $recurringDueDates[$str] = array('value' => "1998-01-$dayStr", 'data-num' => $i, 'class' => 'monthly'); + $recurringDueDates[$str] = ['value' => "1998-01-$dayStr", 'data-num' => $i, 'class' => 'monthly']; } - $recurringDueDates[trans('texts.last_day_of_month')] = array('value' => "1998-01-31", 'data-num' => 31, 'class' => 'monthly'); + $recurringDueDates[trans('texts.last_day_of_month')] = ['value' => '1998-01-31', 'data-num' => 31, 'class' => 'monthly']; - $daysOfWeek = array( + $daysOfWeek = [ trans('texts.sunday'), trans('texts.monday'), trans('texts.tuesday'), @@ -319,14 +322,14 @@ class InvoiceController extends BaseController trans('texts.thursday'), trans('texts.friday'), trans('texts.saturday'), - ); - foreach(array('1st','2nd','3rd','4th') as $i=>$ordinal){ + ]; + foreach(['1st','2nd','3rd','4th'] as $i=>$ordinal){ foreach($daysOfWeek as $j=>$dayOfWeek){ - $str = trans('texts.day_of_week_after', array('ordinal' => $ordinal, 'day' => $dayOfWeek)); + $str = trans('texts.day_of_week_after', ['ordinal' => $ordinal, 'day' => $dayOfWeek]); $day = $i * 7 + $j + 1; $dayStr = str_pad($day, 2, '0', STR_PAD_LEFT); - $recurringDueDates[$str] = array('value' => "1998-02-$dayStr", 'data-num' => $day, 'class' => 'weekly'); + $recurringDueDates[$str] = ['value' => "1998-02-$dayStr", 'data-num' => $day, 'class' => 'weekly']; } } @@ -335,26 +338,26 @@ class InvoiceController extends BaseController $rates = TaxRate::scope()->orderBy('name')->get(); $options = []; $defaultTax = false; - + foreach ($rates as $rate) { - $options[$rate->rate . ' ' . $rate->name] = $rate->name . ' ' . ($rate->rate+0) . '%'; - + $options[$rate->rate . ' ' . $rate->name] = $rate->name . ' ' . ($rate->rate+0) . '%'; + // load default invoice tax if ($rate->id == $account->default_tax_rate_id) { $defaultTax = $rate; } - } - + } + // Check for any taxes which have been deleted if ($invoice->exists) { foreach ($invoice->getTaxes() as $key => $rate) { if (isset($options[$key])) { continue; - } + } $options[$key] = $rate['name'] . ' ' . $rate['rate'] . '%'; } } - + return [ 'data' => Input::old('data'), 'account' => Auth::user()->account->load('country'), @@ -362,21 +365,19 @@ class InvoiceController extends BaseController 'taxRateOptions' => $options, 'defaultTax' => $defaultTax, 'currencies' => Cache::get('currencies'), - 'languages' => Cache::get('languages'), 'sizes' => Cache::get('sizes'), 'paymentTerms' => Cache::get('paymentTerms'), - 'industries' => Cache::get('industries'), 'invoiceDesigns' => InvoiceDesign::getDesigns(), 'invoiceFonts' => Cache::get('fonts'), - 'frequencies' => array( - 1 => 'Weekly', - 2 => 'Two weeks', - 3 => 'Four weeks', - 4 => 'Monthly', - 5 => 'Three months', - 6 => 'Six months', - 7 => 'Annually', - ), + 'frequencies' => [ + 1 => trans('texts.freq_weekly'), + 2 => trans('texts.freq_two_weeks'), + 3 => trans('texts.freq_four_weeks'), + 4 => trans('texts.freq_monthly'), + 5 => trans('texts.freq_three_months'), + 6 => trans('texts.freq_six_months'), + 7 => trans('texts.freq_annually'), + ], 'recurringDueDates' => $recurringDueDates, 'recurringHelp' => $recurringHelp, 'recurringDueDateHelp' => $recurringDueDateHelp, @@ -396,10 +397,10 @@ class InvoiceController extends BaseController { $data = $request->input(); $data['documents'] = $request->file('documents'); - + $action = Input::get('action'); $entityType = Input::get('entityType'); - + $invoice = $this->invoiceService->save($data); $entityType = $invoice->getEntityType(); $message = trans("texts.created_{$entityType}"); @@ -433,7 +434,7 @@ class InvoiceController extends BaseController { $data = $request->input(); $data['documents'] = $request->file('documents'); - + $action = Input::get('action'); $entityType = Input::get('entityType'); @@ -547,7 +548,7 @@ class InvoiceController extends BaseController $clone = $this->invoiceService->convertQuote($request->entity()); Session::flash('message', trans('texts.converted_to_invoice')); - + return Redirect::to('invoices/' . $clone->public_id); } @@ -567,9 +568,9 @@ class InvoiceController extends BaseController 'remove_created_by' => Auth::user()->hasFeature(FEATURE_REMOVE_CREATED_BY), 'invoice_settings' => Auth::user()->hasFeature(FEATURE_INVOICE_SETTINGS), ]; - $invoice->is_quote = intval($invoice->is_quote); + $invoice->invoice_type_id = intval($invoice->invoice_type_id); - $activityTypeId = $invoice->is_quote ? ACTIVITY_TYPE_UPDATE_QUOTE : ACTIVITY_TYPE_UPDATE_INVOICE; + $activityTypeId = $invoice->isType(INVOICE_TYPE_QUOTE) ? ACTIVITY_TYPE_UPDATE_QUOTE : ACTIVITY_TYPE_UPDATE_INVOICE; $activities = Activity::scope(false, $invoice->account_id) ->where('activity_type_id', '=', $activityTypeId) ->where('invoice_id', '=', $invoice->id) @@ -589,7 +590,7 @@ class InvoiceController extends BaseController 'remove_created_by' => Auth::user()->hasFeature(FEATURE_REMOVE_CREATED_BY), 'invoice_settings' => Auth::user()->hasFeature(FEATURE_INVOICE_SETTINGS), ]; - $backup->is_quote = isset($backup->is_quote) && intval($backup->is_quote); + $backup->invoice_type_id = isset($backup->invoice_type_id) && intval($backup->invoice_type_id) == INVOICE_TYPE_QUOTE; $backup->account = $invoice->account->toArray(); $versionsJson[$activity->id] = $backup; diff --git a/app/Http/Controllers/NinjaController.php b/app/Http/Controllers/NinjaController.php new file mode 100644 index 0000000000..635207d762 --- /dev/null +++ b/app/Http/Controllers/NinjaController.php @@ -0,0 +1,267 @@ +accountRepo = $accountRepo; + $this->contactMailer = $contactMailer; + } + + /** + * @param array $input + * @param Affiliate $affiliate + * + * @return array + */ + private function getLicensePaymentDetails(array $input, Affiliate $affiliate) + { + $country = Country::find($input['country_id']); + + $data = [ + 'firstName' => $input['first_name'], + 'lastName' => $input['last_name'], + 'email' => $input['email'], + 'number' => $input['card_number'], + 'expiryMonth' => $input['expiration_month'], + 'expiryYear' => $input['expiration_year'], + 'cvv' => $input['cvv'], + 'billingAddress1' => $input['address1'], + 'billingAddress2' => $input['address2'], + 'billingCity' => $input['city'], + 'billingState' => $input['state'], + 'billingPostcode' => $input['postal_code'], + 'billingCountry' => $country->iso_3166_2, + 'shippingAddress1' => $input['address1'], + 'shippingAddress2' => $input['address2'], + 'shippingCity' => $input['city'], + 'shippingState' => $input['state'], + 'shippingPostcode' => $input['postal_code'], + 'shippingCountry' => $country->iso_3166_2 + ]; + + $card = new CreditCard($data); + + return [ + 'amount' => $affiliate->price, + 'card' => $card, + 'currency' => 'USD', + 'returnUrl' => URL::to('license_complete'), + 'cancelUrl' => URL::to('/') + ]; + } + + /** + * @return $this|\Illuminate\Contracts\View\View + */ + public function show_license_payment() + { + if (Input::has('return_url')) { + Session::set('return_url', Input::get('return_url')); + } + + if (Input::has('affiliate_key')) { + if ($affiliate = Affiliate::where('affiliate_key', '=', Input::get('affiliate_key'))->first()) { + Session::set('affiliate_id', $affiliate->id); + } + } + + if (Input::has('product_id')) { + Session::set('product_id', Input::get('product_id')); + } else if (!Session::has('product_id')) { + Session::set('product_id', PRODUCT_ONE_CLICK_INSTALL); + } + + if (!Session::get('affiliate_id')) { + return Utils::fatalError(); + } + + if (Utils::isNinjaDev() && Input::has('test_mode')) { + Session::set('test_mode', Input::get('test_mode')); + } + + $account = $this->accountRepo->getNinjaAccount(); + $account->load('account_gateways.gateway'); + $accountGateway = $account->getGatewayByType(GATEWAY_TYPE_CREDIT_CARD); + $gateway = $accountGateway->gateway; + $acceptedCreditCardTypes = $accountGateway->getCreditcardTypes(); + + $affiliate = Affiliate::find(Session::get('affiliate_id')); + + $data = [ + 'showBreadcrumbs' => false, + 'hideHeader' => true, + 'url' => 'license', + 'amount' => $affiliate->price, + 'client' => false, + 'contact' => false, + 'gateway' => $gateway, + 'account' => $account, + 'accountGateway' => $accountGateway, + 'acceptedCreditCardTypes' => $acceptedCreditCardTypes, + 'countries' => Cache::get('countries'), + 'currencyId' => 1, + 'currencyCode' => 'USD', + 'paymentTitle' => $affiliate->payment_title, + 'paymentSubtitle' => $affiliate->payment_subtitle, + 'showAddress' => true, + ]; + + return View::make('payments.stripe.credit_card', $data); + } + + /** + * @return \Illuminate\Contracts\View\View + */ + public function do_license_payment() + { + $testMode = Session::get('test_mode') === 'true'; + + $rules = [ + 'first_name' => 'required', + 'last_name' => 'required', + 'email' => 'required', + 'card_number' => 'required', + 'expiration_month' => 'required', + 'expiration_year' => 'required', + 'cvv' => 'required', + 'address1' => 'required', + 'city' => 'required', + 'state' => 'required', + 'postal_code' => 'required', + 'country_id' => 'required', + ]; + + $validator = Validator::make(Input::all(), $rules); + + if ($validator->fails()) { + return redirect()->to('license') + ->withErrors($validator) + ->withInput(); + } + + $account = $this->accountRepo->getNinjaAccount(); + $account->load('account_gateways.gateway'); + $accountGateway = $account->getGatewayByType(GATEWAY_TYPE_CREDIT_CARD); + + try { + $affiliate = Affiliate::find(Session::get('affiliate_id')); + + if ($testMode) { + $ref = 'TEST_MODE'; + } else { + $details = self::getLicensePaymentDetails(Input::all(), $affiliate); + + $gateway = Omnipay::create($accountGateway->gateway->provider); + $gateway->initialize((array) $accountGateway->getConfig()); + $response = $gateway->purchase($details)->send(); + + $ref = $response->getTransactionReference(); + + if (!$response->isSuccessful() || !$ref) { + $this->error('License', $response->getMessage(), $accountGateway); + return redirect()->to('license')->withInput(); + } + } + + $licenseKey = Utils::generateLicense(); + + $license = new License(); + $license->first_name = Input::get('first_name'); + $license->last_name = Input::get('last_name'); + $license->email = Input::get('email'); + $license->transaction_reference = $ref; + $license->license_key = $licenseKey; + $license->affiliate_id = Session::get('affiliate_id'); + $license->product_id = Session::get('product_id'); + $license->save(); + + $data = [ + 'message' => $affiliate->payment_subtitle, + 'license' => $licenseKey, + 'hideHeader' => true, + 'productId' => $license->product_id, + 'price' => $affiliate->price, + ]; + + $name = "{$license->first_name} {$license->last_name}"; + $this->contactMailer->sendLicensePaymentConfirmation($name, $license->email, $affiliate->price, $license->license_key, $license->product_id); + + if (Session::has('return_url')) { + $data['redirectTo'] = Session::get('return_url')."?license_key={$license->license_key}&product_id=".Session::get('product_id'); + $data['message'] = 'Redirecting to ' . Session::get('return_url'); + } + + return View::make('public.license', $data); + } catch (\Exception $e) { + $this->error('License-Uncaught', false, $accountGateway, $e); + return redirect()->to('license')->withInput(); + } + } + + /** + * @return string + */ + public function claim_license() + { + $licenseKey = Input::get('license_key'); + $productId = Input::get('product_id', PRODUCT_ONE_CLICK_INSTALL); + + $license = License::where('license_key', '=', $licenseKey) + ->where('is_claimed', '<', 10) + ->where('product_id', '=', $productId) + ->first(); + + if ($license) { + if ($license->transaction_reference != 'TEST_MODE') { + $license->is_claimed = $license->is_claimed + 1; + $license->save(); + } + + if ($productId == PRODUCT_INVOICE_DESIGNS) { + return file_get_contents(storage_path() . '/invoice_designs.txt'); + } else { + // temporary fix to enable previous version to work + if (Input::get('get_date')) { + return $license->created_at->format('Y-m-d'); + } else { + return 'valid'; + } + } + } else { + return RESULT_FAILURE; + } + } + +} diff --git a/app/Http/Controllers/OnlinePaymentController.php b/app/Http/Controllers/OnlinePaymentController.php new file mode 100644 index 0000000000..60483bf7b2 --- /dev/null +++ b/app/Http/Controllers/OnlinePaymentController.php @@ -0,0 +1,206 @@ +paymentService = $paymentService; + $this->userMailer = $userMailer; + } + + /** + * @param $invitationKey + * @param bool $gatewayType + * @param bool $sourceId + * @return \Illuminate\Http\RedirectResponse + */ + public function showPayment($invitationKey, $gatewayType = false, $sourceId = false) + { + $invitation = Invitation::with('invoice.invoice_items', 'invoice.client.currency', 'invoice.client.account.account_gateways.gateway') + ->where('invitation_key', '=', $invitationKey)->firstOrFail(); + + if ( ! $gatewayType) { + $gatewayType = Session::get($invitation->id . 'gateway_type'); + } + + $paymentDriver = $invitation->account->paymentDriver($invitation, $gatewayType); + + try { + return $paymentDriver->startPurchase(Input::all(), $sourceId); + } catch (Exception $exception) { + return $this->error($paymentDriver, $exception); + } + } + + /** + * @param CreateOnlinePaymentRequest $request + * @return \Illuminate\Http\RedirectResponse + */ + public function doPayment(CreateOnlinePaymentRequest $request) + { + $invitation = $request->invitation; + $gatewayType = Session::get($invitation->id . 'gateway_type'); + $paymentDriver = $invitation->account->paymentDriver($invitation, $gatewayType); + + try { + $paymentDriver->completeOnsitePurchase($request->all()); + + if ($paymentDriver->isTwoStep()) { + Session::flash('warning', trans('texts.bank_account_verification_next_steps')); + } else { + Session::flash('message', trans('texts.applied_payment')); + } + return redirect()->to('view/' . $invitation->invitation_key); + } catch (Exception $exception) { + return $this->error($paymentDriver, $exception, true); + } + } + + /** + * @param bool $invitationKey + * @param bool $gatewayType + * @return \Illuminate\Http\RedirectResponse + */ + public function offsitePayment($invitationKey = false, $gatewayType = false) + { + $invitationKey = $invitationKey ?: Session::get('invitation_key'); + $invitation = Invitation::with('invoice.invoice_items', 'invoice.client.currency', 'invoice.client.account.account_gateways.gateway') + ->where('invitation_key', '=', $invitationKey)->firstOrFail(); + + $gatewayType = $gatewayType ?: Session::get($invitation->id . 'gateway_type'); + $paymentDriver = $invitation->account->paymentDriver($invitation, $gatewayType); + + if ($error = Input::get('error_description') ?: Input::get('error')) { + return $this->error($paymentDriver, $error); + } + + try { + $paymentDriver->completeOffsitePurchase(Input::all()); + Session::flash('message', trans('texts.applied_payment')); + return redirect()->to('view/' . $invitation->invitation_key); + } catch (Exception $exception) { + return $this->error($paymentDriver, $exception); + } + } + + /** + * @param $paymentDriver + * @param $exception + * @param bool $showPayment + * @return \Illuminate\Http\RedirectResponse + */ + private function error($paymentDriver, $exception, $showPayment = false) + { + if (is_string($exception)) { + $displayError = $exception; + $logError = $exception; + } else { + $displayError = $exception->getMessage(); + $logError = Utils::getErrorString($exception); + } + + $message = sprintf('%s: %s', ucwords($paymentDriver->providerName()), $displayError); + Session::flash('error', $message); + + $message = sprintf('Payment Error [%s]: %s', $paymentDriver->providerName(), $logError); + Utils::logError($message, 'PHP', true); + + $route = $showPayment ? 'payment/' : 'view/'; + return redirect()->to($route . $paymentDriver->invitation->invitation_key); + } + + /** + * @param $routingNumber + * @return \Illuminate\Http\JsonResponse + */ + public function getBankInfo($routingNumber) { + if (strlen($routingNumber) != 9 || !preg_match('/\d{9}/', $routingNumber)) { + return response()->json([ + 'message' => 'Invalid routing number', + ], 400); + } + + $data = PaymentMethod::lookupBankData($routingNumber); + + if (is_string($data)) { + return response()->json([ + 'message' => $data, + ], 500); + } elseif (!empty($data)) { + return response()->json($data); + } + + return response()->json([ + 'message' => 'Bank not found', + ], 404); + } + + /** + * @param $accountKey + * @param $gatewayId + * @return \Illuminate\Http\JsonResponse + */ + public function handlePaymentWebhook($accountKey, $gatewayId) + { + $gatewayId = intval($gatewayId); + + $account = Account::where('accounts.account_key', '=', $accountKey)->first(); + + if (!$account) { + return response()->json([ + 'message' => 'Unknown account', + ], 404); + } + + $accountGateway = $account->getGatewayConfig(intval($gatewayId)); + + if (!$accountGateway) { + return response()->json([ + 'message' => 'Unknown gateway', + ], 404); + } + + $paymentDriver = $accountGateway->paymentDriver(); + + try { + $result = $paymentDriver->handleWebHook(Input::all()); + return response()->json(['message' => $result]); + } catch (Exception $exception) { + Utils::logError($exception->getMessage(), 'PHP'); + return response()->json(['message' => $exception->getMessage()], 500); + } + } + +} diff --git a/app/Http/Controllers/PaymentApiController.php b/app/Http/Controllers/PaymentApiController.php index 3355b6bff8..b311b1caf4 100644 --- a/app/Http/Controllers/PaymentApiController.php +++ b/app/Http/Controllers/PaymentApiController.php @@ -1,17 +1,11 @@ paymentRepo = $paymentRepo; - $this->invoiceRepo = $invoiceRepo; - $this->accountRepo = $accountRepo; $this->contactMailer = $contactMailer; $this->paymentService = $paymentService; } + /** + * @return \Illuminate\Contracts\View\View + */ public function index() { - return View::make('list', array( + return View::make('list', [ 'entityType' => ENTITY_PAYMENT, 'title' => trans('texts.payments'), - 'sortCol' => '6', + 'sortCol' => '7', 'columns' => Utils::trans([ 'checkbox', 'invoice', 'client', 'transaction_reference', 'method', + 'source', 'payment_amount', 'payment_date', + 'status', '' ]), - )); + ]); } + /** + * @param null $clientPublicId + * @return \Illuminate\Http\JsonResponse + */ public function getDatatable($clientPublicId = null) { return $this->paymentService->getDatatable($clientPublicId, Input::get('sSearch')); } + /** + * @param PaymentRequest $request + * @return \Illuminate\Contracts\View\View + */ public function create(PaymentRequest $request) { $invoices = Invoice::scope() - ->viewable() + ->invoiceType(INVOICE_TYPE_STANDARD) ->where('is_recurring', '=', false) - ->where('is_quote', '=', false) ->where('invoices.balance', '>', 0) ->with('client', 'invoice_status') ->orderBy('invoice_number')->get(); - $data = array( + $data = [ 'clientPublicId' => Input::old('client') ? Input::old('client') : ($request->client_id ?: 0), 'invoicePublicId' => Input::old('invoice') ? Input::old('invoice') : ($request->invoice_id ?: 0), 'invoice' => null, 'invoices' => $invoices, 'payment' => null, 'method' => 'POST', - 'url' => "payments", + 'url' => 'payments', 'title' => trans('texts.new_payment'), - 'paymentTypes' => Cache::get('paymentTypes'), 'paymentTypeId' => Input::get('paymentTypeId'), - 'clients' => Client::scope()->viewable()->with('contacts')->orderBy('name')->get(), ); + 'clients' => Client::scope()->with('contacts')->orderBy('name')->get(), ]; return View::make('payments.edit', $data); } + /** + * @param PaymentRequest $request + * @return \Illuminate\Contracts\View\View + */ public function edit(PaymentRequest $request) { $payment = $request->entity(); $payment->payment_date = Utils::fromSqlDate($payment->payment_date); - $data = array( + $data = [ 'client' => null, 'invoice' => null, - 'invoices' => Invoice::scope()->where('is_recurring', '=', false)->where('is_quote', '=', false) + 'invoices' => Invoice::scope()->invoiceType(INVOICE_TYPE_STANDARD)->where('is_recurring', '=', false) ->with('client', 'invoice_status')->orderBy('invoice_number')->get(), 'payment' => $payment, 'method' => 'PUT', 'url' => 'payments/'.$payment->public_id, 'title' => trans('texts.edit_payment'), 'paymentTypes' => Cache::get('paymentTypes'), - 'clients' => Client::scope()->with('contacts')->orderBy('name')->get(), ); + 'clients' => Client::scope()->with('contacts')->orderBy('name')->get(), ]; return View::make('payments.edit', $data); } - private function getLicensePaymentDetails($input, $affiliate) - { - $data = $this->paymentService->convertInputForOmnipay($input); - $card = new CreditCard($data); - - return [ - 'amount' => $affiliate->price, - 'card' => $card, - 'currency' => 'USD', - 'returnUrl' => URL::to('license_complete'), - 'cancelUrl' => URL::to('/') - ]; - } - - public function show_payment($invitationKey, $paymentType = false) - { - - $invitation = Invitation::with('invoice.invoice_items', 'invoice.client.currency', 'invoice.client.account.account_gateways.gateway')->where('invitation_key', '=', $invitationKey)->firstOrFail(); - $invoice = $invitation->invoice; - $client = $invoice->client; - $account = $client->account; - $useToken = false; - - if ($paymentType) { - $paymentType = 'PAYMENT_TYPE_' . strtoupper($paymentType); - } else { - $paymentType = Session::get($invitation->id . 'payment_type') ?: - $account->account_gateways[0]->getPaymentType(); - } - - if ($paymentType == PAYMENT_TYPE_TOKEN) { - $useToken = true; - $paymentType = PAYMENT_TYPE_CREDIT_CARD; - } - Session::put($invitation->id . 'payment_type', $paymentType); - - $accountGateway = $invoice->client->account->getGatewayByType($paymentType); - $gateway = $accountGateway->gateway; - - $acceptedCreditCardTypes = $accountGateway->getCreditcardTypes(); - - - // Handle offsite payments - if ($useToken || $paymentType != PAYMENT_TYPE_CREDIT_CARD - || $gateway->id == GATEWAY_EWAY - || $gateway->id == GATEWAY_TWO_CHECKOUT - || $gateway->id == GATEWAY_PAYFAST - || $gateway->id == GATEWAY_MOLLIE) { - if (Session::has('error')) { - Session::reflash(); - return Redirect::to('view/'.$invitationKey); - } else { - return self::do_payment($invitationKey, false, $useToken); - } - } - - $data = [ - 'showBreadcrumbs' => false, - 'url' => 'payment/'.$invitationKey, - 'amount' => $invoice->getRequestedAmount(), - 'invoiceNumber' => $invoice->invoice_number, - 'client' => $client, - 'contact' => $invitation->contact, - 'gateway' => $gateway, - 'accountGateway' => $accountGateway, - 'acceptedCreditCardTypes' => $acceptedCreditCardTypes, - 'countries' => Cache::get('countries'), - 'currencyId' => $client->getCurrencyId(), - 'currencyCode' => $client->currency ? $client->currency->code : ($account->currency ? $account->currency->code : 'USD'), - 'account' => $client->account, - 'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL), - 'hideHeader' => $account->isNinjaAccount(), - 'clientViewCSS' => $account->clientViewCSS(), - 'clientFontUrl' => $account->getFontsUrl(), - 'showAddress' => $accountGateway->show_address, - ]; - - return View::make('payments.payment', $data); - } - - public function show_license_payment() - { - if (Input::has('return_url')) { - Session::set('return_url', Input::get('return_url')); - } - - if (Input::has('affiliate_key')) { - if ($affiliate = Affiliate::where('affiliate_key', '=', Input::get('affiliate_key'))->first()) { - Session::set('affiliate_id', $affiliate->id); - } - } - - if (Input::has('product_id')) { - Session::set('product_id', Input::get('product_id')); - } else if (!Session::has('product_id')) { - Session::set('product_id', PRODUCT_ONE_CLICK_INSTALL); - } - - if (!Session::get('affiliate_id')) { - return Utils::fatalError(); - } - - if (Utils::isNinjaDev() && Input::has('test_mode')) { - Session::set('test_mode', Input::get('test_mode')); - } - - $account = $this->accountRepo->getNinjaAccount(); - $account->load('account_gateways.gateway'); - $accountGateway = $account->getGatewayByType(PAYMENT_TYPE_CREDIT_CARD); - $gateway = $accountGateway->gateway; - $acceptedCreditCardTypes = $accountGateway->getCreditcardTypes(); - - $affiliate = Affiliate::find(Session::get('affiliate_id')); - - $data = [ - 'showBreadcrumbs' => false, - 'hideHeader' => true, - 'url' => 'license', - 'amount' => $affiliate->price, - 'client' => false, - 'contact' => false, - 'gateway' => $gateway, - 'account' => $account, - 'accountGateway' => $accountGateway, - 'acceptedCreditCardTypes' => $acceptedCreditCardTypes, - 'countries' => Cache::get('countries'), - 'currencyId' => 1, - 'currencyCode' => 'USD', - 'paymentTitle' => $affiliate->payment_title, - 'paymentSubtitle' => $affiliate->payment_subtitle, - 'showAddress' => true, - ]; - - return View::make('payments.payment', $data); - } - - public function do_license_payment() - { - $testMode = Session::get('test_mode') === 'true'; - - $rules = array( - 'first_name' => 'required', - 'last_name' => 'required', - 'card_number' => 'required', - 'expiration_month' => 'required', - 'expiration_year' => 'required', - 'cvv' => 'required', - 'address1' => 'required', - 'city' => 'required', - 'state' => 'required', - 'postal_code' => 'required', - 'country_id' => 'required', - ); - - $validator = Validator::make(Input::all(), $rules); - - if ($validator->fails()) { - return Redirect::to('license') - ->withErrors($validator) - ->withInput(); - } - - $account = $this->accountRepo->getNinjaAccount(); - $account->load('account_gateways.gateway'); - $accountGateway = $account->getGatewayByType(PAYMENT_TYPE_CREDIT_CARD); - - try { - $affiliate = Affiliate::find(Session::get('affiliate_id')); - - if ($testMode) { - $ref = 'TEST_MODE'; - } else { - $gateway = $this->paymentService->createGateway($accountGateway); - $details = self::getLicensePaymentDetails(Input::all(), $affiliate); - $response = $gateway->purchase($details)->send(); - $ref = $response->getTransactionReference(); - - if (!$response->isSuccessful() || !$ref) { - $this->error('License', $response->getMessage(), $accountGateway); - return Redirect::to('license')->withInput(); - } - } - - $licenseKey = Utils::generateLicense(); - - $license = new License(); - $license->first_name = Input::get('first_name'); - $license->last_name = Input::get('last_name'); - $license->email = Input::get('email'); - $license->transaction_reference = $ref; - $license->license_key = $licenseKey; - $license->affiliate_id = Session::get('affiliate_id'); - $license->product_id = Session::get('product_id'); - $license->save(); - - $data = [ - 'message' => $affiliate->payment_subtitle, - 'license' => $licenseKey, - 'hideHeader' => true, - 'productId' => $license->product_id, - 'price' => $affiliate->price, - ]; - - $name = "{$license->first_name} {$license->last_name}"; - $this->contactMailer->sendLicensePaymentConfirmation($name, $license->email, $affiliate->price, $license->license_key, $license->product_id); - - if (Session::has('return_url')) { - $data['redirectTo'] = Session::get('return_url')."?license_key={$license->license_key}&product_id=".Session::get('product_id'); - $data['message'] = "Redirecting to " . Session::get('return_url'); - } - - return View::make('public.license', $data); - } catch (\Exception $e) { - $this->error('License-Uncaught', false, $accountGateway, $e); - return Redirect::to('license')->withInput(); - } - } - - public function claim_license() - { - $licenseKey = Input::get('license_key'); - $productId = Input::get('product_id', PRODUCT_ONE_CLICK_INSTALL); - - $license = License::where('license_key', '=', $licenseKey) - ->where('is_claimed', '<', 5) - ->where('product_id', '=', $productId) - ->first(); - - if ($license) { - if ($license->transaction_reference != 'TEST_MODE') { - $license->is_claimed = $license->is_claimed + 1; - $license->save(); - } - - if ($productId == PRODUCT_INVOICE_DESIGNS) { - return file_get_contents(storage_path() . '/invoice_designs.txt'); - } else { - // temporary fix to enable previous version to work - if (Input::get('get_date')) { - return $license->created_at->format('Y-m-d'); - } else { - return 'valid'; - } - } - } else { - return RESULT_FAILURE; - } - } - - public function do_payment($invitationKey, $onSite = true, $useToken = false) - { - $invitation = Invitation::with('invoice.invoice_items', 'invoice.client.currency', 'invoice.client.account.currency', 'invoice.client.account.account_gateways.gateway')->where('invitation_key', '=', $invitationKey)->firstOrFail(); - $invoice = $invitation->invoice; - $client = $invoice->client; - $account = $client->account; - $accountGateway = $account->getGatewayByType(Session::get($invitation->id . 'payment_type')); - - - $rules = [ - 'first_name' => 'required', - 'last_name' => 'required', - ]; - - if ( ! Input::get('stripeToken')) { - $rules = array_merge( - $rules, - [ - 'card_number' => 'required', - 'expiration_month' => 'required', - 'expiration_year' => 'required', - 'cvv' => 'required', - ] - ); - } - - if ($accountGateway->show_address) { - $rules = array_merge($rules, [ - 'address1' => 'required', - 'city' => 'required', - 'state' => 'required', - 'postal_code' => 'required', - 'country_id' => 'required', - ]); - } - - if ($onSite) { - $validator = Validator::make(Input::all(), $rules); - - if ($validator->fails()) { - return Redirect::to('payment/'.$invitationKey) - ->withErrors($validator) - ->withInput(Request::except('cvv')); - } - - if ($accountGateway->update_address) { - $client->address1 = trim(Input::get('address1')); - $client->address2 = trim(Input::get('address2')); - $client->city = trim(Input::get('city')); - $client->state = trim(Input::get('state')); - $client->postal_code = trim(Input::get('postal_code')); - $client->country_id = Input::get('country_id'); - $client->save(); - } - } - - try { - // For offsite payments send the client's details on file - // If we're using a token then we don't need to send any other data - if (!$onSite || $useToken) { - $data = false; - } else { - $data = Input::all(); - } - - $gateway = $this->paymentService->createGateway($accountGateway); - $details = $this->paymentService->getPaymentDetails($invitation, $accountGateway, $data); - - // check if we're creating/using a billing token - if ($accountGateway->gateway_id == GATEWAY_STRIPE) { - if ($token = Input::get('stripeToken')) { - $details['token'] = $token; - unset($details['card']); - } - - if ($useToken) { - $details['customerReference'] = $client->getGatewayToken(); - } elseif ($account->token_billing_type_id == TOKEN_BILLING_ALWAYS || Input::get('token_billing')) { - $token = $this->paymentService->createToken($gateway, $details, $accountGateway, $client, $invitation->contact_id); - if ($token) { - $details['customerReference'] = $token; - } else { - $this->error('Token-No-Ref', $this->paymentService->lastError, $accountGateway); - return Redirect::to('payment/'.$invitationKey)->withInput(Request::except('cvv')); - } - } - } - - $response = $gateway->purchase($details)->send(); - - - if ($accountGateway->gateway_id == GATEWAY_EWAY) { - $ref = $response->getData()['AccessCode']; - } elseif ($accountGateway->gateway_id == GATEWAY_TWO_CHECKOUT) { - $ref = $response->getData()['cart_order_id']; - } elseif ($accountGateway->gateway_id == GATEWAY_PAYFAST) { - $ref = $response->getData()['m_payment_id']; - } elseif ($accountGateway->gateway_id == GATEWAY_GOCARDLESS) { - $ref = $response->getData()['signature']; - } elseif ($accountGateway->gateway_id == GATEWAY_CYBERSOURCE) { - $ref = $response->getData()['transaction_uuid']; - } else { - $ref = $response->getTransactionReference(); - } - - if (!$ref) { - $this->error('No-Ref', $response->getMessage(), $accountGateway); - - if ($onSite) { - return Redirect::to('payment/'.$invitationKey) - ->withInput(Request::except('cvv')); - } else { - return Redirect::to('view/'.$invitationKey); - } - } - - if ($response->isSuccessful()) { - $payment = $this->paymentService->createPayment($invitation, $accountGateway, $ref); - Session::flash('message', trans('texts.applied_payment')); - - if ($account->account_key == NINJA_ACCOUNT_KEY) { - Session::flash('trackEventCategory', '/account'); - Session::flash('trackEventAction', '/buy_pro_plan'); - Session::flash('trackEventAmount', $payment->amount); - } - - return Redirect::to('view/'.$payment->invitation->invitation_key); - } elseif ($response->isRedirect()) { - - $invitation->transaction_reference = $ref; - $invitation->save(); - Session::put('transaction_reference', $ref); - Session::save(); - $response->redirect(); - } else { - $this->error('Unknown', $response->getMessage(), $accountGateway); - if ($onSite) { - return Redirect::to('payment/'.$invitationKey)->withInput(Request::except('cvv')); - } else { - return Redirect::to('view/'.$invitationKey); - } - } - } catch (\Exception $e) { - $this->error('Uncaught', false, $accountGateway, $e); - if ($onSite) { - return Redirect::to('payment/'.$invitationKey)->withInput(Request::except('cvv')); - } else { - return Redirect::to('view/'.$invitationKey); - } - } - } - - public function offsite_payment() - { - $payerId = Request::query('PayerID'); - $token = Request::query('token'); - - if (!$token) { - $token = Session::pull('transaction_reference'); - } - if (!$token) { - return redirect(NINJA_WEB_URL); - } - - $invitation = Invitation::with('invoice.client.currency', 'invoice.client.account.account_gateways.gateway')->where('transaction_reference', '=', $token)->firstOrFail(); - $invoice = $invitation->invoice; - $client = $invoice->client; - $account = $client->account; - - if ($payerId) { - $paymentType = PAYMENT_TYPE_PAYPAL; - } else { - $paymentType = Session::get($invitation->id . 'payment_type'); - } - if (!$paymentType) { - $this->error('No-Payment-Type', false, false); - return Redirect::to($invitation->getLink()); - } - $accountGateway = $account->getGatewayByType($paymentType); - $gateway = $this->paymentService->createGateway($accountGateway); - - // Check for Dwolla payment error - if ($accountGateway->isGateway(GATEWAY_DWOLLA) && Input::get('error')) { - $this->error('Dwolla', Input::get('error_description'), $accountGateway); - return Redirect::to($invitation->getLink()); - } - - // PayFast transaction referencce - if ($accountGateway->isGateway(GATEWAY_PAYFAST) && Request::has('pt')) { - $token = Request::query('pt'); - } - - try { - if ($accountGateway->isGateway(GATEWAY_CYBERSOURCE)) { - if (Input::get('decision') == 'ACCEPT') { - $payment = $this->paymentService->createPayment($invitation, $accountGateway, $token, $payerId); - Session::flash('message', trans('texts.applied_payment')); - } else { - $message = Input::get('message') . ': ' . Input::get('invalid_fields'); - Session::flash('error', $message); - } - return Redirect::to($invitation->getLink()); - } elseif (method_exists($gateway, 'completePurchase') - && !$accountGateway->isGateway(GATEWAY_TWO_CHECKOUT) - && !$accountGateway->isGateway(GATEWAY_CHECKOUT_COM)) { - $details = $this->paymentService->getPaymentDetails($invitation, $accountGateway); - - $response = $this->paymentService->completePurchase($gateway, $accountGateway, $details, $token); - - $ref = $response->getTransactionReference() ?: $token; - - if ($response->isCancelled()) { - // do nothing - } elseif ($response->isSuccessful()) { - $payment = $this->paymentService->createPayment($invitation, $accountGateway, $ref, $payerId); - Session::flash('message', trans('texts.applied_payment')); - } else { - $this->error('offsite', $response->getMessage(), $accountGateway); - } - return Redirect::to($invitation->getLink()); - } else { - $payment = $this->paymentService->createPayment($invitation, $accountGateway, $token, $payerId); - Session::flash('message', trans('texts.applied_payment')); - return Redirect::to($invitation->getLink()); - } - } catch (\Exception $e) { - $this->error('Offsite-uncaught', false, $accountGateway, $e); - return Redirect::to($invitation->getLink()); - } - } - + /** + * @param CreatePaymentRequest $request + * @return \Illuminate\Http\RedirectResponse + */ public function store(CreatePaymentRequest $request) { $input = $request->input(); @@ -613,6 +162,10 @@ class PaymentController extends BaseController return redirect()->to($payment->client->getRoute()); } + /** + * @param UpdatePaymentRequest $request + * @return \Illuminate\Http\RedirectResponse + */ public function update(UpdatePaymentRequest $request) { $payment = $this->paymentRepo->save($request->input(), $request->entity()); @@ -622,29 +175,21 @@ class PaymentController extends BaseController return redirect()->to($payment->getRoute()); } + /** + * @return mixed + */ public function bulk() { $action = Input::get('action'); + $amount = Input::get('amount'); $ids = Input::get('public_id') ? Input::get('public_id') : Input::get('ids'); - $count = $this->paymentService->bulk($ids, $action); + $count = $this->paymentService->bulk($ids, $action, ['amount'=>$amount]); if ($count > 0) { - $message = Utils::pluralize($action.'d_payment', $count); + $message = Utils::pluralize($action=='refund'?'refunded_payment':$action.'d_payment', $count); Session::flash('message', $message); } - return Redirect::to('payments'); - } - - private function error($type, $error, $accountGateway = false, $exception = false) - { - $message = ''; - if ($accountGateway && $accountGateway->gateway) { - $message = $accountGateway->gateway->name . ': '; - } - $message .= $error ?: trans('texts.payment_error'); - - Session::flash('error', $message); - Utils::logError("Payment Error [{$type}]: " . ($exception ? Utils::getErrorString($exception) : $message), 'PHP', true); + return redirect()->to('payments'); } } diff --git a/app/Http/Controllers/PaymentTermController.php b/app/Http/Controllers/PaymentTermController.php index 35b57ce26d..30f3c5bf42 100644 --- a/app/Http/Controllers/PaymentTermController.php +++ b/app/Http/Controllers/PaymentTermController.php @@ -1,25 +1,25 @@ paymentTermService = $paymentTermService; } + /** + * @return \Illuminate\Http\RedirectResponse + */ public function index() { return Redirect::to('settings/' . ACCOUNT_PAYMENT_TERMS); } + /** + * @return \Illuminate\Http\JsonResponse + */ public function getDatatable() { return $this->paymentTermService->getDatatable(); } + /** + * @param $publicId + * @return \Illuminate\Contracts\View\View + */ public function edit($publicId) { $data = [ @@ -49,6 +59,9 @@ class PaymentTermController extends BaseController return View::make('accounts.payment_term', $data); } + /** + * @return \Illuminate\Contracts\View\View + */ public function create() { $data = [ @@ -61,16 +74,27 @@ class PaymentTermController extends BaseController return View::make('accounts.payment_term', $data); } + /** + * @return \Illuminate\Http\RedirectResponse + */ public function store() { return $this->save(); } + /** + * @param $publicId + * @return \Illuminate\Http\RedirectResponse + */ public function update($publicId) { return $this->save($publicId); } + /** + * @param bool $publicId + * @return \Illuminate\Http\RedirectResponse + */ private function save($publicId = false) { if ($publicId) { @@ -89,6 +113,9 @@ class PaymentTermController extends BaseController return Redirect::to('settings/' . ACCOUNT_PAYMENT_TERMS); } + /** + * @return \Illuminate\Http\RedirectResponse + */ public function bulk() { $action = Input::get('bulk_action'); diff --git a/app/Http/Controllers/ProductApiController.php b/app/Http/Controllers/ProductApiController.php index 6a8756eda4..0143007d84 100644 --- a/app/Http/Controllers/ProductApiController.php +++ b/app/Http/Controllers/ProductApiController.php @@ -5,12 +5,26 @@ use App\Ninja\Repositories\ProductRepository; use App\Http\Requests\CreateProductRequest; use App\Http\Requests\UpdateProductRequest; +/** + * Class ProductApiController + */ class ProductApiController extends BaseAPIController { - protected $productRepo; - + /** + * @var string + */ protected $entityType = ENTITY_PRODUCT; + /** + * @var ProductRepository + */ + protected $productRepo; + + /** + * ProductApiController constructor. + * + * @param ProductRepository $productRepo + */ public function __construct(ProductRepository $productRepo) { parent::__construct(); @@ -18,6 +32,9 @@ class ProductApiController extends BaseAPIController $this->productRepo = $productRepo; } + /** + * @return \Illuminate\Http\Response + */ public function index() { $products = Product::scope() @@ -27,6 +44,10 @@ class ProductApiController extends BaseAPIController return $this->listResponse($products); } + /** + * @param CreateProductRequest $request + * @return \Illuminate\Http\Response + */ public function store(CreateProductRequest $request) { $product = $this->productRepo->save($request->input()); @@ -34,6 +55,11 @@ class ProductApiController extends BaseAPIController return $this->itemResponse($product); } + /** + * @param UpdateProductRequest $request + * @param $publicId + * @return \Illuminate\Http\Response + */ public function update(UpdateProductRequest $request, $publicId) { if ($request->action) { @@ -46,9 +72,4 @@ class ProductApiController extends BaseAPIController return $this->itemResponse($product); } - - public function destroy($publicId) - { - //stub - } } diff --git a/app/Http/Controllers/ProductController.php b/app/Http/Controllers/ProductController.php index bd5eed57db..626edbae2f 100644 --- a/app/Http/Controllers/ProductController.php +++ b/app/Http/Controllers/ProductController.php @@ -1,24 +1,30 @@ productService = $productService; } + /** + * @return \Illuminate\Http\RedirectResponse + */ public function index() { return Redirect::to('settings/' . ACCOUNT_PRODUCTS); } + /** + * @return \Illuminate\Http\JsonResponse + */ public function getDatatable() { return $this->productService->getDatatable(Auth::user()->account_id); } + /** + * @param $publicId + * @return \Illuminate\Contracts\View\View + */ public function edit($publicId) { $account = Auth::user()->account; @@ -52,6 +68,9 @@ class ProductController extends BaseController return View::make('accounts.product', $data); } + /** + * @return \Illuminate\Contracts\View\View + */ public function create() { $account = Auth::user()->account; @@ -68,16 +87,27 @@ class ProductController extends BaseController return View::make('accounts.product', $data); } + /** + * @return \Illuminate\Http\RedirectResponse + */ public function store() { return $this->save(); } + /** + * @param $publicId + * @return \Illuminate\Http\RedirectResponse + */ public function update($publicId) { return $this->save($publicId); } + /** + * @param bool $productPublicId + * @return \Illuminate\Http\RedirectResponse + */ private function save($productPublicId = false) { if ($productPublicId) { @@ -99,6 +129,9 @@ class ProductController extends BaseController return Redirect::to('settings/' . ACCOUNT_PRODUCTS); } + /** + * @return \Illuminate\Http\RedirectResponse + */ public function bulk() { $action = Input::get('bulk_action'); diff --git a/app/Http/Controllers/QuoteApiController.php b/app/Http/Controllers/QuoteApiController.php index 9acd645ed7..d6c572ceb0 100644 --- a/app/Http/Controllers/QuoteApiController.php +++ b/app/Http/Controllers/QuoteApiController.php @@ -1,13 +1,8 @@ withTrashed() - ->where('is_quote', '=', '1') + ->quotes() ->with('invoice_items', 'client') ->orderBy('created_at', 'desc'); diff --git a/app/Http/Controllers/QuoteController.php b/app/Http/Controllers/QuoteController.php index 58807ba4a9..2efd429be5 100644 --- a/app/Http/Controllers/QuoteController.php +++ b/app/Http/Controllers/QuoteController.php @@ -6,25 +6,18 @@ use Redirect; use Utils; use View; use Cache; -use Event; use Session; use App\Models\Account; use App\Models\Client; use App\Models\Country; -use App\Models\Currency; -use App\Models\Industry; use App\Models\InvoiceDesign; -use App\Models\PaymentTerm; use App\Models\Product; -use App\Models\Size; use App\Models\TaxRate; use App\Models\Invitation; -use App\Models\Activity; use App\Models\Invoice; use App\Ninja\Mailers\ContactMailer as Mailer; use App\Ninja\Repositories\InvoiceRepository; use App\Ninja\Repositories\ClientRepository; -use App\Events\QuoteInvitationWasApproved; use App\Services\InvoiceService; use App\Http\Requests\InvoiceRequest; @@ -48,10 +41,6 @@ class QuoteController extends BaseController public function index() { - if (!Utils::hasFeature(FEATURE_QUOTES)) { - return Redirect::to('/invoices/create'); - } - $data = [ 'title' => trans('texts.quotes'), 'entityType' => ENTITY_QUOTE, @@ -126,7 +115,7 @@ class QuoteController extends BaseController return [ 'entityType' => ENTITY_QUOTE, 'account' => Auth::user()->account, - 'products' => Product::scope()->orderBy('id')->get(array('product_key', 'notes', 'cost', 'qty')), + 'products' => Product::scope()->orderBy('id')->get(['product_key', 'notes', 'cost', 'qty']), 'taxRateOptions' => $options, 'defaultTax' => $defaultTax, 'countries' => Cache::get('countries'), @@ -160,15 +149,15 @@ class QuoteController extends BaseController $count = $this->invoiceService->bulk($ids, $action); if ($count > 0) { - $key = $action == 'markSent' ? "updated_quote" : "{$action}d_quote"; + $key = $action == 'markSent' ? 'updated_quote' : "{$action}d_quote"; $message = Utils::pluralize($key, $count); Session::flash('message', $message); } if ($action == 'restore' && $count == 1) { - return Redirect::to("quotes/".Utils::getFirst($ids)); + return Redirect::to('quotes/'.Utils::getFirst($ids)); } else { - return Redirect::to("quotes"); + return Redirect::to('quotes'); } } diff --git a/app/Http/Controllers/RecurringInvoiceController.php b/app/Http/Controllers/RecurringInvoiceController.php index 2982e04e33..4a1d6431ed 100644 --- a/app/Http/Controllers/RecurringInvoiceController.php +++ b/app/Http/Controllers/RecurringInvoiceController.php @@ -3,10 +3,20 @@ use Utils; use App\Ninja\Repositories\InvoiceRepository; +/** + * Class RecurringInvoiceController + */ class RecurringInvoiceController extends BaseController { + /** + * @var InvoiceRepository + */ protected $invoiceRepo; + /** + * RecurringInvoiceController constructor. + * @param InvoiceRepository $invoiceRepo + */ public function __construct(InvoiceRepository $invoiceRepo) { //parent::__construct(); @@ -14,6 +24,9 @@ class RecurringInvoiceController extends BaseController $this->invoiceRepo = $invoiceRepo; } + /** + * @return mixed + */ public function index() { $data = [ diff --git a/app/Http/Controllers/ReportController.php b/app/Http/Controllers/ReportController.php index 349cda2918..aa169b3e58 100644 --- a/app/Http/Controllers/ReportController.php +++ b/app/Http/Controllers/ReportController.php @@ -14,8 +14,14 @@ use App\Models\Client; use App\Models\Payment; use App\Models\Expense; +/** + * Class ReportController + */ class ReportController extends BaseController { + /** + * @return \Illuminate\Contracts\View\View + */ public function d3() { $message = ''; @@ -42,6 +48,9 @@ class ReportController extends BaseController return View::make('reports.d3', $data); } + /** + * @return \Illuminate\Contracts\View\View + */ public function showReports() { $action = Input::get('action'); @@ -123,6 +132,12 @@ class ReportController extends BaseController return View::make('reports.chart_builder', $params); } + /** + * @param $groupBy + * @param $startDate + * @param $endDate + * @return array + */ private function generateChart($groupBy, $startDate, $endDate) { $width = 10; @@ -168,7 +183,7 @@ class ReportController extends BaseController ->groupBy($groupBy); if ($entityType == ENTITY_INVOICE) { - $records->where('is_quote', '=', false) + $records->where('invoice_type_id', '=', INVOICE_TYPE_STANDARD) ->where('is_recurring', '=', false); } elseif ($entityType == ENTITY_PAYMENT) { $records->join('invoices', 'invoices.id', '=', 'payments.invoice_id') @@ -221,6 +236,14 @@ class ReportController extends BaseController ]; } + /** + * @param $reportType + * @param $startDate + * @param $endDate + * @param $dateField + * @param $isExport + * @return array + */ private function generateReport($reportType, $startDate, $endDate, $dateField, $isExport) { if ($reportType == ENTITY_CLIENT) { @@ -236,6 +259,13 @@ class ReportController extends BaseController } } + /** + * @param $startDate + * @param $endDate + * @param $dateField + * @param $isExport + * @return array + */ private function generateTaxRateReport($startDate, $endDate, $dateField, $isExport) { $columns = ['tax_name', 'tax_rate', 'amount', 'paid']; @@ -313,6 +343,12 @@ class ReportController extends BaseController } + /** + * @param $startDate + * @param $endDate + * @param $isExport + * @return array + */ private function generatePaymentReport($startDate, $endDate, $isExport) { $columns = ['client', 'invoice_number', 'invoice_date', 'amount', 'payment_date', 'paid', 'method']; @@ -358,6 +394,12 @@ class ReportController extends BaseController ]; } + /** + * @param $startDate + * @param $endDate + * @param $isExport + * @return array + */ private function generateInvoiceReport($startDate, $endDate, $isExport) { $columns = ['client', 'invoice_number', 'invoice_date', 'amount', 'payment_date', 'paid', 'method']; @@ -374,7 +416,7 @@ class ReportController extends BaseController $query->where('invoice_date', '>=', $startDate) ->where('invoice_date', '<=', $endDate) ->where('is_deleted', '=', false) - ->where('is_quote', '=', false) + ->where('invoice_type_id', '=', INVOICE_TYPE_STANDARD) ->where('is_recurring', '=', false) ->with(['payments' => function($query) { $query->withTrashed() @@ -405,7 +447,7 @@ class ReportController extends BaseController $reportTotals = $this->addToTotals($reportTotals, $client->currency_id, 'balance', $invoice->balance); } } - + return [ 'columns' => $columns, 'displayData' => $displayData, @@ -413,6 +455,12 @@ class ReportController extends BaseController ]; } + /** + * @param $startDate + * @param $endDate + * @param $isExport + * @return array + */ private function generateClientReport($startDate, $endDate, $isExport) { $columns = ['client', 'amount', 'paid', 'balance']; @@ -427,7 +475,7 @@ class ReportController extends BaseController ->with(['invoices' => function($query) use ($startDate, $endDate) { $query->where('invoice_date', '>=', $startDate) ->where('invoice_date', '<=', $endDate) - ->where('is_quote', '=', false) + ->where('invoice_type_id', '=', INVOICE_TYPE_STANDARD) ->where('is_recurring', '=', false) ->withArchived(); }]); @@ -460,6 +508,12 @@ class ReportController extends BaseController ]; } + /** + * @param $startDate + * @param $endDate + * @param $isExport + * @return array + */ private function generateExpenseReport($startDate, $endDate, $isExport) { $columns = ['vendor', 'client', 'date', 'expense_amount', 'invoiced_amount']; @@ -501,6 +555,13 @@ class ReportController extends BaseController ]; } + /** + * @param $data + * @param $currencyId + * @param $field + * @param $value + * @return mixed + */ private function addToTotals($data, $currencyId, $field, $value) { $currencyId = $currencyId ?: Auth::user()->account->getCurrencyId(); @@ -513,6 +574,12 @@ class ReportController extends BaseController return $data; } + /** + * @param $reportType + * @param $data + * @param $columns + * @param $totals + */ private function export($reportType, $data, $columns, $totals) { $output = fopen('php://output', 'w') or Utils::fatalError(); diff --git a/app/Http/Controllers/TaskApiController.php b/app/Http/Controllers/TaskApiController.php index 7945008bcc..02ac417cf0 100644 --- a/app/Http/Controllers/TaskApiController.php +++ b/app/Http/Controllers/TaskApiController.php @@ -1,12 +1,10 @@ withTrashed() ->orderBy('created_at', 'desc'); - return $this->listResponse($payments); + return $this->listResponse($tasks); } /** diff --git a/app/Http/Controllers/TaskController.php b/app/Http/Controllers/TaskController.php index 8eb90df159..49def0aae8 100644 --- a/app/Http/Controllers/TaskController.php +++ b/app/Http/Controllers/TaskController.php @@ -5,30 +5,54 @@ use View; use URL; use Utils; use Input; -use Datatable; -use Validator; use Redirect; use Session; use DropdownButton; -use DateTime; -use DateTimeZone; use App\Models\Client; use App\Models\Task; use App\Ninja\Repositories\TaskRepository; use App\Ninja\Repositories\InvoiceRepository; use App\Services\TaskService; - use App\Http\Requests\TaskRequest; use App\Http\Requests\CreateTaskRequest; use App\Http\Requests\UpdateTaskRequest; +/** + * Class TaskController + */ class TaskController extends BaseController { + /** + * @var TaskRepository + */ protected $taskRepo; + + /** + * @var TaskService + */ protected $taskService; + + /** + * @var + */ protected $entityType = ENTITY_TASK; - public function __construct(TaskRepository $taskRepo, InvoiceRepository $invoiceRepo, TaskService $taskService) + /** + * @var InvoiceRepository + */ + protected $invoiceRepo; + + /** + * TaskController constructor. + * @param TaskRepository $taskRepo + * @param InvoiceRepository $invoiceRepo + * @param TaskService $taskService + */ + public function __construct( + TaskRepository $taskRepo, + InvoiceRepository $invoiceRepo, + TaskService $taskService + ) { // parent::__construct(); @@ -38,13 +62,11 @@ class TaskController extends BaseController } /** - * Display a listing of the resource. - * - * @return Response + * @return \Illuminate\Contracts\View\View */ public function index() { - return View::make('list', array( + return View::make('list', [ 'entityType' => ENTITY_TASK, 'title' => trans('texts.tasks'), 'sortCol' => '2', @@ -57,9 +79,13 @@ class TaskController extends BaseController 'status', '' ]), - )); + ]); } + /** + * @param null $clientPublicId + * @return \Illuminate\Http\JsonResponse + */ public function getDatatable($clientPublicId = null) { return $this->taskService->getDatatable($clientPublicId, Input::get('sSearch')); @@ -68,13 +94,19 @@ class TaskController extends BaseController /** * Store a newly created resource in storage. * - * @return Response + * @param CreateTaskRequest $request + * + * @return \Illuminate\Http\RedirectResponse */ public function store(CreateTaskRequest $request) { return $this->save(); } + /** + * @param $publicId + * @return \Illuminate\Http\RedirectResponse + */ public function show($publicId) { Session::reflash(); @@ -85,7 +117,9 @@ class TaskController extends BaseController /** * Show the form for creating a new resource. * - * @return Response + * @param TaskRequest $request + * + * @return \Illuminate\Contracts\View\View */ public function create(TaskRequest $request) { @@ -109,8 +143,9 @@ class TaskController extends BaseController /** * Show the form for editing the specified resource. * - * @param int $id - * @return Response + * @param TaskRequest $request + * + * @return \Illuminate\Contracts\View\View */ public function edit(TaskRequest $request) { @@ -120,15 +155,15 @@ class TaskController extends BaseController $actions = []; if ($task->invoice) { - $actions[] = ['url' => URL::to("invoices/{$task->invoice->public_id}/edit"), 'label' => trans("texts.view_invoice")]; + $actions[] = ['url' => URL::to("invoices/{$task->invoice->public_id}/edit"), 'label' => trans('texts.view_invoice')]; } else { - $actions[] = ['url' => 'javascript:submitAction("invoice")', 'label' => trans("texts.invoice_task")]; + $actions[] = ['url' => 'javascript:submitAction("invoice")', 'label' => trans('texts.invoice_task')]; // check for any open invoices $invoices = $task->client_id ? $this->invoiceRepo->findOpenInvoices($task->client_id) : []; foreach ($invoices as $invoice) { - $actions[] = ['url' => 'javascript:submitAction("add_to_invoice", '.$invoice->public_id.')', 'label' => trans("texts.add_to_invoice", ["invoice" => $invoice->invoice_number])]; + $actions[] = ['url' => 'javascript:submitAction("add_to_invoice", '.$invoice->public_id.')', 'label' => trans('texts.add_to_invoice', ['invoice' => $invoice->invoice_number])]; } } @@ -161,8 +196,9 @@ class TaskController extends BaseController /** * Update the specified resource in storage. * - * @param int $id - * @return Response + * @param UpdateTaskRequest $request + * + * @return \Illuminate\Http\RedirectResponse */ public function update(UpdateTaskRequest $request) { @@ -171,6 +207,9 @@ class TaskController extends BaseController return $this->save($task->public_id); } + /** + * @return array + */ private static function getViewModel() { return [ @@ -179,6 +218,10 @@ class TaskController extends BaseController ]; } + /** + * @param null $publicId + * @return \Illuminate\Http\RedirectResponse + */ private function save($publicId = null) { $action = Input::get('action'); @@ -188,7 +231,12 @@ class TaskController extends BaseController } $task = $this->taskRepo->save($publicId, Input::all()); - Session::flash('message', trans($publicId ? 'texts.updated_task' : 'texts.created_task')); + + if($publicId) { + Session::flash('message', trans('texts.updated_task')); + } else { + Session::flash('message', trans('texts.created_task')); + } if (in_array($action, ['invoice', 'add_to_invoice'])) { return self::bulk(); @@ -197,6 +245,9 @@ class TaskController extends BaseController return Redirect::to("tasks/{$task->public_id}/edit"); } + /** + * @return \Illuminate\Http\RedirectResponse + */ public function bulk() { $action = Input::get('action'); diff --git a/app/Http/Controllers/TaxRateApiController.php b/app/Http/Controllers/TaxRateApiController.php index 85756205d9..e5b0003d6e 100644 --- a/app/Http/Controllers/TaxRateApiController.php +++ b/app/Http/Controllers/TaxRateApiController.php @@ -7,10 +7,20 @@ use App\Http\Requests\UpdateTaxRateRequest; class TaxRateApiController extends BaseAPIController { + /** + * @var TaxRateRepository + */ protected $taxRateRepo; - + + /** + * @var string + */ protected $entityType = ENTITY_TAX_RATE; + /** + * TaxRateApiController constructor. + * @param TaxRateRepository $taxRateRepo + */ public function __construct(TaxRateRepository $taxRateRepo) { parent::__construct(); @@ -34,6 +44,11 @@ class TaxRateApiController extends BaseAPIController return $this->itemResponse($taxRate); } + /** + * @param UpdateTaxRateRequest $request + * @param $publicId + * @return \Illuminate\Http\Response + */ public function update(UpdateTaxRateRequest $request, $publicId) { if ($request->action) { @@ -46,9 +61,4 @@ class TaxRateApiController extends BaseAPIController return $this->itemResponse($taxRate); } - - public function destroy($publicId) - { - //stub - } } diff --git a/app/Http/Controllers/TaxRateController.php b/app/Http/Controllers/TaxRateController.php index cba4058756..61129e2a83 100644 --- a/app/Http/Controllers/TaxRateController.php +++ b/app/Http/Controllers/TaxRateController.php @@ -1,20 +1,14 @@ tokenService = $tokenService; } + /** + * @return \Illuminate\Http\RedirectResponse + */ public function index() { return Redirect::to('settings/' . ACCOUNT_API_TOKENS); } + /** + * @return \Illuminate\Http\JsonResponse + */ public function getDatatable() { return $this->tokenService->getDatatable(Auth::user()->id); } + /** + * @param $publicId + * @return \Illuminate\Contracts\View\View + */ public function edit($publicId) { $token = AccountToken::where('account_id', '=', Auth::user()->account_id) @@ -50,19 +66,26 @@ class TokenController extends BaseController return View::make('accounts.token', $data); } + /** + * @param $publicId + * @return \Illuminate\Http\RedirectResponse + */ public function update($publicId) { return $this->save($publicId); } + /** + * @return \Illuminate\Http\RedirectResponse + */ public function store() { return $this->save(); } + /** - * Displays the form for account creation - * + * @return \Illuminate\Contracts\View\View */ public function create() { @@ -76,6 +99,9 @@ class TokenController extends BaseController return View::make('accounts.token', $data); } + /** + * @return \Illuminate\Http\RedirectResponse + */ public function bulk() { $action = Input::get('bulk_action'); @@ -87,9 +113,10 @@ class TokenController extends BaseController return Redirect::to('settings/' . ACCOUNT_API_TOKENS); } + /** - * Stores new account - * + * @param bool $tokenPublicId + * @return $this|\Illuminate\Http\RedirectResponse */ public function save($tokenPublicId = false) { diff --git a/app/Http/Controllers/UserApiController.php b/app/Http/Controllers/UserApiController.php index 2869c3512f..be37ecc66c 100644 --- a/app/Http/Controllers/UserApiController.php +++ b/app/Http/Controllers/UserApiController.php @@ -5,7 +5,6 @@ use App\Ninja\Repositories\UserRepository; use App\Ninja\Transformers\UserTransformer; use Auth; use App\Models\User; - use App\Http\Requests\CreateUserRequest; use App\Http\Requests\UpdateUserRequest; diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index 6b3ab9ca5b..b8d5e15f54 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -1,10 +1,6 @@ registered) { + if ( ! Auth::user()->registered) { Session::flash('error', trans('texts.register_to_add_user')); return Redirect::to('settings/' . ACCOUNT_USER_MANAGEMENT); } - if (!Auth::user()->confirmed) { + + if ( ! Auth::user()->confirmed) { Session::flash('error', trans('texts.confirmation_required')); return Redirect::to('settings/' . ACCOUNT_USER_MANAGEMENT); } - if (Utils::isNinja()) { - $count = User::where('account_id', '=', Auth::user()->account_id)->count(); - if ($count >= MAX_NUM_USERS) { - Session::flash('error', trans('texts.limit_users')); - return Redirect::to('settings/' . ACCOUNT_USER_MANAGEMENT); - } + if (Utils::isNinja() && ! Auth::user()->caddAddUsers()) { + Session::flash('error', trans('texts.max_users_reached')); + return Redirect::to('settings/' . ACCOUNT_USER_MANAGEMENT); } $data = [ @@ -137,6 +130,11 @@ class UserController extends BaseController if ($action === 'archive') { $user->delete(); } else { + if ( ! Auth::user()->caddAddUsers()) { + return Redirect::to('settings/' . ACCOUNT_USER_MANAGEMENT) + ->with('error', trans('texts.max_users_reached')); + } + $user->restore(); } @@ -145,19 +143,6 @@ class UserController extends BaseController return Redirect::to('settings/' . ACCOUNT_USER_MANAGEMENT); } - public function restoreUser($userPublicId) - { - $user = User::where('account_id', '=', Auth::user()->account_id) - ->where('public_id', '=', $userPublicId) - ->withTrashed()->firstOrFail(); - - $user->restore(); - - Session::flash('message', trans('texts.restored_user')); - - return Redirect::to('settings/' . ACCOUNT_USER_MANAGEMENT); - } - /** * Stores new account * @@ -263,14 +248,17 @@ class UserController extends BaseController return Redirect::to("/password/reset/{$token}"); } else { - if (Session::has(REQUESTED_PRO_PLAN)) { - Session::forget(REQUESTED_PRO_PLAN); - $invitation = $this->accountRepo->enableProPlan(); - - return Redirect::to($invitation->getLink()); + if (Auth::check()) { + if (Session::has(REQUESTED_PRO_PLAN)) { + Session::forget(REQUESTED_PRO_PLAN); + $url = '/settings/account_management?upgrade=true'; + } else { + $url = '/dashboard'; + } } else { - return Redirect::to(Auth::check() ? '/dashboard' : '/login')->with('message', $notice_msg); + $url = '/login'; } + return Redirect::to($url)->with('message', $notice_msg); } } else { $error_msg = trans('texts.security.wrong_confirmation'); @@ -291,7 +279,7 @@ class UserController extends BaseController $account = Auth::user()->account; $this->accountRepo->unlinkAccount($account); if ($account->company->accounts->count() == 1) { - $account->company->forceDelete(); + $account->company->forceDelete(); } $account->forceDelete(); } diff --git a/app/Http/Controllers/VendorApiController.php b/app/Http/Controllers/VendorApiController.php index e15207934c..3b0c2dadd7 100644 --- a/app/Http/Controllers/VendorApiController.php +++ b/app/Http/Controllers/VendorApiController.php @@ -3,12 +3,9 @@ use Utils; use Response; use Input; -use Auth; use App\Models\Vendor; use App\Ninja\Repositories\VendorRepository; use App\Http\Requests\CreateVendorRequest; -use App\Http\Controllers\BaseAPIController; -use App\Ninja\Transformers\VendorTransformer; class VendorApiController extends BaseAPIController { diff --git a/app/Http/Controllers/VendorController.php b/app/Http/Controllers/VendorController.php index f1952e20de..88bde90db6 100644 --- a/app/Http/Controllers/VendorController.php +++ b/app/Http/Controllers/VendorController.php @@ -1,28 +1,17 @@ 'vendor', 'title' => trans('texts.vendors'), 'sortCol' => '4', @@ -61,7 +50,7 @@ class VendorController extends BaseController 'date_created', '' ]), - )); + ]); } public function getDatatable() @@ -99,7 +88,7 @@ class VendorController extends BaseController ['label' => trans('texts.new_vendor'), 'url' => URL::to('/vendors/create/' . $vendor->public_id)] ]; - $data = array( + $data = [ 'actionLinks' => $actionLinks, 'showBreadcrumbs' => false, 'vendor' => $vendor, @@ -108,7 +97,7 @@ class VendorController extends BaseController 'hasRecurringInvoices' => false, 'hasQuotes' => false, 'hasTasks' => false, - ); + ]; return View::make('vendors.show', $data); } @@ -121,7 +110,7 @@ class VendorController extends BaseController public function create(VendorRequest $request) { if (Vendor::scope()->count() > Auth::user()->getMaxNumVendors()) { - return View::make('error', ['hideHeader' => true, 'error' => "Sorry, you've exceeded the limit of ".Auth::user()->getMaxNumVendors()." vendors"]); + return View::make('error', ['hideHeader' => true, 'error' => "Sorry, you've exceeded the limit of ".Auth::user()->getMaxNumVendors().' vendors']); } $data = [ diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 1142338b20..8f7db1f0fa 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -17,6 +17,7 @@ class Kernel extends HttpKernel { 'Illuminate\View\Middleware\ShareErrorsFromSession', 'App\Http\Middleware\VerifyCsrfToken', 'App\Http\Middleware\DuplicateSubmissionCheck', + 'App\Http\Middleware\QueryLogging', 'App\Http\Middleware\StartupCheck', ]; diff --git a/app/Http/Middleware/ApiCheck.php b/app/Http/Middleware/ApiCheck.php index 524b718cc4..19181b8da5 100644 --- a/app/Http/Middleware/ApiCheck.php +++ b/app/Http/Middleware/ApiCheck.php @@ -7,9 +7,11 @@ use Session; use Response; use Auth; use Cache; - use App\Models\AccountToken; +/** + * Class ApiCheck + */ class ApiCheck { /** diff --git a/app/Http/Middleware/Authenticate.php b/app/Http/Middleware/Authenticate.php index 81fde62439..de82df62ae 100644 --- a/app/Http/Middleware/Authenticate.php +++ b/app/Http/Middleware/Authenticate.php @@ -5,87 +5,116 @@ use Auth; use Session; use App\Models\Invitation; use App\Models\Contact; -use App\Models\Account; -class Authenticate { - /** - * Handle an incoming request. - * - * @param \Illuminate\Http\Request $request - * @param \Closure $next - * @return mixed - */ - public function handle($request, Closure $next, $guard = 'user') - { - $authenticated = Auth::guard($guard)->check(); - - if($guard == 'client' && !empty($request->invitation_key)){ - $old_key = session('invitation_key'); - if($old_key && $old_key != $request->invitation_key){ - if($this->getInvitationContactId($old_key) != $this->getInvitationContactId($request->invitation_key)){ - // This is a different client; reauthenticate - $authenticated = false; - Auth::guard($guard)->logout(); - } - } - Session::put('invitation_key', $request->invitation_key); - } - - if($guard=='client'){ - $invitation_key = session('invitation_key'); - $account_id = $this->getInvitationAccountId($invitation_key); - - if(Auth::guard('user')->check() && Auth::user('user')->account_id === $account_id){ - // This is an admin; let them pretend to be a client - $authenticated = true; - } - - // Does this account require portal passwords? - $account = Account::whereId($account_id)->first(); - if($account && (!$account->enable_portal_password || !$account->hasFeature(FEATURE_CLIENT_PORTAL_PASSWORD))){ - $authenticated = true; - } - - if(!$authenticated){ - $contact = Contact::whereId($this->getInvitationContactId($invitation_key))->first(); - if($contact && !$contact->password){ - $authenticated = true; - } - } - } - - if (!$authenticated) - { - if ($request->ajax()) - { - return response('Unauthorized.', 401); - } - else - { - return redirect()->guest($guard=='client'?'/client/login':'/login'); - } - } +/** + * Class Authenticate + */ +class Authenticate +{ + /** + * Handle an incoming request. + * + * @param \Illuminate\Http\Request $request + * @param \Closure $next + * @param string $guard + * @return mixed + */ + public function handle($request, Closure $next, $guard = 'user') + { + $authenticated = Auth::guard($guard)->check(); - return $next($request); - } - - protected function getInvitation($key){ - $invitation = Invitation::withTrashed()->where('invitation_key', '=', $key)->first(); - if ($invitation && !$invitation->is_deleted) { - return $invitation; - } - else return null; - } - - protected function getInvitationContactId($key){ - $invitation = $this->getInvitation($key); - - return $invitation?$invitation->contact_id:null; - } - - protected function getInvitationAccountId($key){ - $invitation = $this->getInvitation($key); - - return $invitation?$invitation->account_id:null; - } + if ($guard == 'client') { + if (!empty($request->invitation_key)) { + $contact_key = session('contact_key'); + if ($contact_key) { + $contact = $this->getContact($contact_key); + $invitation = $this->getInvitation($request->invitation_key); + + if (!$invitation) { + return response()->view('error', [ + 'error' => trans('texts.invoice_not_found'), + 'hideHeader' => true, + ]); + } + + if ($contact && $contact->id != $invitation->contact_id) { + // This is a different client; reauthenticate + $authenticated = false; + Auth::guard($guard)->logout(); + } + Session::put('contact_key', $invitation->contact->contact_key); + } + } + + if (!empty($request->contact_key)) { + $contact_key = $request->contact_key; + Session::put('contact_key', $contact_key); + } else { + $contact_key = session('contact_key'); + } + + if ($contact_key) { + $contact = $this->getContact($contact_key); + } elseif (!empty($request->invitation_key)) { + $invitation = $this->getInvitation($request->invitation_key); + $contact = $invitation->contact; + Session::put('contact_key', $contact->contact_key); + } else { + return \Redirect::to('client/sessionexpired'); + } + $account = $contact->account; + + if (Auth::guard('user')->check() && Auth::user('user')->account_id === $account->id) { + // This is an admin; let them pretend to be a client + $authenticated = true; + } + + // Does this account require portal passwords? + if ($account && (!$account->enable_portal_password || !$account->hasFeature(FEATURE_CLIENT_PORTAL_PASSWORD))) { + $authenticated = true; + } + + if (!$authenticated && $contact && !$contact->password) { + $authenticated = true; + } + } + + if (!$authenticated) { + if ($request->ajax()) { + return response('Unauthorized.', 401); + } else { + return redirect()->guest($guard == 'client' ? '/client/login' : '/login'); + } + } + + return $next($request); + } + + /** + * @param $key + * @return \Illuminate\Database\Eloquent\Model|null|static + */ + protected function getInvitation($key) + { + $invitation = Invitation::withTrashed()->where('invitation_key', '=', $key)->first(); + if ($invitation && !$invitation->is_deleted) { + return $invitation; + } else { + return null; + } + } + + /** + * @param $key + * @return \Illuminate\Database\Eloquent\Model|null|static + */ + protected function getContact($key) + { + $contact = Contact::withTrashed()->where('contact_key', '=', $key)->first(); + if ($contact && !$contact->is_deleted) { + return $contact; + } else { + return null; + } + } } diff --git a/app/Http/Middleware/DuplicateSubmissionCheck.php b/app/Http/Middleware/DuplicateSubmissionCheck.php index 6f3374a47e..cffa06ecf9 100644 --- a/app/Http/Middleware/DuplicateSubmissionCheck.php +++ b/app/Http/Middleware/DuplicateSubmissionCheck.php @@ -1,19 +1,27 @@ is('api/v1/*')) { return $next($request); } $path = $request->path(); - + if (strpos($path, 'charts_and_reports') !== false) { return $next($request); } @@ -21,7 +29,7 @@ class DuplicateSubmissionCheck if (in_array($request->method(), ['POST', 'PUT', 'DELETE'])) { $lastPage = session(SESSION_LAST_REQUEST_PAGE); $lastTime = session(SESSION_LAST_REQUEST_TIME); - + if ($lastPage == $path && (microtime(true) - $lastTime <= 1)) { return redirect('/')->with('warning', trans('texts.duplicate_post')); } diff --git a/app/Http/Middleware/PermissionsRequired.php b/app/Http/Middleware/PermissionsRequired.php index af0e0015a3..636bc82c8b 100644 --- a/app/Http/Middleware/PermissionsRequired.php +++ b/app/Http/Middleware/PermissionsRequired.php @@ -1,56 +1,64 @@ [action => permission] +/** + * Class PermissionsRequired + */ +class PermissionsRequired +{ + + /** + * @var array */ static protected $actions = []; - - /** - * Handle an incoming request. - * - * @param \Illuminate\Http\Request $request - * @param \Closure $next - * @return mixed - */ - public function handle($request, Closure $next, $guard = 'user') - { - // Get the current route. - $route = $request->route(); - // Get the current route actions. - $actions = $route->getAction(); + /** + * Handle an incoming request. + * + * @param Request $request + * @param Closure $next + * @param string $guard + * + * @return mixed + */ + public function handle(Request $request, Closure $next, $guard = 'user') + { + // Get the current route. + $route = $request->route(); - // Check if we have any permissions to check the user has. - if ($permissions = !empty($actions['permissions']) ? $actions['permissions'] : null) - { - if(!Auth::user($guard)->hasPermission($permissions, !empty($actions['permissions_require_all']))){ - return response('Unauthorized.', 401); - } - } - - // Check controller permissions - $action = explode('@', $request->route()->getActionName()); - if(isset(static::$actions[$action[0]]) && isset(static::$actions[$action[0]][$action[1]])) { - $controller_permissions = static::$actions[$action[0]][$action[1]]; - if(!Auth::user($guard)->hasPermission($controller_permissions)){ - return response('Unauthorized.', 401); - } + // Get the current route actions. + $actions = $route->getAction(); + + // Check if we have any permissions to check the user has. + if ($permissions = !empty($actions['permissions']) ? $actions['permissions'] : null) { + if (!Auth::user($guard)->hasPermission($permissions, !empty($actions['permissions_require_all']))) { + return response('Unauthorized.', 401); + } } - return $next($request); - } + // Check controller permissions + $action = explode('@', $request->route()->getActionName()); + if (isset(static::$actions[$action[0]]) && isset(static::$actions[$action[0]][$action[1]])) { + $controller_permissions = static::$actions[$action[0]][$action[1]]; + if (!Auth::user($guard)->hasPermission($controller_permissions)) { + return response('Unauthorized.', 401); + } + } + + return $next($request); + } /** * add a controller's action permission * - * @param \App\Http\Controllers\Controller $controller + * @param Controller $controller * @param array $permissions */ - public static function addPermission(\App\Http\Controllers\Controller $controller, $permissions) + public static function addPermission(Controller $controller, array $permissions) { static::$actions[get_class($controller)] = $permissions; } diff --git a/app/Http/Middleware/QueryLogging.php b/app/Http/Middleware/QueryLogging.php new file mode 100644 index 0000000000..42bf472889 --- /dev/null +++ b/app/Http/Middleware/QueryLogging.php @@ -0,0 +1,41 @@ +url(), '_debugbar') === false) { + $queries = DB::getQueryLog(); + $count = count($queries); + Log::info($request->method() . ' - ' . $request->url() . ": $count queries"); + } + } + + return $response; + } +} diff --git a/app/Http/Middleware/RedirectIfAuthenticated.php b/app/Http/Middleware/RedirectIfAuthenticated.php index 41394b4cbd..1e0cb5a133 100644 --- a/app/Http/Middleware/RedirectIfAuthenticated.php +++ b/app/Http/Middleware/RedirectIfAuthenticated.php @@ -1,48 +1,51 @@ auth = $auth; - } + /** + * Create a new filter instance. + * + * @param Guard $auth + */ + public function __construct(Guard $auth) + { + $this->auth = $auth; + } - /** - * Handle an incoming request. - * - * @param \Illuminate\Http\Request $request - * @param \Closure $next - * @return mixed - */ - public function handle($request, Closure $next) - { - if ($this->auth->check() && Client::scope()->count() > 0) - { + /** + * Handle an incoming request. + * + * @param Request $request + * @param Closure $next + * @return mixed + */ + public function handle(Request $request, Closure $next) + { + if ($this->auth->check() && Client::scope()->count() > 0) { Session::reflash(); - return new RedirectResponse(url('/dashboard')); - } + return new RedirectResponse(url('/dashboard')); + } - return $next($request); - } + return $next($request); + } } diff --git a/app/Http/Middleware/StartupCheck.php b/app/Http/Middleware/StartupCheck.php index 334f867763..c8b89b0026 100644 --- a/app/Http/Middleware/StartupCheck.php +++ b/app/Http/Middleware/StartupCheck.php @@ -1,7 +1,7 @@ OUTDATE_BROWSER_URL])); } $response = $next($request); diff --git a/app/Http/Middleware/VerifyCsrfToken.php b/app/Http/Middleware/VerifyCsrfToken.php index 7766a09913..90ca57627a 100644 --- a/app/Http/Middleware/VerifyCsrfToken.php +++ b/app/Http/Middleware/VerifyCsrfToken.php @@ -3,16 +3,23 @@ use Closure; use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier; -class VerifyCsrfToken extends BaseVerifier { +/** + * Class VerifyCsrfToken + */ +class VerifyCsrfToken extends BaseVerifier +{ + /** + * @var array + */ private $openRoutes = [ 'complete', 'signup/register', 'api/v1/*', 'api/v1/login', - 'api/v1/clients/*', + 'api/v1/clients/*', 'api/v1/clients', - 'api/v1/invoices/*', + 'api/v1/invoices/*', 'api/v1/invoices', 'api/v1/quotes', 'api/v1/payments', @@ -22,25 +29,25 @@ class VerifyCsrfToken extends BaseVerifier { 'hook/email_opened', 'hook/email_bounced', 'reseller_stats', + 'payment_hook/*', ]; - /** - * Handle an incoming request. - * - * @param \Illuminate\Http\Request $request - * @param \Closure $next - * @return mixed - */ - public function handle($request, Closure $next) - { - foreach($this->openRoutes as $route) { + /** + * Handle an incoming request. + * + * @param Request $request + * @param Closure $next + * @return mixed + */ + public function handle($request, Closure $next) + { + foreach ($this->openRoutes as $route) { - if ($request->is($route)) { - return $next($request); - } + if ($request->is($route)) { + return $next($request); + } } - return parent::handle($request, $next); - } - + return parent::handle($request, $next); + } } diff --git a/app/Http/Requests/CreateBankAccountRequest.php b/app/Http/Requests/CreateBankAccountRequest.php index eac988349c..a39e91cb34 100644 --- a/app/Http/Requests/CreateBankAccountRequest.php +++ b/app/Http/Requests/CreateBankAccountRequest.php @@ -1,7 +1,6 @@ user()->hasFeature(FEATURE_DOCUMENTS)) { + return false; + } + + if ($this->invoice && $this->user()->cannot('edit', $this->invoice)) { + return false; + } + + if ($this->expense && $this->user()->cannot('edit', $this->expense)) { + return false; + } + return $this->user()->can('create', ENTITY_DOCUMENT); } @@ -20,7 +40,8 @@ class CreateDocumentRequest extends DocumentRequest public function rules() { return [ - + //'file' => 'mimes:jpg' ]; } + } diff --git a/app/Http/Requests/CreateExpenseCategoryRequest.php b/app/Http/Requests/CreateExpenseCategoryRequest.php new file mode 100644 index 0000000000..c54108e225 --- /dev/null +++ b/app/Http/Requests/CreateExpenseCategoryRequest.php @@ -0,0 +1,27 @@ +user()->can('create', ENTITY_EXPENSE_CATEGORY); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules() + { + return [ + 'name' => sprintf('required|unique:expense_categories,name,,id,account_id,%s', $this->user()->account_id), + ]; + } +} diff --git a/app/Http/Requests/CreateOnlinePaymentRequest.php b/app/Http/Requests/CreateOnlinePaymentRequest.php new file mode 100644 index 0000000000..815c8f5b21 --- /dev/null +++ b/app/Http/Requests/CreateOnlinePaymentRequest.php @@ -0,0 +1,46 @@ +invitation->account; + + $paymentDriver = $account->paymentDriver($this->invitation, $this->gateway_type); + + return $paymentDriver->rules(); + } + + public function sanitize() + { + $input = $this->all(); + + $invitation = Invitation::with('invoice.invoice_items', 'invoice.client.currency', 'invoice.client.account.currency', 'invoice.client.account.account_gateways.gateway') + ->where('invitation_key', '=', $this->invitation_key) + ->firstOrFail(); + + $input['invitation'] = $invitation; + $input['gateway_type'] = session($invitation->id . 'gateway_type'); + + $this->replace($input); + + return $this->all(); + } +} diff --git a/app/Http/Requests/CreatePaymentAPIRequest.php b/app/Http/Requests/CreatePaymentAPIRequest.php index 08a520c166..2643800d0d 100644 --- a/app/Http/Requests/CreatePaymentAPIRequest.php +++ b/app/Http/Requests/CreatePaymentAPIRequest.php @@ -35,9 +35,9 @@ class CreatePaymentAPIRequest extends PaymentRequest 'client_id' => $invoice->client->id, ]); - $rules = array( + $rules = [ 'amount' => "required|less_than:{$invoice->balance}|positive", - ); + ]; if ($this->payment_type_id == PAYMENT_TYPE_CREDIT) { $rules['payment_type_id'] = 'has_credit:' . $invoice->client->public_id . ',' . $this->amount; diff --git a/app/Http/Requests/CreatePaymentRequest.php b/app/Http/Requests/CreatePaymentRequest.php index d14d1ddba6..ae1ed9f74e 100644 --- a/app/Http/Requests/CreatePaymentRequest.php +++ b/app/Http/Requests/CreatePaymentRequest.php @@ -23,14 +23,14 @@ class CreatePaymentRequest extends PaymentRequest { $input = $this->input(); $invoice = Invoice::scope($input['invoice'])->firstOrFail(); - - $rules = array( - 'client' => 'required', - 'invoice' => 'required', - 'amount' => "required|less_than:{$invoice->balance}|positive", - ); - if ($input['payment_type_id'] == PAYMENT_TYPE_CREDIT) { + $rules = [ + 'client' => 'required', // TODO: change to client_id once views are updated + 'invoice' => 'required', // TODO: change to invoice_id once views are updated + 'amount' => "required|less_than:{$invoice->balance}|positive", + ]; + + if ( ! empty($input['payment_type_id']) && $input['payment_type_id'] == PAYMENT_TYPE_CREDIT) { $rules['payment_type_id'] = 'has_credit:'.$input['client'].','.$input['amount']; } diff --git a/app/Http/Requests/CreateTaxRateRequest.php b/app/Http/Requests/CreateTaxRateRequest.php index d8fef50093..6a83dc0cbc 100644 --- a/app/Http/Requests/CreateTaxRateRequest.php +++ b/app/Http/Requests/CreateTaxRateRequest.php @@ -1,7 +1,6 @@ entityType . $suffix; - if ($this->$field) { - $publicId= $this->$field; + $field = $this->entityType . '_id'; + if ( ! empty($this->$field)) { + $publicId = $this->$field; + } + if ( ! $publicId) { + $field = Utils::pluralizeEntityType($this->entityType); + if ( ! empty($this->$field)) { + $publicId = $this->$field; } } if ( ! $publicId) { @@ -31,8 +34,8 @@ class EntityRequest extends Request { } $class = Utils::getEntityClass($this->entityType); - - if (method_exists($class, 'withTrashed')) { + + if (method_exists($class, 'trashed')) { $this->entity = $class::scope($publicId)->withTrashed()->firstOrFail(); } else { $this->entity = $class::scope($publicId)->firstOrFail(); diff --git a/app/Http/Requests/ExpenseCategoryRequest.php b/app/Http/Requests/ExpenseCategoryRequest.php new file mode 100644 index 0000000000..810e7e56be --- /dev/null +++ b/app/Http/Requests/ExpenseCategoryRequest.php @@ -0,0 +1,7 @@ +make( + $this->sanitizeInput(), $this->container->call([$this, 'rules']), $this->messages() + ); + } + + /** + * Sanitize the input. + * + * @return array + */ + protected function sanitizeInput() + { + if (method_exists($this, 'sanitize')) { + $input = $this->container->call([$this, 'sanitize']); + } else { + $input = $this->all(); + } + + // autoload referenced entities + foreach ($this->autoload as $entityType) { + if ($id = $this->input("{$entityType}_public_id") ?: $this->input("{$entityType}_id")) { + $class = 'App\\Models\\' . ucwords($entityType); + $entity = $class::scope($id)->firstOrFail(); + $input[$entityType] = $entity; + $input[$entityType . '_id'] = $entity->id; + } + } + + $this->replace($input); + + return $this->all(); + } } diff --git a/app/Http/Requests/UpdateAccountRequest.php b/app/Http/Requests/UpdateAccountRequest.php index 0d24f73057..0d67304b91 100644 --- a/app/Http/Requests/UpdateAccountRequest.php +++ b/app/Http/Requests/UpdateAccountRequest.php @@ -1,7 +1,6 @@ user()->can('edit', $this->entity()); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules() + { + return [ + 'name' => 'required', + 'name' => sprintf('required|unique:expense_categories,name,%s,id,account_id,%s', $this->entity()->id, $this->user()->account_id), + ]; + } +} diff --git a/app/Http/Requests/UpdateTaxRateRequest.php b/app/Http/Requests/UpdateTaxRateRequest.php index a4bdc6301c..381990f32b 100644 --- a/app/Http/Requests/UpdateTaxRateRequest.php +++ b/app/Http/Requests/UpdateTaxRateRequest.php @@ -1,7 +1,6 @@ with('industries', Cache::get('industries')->each(function ($industry) { + $industry->name = trans('texts.industry_'.$industry->name); + })->sortBy(function ($industry) { + return $industry->name; + })); + + $view->with('countries', Cache::get('countries')->each(function ($country) { + $country->name = trans('texts.country_'.$country->name); + })->sortBy(function ($country) { + return $country->name; + })); + + $view->with('paymentTypes', Cache::get('paymentTypes')->each(function ($pType) { + $pType->name = trans('texts.payment_type_'.$pType->name); + })->sortBy(function ($pType) { + return $pType->name; + })); + + $view->with('languages', Cache::get('languages')->each(function ($lang) { + $lang->name = trans('texts.lang_'.$lang->name); + })->sortBy(function ($lang) { + return $lang->name; + })); + } +} \ No newline at end of file diff --git a/app/Http/routes.php b/app/Http/routes.php index 4955f9d159..7bd65e479d 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -1,5 +1,6 @@ 'auth:client'], function() { - Route::get('view/{invitation_key}', 'PublicClientController@view'); - Route::get('download/{invitation_key}', 'PublicClientController@download'); + Route::get('view/{invitation_key}', 'ClientPortalController@view'); + Route::get('download/{invitation_key}', 'ClientPortalController@download'); Route::get('view', 'HomeController@viewLogo'); Route::get('approve/{invitation_key}', 'QuoteController@approve'); - Route::get('payment/{invitation_key}/{payment_type?}', 'PaymentController@show_payment'); - Route::post('payment/{invitation_key}', 'PaymentController@do_payment'); - Route::match(['GET', 'POST'], 'complete', 'PaymentController@offsite_payment'); - Route::get('client/quotes', 'PublicClientController@quoteIndex'); - Route::get('client/invoices', 'PublicClientController@invoiceIndex'); - Route::get('client/documents', 'PublicClientController@documentIndex'); - Route::get('client/payments', 'PublicClientController@paymentIndex'); - Route::get('client/dashboard', 'PublicClientController@dashboard'); - Route::get('client/documents/js/{documents}/{filename}', 'PublicClientController@getDocumentVFSJS'); - Route::get('client/documents/{invitation_key}/{documents}/{filename?}', 'PublicClientController@getDocument'); - Route::get('client/documents/{invitation_key}/{filename?}', 'PublicClientController@getInvoiceDocumentsZip'); + Route::get('payment/{invitation_key}/{gateway_type?}/{source_id?}', 'OnlinePaymentController@showPayment'); + Route::post('payment/{invitation_key}', 'OnlinePaymentController@doPayment'); + Route::match(['GET', 'POST'], 'complete/{invitation_key?}/{gateway_type?}', 'OnlinePaymentController@offsitePayment'); + Route::get('bank/{routing_number}', 'OnlinePaymentController@getBankInfo'); + Route::get('client/payment_methods', 'ClientPortalController@paymentMethods'); + Route::post('client/payment_methods/verify', 'ClientPortalController@verifyPaymentMethod'); + //Route::get('client/payment_methods/add/{gateway_type}/{source_id?}', 'ClientPortalController@addPaymentMethod'); + //Route::post('client/payment_methods/add/{gateway_type}', 'ClientPortalController@postAddPaymentMethod'); + Route::post('client/payment_methods/default', 'ClientPortalController@setDefaultPaymentMethod'); + Route::post('client/payment_methods/{source_id}/remove', 'ClientPortalController@removePaymentMethod'); + Route::get('client/quotes', 'ClientPortalController@quoteIndex'); + Route::get('client/invoices', 'ClientPortalController@invoiceIndex'); + Route::get('client/invoices/recurring', 'ClientPortalController@recurringInvoiceIndex'); + Route::post('client/invoices/auto_bill', 'ClientPortalController@setAutoBill'); + Route::get('client/documents', 'ClientPortalController@documentIndex'); + Route::get('client/payments', 'ClientPortalController@paymentIndex'); + Route::get('client/dashboard', 'ClientPortalController@dashboard'); + Route::get('client/dashboard/{contact_key}', 'ClientPortalController@contactIndex'); + Route::get('client/documents/js/{documents}/{filename}', 'ClientPortalController@getDocumentVFSJS'); + Route::get('client/documents/{invitation_key}/{documents}/{filename?}', 'ClientPortalController@getDocument'); + Route::get('client/documents/{invitation_key}/{filename?}', 'ClientPortalController@getInvoiceDocumentsZip'); - Route::get('api/client.quotes', array('as'=>'api.client.quotes', 'uses'=>'PublicClientController@quoteDatatable')); - Route::get('api/client.invoices', array('as'=>'api.client.invoices', 'uses'=>'PublicClientController@invoiceDatatable')); - Route::get('api/client.documents', array('as'=>'api.client.documents', 'uses'=>'PublicClientController@documentDatatable')); - Route::get('api/client.payments', array('as'=>'api.client.payments', 'uses'=>'PublicClientController@paymentDatatable')); - Route::get('api/client.activity', array('as'=>'api.client.activity', 'uses'=>'PublicClientController@activityDatatable')); + Route::get('api/client.quotes', ['as'=>'api.client.quotes', 'uses'=>'ClientPortalController@quoteDatatable']); + Route::get('api/client.invoices', ['as'=>'api.client.invoices', 'uses'=>'ClientPortalController@invoiceDatatable']); + Route::get('api/client.recurring_invoices', ['as'=>'api.client.recurring_invoices', 'uses'=>'ClientPortalController@recurringInvoiceDatatable']); + Route::get('api/client.documents', ['as'=>'api.client.documents', 'uses'=>'ClientPortalController@documentDatatable']); + Route::get('api/client.payments', ['as'=>'api.client.payments', 'uses'=>'ClientPortalController@paymentDatatable']); + Route::get('api/client.activity', ['as'=>'api.client.activity', 'uses'=>'ClientPortalController@activityDatatable']); }); -Route::get('license', 'PaymentController@show_license_payment'); -Route::post('license', 'PaymentController@do_license_payment'); -Route::get('claim_license', 'PaymentController@claim_license'); +Route::get('license', 'NinjaController@show_license_payment'); +Route::post('license', 'NinjaController@do_license_payment'); +Route::get('claim_license', 'NinjaController@claim_license'); Route::post('signup/validate', 'AccountController@checkEmail'); Route::post('signup/submit', 'AccountController@submitSignup'); @@ -72,27 +84,29 @@ Route::get('/auth_unlink', 'Auth\AuthController@authUnlink'); Route::post('/hook/email_bounced', 'AppController@emailBounced'); Route::post('/hook/email_opened', 'AppController@emailOpened'); +Route::post('/payment_hook/{accountKey}/{gatewayId}', 'OnlinePaymentController@handlePaymentWebhook'); // Laravel auth routes -Route::get('/signup', array('as' => 'signup', 'uses' => 'Auth\AuthController@getRegister')); -Route::post('/signup', array('as' => 'signup', 'uses' => 'Auth\AuthController@postRegister')); -Route::get('/login', array('as' => 'login', 'uses' => 'Auth\AuthController@getLoginWrapper')); -Route::post('/login', array('as' => 'login', 'uses' => 'Auth\AuthController@postLoginWrapper')); -Route::get('/logout', array('as' => 'logout', 'uses' => 'Auth\AuthController@getLogoutWrapper')); -Route::get('/recover_password', array('as' => 'forgot', 'uses' => 'Auth\PasswordController@getEmail')); -Route::post('/recover_password', array('as' => 'forgot', 'uses' => 'Auth\PasswordController@postEmail')); -Route::get('/password/reset/{token}', array('as' => 'forgot', 'uses' => 'Auth\PasswordController@getReset')); -Route::post('/password/reset', array('as' => 'forgot', 'uses' => 'Auth\PasswordController@postReset')); +Route::get('/signup', ['as' => 'signup', 'uses' => 'Auth\AuthController@getRegister']); +Route::post('/signup', ['as' => 'signup', 'uses' => 'Auth\AuthController@postRegister']); +Route::get('/login', ['as' => 'login', 'uses' => 'Auth\AuthController@getLoginWrapper']); +Route::post('/login', ['as' => 'login', 'uses' => 'Auth\AuthController@postLoginWrapper']); +Route::get('/logout', ['as' => 'logout', 'uses' => 'Auth\AuthController@getLogoutWrapper']); +Route::get('/recover_password', ['as' => 'forgot', 'uses' => 'Auth\PasswordController@getEmail']); +Route::post('/recover_password', ['as' => 'forgot', 'uses' => 'Auth\PasswordController@postEmail']); +Route::get('/password/reset/{token}', ['as' => 'forgot', 'uses' => 'Auth\PasswordController@getReset']); +Route::post('/password/reset', ['as' => 'forgot', 'uses' => 'Auth\PasswordController@postReset']); Route::get('/user/confirm/{code}', 'UserController@confirm'); // Client auth -Route::get('/client/login', array('as' => 'login', 'uses' => 'ClientAuth\AuthController@getLogin')); -Route::post('/client/login', array('as' => 'login', 'uses' => 'ClientAuth\AuthController@postLogin')); -Route::get('/client/logout', array('as' => 'logout', 'uses' => 'ClientAuth\AuthController@getLogout')); -Route::get('/client/recover_password', array('as' => 'forgot', 'uses' => 'ClientAuth\PasswordController@getEmail')); -Route::post('/client/recover_password', array('as' => 'forgot', 'uses' => 'ClientAuth\PasswordController@postEmail')); -Route::get('/client/password/reset/{invitation_key}/{token}', array('as' => 'forgot', 'uses' => 'ClientAuth\PasswordController@getReset')); -Route::post('/client/password/reset', array('as' => 'forgot', 'uses' => 'ClientAuth\PasswordController@postReset')); +Route::get('/client/login', ['as' => 'login', 'uses' => 'ClientAuth\AuthController@getLogin']); +Route::post('/client/login', ['as' => 'login', 'uses' => 'ClientAuth\AuthController@postLogin']); +Route::get('/client/logout', ['as' => 'logout', 'uses' => 'ClientAuth\AuthController@getLogout']); +Route::get('/client/sessionexpired', ['as' => 'logout', 'uses' => 'ClientAuth\AuthController@getSessionExpired']); +Route::get('/client/recover_password', ['as' => 'forgot', 'uses' => 'ClientAuth\PasswordController@getEmail']); +Route::post('/client/recover_password', ['as' => 'forgot', 'uses' => 'ClientAuth\PasswordController@postEmail']); +Route::get('/client/password/reset/{invitation_key}/{token}', ['as' => 'forgot', 'uses' => 'ClientAuth\PasswordController@getReset']); +Route::post('/client/password/reset', ['as' => 'forgot', 'uses' => 'ClientAuth\PasswordController@postReset']); if (Utils::isNinja()) { @@ -110,29 +124,29 @@ Route::group(['middleware' => 'auth:user'], function() { Route::get('view_archive/{entity_type}/{visible}', 'AccountController@setTrashVisible'); Route::get('hide_message', 'HomeController@hideMessage'); Route::get('force_inline_pdf', 'UserController@forcePDFJS'); - Route::get('account/getSearchData', array('as' => 'getSearchData', 'uses' => 'AccountController@getSearchData')); + Route::get('account/getSearchData', ['as' => 'getSearchData', 'uses' => 'AccountController@getSearchData']); Route::get('settings/user_details', 'AccountController@showUserDetails'); Route::post('settings/user_details', 'AccountController@saveUserDetails'); Route::post('users/change_password', 'UserController@changePassword'); Route::resource('clients', 'ClientController'); - Route::get('api/clients', array('as'=>'api.clients', 'uses'=>'ClientController@getDatatable')); - Route::get('api/activities/{client_id?}', array('as'=>'api.activities', 'uses'=>'ActivityController@getDatatable')); + Route::get('api/clients', ['as'=>'api.clients', 'uses'=>'ClientController@getDatatable']); + Route::get('api/activities/{client_id?}', ['as'=>'api.activities', 'uses'=>'ActivityController@getDatatable']); Route::post('clients/bulk', 'ClientController@bulk'); Route::resource('tasks', 'TaskController'); - Route::get('api/tasks/{client_id?}', array('as'=>'api.tasks', 'uses'=>'TaskController@getDatatable')); + Route::get('api/tasks/{client_id?}', ['as'=>'api.tasks', 'uses'=>'TaskController@getDatatable']); Route::get('tasks/create/{client_id?}', 'TaskController@create'); Route::post('tasks/bulk', 'TaskController@bulk'); - Route::get('api/recurring_invoices/{client_id?}', array('as'=>'api.recurring_invoices', 'uses'=>'InvoiceController@getRecurringDatatable')); + Route::get('api/recurring_invoices/{client_id?}', ['as'=>'api.recurring_invoices', 'uses'=>'InvoiceController@getRecurringDatatable']); Route::get('invoices/invoice_history/{invoice_id}', 'InvoiceController@invoiceHistory'); Route::get('quotes/quote_history/{invoice_id}', 'InvoiceController@invoiceHistory'); Route::resource('invoices', 'InvoiceController'); - Route::get('api/invoices/{client_id?}', array('as'=>'api.invoices', 'uses'=>'InvoiceController@getDatatable')); + Route::get('api/invoices/{client_id?}', ['as'=>'api.invoices', 'uses'=>'InvoiceController@getDatatable']); Route::get('invoices/create/{client_id?}', 'InvoiceController@create'); Route::get('recurring_invoices/create/{client_id?}', 'InvoiceController@createRecurring'); Route::get('recurring_invoices', 'RecurringInvoiceController@index'); @@ -143,7 +157,7 @@ Route::group(['middleware' => 'auth:user'], function() { Route::get('documents/{documents}/{filename?}', 'DocumentController@get'); Route::get('documents/js/{documents}/{filename}', 'DocumentController@getVFSJS'); Route::get('documents/preview/{documents}/{filename?}', 'DocumentController@getPreview'); - Route::post('document', 'DocumentController@postUpload'); + Route::post('documents', 'DocumentController@postUpload'); Route::delete('documents/{documents}', 'DocumentController@delete'); Route::get('quotes/create/{client_id?}', 'QuoteController@create'); @@ -153,17 +167,17 @@ Route::group(['middleware' => 'auth:user'], function() { Route::get('quotes/{invoices}', 'InvoiceController@edit'); Route::post('quotes', 'InvoiceController@store'); Route::get('quotes', 'QuoteController@index'); - Route::get('api/quotes/{client_id?}', array('as'=>'api.quotes', 'uses'=>'QuoteController@getDatatable')); + Route::get('api/quotes/{client_id?}', ['as'=>'api.quotes', 'uses'=>'QuoteController@getDatatable']); Route::post('quotes/bulk', 'QuoteController@bulk'); Route::resource('payments', 'PaymentController'); Route::get('payments/create/{client_id?}/{invoice_id?}', 'PaymentController@create'); - Route::get('api/payments/{client_id?}', array('as'=>'api.payments', 'uses'=>'PaymentController@getDatatable')); + Route::get('api/payments/{client_id?}', ['as'=>'api.payments', 'uses'=>'PaymentController@getDatatable']); Route::post('payments/bulk', 'PaymentController@bulk'); Route::resource('credits', 'CreditController'); 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?}', ['as'=>'api.credits', 'uses'=>'CreditController@getDatatable']); Route::post('credits/bulk', 'CreditController@bulk'); Route::get('/resend_confirmation', 'AccountController@resendConfirmation'); @@ -172,41 +186,47 @@ Route::group(['middleware' => 'auth:user'], function() { // vendor Route::resource('vendors', 'VendorController'); - Route::get('api/vendor', array('as'=>'api.vendors', 'uses'=>'VendorController@getDatatable')); + Route::get('api/vendor', ['as'=>'api.vendors', 'uses'=>'VendorController@getDatatable']); Route::post('vendors/bulk', 'VendorController@bulk'); // Expense Route::resource('expenses', 'ExpenseController'); Route::get('expenses/create/{vendor_id?}/{client_id?}', 'ExpenseController@create'); - Route::get('api/expense', array('as'=>'api.expenses', 'uses'=>'ExpenseController@getDatatable')); - Route::get('api/expenseVendor/{id}', array('as'=>'api.expense', 'uses'=>'ExpenseController@getDatatableVendor')); + Route::get('api/expense', ['as'=>'api.expenses', 'uses'=>'ExpenseController@getDatatable']); + Route::get('api/vendor_expense/{id}', ['as'=>'api.expense', 'uses'=>'ExpenseController@getDatatableVendor']); Route::post('expenses/bulk', 'ExpenseController@bulk'); + Route::get('expense_categories', 'ExpenseCategoryController@index'); + Route::get('api/expense_categories', ['as'=>'api.expense_categories', 'uses'=>'ExpenseCategoryController@getDatatable']); + Route::get('expense_categories/create', 'ExpenseCategoryController@create'); + Route::post('expense_categories', 'ExpenseCategoryController@store'); + Route::put('expense_categories/{expense_categories}', 'ExpenseCategoryController@update'); + Route::get('expense_categories/{expense_categories}/edit', 'ExpenseCategoryController@edit'); + Route::post('expense_categories/bulk', 'ExpenseCategoryController@bulk'); }); Route::group([ 'middleware' => ['auth:user', 'permissions.required'], 'permissions' => 'admin', ], function() { - Route::get('api/users', array('as'=>'api.users', 'uses'=>'UserController@getDatatable')); + Route::get('api/users', ['as'=>'api.users', 'uses'=>'UserController@getDatatable']); Route::resource('users', 'UserController'); Route::post('users/bulk', 'UserController@bulk'); Route::get('send_confirmation/{user_id}', 'UserController@sendConfirmation'); Route::get('start_trial/{plan}', 'AccountController@startTrial') ->where(['plan'=>'pro']); - Route::get('restore_user/{user_id}', 'UserController@restoreUser'); Route::get('/switch_account/{user_id}', 'UserController@switchAccount'); Route::get('/unlink_account/{user_account_id}/{user_id}', 'UserController@unlinkAccount'); Route::get('/manage_companies', 'UserController@manageCompanies'); - Route::get('api/tokens', array('as'=>'api.tokens', 'uses'=>'TokenController@getDatatable')); + Route::get('api/tokens', ['as'=>'api.tokens', 'uses'=>'TokenController@getDatatable']); Route::resource('tokens', 'TokenController'); Route::post('tokens/bulk', 'TokenController@bulk'); - Route::get('api/products', array('as'=>'api.products', 'uses'=>'ProductController@getDatatable')); + Route::get('api/products', ['as'=>'api.products', 'uses'=>'ProductController@getDatatable']); Route::resource('products', 'ProductController'); Route::post('products/bulk', 'ProductController@bulk'); - Route::get('api/tax_rates', array('as'=>'api.tax_rates', 'uses'=>'TaxRateController@getDatatable')); + Route::get('api/tax_rates', ['as'=>'api.tax_rates', 'uses'=>'TaxRateController@getDatatable']); Route::resource('tax_rates', 'TaxRateController'); Route::post('tax_rates/bulk', 'TaxRateController@bulk'); @@ -224,18 +244,21 @@ Route::group([ Route::post('user/setTheme', 'UserController@setTheme'); Route::post('remove_logo', 'AccountController@removeLogo'); - Route::post('account/go_pro', 'AccountController@enableProPlan'); Route::post('/export', 'ExportController@doExport'); Route::post('/import', 'ImportController@doImport'); Route::post('/import_csv', 'ImportController@doImportCSV'); + Route::get('gateways/create/{show_wepay?}', 'AccountGatewayController@create'); Route::resource('gateways', 'AccountGatewayController'); - Route::get('api/gateways', array('as'=>'api.gateways', 'uses'=>'AccountGatewayController@getDatatable')); + Route::get('gateways/{public_id}/resend_confirmation', 'AccountGatewayController@resendConfirmation'); + Route::get('api/gateways', ['as'=>'api.gateways', 'uses'=>'AccountGatewayController@getDatatable']); Route::post('account_gateways/bulk', 'AccountGatewayController@bulk'); + Route::get('bank_accounts/import_ofx', 'BankAccountController@showImportOFX'); + Route::post('bank_accounts/import_ofx', 'BankAccountController@doImportOFX'); Route::resource('bank_accounts', 'BankAccountController'); - Route::get('api/bank_accounts', array('as'=>'api.bank_accounts', 'uses'=>'BankAccountController@getDatatable')); + Route::get('api/bank_accounts', ['as'=>'api.bank_accounts', 'uses'=>'BankAccountController@getDatatable']); Route::post('bank_accounts/bulk', 'BankAccountController@bulk'); Route::post('bank_accounts/validate', 'BankAccountController@validateAccount'); Route::post('bank_accounts/import_expenses/{bank_id}', 'BankAccountController@importExpenses'); @@ -269,6 +292,7 @@ Route::group(['middleware' => 'api', 'prefix' => 'api/v1'], function() Route::post('add_token', 'AccountApiController@addDeviceToken'); Route::post('update_notifications', 'AccountApiController@updatePushNotifications'); Route::get('dashboard', 'DashboardApiController@index'); + Route::resource('documents', 'DocumentAPIController'); // Vendor Route::resource('vendors', 'VendorApiController'); @@ -312,7 +336,6 @@ Route::get('/comments/feed', function() { return Redirect::to(NINJA_WEB_URL.'/comments/feed', 301); }); - if (!defined('CONTACT_EMAIL')) { define('CONTACT_EMAIL', Config::get('mail.from.address')); define('CONTACT_NAME', Config::get('mail.from.name')); @@ -347,6 +370,10 @@ if (!defined('CONTACT_EMAIL')) { define('ENTITY_EXPENSE_ACTIVITY', 'expense_activity'); define('ENTITY_BANK_ACCOUNT', 'bank_account'); define('ENTITY_BANK_SUBACCOUNT', 'bank_subaccount'); + define('ENTITY_EXPENSE_CATEGORY', 'expense_category'); + + define('INVOICE_TYPE_STANDARD', 1); + define('INVOICE_TYPE_QUOTE', 2); define('PERSON_CONTACT', 'contact'); define('PERSON_USER', 'user'); @@ -384,6 +411,7 @@ if (!defined('CONTACT_EMAIL')) { define('ACTION_RESTORE', 'restore'); define('ACTION_ARCHIVE', 'archive'); + define('ACTION_CLONE', 'clone'); define('ACTION_CONVERT', 'convert'); define('ACTION_DELETE', 'delete'); @@ -402,6 +430,9 @@ if (!defined('CONTACT_EMAIL')) { //define('ACTIVITY_TYPE_UPDATE_PAYMENT', 11); define('ACTIVITY_TYPE_ARCHIVE_PAYMENT', 12); define('ACTIVITY_TYPE_DELETE_PAYMENT', 13); + define('ACTIVITY_TYPE_VOIDED_PAYMENT', 39); + define('ACTIVITY_TYPE_REFUNDED_PAYMENT', 40); + define('ACTIVITY_TYPE_FAILED_PAYMENT', 41); define('ACTIVITY_TYPE_CREATE_CREDIT', 14); //define('ACTIVITY_TYPE_UPDATE_CREDIT', 15); @@ -434,6 +465,10 @@ if (!defined('CONTACT_EMAIL')) { define('ACTIVITY_TYPE_DELETE_EXPENSE', 36); define('ACTIVITY_TYPE_RESTORE_EXPENSE', 37); + // tasks + define('ACTIVITY_TYPE_CREATE_TASK', 42); + define('ACTIVITY_TYPE_UPDATE_TASK', 43); + define('DEFAULT_INVOICE_NUMBER', '0001'); define('RECENTLY_VIEWED_LIMIT', 8); define('LOGGED_ERROR_LIMIT', 100); @@ -453,6 +488,7 @@ if (!defined('CONTACT_EMAIL')) { define('DEFAULT_SEND_RECURRING_HOUR', 8); define('IMPORT_CSV', 'CSV'); + define('IMPORT_JSON', 'JSON'); define('IMPORT_FRESHBOOKS', 'FreshBooks'); define('IMPORT_WAVE', 'Wave'); define('IMPORT_RONIN', 'Ronin'); @@ -479,7 +515,13 @@ if (!defined('CONTACT_EMAIL')) { define('INVOICE_STATUS_PARTIAL', 5); define('INVOICE_STATUS_PAID', 6); - define('PAYMENT_TYPE_CREDIT', 1); + define('PAYMENT_STATUS_PENDING', 1); + define('PAYMENT_STATUS_VOIDED', 2); + define('PAYMENT_STATUS_FAILED', 3); + define('PAYMENT_STATUS_COMPLETED', 4); + define('PAYMENT_STATUS_PARTIALLY_REFUNDED', 5); + define('PAYMENT_STATUS_REFUNDED', 6); + define('CUSTOM_DESIGN', 11); define('FREQUENCY_WEEKLY', 1); @@ -525,7 +567,6 @@ if (!defined('CONTACT_EMAIL')) { define('PAYMENT_LIBRARY_PHP_PAYMENTS', 2); define('GATEWAY_AUTHORIZE_NET', 1); - define('GATEWAY_AUTHORIZE_NET_SIM', 2); define('GATEWAY_EWAY', 4); define('GATEWAY_MOLLIE', 9); define('GATEWAY_PAYFAST', 13); @@ -543,6 +584,12 @@ if (!defined('CONTACT_EMAIL')) { define('GATEWAY_DWOLLA', 43); define('GATEWAY_CHECKOUT_COM', 47); define('GATEWAY_CYBERSOURCE', 49); + define('GATEWAY_WEPAY', 60); + define('GATEWAY_BRAINTREE', 61); + + // The customer exists, but only as a local concept + // The remote gateway doesn't understand the concept of customers + define('CUSTOMER_REFERENCE_LOCAL', 'local'); define('EVENT_CREATE_CLIENT', 1); define('EVENT_CREATE_INVOICE', 2); @@ -559,7 +606,7 @@ if (!defined('CONTACT_EMAIL')) { define('NINJA_WEB_URL', env('NINJA_WEB_URL', 'https://www.invoiceninja.com')); define('NINJA_APP_URL', env('NINJA_APP_URL', 'https://app.invoiceninja.com')); define('NINJA_DATE', '2000-01-01'); - define('NINJA_VERSION', '2.5.2.2' . env('NINJA_VERSION_SUFFIX')); + define('NINJA_VERSION', '2.6' . env('NINJA_VERSION_SUFFIX')); define('SOCIAL_LINK_FACEBOOK', env('SOCIAL_LINK_FACEBOOK', 'https://www.facebook.com/invoiceninja')); define('SOCIAL_LINK_TWITTER', env('SOCIAL_LINK_TWITTER', 'https://twitter.com/invoiceninja')); @@ -589,10 +636,10 @@ if (!defined('CONTACT_EMAIL')) { define('INVOICE_DESIGNS_AFFILIATE_KEY', 'T3RS74'); define('SELF_HOST_AFFILIATE_KEY', '8S69AD'); - define('PLAN_PRICE_PRO_MONTHLY', env('PLAN_PRICE_PRO_MONTHLY', 5)); - define('PLAN_PRICE_PRO_YEARLY', env('PLAN_PRICE_PRO_YEARLY', 50)); - define('PLAN_PRICE_ENTERPRISE_MONTHLY', env('PLAN_PRICE_ENTERPRISE_MONTHLY', 10)); - define('PLAN_PRICE_ENTERPRISE_YEARLY', env('PLAN_PRICE_ENTERPRISE_YEARLY', 100)); + define('PLAN_PRICE_PRO_MONTHLY', env('PLAN_PRICE_PRO_MONTHLY', 12)); + define('PLAN_PRICE_ENTERPRISE_MONTHLY_2', env('PLAN_PRICE_ENTERPRISE_MONTHLY_2', 18)); + define('PLAN_PRICE_ENTERPRISE_MONTHLY_5', env('PLAN_PRICE_ENTERPRISE_MONTHLY_5', 26)); + define('PLAN_PRICE_ENTERPRISE_MONTHLY_10', env('PLAN_PRICE_ENTERPRISE_MONTHLY_10', 38)); define('WHITE_LABEL_PRICE', env('WHITE_LABEL_PRICE', 20)); define('INVOICE_DESIGNS_PRICE', env('INVOICE_DESIGNS_PRICE', 10)); @@ -613,13 +660,35 @@ if (!defined('CONTACT_EMAIL')) { define('TOKEN_BILLING_OPT_OUT', 3); define('TOKEN_BILLING_ALWAYS', 4); - define('PAYMENT_TYPE_PAYPAL', 'PAYMENT_TYPE_PAYPAL'); - define('PAYMENT_TYPE_CREDIT_CARD', 'PAYMENT_TYPE_CREDIT_CARD'); - define('PAYMENT_TYPE_DIRECT_DEBIT', 'PAYMENT_TYPE_DIRECT_DEBIT'); - define('PAYMENT_TYPE_BITCOIN', 'PAYMENT_TYPE_BITCOIN'); - define('PAYMENT_TYPE_DWOLLA', 'PAYMENT_TYPE_DWOLLA'); - define('PAYMENT_TYPE_TOKEN', 'PAYMENT_TYPE_TOKEN'); - define('PAYMENT_TYPE_ANY', 'PAYMENT_TYPE_ANY'); + define('PAYMENT_TYPE_CREDIT', 1); + define('PAYMENT_TYPE_ACH', 5); + define('PAYMENT_TYPE_VISA', 6); + define('PAYMENT_TYPE_MASTERCARD', 7); + define('PAYMENT_TYPE_AMERICAN_EXPRESS', 8); + define('PAYMENT_TYPE_DISCOVER', 9); + define('PAYMENT_TYPE_DINERS', 10); + define('PAYMENT_TYPE_EUROCARD', 11); + define('PAYMENT_TYPE_NOVA', 12); + define('PAYMENT_TYPE_CREDIT_CARD_OTHER', 13); + define('PAYMENT_TYPE_PAYPAL', 14); + define('PAYMENT_TYPE_CARTE_BLANCHE', 17); + define('PAYMENT_TYPE_UNIONPAY', 18); + define('PAYMENT_TYPE_JCB', 19); + define('PAYMENT_TYPE_LASER', 20); + define('PAYMENT_TYPE_MAESTRO', 21); + define('PAYMENT_TYPE_SOLO', 22); + define('PAYMENT_TYPE_SWITCH', 23); + + define('PAYMENT_METHOD_STATUS_NEW', 'new'); + define('PAYMENT_METHOD_STATUS_VERIFICATION_FAILED', 'verification_failed'); + define('PAYMENT_METHOD_STATUS_VERIFIED', 'verified'); + + define('GATEWAY_TYPE_CREDIT_CARD', 'credit_card'); + define('GATEWAY_TYPE_BANK_TRANSFER', 'bank_transfer'); + define('GATEWAY_TYPE_PAYPAL', 'paypal'); + define('GATEWAY_TYPE_BITCOIN', 'bitcoin'); + define('GATEWAY_TYPE_DWOLLA', 'dwolla'); + define('GATEWAY_TYPE_TOKEN', 'token'); define('REMINDER1', 'reminder1'); define('REMINDER2', 'reminder2'); @@ -657,6 +726,11 @@ if (!defined('CONTACT_EMAIL')) { define('RESELLER_REVENUE_SHARE', 'A'); define('RESELLER_LIMITED_USERS', 'B'); + define('AUTO_BILL_OFF', 1); + define('AUTO_BILL_OPT_IN', 2); + define('AUTO_BILL_OPT_OUT', 3); + define('AUTO_BILL_ALWAYS', 4); + // These must be lowercase define('PLAN_FREE', 'free'); define('PLAN_PRO', 'pro'); @@ -675,6 +749,8 @@ if (!defined('CONTACT_EMAIL')) { define('FEATURE_PDF_ATTACHMENT', 'pdf_attachment'); define('FEATURE_MORE_INVOICE_DESIGNS', 'more_invoice_designs'); define('FEATURE_QUOTES', 'quotes'); + define('FEATURE_TASKS', 'tasks'); + define('FEATURE_EXPENSES', 'expenses'); define('FEATURE_REPORTS', 'reports'); define('FEATURE_API', 'api'); define('FEATURE_CLIENT_PORTAL_PASSWORD', 'client_portal_password'); @@ -695,6 +771,21 @@ if (!defined('CONTACT_EMAIL')) { // Pro users who started paying on or before this date will be able to manage users define('PRO_USERS_GRANDFATHER_DEADLINE', '2016-06-04'); + define('EXTRAS_GRANDFATHER_COMPANY_ID', 0); + + // WePay + define('WEPAY_PRODUCTION', 'production'); + define('WEPAY_STAGE', 'stage'); + define('WEPAY_CLIENT_ID', env('WEPAY_CLIENT_ID')); + define('WEPAY_CLIENT_SECRET', env('WEPAY_CLIENT_SECRET')); + define('WEPAY_AUTO_UPDATE', env('WEPAY_AUTO_UPDATE', false)); + define('WEPAY_ENVIRONMENT', env('WEPAY_ENVIRONMENT', WEPAY_PRODUCTION)); + define('WEPAY_ENABLE_CANADA', env('WEPAY_ENABLE_CANADA', false)); + define('WEPAY_THEME', env('WEPAY_THEME','{"name":"Invoice Ninja","primary_color":"0b4d78","secondary_color":"0b4d78","background_color":"f8f8f8","button_color":"33b753"}')); + + define('WEPAY_FEE_PAYER', env('WEPAY_FEE_PAYER', 'payee')); + define('WEPAY_APP_FEE_MULTIPLIER', env('WEPAY_APP_FEE_MULTIPLIER', 0.002)); + define('WEPAY_APP_FEE_FIXED', env('WEPAY_APP_FEE_MULTIPLIER', 0.00)); $creditCards = [ 1 => ['card' => 'images/credit_cards/Test-Visa-Icon.png', 'text' => 'Visa'], diff --git a/app/Includes/parsecsv.lib.php b/app/Includes/parsecsv.lib.php index c5941b9dbc..7fe04984db 100644 --- a/app/Includes/parsecsv.lib.php +++ b/app/Includes/parsecsv.lib.php @@ -88,7 +88,7 @@ class parseCSV { var $heading = true; # override field names - var $fields = array(); + var $fields = []; # sort entries by this field var $sort_by = null; @@ -141,10 +141,10 @@ class parseCSV { var $file_data; # array of field values in data parsed - var $titles = array(); + var $titles = []; # two dimentional array of CSV data - var $data = array(); + var $data = []; /** @@ -193,7 +193,7 @@ class parseCSV { * @param fields field names * @return true or false */ - function save ($file = null, $data = array(), $append = false, $fields = array()) { + function save ($file = null, $data = [], $append = false, $fields = []) { if ( empty($file) ) $file = &$this->file; $mode = ( $append ) ? 'at' : 'wt' ; $is_php = ( preg_match('/\.php$/i', $file) ) ? true : false ; @@ -209,7 +209,7 @@ class parseCSV { * @param delimiter delimiter used to separate data * @return CSV data using delimiter of choice, or default */ - function output ($output = true, $filename = null, $data = array(), $fields = array(), $delimiter = null) { + function output ($output = true, $filename = null, $data = [], $fields = [], $delimiter = null) { if ( empty($filename) ) $filename = $this->output_filename; if ( $delimiter === null ) $delimiter = $this->output_delimiter; $data = $this->unparse($data, $fields, null, null, $delimiter); @@ -259,7 +259,7 @@ class parseCSV { $data = &$this->file_data; } - $chars = array(); + $chars = []; $strlen = strlen($data); $enclosed = false; $n = 1; @@ -302,7 +302,7 @@ class parseCSV { // filtering $depth = ( $to_end ) ? $n-1 : $n ; - $filtered = array(); + $filtered = []; foreach( $chars as $char => $value ) { if ( $match = $this->_check_count($char, $value, $depth, $preferred) ) { $filtered[$match] = $char; @@ -349,11 +349,11 @@ class parseCSV { } else return false; } - $rows = array(); - $row = array(); + $rows = []; + $row = []; $row_count = 0; $current = ''; - $head = ( !empty($this->fields) ) ? $this->fields : array() ; + $head = ( !empty($this->fields) ) ? $this->fields : [] ; $col = 0; $enclosed = false; $was_enclosed = false; @@ -399,7 +399,7 @@ class parseCSV { } else $rows[] = $row; } } - $row = array(); + $row = []; $col = 0; $row_count++; if ( $this->sort_by === null && $this->limit !== null && count($rows) == $this->limit ) { @@ -432,13 +432,13 @@ class parseCSV { * @param delimiter field delimiter to use * @return CSV data (text string) */ - function unparse ( $data = array(), $fields = array(), $append = false , $is_php = false, $delimiter = null) { + function unparse ( $data = [], $fields = [], $append = false , $is_php = false, $delimiter = null) { if ( !is_array($data) || empty($data) ) $data = &$this->data; if ( !is_array($fields) || empty($fields) ) $fields = &$this->titles; if ( $delimiter === null ) $delimiter = $this->delimiter; $string = ( $is_php ) ? "".$this->linefeed : '' ; - $entry = array(); + $entry = []; // create heading if ( $this->heading && !$append ) { @@ -446,7 +446,7 @@ class parseCSV { $entry[] = $this->_enclose_value($value); } $string .= implode($delimiter, $entry).$this->linefeed; - $entry = array(); + $entry = []; } // create data @@ -455,7 +455,7 @@ class parseCSV { $entry[] = $this->_enclose_value($value); } $string .= implode($delimiter, $entry).$this->linefeed; - $entry = array(); + $entry = []; } return $string; @@ -500,10 +500,10 @@ class parseCSV { * @param conditions specified conditions that the row must match * @return true of false */ - function _validate_row_conditions ($row = array(), $conditions = null) { + function _validate_row_conditions ($row = [], $conditions = null) { if ( !empty($row) ) { if ( !empty($conditions) ) { - $conditions = (strpos($conditions, ' OR ') !== false) ? explode(' OR ', $conditions) : array($conditions) ; + $conditions = (strpos($conditions, ' OR ') !== false) ? explode(' OR ', $conditions) : [$conditions] ; $or = ''; foreach( $conditions as $key => $value ) { if ( strpos($value, ' AND ') !== false ) { @@ -531,7 +531,7 @@ class parseCSV { * @return true of false */ function _validate_row_condition ($row, $condition) { - $operators = array( + $operators = [ '=', 'equals', 'is', '!=', 'is not', '<', 'is less than', @@ -540,8 +540,8 @@ class parseCSV { '>=', 'is greater than or equals', 'contains', 'does not contain', - ); - $operators_regex = array(); + ]; + $operators_regex = []; foreach( $operators as $value ) { $operators_regex[] = preg_quote($value, '/'); } @@ -553,9 +553,9 @@ class parseCSV { if ( preg_match('/^([\'\"]{1})(.*)([\'\"]{1})$/i', $value, $capture) ) { if ( $capture[1] == $capture[3] ) { $value = $capture[2]; - $value = str_replace("\\n", "\n", $value); - $value = str_replace("\\r", "\r", $value); - $value = str_replace("\\t", "\t", $value); + $value = str_replace('\\n', "\n", $value); + $value = str_replace('\\r', "\r", $value); + $value = str_replace('\\t', "\t", $value); $value = stripslashes($value); } } @@ -604,7 +604,7 @@ class parseCSV { if ( $value !== null && $value != '' ) { $delimiter = preg_quote($this->delimiter, '/'); $enclosure = preg_quote($this->enclosure, '/'); - if ( preg_match("/".$delimiter."|".$enclosure."|\n|\r/i", $value) || ($value{0} == ' ' || substr($value, -1) == ' ') ) { + if ( preg_match('/'.$delimiter.'|'.$enclosure."|\n|\r/i", $value) || ($value{0} == ' ' || substr($value, -1) == ' ') ) { $value = str_replace($this->enclosure, $this->enclosure.$this->enclosure, $value); $value = $this->enclosure.$value.$this->enclosure; } diff --git a/app/Libraries/OFX.php b/app/Libraries/OFX.php index 721c9f529f..83edb3085d 100644 --- a/app/Libraries/OFX.php +++ b/app/Libraries/OFX.php @@ -24,18 +24,18 @@ class OFX curl_setopt($c, CURLOPT_URL, $this->bank->url); curl_setopt($c, CURLOPT_POST, 1); // User-Agent: http://www.ofxhome.com/ofxforum/viewtopic.php?pid=108091#p108091 - curl_setopt($c, CURLOPT_HTTPHEADER, array('Content-Type: application/x-ofx', 'User-Agent: httpclient')); + curl_setopt($c, CURLOPT_HTTPHEADER, ['Content-Type: application/x-ofx', 'User-Agent: httpclient']); curl_setopt($c, CURLOPT_POSTFIELDS, $this->request); curl_setopt($c, CURLOPT_RETURNTRANSFER, 1); - + $this->response = curl_exec($c); - + if (Utils::isNinjaDev()) { Log::info(print_r($this->response, true)); } - + curl_close($c); - + $tmp = explode('', $this->response); $this->responseHeader = $tmp[0]; $this->responseBody = ''.$tmp[1]; @@ -48,6 +48,7 @@ class OFX return $x; } + public static function closeTags($x) { $x = preg_replace('/\s+/', '', $x); @@ -105,13 +106,13 @@ class Login "\n". "\n". "20110412162900.000[-7:MST]\n". - "".$this->id."\n". - "".$this->pass."\n". + ''.$this->id."\n". + ''.$this->pass."\n". "N\n". "ENG\n". "\n". - "".$this->bank->org."\n". - "".$this->bank->fid."\n". + ''.$this->bank->org."\n". + ''.$this->bank->fid."\n". "\n". "QWIN\n". "2500\n". @@ -119,7 +120,7 @@ class Login "\n". "\n". "\n". - "".md5(time().$this->bank->url.$this->id)."\n". + ''.md5(time().$this->bank->url.$this->id)."\n". "\n". "19900101\n". "\n". @@ -173,12 +174,12 @@ class Account "\n". "\n". "20110412162900.000[-7:MST]\n". - "".$this->login->id."\n". - "".$this->login->pass."\n". + ''.$this->login->id."\n". + ''.$this->login->pass."\n". "ENG\n". "\n". - "".$this->login->bank->org."\n". - "".$this->login->bank->fid."\n". + ''.$this->login->bank->org."\n". + ''.$this->login->bank->fid."\n". "\n". "QWIN\n". "2500\n". @@ -188,16 +189,16 @@ class Account $ofxRequest .= " \n". " \n". - " ".md5(time().$this->login->bank->url.$this->id)."\n". + ' '.md5(time().$this->login->bank->url.$this->id)."\n". " \n". " \n". - " ".$this->bankId."\n". - " ".$this->id."\n". - " ".$this->subType."\n". + ' '.$this->bankId."\n". + ' '.$this->id."\n". + ' '.$this->subType."\n". " \n". " \n". " 20110301\n". - " ".($includeTransactions ? 'Y' : 'N')."\n". + ' '.($includeTransactions ? 'Y' : 'N')."\n". " \n". " \n". " \n". @@ -206,21 +207,21 @@ class Account $ofxRequest .= " \n". " \n". - " ".md5(time().$this->login->bank->url.$this->id)."\n". + ' '.md5(time().$this->login->bank->url.$this->id)."\n". " \n". " \n". - " ".$this->id."\n". + ' '.$this->id."\n". " \n". " \n". " 20110320\n". - " ".($includeTransactions ? 'Y' : 'N')."\n". + ' '.($includeTransactions ? 'Y' : 'N')."\n". " \n". " \n". " \n". " \n"; } $ofxRequest .= - ""; + ''; $o = new OFX($this->login->bank, $ofxRequest); $o->go(); $this->response = $o->response; @@ -233,4 +234,3 @@ class Account } } } - diff --git a/app/Libraries/Utils.php b/app/Libraries/Utils.php index c02c719169..3447e81f53 100644 --- a/app/Libraries/Utils.php +++ b/app/Libraries/Utils.php @@ -2,7 +2,6 @@ use Auth; use Cache; -use DB; use App; use Schema; use Session; @@ -15,11 +14,15 @@ use Log; use DateTime; use stdClass; use Carbon; - -use App\Models\Currency; +use WePay; class Utils { + private static $weekdayNames = [ + "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", + ]; + + public static function isRegistered() { return Auth::check() && Auth::user()->registered; @@ -152,11 +155,11 @@ class Utils { return App::getLocale() == 'en'; } - + public static function getLocaleRegion() { - $parts = explode('_', App::getLocale()); - + $parts = explode('_', App::getLocale()); + return count($parts) ? $parts[0] : 'en'; } @@ -183,7 +186,7 @@ class Utils $response = new stdClass(); $response->message = isset($_ENV["{$userType}_MESSAGE"]) ? $_ENV["{$userType}_MESSAGE"] : ''; $response->id = isset($_ENV["{$userType}_ID"]) ? $_ENV["{$userType}_ID"] : ''; - $response->version = NINJA_VERSION; + $response->version = env('NINJA_SELF_HOST_VERSION', NINJA_VERSION); return $response; } @@ -212,6 +215,46 @@ class Utils } } + public static function getPlanPrice($plan) + { + $term = $plan['term']; + $numUsers = $plan['num_users']; + $plan = $plan['plan']; + + if ($plan == PLAN_FREE) { + $price = 0; + } elseif ($plan == PLAN_PRO) { + $price = PLAN_PRICE_PRO_MONTHLY; + } elseif ($plan == PLAN_ENTERPRISE) { + if ($numUsers <= 2) { + $price = PLAN_PRICE_ENTERPRISE_MONTHLY_2; + } elseif ($numUsers <= 5) { + $price = PLAN_PRICE_ENTERPRISE_MONTHLY_5; + } elseif ($numUsers <= 10) { + $price = PLAN_PRICE_ENTERPRISE_MONTHLY_10; + } else { + static::fatalError('Invalid number of users: ' . $numUsers); + } + } + + if ($term == PLAN_TERM_YEARLY) { + $price = $price * 10; + } + + return $price; + } + + public static function getMinNumUsers($max) + { + if ($max <= 2) { + return 1; + } elseif ($max <= 5) { + return 3; + } else { + return 6; + } + } + public static function basePath() { return substr($_SERVER['SCRIPT_NAME'], 0, strrpos($_SERVER['SCRIPT_NAME'], '/') + 1); @@ -222,7 +265,7 @@ class Utils $data = []; foreach ($input as $field) { - if ($field == "checkbox") { + if ($field == 'checkbox') { $data[] = $field; } elseif ($field) { $data[] = trans("texts.$field"); @@ -237,7 +280,7 @@ class Utils public static function fatalError($message = false, $exception = false) { if (!$message) { - $message = "An error occurred, please try again later."; + $message = 'An error occurred, please try again later.'; } static::logError($message.' '.$exception); @@ -284,7 +327,7 @@ class Utils if ($info) { Log::info($error."\n", $data); } else { - Log::error($error."\n", $data); + Log::error($error."\n", $data); } /* @@ -311,12 +354,12 @@ class Utils public static function getFromCache($id, $type) { $cache = Cache::get($type); - + if ( ! $cache) { static::logError("Cache for {$type} is not set"); return null; } - + $data = $cache->filter(function($item) use ($id) { return $item->id == $id; }); @@ -343,7 +386,7 @@ class Utils $decimal = $currency->decimal_separator; $precision = $currency->precision; $code = $currency->code; - $swapSymbol = false; + $swapSymbol = $currency->swap_currency_symbol; if ($countryId && $currencyId == CURRENCY_EURO) { $country = self::getFromCache($countryId, 'countries'); @@ -376,6 +419,15 @@ class Utils return $string; } + public static function pluralizeEntityType($type) + { + if ($type === ENTITY_EXPENSE_CATEGORY) { + return 'expense_categories'; + } else { + return $type . 's'; + } + } + public static function maskAccountNumber($value) { $length = strlen($value); @@ -426,7 +478,12 @@ class Utils public static function toCamelCase($string) { - return lcfirst(str_replace(' ', '', ucwords(str_replace('_', ' ', $string)))); + return lcfirst(static::toClassCase($string)); + } + + public static function toClassCase($string) + { + return str_replace(' ', '', ucwords(str_replace('_', ' ', $string))); } public static function timestampToDateTimeString($timestamp) @@ -528,7 +585,7 @@ class Utils { // http://stackoverflow.com/a/3172665 $f = ':'; - return sprintf("%02d%s%02d%s%02d", floor($t/3600), $f, ($t/60)%60, $f, $t%60); + return sprintf('%02d%s%02d%s%02d', floor($t/3600), $f, ($t/60)%60, $f, $t%60); } public static function today($formatResult = true) @@ -640,8 +697,8 @@ class Utils private static function getMonth($offset) { - $months = [ "january", "february", "march", "april", "may", "june", - "july", "august", "september", "october", "november", "december", ]; + $months = ['january', 'february', 'march', 'april', 'may', 'june', + 'july', 'august', 'september', 'october', 'november', 'december', ]; $month = intval(date('n')) - 1; @@ -794,12 +851,12 @@ class Utils public static function startsWith($haystack, $needle) { - return $needle === "" || strpos($haystack, $needle) === 0; + return $needle === '' || strpos($haystack, $needle) === 0; } public static function endsWith($haystack, $needle) { - return $needle === "" || substr($haystack, -strlen($needle)) === $needle; + return $needle === '' || substr($haystack, -strlen($needle)) === $needle; } public static function getEntityRowClass($model) @@ -846,6 +903,7 @@ class Utils } // nouns in German and French should be uppercase + // TODO remove this public static function transFlowText($key) { $str = trans("texts.$key"); @@ -903,7 +961,7 @@ class Utils $name = trim($name); $lastName = (strpos($name, ' ') === false) ? '' : preg_replace('#.*\s([\w-]*)$#', '$1', $name); $firstName = trim(preg_replace('#'.$lastName.'#', '', $name)); - return array($firstName, $lastName); + return [$firstName, $lastName]; } public static function decodePDF($string) @@ -946,7 +1004,7 @@ class Utils $link = $prefix.$link; } - return link_to($link, $title, array('target' => '_blank')); + return link_to($link, $title, ['target' => '_blank']); } public static function wrapAdjustment($adjustment, $currencyId, $countryId) @@ -984,10 +1042,51 @@ class Utils public static function addHttp($url) { - if (!preg_match("~^(?:f|ht)tps?://~i", $url)) { - $url = "http://" . $url; + if (!preg_match('~^(?:f|ht)tps?://~i', $url)) { + $url = 'http://' . $url; } return $url; } + + public static function setupWePay($accountGateway = null) + { + if (WePay::getEnvironment() == 'none') { + if (WEPAY_ENVIRONMENT == WEPAY_STAGE) { + WePay::useStaging(WEPAY_CLIENT_ID, WEPAY_CLIENT_SECRET); + } else { + WePay::useProduction(WEPAY_CLIENT_ID, WEPAY_CLIENT_SECRET); + } + } + + if ($accountGateway) { + return new WePay($accountGateway->getConfig()->accessToken); + } else { + return new WePay(null); + } + } + + /** + * Gets an array of weekday names (in English) + * + * @see getTranslatedWeekdayNames() + * + * @return \Illuminate\Support\Collection + */ + public static function getWeekdayNames() + { + return collect(static::$weekdayNames); + } + + /** + * Gets an array of translated weekday names + * + * @return \Illuminate\Support\Collection + */ + public static function getTranslatedWeekdayNames() + { + return collect(static::$weekdayNames)->transform(function ($day) { + return trans('texts.'.strtolower($day)); + }); + } } diff --git a/app/Libraries/lib_autolink.php b/app/Libraries/lib_autolink.php index 3bc86b843e..fa98d75015 100644 --- a/app/Libraries/lib_autolink.php +++ b/app/Libraries/lib_autolink.php @@ -15,13 +15,13 @@ # functions to change the output. # - $GLOBALS['autolink_options'] = array( + $GLOBALS['autolink_options'] = [ # Should http:// be visibly stripped from the front # of URLs? 'strip_protocols' => false, - ); + ]; #################################################################### @@ -69,7 +69,7 @@ # substring found - first check to see if we're inside a link tag already... # - $bits = preg_split("!!i", $pre); + $bits = preg_split('!!i', $pre); $last_bit = array_pop($bits); if (preg_match("!!i", $pre); + $bits = preg_split('!!i', $pre); $last_bit = array_pop($bits); if (preg_match("!activityRepo = $activityRepo; } - // Clients + /** + * @param ClientWasCreated $event + */ public function createdClient(ClientWasCreated $event) { $this->activityRepo->create( @@ -48,6 +65,9 @@ class ActivityListener ); } + /** + * @param ClientWasDeleted $event + */ public function deletedClient(ClientWasDeleted $event) { $this->activityRepo->create( @@ -56,6 +76,9 @@ class ActivityListener ); } + /** + * @param ClientWasArchived $event + */ public function archivedClient(ClientWasArchived $event) { if ($event->client->is_deleted) { @@ -68,6 +91,9 @@ class ActivityListener ); } + /** + * @param ClientWasRestored $event + */ public function restoredClient(ClientWasRestored $event) { $this->activityRepo->create( @@ -76,7 +102,9 @@ class ActivityListener ); } - // Invoices + /** + * @param InvoiceWasCreated $event + */ public function createdInvoice(InvoiceWasCreated $event) { $this->activityRepo->create( @@ -86,6 +114,9 @@ class ActivityListener ); } + /** + * @param InvoiceWasUpdated $event + */ public function updatedInvoice(InvoiceWasUpdated $event) { if (! $event->invoice->isChanged()) { @@ -104,6 +135,9 @@ class ActivityListener $activity->save(); } + /** + * @param InvoiceWasDeleted $event + */ public function deletedInvoice(InvoiceWasDeleted $event) { $invoice = $event->invoice; @@ -116,6 +150,9 @@ class ActivityListener ); } + /** + * @param InvoiceWasArchived $event + */ public function archivedInvoice(InvoiceWasArchived $event) { if ($event->invoice->is_deleted) { @@ -128,6 +165,9 @@ class ActivityListener ); } + /** + * @param InvoiceWasRestored $event + */ public function restoredInvoice(InvoiceWasRestored $event) { $invoice = $event->invoice; @@ -140,6 +180,9 @@ class ActivityListener ); } + /** + * @param InvoiceInvitationWasEmailed $event + */ public function emailedInvoice(InvoiceInvitationWasEmailed $event) { $this->activityRepo->create( @@ -151,6 +194,9 @@ class ActivityListener ); } + /** + * @param InvoiceInvitationWasViewed $event + */ public function viewedInvoice(InvoiceInvitationWasViewed $event) { $this->activityRepo->create( @@ -162,7 +208,9 @@ class ActivityListener ); } - // Quotes + /** + * @param QuoteWasCreated $event + */ public function createdQuote(QuoteWasCreated $event) { $this->activityRepo->create( @@ -171,6 +219,9 @@ class ActivityListener ); } + /** + * @param QuoteWasUpdated $event + */ public function updatedQuote(QuoteWasUpdated $event) { if (! $event->quote->isChanged()) { @@ -188,6 +239,9 @@ class ActivityListener $activity->save(); } + /** + * @param QuoteWasDeleted $event + */ public function deletedQuote(QuoteWasDeleted $event) { $this->activityRepo->create( @@ -196,6 +250,9 @@ class ActivityListener ); } + /** + * @param QuoteWasArchived $event + */ public function archivedQuote(QuoteWasArchived $event) { if ($event->quote->is_deleted) { @@ -208,6 +265,9 @@ class ActivityListener ); } + /** + * @param QuoteWasRestored $event + */ public function restoredQuote(QuoteWasRestored $event) { $this->activityRepo->create( @@ -216,6 +276,9 @@ class ActivityListener ); } + /** + * @param QuoteInvitationWasEmailed $event + */ public function emailedQuote(QuoteInvitationWasEmailed $event) { $this->activityRepo->create( @@ -227,6 +290,9 @@ class ActivityListener ); } + /** + * @param QuoteInvitationWasViewed $event + */ public function viewedQuote(QuoteInvitationWasViewed $event) { $this->activityRepo->create( @@ -238,6 +304,9 @@ class ActivityListener ); } + /** + * @param QuoteInvitationWasApproved $event + */ public function approvedQuote(QuoteInvitationWasApproved $event) { $this->activityRepo->create( @@ -249,7 +318,9 @@ class ActivityListener ); } - // Credits + /** + * @param CreditWasCreated $event + */ public function createdCredit(CreditWasCreated $event) { $this->activityRepo->create( @@ -258,6 +329,9 @@ class ActivityListener ); } + /** + * @param CreditWasDeleted $event + */ public function deletedCredit(CreditWasDeleted $event) { $this->activityRepo->create( @@ -266,6 +340,9 @@ class ActivityListener ); } + /** + * @param CreditWasArchived $event + */ public function archivedCredit(CreditWasArchived $event) { if ($event->credit->is_deleted) { @@ -278,6 +355,9 @@ class ActivityListener ); } + /** + * @param CreditWasRestored $event + */ public function restoredCredit(CreditWasRestored $event) { $this->activityRepo->create( @@ -286,7 +366,9 @@ class ActivityListener ); } - // Payments + /** + * @param PaymentWasCreated $event + */ public function createdPayment(PaymentWasCreated $event) { $this->activityRepo->create( @@ -297,6 +379,9 @@ class ActivityListener ); } + /** + * @param PaymentWasDeleted $event + */ public function deletedPayment(PaymentWasDeleted $event) { $payment = $event->payment; @@ -304,11 +389,59 @@ class ActivityListener $this->activityRepo->create( $payment, ACTIVITY_TYPE_DELETE_PAYMENT, + $payment->getCompletedAmount(), + $payment->getCompletedAmount() * -1 + ); + } + + /** + * @param PaymentWasRefunded $event + */ + public function refundedPayment(PaymentWasRefunded $event) + { + $payment = $event->payment; + + $this->activityRepo->create( + $payment, + ACTIVITY_TYPE_REFUNDED_PAYMENT, + $event->refundAmount, + $event->refundAmount * -1 + ); + } + + /** + * @param PaymentWasVoided $event + */ + public function voidedPayment(PaymentWasVoided $event) + { + $payment = $event->payment; + + $this->activityRepo->create( + $payment, + ACTIVITY_TYPE_VOIDED_PAYMENT, $payment->amount, $payment->amount * -1 ); } + /** + * @param PaymentFailed $event + */ + public function failedPayment(PaymentFailed $event) + { + $payment = $event->payment; + + $this->activityRepo->create( + $payment, + ACTIVITY_TYPE_FAILED_PAYMENT, + $payment->getCompletedAmount(), + $payment->getCompletedAmount() * -1 + ); + } + + /** + * @param PaymentWasArchived $event + */ public function archivedPayment(PaymentWasArchived $event) { if ($event->payment->is_deleted) { @@ -321,6 +454,9 @@ class ActivityListener ); } + /** + * @param PaymentWasRestored $event + */ public function restoredPayment(PaymentWasRestored $event) { $payment = $event->payment; @@ -328,8 +464,34 @@ class ActivityListener $this->activityRepo->create( $payment, ACTIVITY_TYPE_RESTORE_PAYMENT, - $event->fromDeleted ? $payment->amount * -1 : 0, - $event->fromDeleted ? $payment->amount : 0 + $event->fromDeleted ? $payment->getCompletedAmount() * -1 : 0, + $event->fromDeleted ? $payment->getCompletedAmount() : 0 + ); + } + + /** + * Creates an activity when a task was created + * + * @param TaskWasCreated $event + */ + public function createdTask(TaskWasCreated $event) + { + $this->activityRepo->create( + $event->task, + ACTIVITY_TYPE_CREATE_TASK + ); + } + + /** + * Creates an activity when a task was updated + * + * @param TaskWasUpdated $event + */ + public function updatedTask(TaskWasUpdated $event) + { + $this->activityRepo->create( + $event->task, + ACTIVITY_TYPE_UPDATE_TASK ); } } diff --git a/app/Listeners/AnalyticsListener.php b/app/Listeners/AnalyticsListener.php index dd574368c4..7015b087cc 100644 --- a/app/Listeners/AnalyticsListener.php +++ b/app/Listeners/AnalyticsListener.php @@ -1,11 +1,16 @@ sendAnalytics($url); - //Log::info($url); $url = $base . "&t=item&in=plan&ip={$amount}&iq=1"; $this->sendAnalytics($url); - //Log::info($url); } + /** + * @param $data + */ private function sendAnalytics($data) { $data = json_encode($data); @@ -48,7 +54,6 @@ class AnalyticsListener ]; curl_setopt_array($curl, $opts); - $response = curl_exec($curl); curl_close($curl); } } diff --git a/app/Listeners/CreditListener.php b/app/Listeners/CreditListener.php index 3a76288a1b..c8d16a4776 100644 --- a/app/Listeners/CreditListener.php +++ b/app/Listeners/CreditListener.php @@ -3,21 +3,35 @@ use Carbon; use App\Models\Credit; use App\Events\PaymentWasDeleted; +use App\Events\PaymentWasRefunded; use App\Ninja\Repositories\CreditRepository; +/** + * Class CreditListener + */ class CreditListener { + /** + * @var CreditRepository + */ protected $creditRepo; + /** + * CreditListener constructor. + * @param CreditRepository $creditRepo + */ public function __construct(CreditRepository $creditRepo) { $this->creditRepo = $creditRepo; } + /** + * @param PaymentWasDeleted $event + */ public function deletedPayment(PaymentWasDeleted $event) { $payment = $event->payment; - + // if the payment was from a credit we need to refund the credit if ($payment->payment_type_id != PAYMENT_TYPE_CREDIT) { return; @@ -26,7 +40,27 @@ class CreditListener $credit = Credit::createNew(); $credit->client_id = $payment->client_id; $credit->credit_date = Carbon::now()->toDateTimeString(); - $credit->balance = $credit->amount = $payment->amount; + $credit->balance = $credit->amount = $payment->getCompletedAmount(); + $credit->private_notes = $payment->transaction_reference; + $credit->save(); + } + + /** + * @param PaymentWasRefunded $event + */ + public function refundedPayment(PaymentWasRefunded $event) + { + $payment = $event->payment; + + // if the payment was from a credit we need to refund the credit + if ($payment->payment_type_id != PAYMENT_TYPE_CREDIT) { + return; + } + + $credit = Credit::createNew(); + $credit->client_id = $payment->client_id; + $credit->credit_date = Carbon::now()->toDateTimeString(); + $credit->balance = $credit->amount = $event->refundAmount; $credit->private_notes = $payment->transaction_reference; $credit->save(); } diff --git a/app/Listeners/ExpenseListener.php b/app/Listeners/ExpenseListener.php index 6ef1d1175c..6f5c3752ef 100644 --- a/app/Listeners/ExpenseListener.php +++ b/app/Listeners/ExpenseListener.php @@ -1,21 +1,32 @@ expenseRepo = $expenseRepo; } + /** + * @param InvoiceWasDeleted $event + */ public function deletedInvoice(InvoiceWasDeleted $event) { // Release any tasks associated with the deleted invoice diff --git a/app/Listeners/HandleUserLoggedIn.php b/app/Listeners/HandleUserLoggedIn.php index bf39d7e34e..75801ce33f 100644 --- a/app/Listeners/HandleUserLoggedIn.php +++ b/app/Listeners/HandleUserLoggedIn.php @@ -1,24 +1,27 @@ accountRepo = $accountRepo; @@ -28,6 +31,7 @@ class HandleUserLoggedIn { * Handle the event. * * @param UserLoggedIn $event + * * @return void */ public function handle(UserLoggedIn $event) @@ -54,5 +58,4 @@ class HandleUserLoggedIn { Session::flash('warning', trans('texts.logo_too_large', ['size' => $account->getLogoSize() . 'KB'])); } } - } diff --git a/app/Listeners/HandleUserSettingsChanged.php b/app/Listeners/HandleUserSettingsChanged.php index 4259833499..8afd72f9a3 100644 --- a/app/Listeners/HandleUserSettingsChanged.php +++ b/app/Listeners/HandleUserSettingsChanged.php @@ -4,16 +4,18 @@ use Auth; use Session; use App\Events\UserSettingsChanged; use App\Ninja\Repositories\AccountRepository; -use Illuminate\Queue\InteractsWithQueue; -use Illuminate\Contracts\Queue\ShouldBeQueued; use App\Ninja\Mailers\UserMailer; +/** + * Class HandleUserSettingsChanged + */ class HandleUserSettingsChanged { /** * Create the event handler. - * - * @return void + * + * @param AccountRepository $accountRepo + * @param UserMailer $userMailer */ public function __construct(AccountRepository $accountRepo, UserMailer $userMailer) { @@ -25,6 +27,7 @@ class HandleUserSettingsChanged { * Handle the event. * * @param UserSettingsChanged $event + * * @return void */ public function handle(UserSettingsChanged $event) @@ -44,5 +47,4 @@ class HandleUserSettingsChanged { Session::flash('warning', trans('texts.verify_email')); } } - } diff --git a/app/Listeners/HandleUserSignedUp.php b/app/Listeners/HandleUserSignedUp.php index 6433a1b5b4..11fd3b90fb 100644 --- a/app/Listeners/HandleUserSignedUp.php +++ b/app/Listeners/HandleUserSignedUp.php @@ -3,19 +3,29 @@ use Utils; use Auth; use App\Events\UserSignedUp; -use App\Models\Activity; use App\Ninja\Repositories\AccountRepository; use App\Ninja\Mailers\UserMailer; +/** + * Class HandleUserSignedUp + */ class HandleUserSignedUp { + /** + * @var AccountRepository + */ protected $accountRepo; + + /** + * @var UserMailer + */ protected $userMailer; /** * Create the event handler. - * - * @return void + * + * @param AccountRepository $accountRepo + * @param UserMailer $userMailer */ public function __construct(AccountRepository $accountRepo, UserMailer $userMailer) { @@ -27,6 +37,7 @@ class HandleUserSignedUp * Handle the event. * * @param UserSignedUp $event + * * @return void */ public function handle(UserSignedUp $event) diff --git a/app/Listeners/InvoiceListener.php b/app/Listeners/InvoiceListener.php index 6395a44d4f..566d9b4994 100644 --- a/app/Listeners/InvoiceListener.php +++ b/app/Listeners/InvoiceListener.php @@ -2,16 +2,24 @@ use Utils; use Auth; -use App\Events\InvoiceWasEmailed; use App\Events\InvoiceWasUpdated; use App\Events\InvoiceWasCreated; use App\Events\PaymentWasCreated; use App\Events\PaymentWasDeleted; +use App\Events\PaymentWasRefunded; use App\Events\PaymentWasRestored; +use App\Events\PaymentWasVoided; +use App\Events\PaymentFailed; use App\Events\InvoiceInvitationWasViewed; +/** + * Class InvoiceListener + */ class InvoiceListener { + /** + * @param InvoiceWasCreated $event + */ public function createdInvoice(InvoiceWasCreated $event) { if (Utils::hasFeature(FEATURE_DIFFERENT_DESIGNS)) { @@ -31,18 +39,27 @@ class InvoiceListener } } + /** + * @param InvoiceWasUpdated $event + */ public function updatedInvoice(InvoiceWasUpdated $event) { $invoice = $event->invoice; $invoice->updatePaidStatus(false); } + /** + * @param InvoiceInvitationWasViewed $event + */ public function viewedInvoice(InvoiceInvitationWasViewed $event) { $invitation = $event->invitation; $invitation->markViewed(); } + /** + * @param PaymentWasCreated $event + */ public function createdPayment(PaymentWasCreated $event) { $payment = $event->payment; @@ -54,7 +71,36 @@ class InvoiceListener $invoice->updatePaidStatus(); } + /** + * @param PaymentWasDeleted $event + */ public function deletedPayment(PaymentWasDeleted $event) + { + $payment = $event->payment; + $invoice = $payment->invoice; + $adjustment = $payment->getCompletedAmount(); + + $invoice->updateBalances($adjustment); + $invoice->updatePaidStatus(); + } + + /** + * @param PaymentWasRefunded $event + */ + public function refundedPayment(PaymentWasRefunded $event) + { + $payment = $event->payment; + $invoice = $payment->invoice; + $adjustment = $event->refundAmount; + + $invoice->updateBalances($adjustment); + $invoice->updatePaidStatus(); + } + + /** + * @param PaymentWasVoided $event + */ + public function voidedPayment(PaymentWasVoided $event) { $payment = $event->payment; $invoice = $payment->invoice; @@ -64,6 +110,22 @@ class InvoiceListener $invoice->updatePaidStatus(); } + /** + * @param PaymentFailed $event + */ + public function failedPayment(PaymentFailed $event) + { + $payment = $event->payment; + $invoice = $payment->invoice; + $adjustment = $payment->getCompletedAmount(); + + $invoice->updateBalances($adjustment); + $invoice->updatePaidStatus(); + } + + /** + * @param PaymentWasRestored $event + */ public function restoredPayment(PaymentWasRestored $event) { if ( ! $event->fromDeleted) { @@ -72,7 +134,7 @@ class InvoiceListener $payment = $event->payment; $invoice = $payment->invoice; - $adjustment = $payment->amount * -1; + $adjustment = $payment->getCompletedAmount() * -1; $invoice->updateBalances($adjustment); $invoice->updatePaidStatus(); diff --git a/app/Listeners/NotificationListener.php b/app/Listeners/NotificationListener.php index 87a6859449..d18b0a3267 100644 --- a/app/Listeners/NotificationListener.php +++ b/app/Listeners/NotificationListener.php @@ -2,29 +2,50 @@ use App\Ninja\Mailers\UserMailer; use App\Ninja\Mailers\ContactMailer; - use App\Events\InvoiceWasEmailed; use App\Events\QuoteWasEmailed; use App\Events\InvoiceInvitationWasViewed; use App\Events\QuoteInvitationWasViewed; use App\Events\QuoteInvitationWasApproved; use App\Events\PaymentWasCreated; -use App\Ninja\Notifications; use App\Services\PushService; +/** + * Class NotificationListener + */ class NotificationListener { + /** + * @var UserMailer + */ protected $userMailer; + /** + * @var ContactMailer + */ protected $contactMailer; + /** + * @var PushService + */ protected $pushService; + /** + * NotificationListener constructor. + * @param UserMailer $userMailer + * @param ContactMailer $contactMailer + * @param PushService $pushService + */ public function __construct(UserMailer $userMailer, ContactMailer $contactMailer, PushService $pushService) { $this->userMailer = $userMailer; $this->contactMailer = $contactMailer; $this->pushService = $pushService; - } + } + /** + * @param $invoice + * @param $type + * @param null $payment + */ private function sendEmails($invoice, $type, $payment = null) { foreach ($invoice->account->users as $user) @@ -36,36 +57,54 @@ class NotificationListener } } + /** + * @param InvoiceWasEmailed $event + */ public function emailedInvoice(InvoiceWasEmailed $event) { $this->sendEmails($event->invoice, 'sent'); $this->pushService->sendNotification($event->invoice, 'sent'); } + /** + * @param QuoteWasEmailed $event + */ public function emailedQuote(QuoteWasEmailed $event) { $this->sendEmails($event->quote, 'sent'); $this->pushService->sendNotification($event->quote, 'sent'); } + /** + * @param InvoiceInvitationWasViewed $event + */ public function viewedInvoice(InvoiceInvitationWasViewed $event) { $this->sendEmails($event->invoice, 'viewed'); $this->pushService->sendNotification($event->invoice, 'viewed'); } + /** + * @param QuoteInvitationWasViewed $event + */ public function viewedQuote(QuoteInvitationWasViewed $event) { $this->sendEmails($event->quote, 'viewed'); $this->pushService->sendNotification($event->quote, 'viewed'); } + /** + * @param QuoteInvitationWasApproved $event + */ public function approvedQuote(QuoteInvitationWasApproved $event) { $this->sendEmails($event->quote, 'approved'); $this->pushService->sendNotification($event->quote, 'approved'); } + /** + * @param PaymentWasCreated $event + */ public function createdPayment(PaymentWasCreated $event) { // only send emails for online payments diff --git a/app/Listeners/QuoteListener.php b/app/Listeners/QuoteListener.php index de857a4bae..d1b85bdf4e 100644 --- a/app/Listeners/QuoteListener.php +++ b/app/Listeners/QuoteListener.php @@ -1,12 +1,15 @@ invitation; diff --git a/app/Listeners/SubscriptionListener.php b/app/Listeners/SubscriptionListener.php index 493a53f111..5b84413cb2 100644 --- a/app/Listeners/SubscriptionListener.php +++ b/app/Listeners/SubscriptionListener.php @@ -1,68 +1,98 @@ client->account); $this->checkSubscriptions(EVENT_CREATE_CLIENT, $event->client, $transformer); } + /** + * @param QuoteWasCreated $event + */ public function createdQuote(QuoteWasCreated $event) { $transformer = new InvoiceTransformer($event->quote->account); $this->checkSubscriptions(EVENT_CREATE_QUOTE, $event->quote, $transformer, ENTITY_CLIENT); } + /** + * @param PaymentWasCreated $event + */ public function createdPayment(PaymentWasCreated $event) { $transformer = new PaymentTransformer($event->payment->account); $this->checkSubscriptions(EVENT_CREATE_PAYMENT, $event->payment, $transformer, [ENTITY_CLIENT, ENTITY_INVOICE]); } + /** + * @param InvoiceWasCreated $event + */ public function createdInvoice(InvoiceWasCreated $event) { $transformer = new InvoiceTransformer($event->invoice->account); $this->checkSubscriptions(EVENT_CREATE_INVOICE, $event->invoice, $transformer, ENTITY_CLIENT); } + /** + * @param CreditWasCreated $event + */ public function createdCredit(CreditWasCreated $event) { - + } + /** + * @param VendorWasCreated $event + */ public function createdVendor(VendorWasCreated $event) { } + /** + * @param ExpenseWasCreated $event + */ public function createdExpense(ExpenseWasCreated $event) { } + /** + * @param $eventId + * @param $entity + * @param $transformer + * @param string $include + */ private function checkSubscriptions($eventId, $entity, $transformer, $include = '') { + if ( ! EntityModel::$notifySubscriptions) { + return; + } + $subscription = $entity->account->getSubscription($eventId); if ($subscription) { diff --git a/app/Listeners/TaskListener.php b/app/Listeners/TaskListener.php index b2038bb3f2..a49a243b9f 100644 --- a/app/Listeners/TaskListener.php +++ b/app/Listeners/TaskListener.php @@ -3,8 +3,14 @@ use App\Models\Task; use App\Events\InvoiceWasDeleted; +/** + * Class TaskListener + */ class TaskListener { + /** + * @param InvoiceWasDeleted $event + */ public function deletedInvoice(InvoiceWasDeleted $event) { // Release any tasks associated with the deleted invoice diff --git a/app/Models/Account.php b/app/Models/Account.php index b86dcfeacd..56c6829f24 100644 --- a/app/Models/Account.php +++ b/app/Models/Account.php @@ -7,33 +7,37 @@ use DateTime; use Event; use Cache; use App; -use File; -use App\Models\Document; use App\Events\UserSettingsChanged; use Illuminate\Support\Facades\Storage; use Illuminate\Database\Eloquent\SoftDeletes; use Laracasts\Presenter\PresentableTrait; +/** + * Class Account + */ class Account extends Eloquent { use PresentableTrait; use SoftDeletes; - public static $plan_prices = array( - PLAN_PRO => array( - PLAN_TERM_MONTHLY => PLAN_PRICE_PRO_MONTHLY, - PLAN_TERM_YEARLY => PLAN_PRICE_PRO_YEARLY, - ), - PLAN_ENTERPRISE => array( - PLAN_TERM_MONTHLY => PLAN_PRICE_ENTERPRISE_MONTHLY, - PLAN_TERM_YEARLY => PLAN_PRICE_ENTERPRISE_YEARLY, - ), - ); - + /** + * @var string + */ protected $presenter = 'App\Ninja\Presenters\AccountPresenter'; + + /** + * @var array + */ protected $dates = ['deleted_at']; + + /** + * @var array + */ protected $hidden = ['ip']; + /** + * @var array + */ protected $fillable = [ 'name', 'id_number', @@ -56,14 +60,22 @@ class Account extends Eloquent 'currency_id', 'language_id', 'military_time', + 'invoice_taxes', + 'invoice_item_taxes', + 'show_item_taxes', + 'default_tax_rate_id', + 'enable_second_tax_rate', + 'start_of_week', ]; + /** + * @var array + */ public static $basicSettings = [ ACCOUNT_COMPANY_DETAILS, ACCOUNT_USER_DETAILS, ACCOUNT_LOCALIZATION, ACCOUNT_PAYMENTS, - ACCOUNT_BANKS, ACCOUNT_TAX_RATES, ACCOUNT_PRODUCTS, ACCOUNT_NOTIFICATIONS, @@ -71,11 +83,15 @@ class Account extends Eloquent ACCOUNT_MANAGEMENT, ]; + /** + * @var array + */ public static $advancedSettings = [ ACCOUNT_INVOICE_SETTINGS, ACCOUNT_INVOICE_DESIGN, ACCOUNT_EMAIL_SETTINGS, ACCOUNT_TEMPLATES_AND_REMINDERS, + ACCOUNT_BANKS, ACCOUNT_CLIENT_PORTAL, ACCOUNT_CHARTS_AND_REPORTS, ACCOUNT_DATA_VISUALIZATIONS, @@ -83,133 +99,210 @@ class Account extends Eloquent ACCOUNT_API_TOKENS, ]; - /* - protected $casts = [ - 'invoice_settings' => 'object', - ]; - */ + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ public function account_tokens() { return $this->hasMany('App\Models\AccountToken'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ public function users() { return $this->hasMany('App\Models\User'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ public function clients() { return $this->hasMany('App\Models\Client'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ public function contacts() { return $this->hasMany('App\Models\Contact'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ public function invoices() { return $this->hasMany('App\Models\Invoice'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ public function account_gateways() { return $this->hasMany('App\Models\AccountGateway'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ public function bank_accounts() { return $this->hasMany('App\Models\BankAccount'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ public function tax_rates() { return $this->hasMany('App\Models\TaxRate'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ public function products() { return $this->hasMany('App\Models\Product'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function country() { return $this->belongsTo('App\Models\Country'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function timezone() { return $this->belongsTo('App\Models\Timezone'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function language() { return $this->belongsTo('App\Models\Language'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function date_format() { return $this->belongsTo('App\Models\DateFormat'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function datetime_format() { return $this->belongsTo('App\Models\DatetimeFormat'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function size() { return $this->belongsTo('App\Models\Size'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function currency() { return $this->belongsTo('App\Models\Currency'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function industry() { return $this->belongsTo('App\Models\Industry'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function default_tax_rate() { return $this->belongsTo('App\Models\TaxRate'); } + /** + * @return mixed + */ public function expenses() { return $this->hasMany('App\Models\Expense','account_id','id')->withTrashed(); } + /** + * @return mixed + */ public function payments() { return $this->hasMany('App\Models\Payment','account_id','id')->withTrashed(); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function company() { return $this->belongsTo('App\Models\Company'); } + /** + * @return mixed + */ + public function expense_categories() + { + return $this->hasMany('App\Models\ExpenseCategory','account_id','id')->withTrashed(); + } + + /** + * @param $value + */ public function setIndustryIdAttribute($value) { $this->attributes['industry_id'] = $value ?: null; } + /** + * @param $value + */ public function setCountryIdAttribute($value) { $this->attributes['country_id'] = $value ?: null; } + /** + * @param $value + */ public function setSizeIdAttribute($value) { $this->attributes['size_id'] = $value ?: null; } - - + /** + * @param int $gatewayId + * @return bool + */ public function isGatewayConfigured($gatewayId = 0) { if ( ! $this->relationLoaded('account_gateways')) { @@ -223,11 +316,17 @@ class Account extends Eloquent } } + /** + * @return bool + */ public function isEnglish() { return !$this->language_id || $this->language_id == DEFAULT_LANGUAGE; } + /** + * @return bool + */ public function hasInvoicePrefix() { if ( ! $this->invoice_number_prefix && ! $this->quote_number_prefix) { @@ -237,6 +336,9 @@ class Account extends Eloquent return $this->invoice_number_prefix != $this->quote_number_prefix; } + /** + * @return mixed + */ public function getDisplayName() { if ($this->name) { @@ -249,12 +351,18 @@ class Account extends Eloquent return $user->getDisplayName(); } + /** + * @return string + */ public function getCityState() { $swap = $this->country && $this->country->swap_postal_code; return Utils::cityStateZip($this->city, $this->state, $this->postal_code, $swap); } + /** + * @return mixed + */ public function getMomentDateTimeFormat() { $format = $this->datetime_format ? $this->datetime_format->format_moment : DEFAULT_DATETIME_MOMENT_FORMAT; @@ -266,6 +374,9 @@ class Account extends Eloquent return $format; } + /** + * @return string + */ public function getMomentDateFormat() { $format = $this->getMomentDateTimeFormat(); @@ -275,6 +386,9 @@ class Account extends Eloquent return trim($format); } + /** + * @return string + */ public function getTimezone() { if ($this->timezone) { @@ -284,6 +398,10 @@ class Account extends Eloquent } } + /** + * @param string $date + * @return DateTime|null|string + */ public function getDateTime($date = 'now') { if ( ! $date) { @@ -297,11 +415,20 @@ class Account extends Eloquent return $date; } + /** + * @return mixed + */ public function getCustomDateFormat() { return $this->date_format ? $this->date_format->format : DEFAULT_DATE_FORMAT; } + /** + * @param $amount + * @param null $client + * @param bool $hideSymbol + * @return string + */ public function formatMoney($amount, $client = null, $hideSymbol = false) { if ($client && $client->currency_id) { @@ -325,11 +452,18 @@ class Account extends Eloquent return Utils::formatMoney($amount, $currencyId, $countryId, $hideSymbol); } + /** + * @return mixed + */ public function getCurrencyId() { return $this->currency_id ?: DEFAULT_CURRENCY; } + /** + * @param $date + * @return null|string + */ public function formatDate($date) { $date = $this->getDateTime($date); @@ -341,6 +475,10 @@ class Account extends Eloquent return $date->format($this->getCustomDateFormat()); } + /** + * @param $date + * @return null|string + */ public function formatDateTime($date) { $date = $this->getDateTime($date); @@ -352,6 +490,10 @@ class Account extends Eloquent return $date->format($this->getCustomDateTimeFormat()); } + /** + * @param $date + * @return null|string + */ public function formatTime($date) { $date = $this->getDateTime($date); @@ -363,11 +505,17 @@ class Account extends Eloquent return $date->format($this->getCustomTimeFormat()); } + /** + * @return string + */ public function getCustomTimeFormat() { return $this->military_time ? 'H:i' : 'g:i a'; } + /** + * @return mixed + */ public function getCustomDateTimeFormat() { $format = $this->datetime_format ? $this->datetime_format->format : DEFAULT_DATETIME_FORMAT; @@ -379,19 +527,114 @@ class Account extends Eloquent return $format; } - public function getGatewayByType($type = PAYMENT_TYPE_ANY) + /* + public function defaultGatewayType() { - foreach ($this->account_gateways as $gateway) { - if (!$type || $type == PAYMENT_TYPE_ANY) { - return $gateway; - } elseif ($gateway->isPaymentType($type)) { - return $gateway; + $accountGateway = $this->account_gateways[0]; + $paymentDriver = $accountGateway->paymentDriver(); + + return $paymentDriver->gatewayTypes()[0]; + } + */ + + /** + * @param bool $type + * @return AccountGateway|bool + */ + public function getGatewayByType($type = false) + { + if ( ! $this->relationLoaded('account_gateways')) { + $this->load('account_gateways'); + } + + /** @var AccountGateway $accountGateway */ + foreach ($this->account_gateways as $accountGateway) { + if ( ! $type) { + return $accountGateway; + } + + $paymentDriver = $accountGateway->paymentDriver(); + + if ($paymentDriver->handles($type)) { + return $accountGateway; } } return false; } + /** + * @return array + */ + public function availableGatewaysIds() + { + if ( ! $this->relationLoaded('account_gateways')) { + $this->load('account_gateways'); + } + + $gatewayTypes = []; + $gatewayIds = []; + + foreach ($this->account_gateways as $accountGateway) { + $paymentDriver = $accountGateway->paymentDriver(); + $gatewayTypes = array_unique(array_merge($gatewayTypes, $paymentDriver->gatewayTypes())); + } + + foreach (Cache::get('gateways') as $gateway) { + $paymentDriverClass = AccountGateway::paymentDriverClass($gateway->provider); + $paymentDriver = new $paymentDriverClass(); + $available = true; + + foreach ($gatewayTypes as $type) { + if ($paymentDriver->handles($type)) { + $available = false; + break; + } + } + if ($available) { + $gatewayIds[] = $gateway->id; + } + } + + return $gatewayIds; + } + + /** + * @param bool $invitation + * @param bool $gatewayType + * @return bool + */ + public function paymentDriver($invitation = false, $gatewayType = false) + { + /** @var AccountGateway $accountGateway */ + if ($accountGateway = $this->getGatewayByType($gatewayType)) { + return $accountGateway->paymentDriver($invitation, $gatewayType); + } + + return false; + } + + /** + * @return mixed + */ + public function gatewayIds() + { + return $this->account_gateways()->pluck('gateway_id')->toArray(); + } + + /** + * @param $gatewayId + * @return bool + */ + public function hasGatewayId($gatewayId) + { + return in_array($gatewayId, $this->gatewayIds()); + } + + /** + * @param $gatewayId + * @return bool + */ public function getGatewayConfig($gatewayId) { foreach ($this->account_gateways as $gateway) { @@ -403,6 +646,9 @@ class Account extends Eloquent return false; } + /** + * @return bool + */ public function hasLogo() { if($this->logo == ''){ @@ -412,6 +658,9 @@ class Account extends Eloquent return !empty($this->logo); } + /** + * @return mixed + */ public function getLogoDisk(){ return Storage::disk(env('LOGO_FILESYSTEM', 'logos')); } @@ -436,6 +685,9 @@ class Account extends Eloquent $this->save(); } + /** + * @return null + */ public function getLogoRaw(){ if(!$this->hasLogo()){ return null; @@ -445,6 +697,10 @@ class Account extends Eloquent return $disk->get($this->logo); } + /** + * @param bool $cachebuster + * @return null|string + */ public function getLogoURL($cachebuster = false) { if(!$this->hasLogo()){ @@ -470,6 +726,9 @@ class Account extends Eloquent return Document::getDirectFileUrl($this->logo, $this->getLogoDisk()); } + /** + * @return mixed + */ public function getPrimaryUser() { return $this->users() @@ -477,6 +736,11 @@ class Account extends Eloquent ->first(); } + /** + * @param $userId + * @param $name + * @return null + */ public function getToken($userId, $name) { foreach ($this->account_tokens as $token) { @@ -488,6 +752,9 @@ class Account extends Eloquent return null; } + /** + * @return mixed|null + */ public function getLogoWidth() { if(!$this->hasLogo()){ @@ -497,6 +764,9 @@ class Account extends Eloquent return $this->logo_width; } + /** + * @return mixed|null + */ public function getLogoHeight() { if(!$this->hasLogo()){ @@ -506,12 +776,17 @@ class Account extends Eloquent return $this->logo_height; } + /** + * @param $entityType + * @param null $clientId + * @return mixed + */ public function createInvoice($entityType = ENTITY_INVOICE, $clientId = null) { $invoice = Invoice::createNew(); $invoice->is_recurring = false; - $invoice->is_quote = false; + $invoice->invoice_type_id = INVOICE_TYPE_STANDARD; $invoice->invoice_date = Utils::today(); $invoice->start_date = Utils::today(); $invoice->invoice_design_id = $this->invoice_design_id; @@ -522,12 +797,12 @@ class Account extends Eloquent $invoice->is_recurring = true; } else { if ($entityType == ENTITY_QUOTE) { - $invoice->is_quote = true; + $invoice->invoice_type_id = INVOICE_TYPE_QUOTE; } if ($this->hasClientNumberPattern($invoice) && !$clientId) { // do nothing, we don't yet know the value - } else { + } elseif ( ! $invoice->invoice_number) { $invoice->invoice_number = $this->getNextInvoiceNumber($invoice); } } @@ -540,34 +815,50 @@ class Account extends Eloquent return $invoice; } - public function getNumberPrefix($isQuote) + /** + * @param $invoice_type_id + * @return string + */ + public function getNumberPrefix($invoice_type_id) { if ( ! $this->hasFeature(FEATURE_INVOICE_SETTINGS)) { return ''; } - return ($isQuote ? $this->quote_number_prefix : $this->invoice_number_prefix) ?: ''; + return ($invoice_type_id == INVOICE_TYPE_QUOTE ? $this->quote_number_prefix : $this->invoice_number_prefix) ?: ''; } - public function hasNumberPattern($isQuote) + /** + * @param $invoice_type_id + * @return bool + */ + public function hasNumberPattern($invoice_type_id) { if ( ! $this->hasFeature(FEATURE_INVOICE_SETTINGS)) { return false; } - return $isQuote ? ($this->quote_number_pattern ? true : false) : ($this->invoice_number_pattern ? true : false); + return $invoice_type_id == INVOICE_TYPE_QUOTE ? ($this->quote_number_pattern ? true : false) : ($this->invoice_number_pattern ? true : false); } + /** + * @param $invoice + * @return string + */ public function hasClientNumberPattern($invoice) { - $pattern = $invoice->is_quote ? $this->quote_number_pattern : $this->invoice_number_pattern; + $pattern = $invoice->invoice_type_id == INVOICE_TYPE_QUOTE ? $this->quote_number_pattern : $this->invoice_number_pattern; return strstr($pattern, '$custom'); } + /** + * @param $invoice + * @return bool|mixed + */ public function getNumberPattern($invoice) { - $pattern = $invoice->is_quote ? $this->quote_number_pattern : $this->invoice_number_pattern; + $pattern = $invoice->invoice_type_id == INVOICE_TYPE_QUOTE ? $this->quote_number_pattern : $this->invoice_number_pattern; if (!$pattern) { return false; @@ -577,7 +868,7 @@ class Account extends Eloquent $replace = [date('Y')]; $search[] = '{$counter}'; - $replace[] = str_pad($this->getCounter($invoice->is_quote), $this->invoice_number_padding, '0', STR_PAD_LEFT); + $replace[] = str_pad($this->getCounter($invoice->invoice_type_id), $this->invoice_number_padding, '0', STR_PAD_LEFT); if (strstr($pattern, '{$userId}')) { $search[] = '{$userId}'; @@ -601,6 +892,11 @@ class Account extends Eloquent return $pattern; } + /** + * @param $pattern + * @param $invoice + * @return mixed + */ private function getClientInvoiceNumber($pattern, $invoice) { if (!$invoice->client) { @@ -620,37 +916,53 @@ class Account extends Eloquent return str_replace($search, $replace, $pattern); } - public function getCounter($isQuote) + /** + * @param $invoice_type_id + * @return mixed + */ + public function getCounter($invoice_type_id) { - return $isQuote && !$this->share_counter ? $this->quote_number_counter : $this->invoice_number_counter; + return $invoice_type_id == INVOICE_TYPE_QUOTE && !$this->share_counter ? $this->quote_number_counter : $this->invoice_number_counter; } + /** + * @param $entityType + * @return mixed|string + */ public function previewNextInvoiceNumber($entityType = ENTITY_INVOICE) { $invoice = $this->createInvoice($entityType); return $this->getNextInvoiceNumber($invoice); } - public function getNextInvoiceNumber($invoice) + /** + * @param $invoice + * @param bool $validateUnique + * @return mixed|string + */ + public function getNextInvoiceNumber($invoice, $validateUnique = true) { - if ($this->hasNumberPattern($invoice->is_quote)) { + if ($this->hasNumberPattern($invoice->invoice_type_id)) { $number = $this->getNumberPattern($invoice); } else { - $counter = $this->getCounter($invoice->is_quote); - $prefix = $this->getNumberPrefix($invoice->is_quote); + $counter = $this->getCounter($invoice->invoice_type_id); + $prefix = $this->getNumberPrefix($invoice->invoice_type_id); $counterOffset = 0; + $check = false; // confirm the invoice number isn't already taken do { $number = $prefix . str_pad($counter, $this->invoice_number_padding, '0', STR_PAD_LEFT); - $check = Invoice::scope(false, $this->id)->whereInvoiceNumber($number)->withTrashed()->first(); - $counter++; - $counterOffset++; + if ($validateUnique) { + $check = Invoice::scope(false, $this->id)->whereInvoiceNumber($number)->withTrashed()->first(); + $counter++; + $counterOffset++; + } } while ($check); // update the invoice counter to be caught up if ($counterOffset > 1) { - if ($invoice->is_quote && !$this->share_counter) { + if ($invoice->isType(INVOICE_TYPE_QUOTE) && !$this->share_counter) { $this->quote_number_counter += $counterOffset - 1; } else { $this->invoice_number_counter += $counterOffset - 1; @@ -667,14 +979,17 @@ class Account extends Eloquent return $number; } + /** + * @param $invoice + */ public function incrementCounter($invoice) { // if they didn't use the counter don't increment it - if ($invoice->invoice_number != $this->getNextInvoiceNumber($invoice)) { + if ($invoice->invoice_number != $this->getNextInvoiceNumber($invoice, false)) { return; } - if ($invoice->is_quote && !$this->share_counter) { + if ($invoice->isType(INVOICE_TYPE_QUOTE) && !$this->share_counter) { $this->quote_number_counter += 1; } else { $this->invoice_number_counter += 1; @@ -683,6 +998,9 @@ class Account extends Eloquent $this->save(); } + /** + * @param null $updatedAt + */ public function loadAllData($updatedAt = null) { $map = [ @@ -693,6 +1011,7 @@ class Account extends Eloquent 'tax_rates' => [], 'expenses' => ['client', 'invoice', 'vendor'], 'payments' => ['invoice'], + 'expense_categories' => [], ]; foreach ($map as $key => $values) { @@ -705,6 +1024,9 @@ class Account extends Eloquent } } + /** + * @param bool $client + */ public function loadLocalizationSettings($client = false) { $this->load('timezone', 'date_format', 'datetime_format', 'language'); @@ -728,8 +1050,13 @@ class Account extends Eloquent $format = str_replace('g:i a', 'H:i', $format); } Session::put(SESSION_DATETIME_FORMAT, $format); + + Session::put('start_of_week', $this->start_of_week); } + /** + * @return array + */ public function getInvoiceLabels() { $data = []; @@ -789,11 +1116,17 @@ class Account extends Eloquent return $data; } + /** + * @return bool + */ public function isNinjaAccount() { return $this->account_key === NINJA_ACCOUNT_KEY; } + /** + * @param $plan + */ public function startTrial($plan) { if ( ! Utils::isNinja()) { @@ -805,6 +1138,10 @@ class Account extends Eloquent $this->company->save(); } + /** + * @param $feature + * @return bool + */ public function hasFeature($feature) { if (Utils::isNinjaDev()) { @@ -825,7 +1162,6 @@ class Account extends Eloquent switch ($feature) { // Pro case FEATURE_CUSTOMIZE_INVOICE_DESIGN: - case FEATURE_REMOVE_CREATED_BY: case FEATURE_DIFFERENT_DESIGNS: case FEATURE_EMAIL_TEMPLATES_REMINDERS: case FEATURE_INVOICE_SETTINGS: @@ -839,6 +1175,10 @@ class Account extends Eloquent case FEATURE_CUSTOM_URL: return $selfHost || !empty($planDetails); + case FEATURE_TASKS: + case FEATURE_EXPENSES: + return $selfHost || !empty($planDetails) || $planDetails['company_id'] < EXTRAS_GRANDFATHER_COMPANY_ID; + // Pro; No trial allowed, unless they're trialing enterprise with an active pro plan case FEATURE_MORE_CLIENTS: return $selfHost || !empty($planDetails) && (!$planDetails['trial'] || !empty($this->getPlanDetails(false, false))); @@ -850,6 +1190,7 @@ class Account extends Eloquent } // Fallthrough case FEATURE_CLIENT_PORTAL_CSS: + case FEATURE_REMOVE_CREATED_BY: return !empty($planDetails);// A plan is required even for self-hosted users // Enterprise; No Trial allowed; grandfathered for old pro users @@ -871,6 +1212,10 @@ class Account extends Eloquent } } + /** + * @param null $plan_details + * @return bool + */ public function isPro(&$plan_details = null) { if (!Utils::isNinjaProd()) { @@ -886,6 +1231,10 @@ class Account extends Eloquent return !empty($plan_details); } + /** + * @param null $plan_details + * @return bool + */ public function isEnterprise(&$plan_details = null) { if (!Utils::isNinjaProd()) { @@ -901,6 +1250,11 @@ class Account extends Eloquent return $plan_details && $plan_details['plan'] == PLAN_ENTERPRISE; } + /** + * @param bool $include_inactive + * @param bool $include_trial + * @return array|null + */ public function getPlanDetails($include_inactive = false, $include_trial = true) { if (!$this->company) { @@ -908,6 +1262,7 @@ class Account extends Eloquent } $plan = $this->company->plan; + $price = $this->company->plan_price; $trial_plan = $this->company->trial_plan; if(!$plan && (!$trial_plan || !$include_trial)) { @@ -970,7 +1325,10 @@ class Account extends Eloquent } if ($use_plan) { - return array( + return [ + 'company_id' => $this->company->id, + 'num_users' => $this->company->num_users, + 'plan_price' => $price, 'trial' => false, 'plan' => $plan, 'started' => DateTime::createFromFormat('Y-m-d', $this->company->plan_started), @@ -978,18 +1336,24 @@ class Account extends Eloquent 'paid' => DateTime::createFromFormat('Y-m-d', $this->company->plan_paid), 'term' => $this->company->plan_term, 'active' => $plan_active, - ); + ]; } else { - return array( + return [ + 'company_id' => $this->company->id, + 'num_users' => 1, + 'plan_price' => 0, 'trial' => true, 'plan' => $trial_plan, 'started' => $trial_started, 'expires' => $trial_expires, 'active' => $trial_active, - ); + ]; } } + /** + * @return bool + */ public function isTrial() { if (!Utils::isNinjaProd()) { @@ -1001,13 +1365,17 @@ class Account extends Eloquent return $plan_details && $plan_details['trial']; } + /** + * @param null $plan + * @return array|bool + */ public function isEligibleForTrial($plan = null) { if (!$this->company->trial_plan) { if ($plan) { return $plan == PLAN_PRO || $plan == PLAN_ENTERPRISE; } else { - return array(PLAN_PRO, PLAN_ENTERPRISE); + return [PLAN_PRO, PLAN_ENTERPRISE]; } } @@ -1015,13 +1383,16 @@ class Account extends Eloquent if ($plan) { return $plan != PLAN_PRO; } else { - return array(PLAN_ENTERPRISE); + return [PLAN_ENTERPRISE]; } } return false; } + /** + * @return int + */ public function getCountTrialDaysLeft() { $planDetails = $this->getPlanDetails(true); @@ -1036,6 +1407,9 @@ class Account extends Eloquent return $interval ? $interval->d : 0; } + /** + * @return mixed + */ public function getRenewalDate() { $planDetails = $this->getPlanDetails(); @@ -1050,6 +1424,9 @@ class Account extends Eloquent return $date->format('Y-m-d'); } + /** + * @return float|null + */ public function getLogoSize() { if(!$this->hasLogo()){ @@ -1059,16 +1436,26 @@ class Account extends Eloquent return round($this->logo_size / 1000); } + /** + * @return bool + */ public function isLogoTooLarge() { return $this->getLogoSize() > MAX_LOGO_FILE_SIZE; } + /** + * @param $eventId + * @return \Illuminate\Database\Eloquent\Model|null|static + */ public function getSubscription($eventId) { return Subscription::where('account_id', '=', $this->id)->where('event_id', '=', $eventId)->first(); } + /** + * @return $this + */ public function hideFieldsForViz() { foreach ($this->clients as $client) { @@ -1091,7 +1478,7 @@ class Account extends Eloquent 'invoice_items', 'created_at', 'is_recurring', - 'is_quote', + 'invoice_type_id', ]); foreach ($invoice->invoice_items as $invoiceItem) { @@ -1115,6 +1502,10 @@ class Account extends Eloquent return $this; } + /** + * @param $entityType + * @return mixed + */ public function getDefaultEmailSubject($entityType) { if (strpos($entityType, 'reminder') !== false) { @@ -1124,6 +1515,10 @@ class Account extends Eloquent return trans("texts.{$entityType}_subject", ['invoice' => '$invoice', 'account' => '$account']); } + /** + * @param $entityType + * @return mixed + */ public function getEmailSubject($entityType) { if ($this->hasFeature(FEATURE_CUSTOM_EMAILS)) { @@ -1138,29 +1533,39 @@ class Account extends Eloquent return $this->getDefaultEmailSubject($entityType); } + /** + * @param $entityType + * @param bool $message + * @return string + */ public function getDefaultEmailTemplate($entityType, $message = false) { if (strpos($entityType, 'reminder') !== false) { $entityType = ENTITY_INVOICE; } - $template = "
    \$client,

    "; + $template = '
    $client,

    '; if ($this->hasFeature(FEATURE_CUSTOM_EMAILS) && $this->email_design_id != EMAIL_DESIGN_PLAIN) { - $template .= "
    " . trans("texts.{$entityType}_message_button", ['amount' => '$amount']) . "

    " . - "
    \$viewButton

    "; + $template .= '
    ' . trans("texts.{$entityType}_message_button", ['amount' => '$amount']) . '

    ' . + '
    $viewButton

    '; } else { - $template .= "
    " . trans("texts.{$entityType}_message", ['amount' => '$amount']) . "

    " . - "
    \$viewLink

    "; + $template .= '
    ' . trans("texts.{$entityType}_message", ['amount' => '$amount']) . '

    ' . + '
    $viewLink

    '; } if ($message) { $template .= "$message

    \r\n\r\n"; } - return $template . "\$footer"; + return $template . '$footer'; } + /** + * @param $entityType + * @param bool $message + * @return mixed + */ public function getEmailTemplate($entityType, $message = false) { $template = false; @@ -1178,21 +1583,32 @@ class Account extends Eloquent return str_replace('/>', ' />', $template); } + /** + * @param string $view + * @return string + */ public function getTemplateView($view = '') { return $this->getEmailDesignId() == EMAIL_DESIGN_PLAIN ? $view : 'design' . $this->getEmailDesignId(); } + /** + * @return mixed|string + */ public function getEmailFooter() { if ($this->email_footer) { // Add line breaks if HTML isn't already being used return strip_tags($this->email_footer) == $this->email_footer ? nl2br($this->email_footer) : $this->email_footer; } else { - return "

    " . trans('texts.email_signature') . "\n
    \$account

    "; + return '

    ' . trans('texts.email_signature') . "\n
    \$account

    "; } } + /** + * @param $reminder + * @return bool + */ public function getReminderDate($reminder) { if ( ! $this->{"enable_reminder{$reminder}"}) { @@ -1205,7 +1621,11 @@ class Account extends Eloquent return date('Y-m-d', strtotime("$plusMinus $numDays days")); } - public function getInvoiceReminder($invoice) + /** + * @param Invoice $invoice + * @return bool|string + */ + public function getInvoiceReminder(Invoice $invoice) { for ($i=1; $i<=3; $i++) { if ($date = $this->getReminderDate($i)) { @@ -1219,9 +1639,13 @@ class Account extends Eloquent return false; } - public function showTokenCheckbox() + /** + * @param null $storage_gateway + * @return bool + */ + public function showTokenCheckbox(&$storage_gateway = null) { - if (!$this->isGatewayConfigured(GATEWAY_STRIPE)) { + if (!($storage_gateway = $this->getTokenGatewayId())) { return false; } @@ -1229,11 +1653,44 @@ class Account extends Eloquent || $this->token_billing_type_id == TOKEN_BILLING_OPT_OUT; } + /** + * @return bool + */ + public function getTokenGatewayId() { + if ($this->isGatewayConfigured(GATEWAY_STRIPE)) { + return GATEWAY_STRIPE; + } elseif ($this->isGatewayConfigured(GATEWAY_BRAINTREE)) { + return GATEWAY_BRAINTREE; + } elseif ($this->isGatewayConfigured(GATEWAY_WEPAY)) { + return GATEWAY_WEPAY; + } else { + return false; + } + } + + /** + * @return bool|void + */ + public function getTokenGateway() { + $gatewayId = $this->getTokenGatewayId(); + if (!$gatewayId) { + return; + } + + return $this->getGatewayConfig($gatewayId); + } + + /** + * @return bool + */ public function selectTokenCheckbox() { return $this->token_billing_type_id == TOKEN_BILLING_OPT_OUT; } + /** + * @return string + */ public function getSiteUrl() { $url = SITE_URL; @@ -1248,6 +1705,10 @@ class Account extends Eloquent return $url; } + /** + * @param $host + * @return bool + */ public function checkSubdomain($host) { if (!$this->subdomain) { @@ -1264,6 +1725,11 @@ class Account extends Eloquent return true; } + /** + * @param $field + * @param bool $entity + * @return bool + */ public function showCustomField($field, $entity = false) { if ($this->hasFeature(FEATURE_INVOICE_SETTINGS)) { @@ -1280,16 +1746,25 @@ class Account extends Eloquent return Utils::isEmpty($entity->$field) ? false : true; } - public function attatchPDF() + /** + * @return bool + */ + public function attachPDF() { return $this->hasFeature(FEATURE_PDF_ATTACHMENT) && $this->pdf_email_attachment; } + /** + * @return mixed + */ public function getEmailDesignId() { return $this->hasFeature(FEATURE_CUSTOM_EMAILS) ? $this->email_design_id : EMAIL_DESIGN_PLAIN; } + /** + * @return string + */ public function clientViewCSS(){ $css = ''; @@ -1310,12 +1785,16 @@ class Account extends Eloquent return $css; } + /** + * @param string $protocol + * @return string + */ public function getFontsUrl($protocol = ''){ $bodyFont = $this->getHeaderFontId(); $headerFont = $this->getBodyFontId(); $bodyFontSettings = Utils::getFromCache($bodyFont, 'fonts'); - $google_fonts = array($bodyFontSettings['google_font']); + $google_fonts = [$bodyFontSettings['google_font']]; if($headerFont != $bodyFont){ $headerFontSettings = Utils::getFromCache($headerFont, 'fonts'); @@ -1325,22 +1804,38 @@ class Account extends Eloquent return ($protocol?$protocol.':':'').'//fonts.googleapis.com/css?family='.implode('|',$google_fonts); } + /** + * @return mixed + */ public function getHeaderFontId() { return ($this->hasFeature(FEATURE_CUSTOMIZE_INVOICE_DESIGN) && $this->header_font_id) ? $this->header_font_id : DEFAULT_HEADER_FONT; } + /** + * @return mixed + */ public function getBodyFontId() { return ($this->hasFeature(FEATURE_CUSTOMIZE_INVOICE_DESIGN) && $this->body_font_id) ? $this->body_font_id : DEFAULT_BODY_FONT; } + /** + * @return null + */ public function getHeaderFontName(){ return Utils::getFromCache($this->getHeaderFontId(), 'fonts')['name']; } + /** + * @return null + */ public function getBodyFontName(){ return Utils::getFromCache($this->getBodyFontId(), 'fonts')['name']; } + /** + * @param bool $include_weight + * @return string + */ public function getHeaderFontCss($include_weight = true){ $font_data = Utils::getFromCache($this->getHeaderFontId(), 'fonts'); $css = 'font-family:'.$font_data['css_stack'].';'; @@ -1352,6 +1847,10 @@ class Account extends Eloquent return $css; } + /** + * @param bool $include_weight + * @return string + */ public function getBodyFontCss($include_weight = true){ $font_data = Utils::getFromCache($this->getBodyFontId(), 'fonts'); $css = 'font-family:'.$font_data['css_stack'].';'; @@ -1363,12 +1862,18 @@ class Account extends Eloquent return $css; } + /** + * @return array + */ public function getFonts(){ - return array_unique(array($this->getHeaderFontId(), $this->getBodyFontId())); + return array_unique([$this->getHeaderFontId(), $this->getBodyFontId()]); } + /** + * @return array + */ public function getFontsData(){ - $data = array(); + $data = []; foreach($this->getFonts() as $font){ $data[] = Utils::getFromCache($font, 'fonts'); @@ -1377,11 +1882,22 @@ class Account extends Eloquent return $data; } + /** + * @return array + */ public function getFontFolders(){ return array_map(function($item){return $item['folder'];}, $this->getFontsData()); } } -Account::updated(function ($account) { +Account::updated(function ($account) +{ + // prevent firing event if the invoice/quote counter was changed + // TODO: remove once counters are moved to separate table + $dirty = $account->getDirty(); + if (isset($dirty['invoice_number_counter']) || isset($dirty['quote_number_counter'])) { + return; + } + Event::fire(new UserSettingsChanged()); }); diff --git a/app/Models/AccountGateway.php b/app/Models/AccountGateway.php index 5e95128534..a2250b9bfc 100644 --- a/app/Models/AccountGateway.php +++ b/app/Models/AccountGateway.php @@ -1,24 +1,45 @@ belongsTo('App\Models\Gateway'); } + /** + * @return array + */ public function getCreditcardTypes() { $flags = unserialize(CREDIT_CARDS); @@ -33,36 +54,72 @@ class AccountGateway extends EntityModel return $arrayOfImages; } - public function getPaymentType() + /** + * @param $provider + * @return string + */ + public static function paymentDriverClass($provider) { - return Gateway::getPaymentType($this->gateway_id); - } - - public function isPaymentType($type) - { - return $this->getPaymentType() == $type; + $folder = 'App\\Ninja\\PaymentDrivers\\'; + $class = $folder . $provider . 'PaymentDriver'; + $class = str_replace('_', '', $class); + + if (class_exists($class)) { + return $class; + } else { + return $folder . 'BasePaymentDriver'; + } } + /** + * @param bool $invitation + * @param bool $gatewayType + * @return mixed + */ + public function paymentDriver($invitation = false, $gatewayType = false) + { + $class = static::paymentDriverClass($this->gateway->provider); + + return new $class($this, $invitation, $gatewayType); + } + + /** + * @param $gatewayId + * @return bool + */ public function isGateway($gatewayId) { return $this->gateway_id == $gatewayId; } + /** + * @param $config + */ public function setConfig($config) { $this->config = Crypt::encrypt(json_encode($config)); } + /** + * @return mixed + */ public function getConfig() { return json_decode(Crypt::decrypt($this->config)); } + /** + * @param $field + * @return mixed + */ public function getConfigField($field) { return object_get($this->getConfig(), $field, false); } + /** + * @return bool|mixed + */ public function getPublishableStripeKey() { if ( ! $this->isGateway(GATEWAY_STRIPE)) { @@ -71,5 +128,88 @@ class AccountGateway extends EntityModel return $this->getConfigField('publishableKey'); } -} + /** + * @return bool + */ + public function getAchEnabled() + { + return !empty($this->getConfigField('enableAch')); + } + + /** + * @return bool + */ + public function getPayPalEnabled() + { + return !empty($this->getConfigField('enablePayPal')); + } + + /** + * @return bool|mixed + */ + public function getPlaidSecret() + { + if ( ! $this->isGateway(GATEWAY_STRIPE)) { + return false; + } + + return $this->getConfigField('plaidSecret'); + } + + /** + * @return bool|mixed + */ + public function getPlaidClientId() + { + if ( ! $this->isGateway(GATEWAY_STRIPE)) { + return false; + } + + return $this->getConfigField('plaidClientId'); + } + + /** + * @return bool|mixed + */ + public function getPlaidPublicKey() + { + if ( ! $this->isGateway(GATEWAY_STRIPE)) { + return false; + } + + return $this->getConfigField('plaidPublicKey'); + } + + /** + * @return bool + */ + public function getPlaidEnabled() + { + return !empty($this->getPlaidClientId()) && $this->getAchEnabled(); + } + + /** + * @return null|string + */ + public function getPlaidEnvironment() + { + if (!$this->getPlaidClientId()) { + return null; + } + + $stripe_key = $this->getPublishableStripeKey(); + + return substr(trim($stripe_key), 0, 8) == 'pk_test_' ? 'tartan' : 'production'; + } + + /** + * @return string + */ + public function getWebhookUrl() + { + $account = $this->account ? $this->account : Account::find($this->account_id); + + return \URL::to(env('WEBHOOK_PREFIX','').'payment_hook/'.$account->account_key.'/'.$this->gateway_id.env('WEBHOOK_SUFFIX','')); + } +} diff --git a/app/Models/AccountGatewayToken.php b/app/Models/AccountGatewayToken.php index b706882af7..b7fc767112 100644 --- a/app/Models/AccountGatewayToken.php +++ b/app/Models/AccountGatewayToken.php @@ -3,9 +3,96 @@ use Eloquent; use Illuminate\Database\Eloquent\SoftDeletes; +/** + * Class AccountGatewayToken + */ class AccountGatewayToken extends Eloquent { use SoftDeletes; + /** + * @var array + */ protected $dates = ['deleted_at']; + /** + * @var bool + */ public $timestamps = true; -} \ No newline at end of file + + /** + * @var array + */ + protected $casts = []; + + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function payment_methods() + { + return $this->hasMany('App\Models\PaymentMethod'); + } + + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function account_gateway() + { + return $this->belongsTo('App\Models\AccountGateway'); + } + + /** + * @return \Illuminate\Database\Eloquent\Relations\HasOne + */ + public function default_payment_method() + { + return $this->hasOne('App\Models\PaymentMethod', 'id', 'default_payment_method_id'); + } + + /** + * @return mixed + */ + public function autoBillLater() + { + return $this->default_payment_method->requiresDelayedAutoBill(); + } + + /** + * @param $query + * @param $clientId + * @param $accountGatewayId + * @return mixed + */ + public function scopeClientAndGateway($query, $clientId, $accountGatewayId) + { + $query->where('client_id', '=', $clientId) + ->where('account_gateway_id', '=', $accountGatewayId); + + return $query; + } + + /** + * @return mixed + */ + public function gatewayName() + { + return $this->account_gateway->gateway->name; + } + + /** + * @return bool|string + */ + public function gatewayLink() + { + $accountGateway = $this->account_gateway; + + if ($accountGateway->gateway_id == GATEWAY_STRIPE) { + return "https://dashboard.stripe.com/customers/{$this->token}"; + } elseif ($accountGateway->gateway_id == GATEWAY_BRAINTREE) { + $merchantId = $accountGateway->getConfig()->merchantId; + $testMode = $accountGateway->getConfig()->testMode; + return $testMode ? "https://sandbox.braintreegateway.com/merchants/{$merchantId}/customers/{$this->token}" : "https://www.braintreegateway.com/merchants/{$merchantId}/customers/{$this->token}"; + } else { + return false; + } + } + +} diff --git a/app/Models/AccountToken.php b/app/Models/AccountToken.php index 55781aabb9..5ef52e1701 100644 --- a/app/Models/AccountToken.php +++ b/app/Models/AccountToken.php @@ -2,21 +2,36 @@ use Illuminate\Database\Eloquent\SoftDeletes; +/** + * Class AccountToken + */ class AccountToken extends EntityModel { use SoftDeletes; + /** + * @var array + */ protected $dates = ['deleted_at']; + /** + * @return mixed + */ public function getEntityType() { return ENTITY_TOKEN; } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function account() { return $this->belongsTo('App\Models\Account'); } + /** + * @return mixed + */ public function user() { return $this->belongsTo('App\Models\User')->withTrashed(); diff --git a/app/Models/Activity.php b/app/Models/Activity.php index 921c037d5f..e196504bcd 100644 --- a/app/Models/Activity.php +++ b/app/Models/Activity.php @@ -2,55 +2,90 @@ use Auth; use Eloquent; -use Utils; -use Session; -use Request; -use Carbon; +/** + * Class Activity + */ class Activity extends Eloquent { + /** + * @var bool + */ public $timestamps = true; + /** + * @param $query + * @return mixed + */ public function scopeScope($query) { return $query->whereAccountId(Auth::user()->account_id); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function account() { return $this->belongsTo('App\Models\Account'); } + /** + * @return mixed + */ public function user() { return $this->belongsTo('App\Models\User')->withTrashed(); } + /** + * @return mixed + */ public function contact() { return $this->belongsTo('App\Models\Contact')->withTrashed(); } + /** + * @return mixed + */ public function client() { return $this->belongsTo('App\Models\Client')->withTrashed(); } + /** + * @return mixed + */ public function invoice() { return $this->belongsTo('App\Models\Invoice')->withTrashed(); } + /** + * @return mixed + */ public function credit() { return $this->belongsTo('App\Models\Credit')->withTrashed(); } + /** + * @return mixed + */ public function payment() { return $this->belongsTo('App\Models\Payment')->withTrashed(); } + public function task() + { + return $this->belongsTo('App\Models\Task')->withTrashed(); + } + + /** + * @return mixed + */ public function getMessage() { $activityTypeId = $this->activity_type_id; @@ -63,14 +98,20 @@ class Activity extends Eloquent $credit = $this->credit; $isSystem = $this->is_system; + /** @var Task $task */ + $task = $this->task; + $data = [ - 'client' => link_to($client->getRoute(), $client->getDisplayName()), + 'client' => $client ? link_to($client->getRoute(), $client->getDisplayName()) : null, 'user' => $isSystem ? '' . trans('texts.system') . '' : $user->getDisplayName(), 'invoice' => $invoice ? link_to($invoice->getRoute(), $invoice->getDisplayName()) : null, 'quote' => $invoice ? link_to($invoice->getRoute(), $invoice->getDisplayName()) : null, 'contact' => $contactId ? $client->getDisplayName() : $user->getDisplayName(), 'payment' => $payment ? $payment->transaction_reference : null, + 'payment_amount' => $payment ? $account->formatMoney($payment->amount, $payment) : null, + 'adjustment' => $this->adjustment ? $account->formatMoney($this->adjustment, $this) : asdf, 'credit' => $credit ? $account->formatMoney($credit->amount, $client) : null, + 'task' => $task ? link_to($task->getRoute(), substr($task->description, 0, 30).'...') : null, ]; return trans("texts.activity_{$activityTypeId}", $data); diff --git a/app/Models/Affiliate.php b/app/Models/Affiliate.php index 63fcb71ce3..4945080ed7 100644 --- a/app/Models/Affiliate.php +++ b/app/Models/Affiliate.php @@ -2,8 +2,17 @@ use Eloquent; +/** + * Class Affiliate + */ class Affiliate extends Eloquent { + /** + * @var bool + */ public $timestamps = true; + /** + * @var bool + */ protected $softDelete = true; } diff --git a/app/Models/BalanceAffecting.php b/app/Models/BalanceAffecting.php index 0ba99f73a2..1486b7ba82 100644 --- a/app/Models/BalanceAffecting.php +++ b/app/Models/BalanceAffecting.php @@ -1,5 +1,8 @@ config); diff --git a/app/Models/BankAccount.php b/app/Models/BankAccount.php index 6bb0a54370..617c04ae94 100644 --- a/app/Models/BankAccount.php +++ b/app/Models/BankAccount.php @@ -1,24 +1,37 @@ belongsTo('App\Models\Bank'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ public function bank_subaccounts() { return $this->hasMany('App\Models\BankSubaccount'); diff --git a/app/Models/BankSubaccount.php b/app/Models/BankSubaccount.php index 0cd33568e0..4cda62da04 100644 --- a/app/Models/BankSubaccount.php +++ b/app/Models/BankSubaccount.php @@ -1,19 +1,28 @@ belongsTo('App\Models\BankAccount'); diff --git a/app/Models/Client.php b/app/Models/Client.php index 6d2b44fbac..6d6dd0b4bc 100644 --- a/app/Models/Client.php +++ b/app/Models/Client.php @@ -6,15 +6,27 @@ use Carbon; use Laracasts\Presenter\PresentableTrait; use Illuminate\Database\Eloquent\SoftDeletes; +/** + * Class Client + */ class Client extends EntityModel { use PresentableTrait; use SoftDeletes; + /** + * @var string + */ protected $presenter = 'App\Ninja\Presenters\ClientPresenter'; + /** + * @var array + */ protected $dates = ['deleted_at']; + /** + * @var array + */ protected $fillable = [ 'name', 'id_number', @@ -37,16 +49,50 @@ class Client extends EntityModel 'website', ]; + /** + * @var string + */ public static $fieldName = 'name'; + /** + * @var string + */ public static $fieldPhone = 'work_phone'; + /** + * @var string + */ public static $fieldAddress1 = 'address1'; + /** + * @var string + */ public static $fieldAddress2 = 'address2'; + /** + * @var string + */ public static $fieldCity = 'city'; + /** + * @var string + */ public static $fieldState = 'state'; + /** + * @var string + */ public static $fieldPostalCode = 'postal_code'; + /** + * @var string + */ public static $fieldNotes = 'notes'; + /** + * @var string + */ public static $fieldCountry = 'country'; + /** + * @var string + */ + public static $fieldWebsite = 'website'; + /** + * @return array + */ public static function getImportColumns() { return [ @@ -59,6 +105,7 @@ class Client extends EntityModel Client::$fieldPostalCode, Client::$fieldCountry, Client::$fieldNotes, + Client::$fieldWebsite, Contact::$fieldFirstName, Contact::$fieldLastName, Contact::$fieldPhone, @@ -66,6 +113,9 @@ class Client extends EntityModel ]; } + /** + * @return array + */ public static function getImportMap() { return [ @@ -81,69 +131,111 @@ class Client extends EntityModel 'zip|postal|code' => 'postal_code', 'country' => 'country', 'note' => 'notes', + 'site|website' => 'website', ]; } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function account() { return $this->belongsTo('App\Models\Account'); } + /** + * @return mixed + */ public function user() { return $this->belongsTo('App\Models\User')->withTrashed(); } + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ public function invoices() { return $this->hasMany('App\Models\Invoice'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ public function payments() { return $this->hasMany('App\Models\Payment'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ public function contacts() { return $this->hasMany('App\Models\Contact'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function country() { return $this->belongsTo('App\Models\Country'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function currency() { return $this->belongsTo('App\Models\Currency'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function language() { return $this->belongsTo('App\Models\Language'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function size() { return $this->belongsTo('App\Models\Size'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function industry() { return $this->belongsTo('App\Models\Industry'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ public function credits() { return $this->hasMany('App\Models\Credit'); } + /** + * @return mixed + */ public function expenses() { return $this->hasMany('App\Models\Expense','client_id','id')->withTrashed(); } + /** + * @param $data + * @param bool $isPrimary + * @return \Illuminate\Database\Eloquent\Model + */ public function addContact($data, $isPrimary = false) { $publicId = isset($data['public_id']) ? $data['public_id'] : (isset($data['id']) ? $data['id'] : false); @@ -154,7 +246,7 @@ class Client extends EntityModel $contact = Contact::createNew(); $contact->send_invoice = true; } - + if (Utils::hasFeature(FEATURE_CLIENT_PORTAL_PASSWORD) && $this->account->enable_portal_password){ if(!empty($data['password']) && $data['password']!='-%unchanged%-'){ $contact->password = bcrypt($data['password']); @@ -162,13 +254,17 @@ class Client extends EntityModel $contact->password = null; } } - + $contact->fill($data); $contact->is_primary = $isPrimary; return $this->contacts()->save($contact); } + /** + * @param $balanceAdjustment + * @param $paidToDateAdjustment + */ public function updateBalances($balanceAdjustment, $paidToDateAdjustment) { if ($balanceAdjustment === 0 && $paidToDateAdjustment === 0) { @@ -177,15 +273,21 @@ class Client extends EntityModel $this->balance = $this->balance + $balanceAdjustment; $this->paid_to_date = $this->paid_to_date + $paidToDateAdjustment; - + $this->save(); } + /** + * @return string + */ public function getRoute() { return "/clients/{$this->public_id}"; } + /** + * @return float|int + */ public function getTotalCredit() { return DB::table('credits') @@ -194,24 +296,33 @@ class Client extends EntityModel ->sum('balance'); } + /** + * @return mixed + */ public function getName() { return $this->name; } - + + /** + * @return mixed + */ public function getPrimaryContact() { return $this->contacts() ->whereIsPrimary(true) ->first(); } - + + /** + * @return mixed|string + */ public function getDisplayName() { if ($this->name) { return $this->name; } - + if ( ! count($this->contacts)) { return ''; } @@ -220,17 +331,26 @@ class Client extends EntityModel return $contact->getDisplayName(); } + /** + * @return string + */ public function getCityState() { $swap = $this->country && $this->country->swap_postal_code; return Utils::cityStateZip($this->city, $this->state, $this->postal_code, $swap); } + /** + * @return mixed + */ public function getEntityType() { return ENTITY_CLIENT; } + /** + * @return bool + */ public function hasAddress() { $fields = [ @@ -251,6 +371,9 @@ class Client extends EntityModel return false; } + /** + * @return string + */ public function getDateCreated() { if ($this->created_at == '0000-00-00 00:00:00') { @@ -260,42 +383,59 @@ class Client extends EntityModel } } - + /** + * @return bool + */ public function getGatewayToken() { - $account = $this->account; - - if ( ! $account->relationLoaded('account_gateways')) { - $account->load('account_gateways'); - } + $accountGateway = $this->account->getGatewayByType(GATEWAY_TYPE_TOKEN); - if (!count($account->account_gateways)) { + if ( ! $accountGateway) { return false; } - $accountGateway = $account->getGatewayConfig(GATEWAY_STRIPE); - - if (!$accountGateway) { - return false; - } - - $token = AccountGatewayToken::where('client_id', '=', $this->id) - ->where('account_gateway_id', '=', $accountGateway->id)->first(); - - return $token ? $token->token : false; + return AccountGatewayToken::clientAndGateway($this->id, $accountGateway->id)->first(); } - public function getGatewayLink() + /** + * @return bool + */ + public function defaultPaymentMethod() { - $token = $this->getGatewayToken(); - return $token ? "https://dashboard.stripe.com/customers/{$token}" : false; + if ($token = $this->getGatewayToken()) { + return $token->default_payment_method; + } + + return false; } + /** + * @return bool + */ + public function autoBillLater() + { + if ($token = $this->getGatewayToken()) { + if ($this->account->auto_bill_on_due_date) { + return true; + } + + return $token->autoBillLater(); + } + + return false; + } + + /** + * @return mixed + */ public function getAmount() { return $this->balance + $this->paid_to_date; } + /** + * @return mixed + */ public function getCurrencyId() { if ($this->currency_id) { @@ -309,6 +449,26 @@ class Client extends EntityModel return $this->account->currency_id ?: DEFAULT_CURRENCY; } + /** + * @return string + */ + public function getCurrencyCode() + { + if ($this->currency) { + return $this->currency->code; + } + + if (!$this->account) { + $this->load('account'); + } + + return $this->account->currency ? $this->account->currency->code : 'USD'; + } + + /** + * @param $isQuote + * @return mixed + */ public function getCounter($isQuote) { return $isQuote ? $this->quote_number_counter : $this->invoice_number_counter; @@ -319,6 +479,13 @@ class Client extends EntityModel $this->last_login = Carbon::now()->toDateTimeString(); $this->save(); } + + /** + * @return bool + */ + public function hasAutoBillConfigurableInvoices(){ + return $this->invoices()->whereIn('auto_bill', [AUTO_BILL_OPT_IN, AUTO_BILL_OPT_OUT])->count() > 0; + } } Client::creating(function ($client) { diff --git a/app/Models/Company.php b/app/Models/Company.php index 1345db9e4b..847289a88e 100644 --- a/app/Models/Company.php +++ b/app/Models/Company.php @@ -3,17 +3,29 @@ use Eloquent; use Illuminate\Database\Eloquent\SoftDeletes; +/** + * Class Company + */ class Company extends Eloquent { use SoftDeletes; + /** + * @var array + */ protected $dates = ['deleted_at']; - + + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ public function accounts() { return $this->hasMany('App\Models\Account'); } - + + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function payment() { return $this->belongsTo('App\Models\Payment'); diff --git a/app/Models/Contact.php b/app/Models/Contact.php index 54610e93f0..fbac37117e 100644 --- a/app/Models/Contact.php +++ b/app/Models/Contact.php @@ -1,6 +1,5 @@ belongsTo('App\Models\Account'); } + /** + * @return mixed + */ public function user() { return $this->belongsTo('App\Models\User')->withTrashed(); } + /** + * @return mixed + */ public function client() { return $this->belongsTo('App\Models\Client')->withTrashed(); } + /** + * @return mixed + */ public function getPersonType() { return PERSON_CONTACT; } + /** + * @return mixed|string + */ public function getName() { return $this->getDisplayName(); } + /** + * @return mixed|string + */ public function getDisplayName() { if ($this->getFullName()) { @@ -60,6 +101,22 @@ class Contact extends EntityModel implements AuthenticatableContract, CanResetPa } } + /** + * @param $contact_key + * @return mixed + */ + public function getContactKeyAttribute($contact_key) + { + if (empty($contact_key) && $this->id) { + $this->contact_key = $contact_key = str_random(RANDOM_KEY_LENGTH); + static::where('id', $this->id)->update(['contact_key' => $contact_key]); + } + return $contact_key; + } + + /** + * @return string + */ public function getFullName() { if ($this->first_name || $this->last_name) { @@ -68,4 +125,12 @@ class Contact extends EntityModel implements AuthenticatableContract, CanResetPa return ''; } } + + /** + * @return string + */ + public function getLinkAttribute() + { + return \URL::to('client/dashboard/' . $this->contact_key); + } } diff --git a/app/Models/Country.php b/app/Models/Country.php index 8a87500e32..d764a76b30 100644 --- a/app/Models/Country.php +++ b/app/Models/Country.php @@ -2,10 +2,19 @@ use Eloquent; +/** + * Class Country + */ class Country extends Eloquent { + /** + * @var bool + */ public $timestamps = false; + /** + * @var array + */ protected $visible = [ 'id', 'name', @@ -15,11 +24,17 @@ class Country extends Eloquent 'decimal_separator' ]; + /** + * @var array + */ protected $casts = [ 'swap_postal_code' => 'boolean', 'swap_currency_symbol' => 'boolean', ]; + /** + * @return mixed + */ public function getName() { return $this->name; diff --git a/app/Models/Credit.php b/app/Models/Credit.php index 340417e7d4..02a3877750 100644 --- a/app/Models/Credit.php +++ b/app/Models/Credit.php @@ -4,44 +4,75 @@ use Illuminate\Database\Eloquent\SoftDeletes; use App\Events\CreditWasCreated; use Laracasts\Presenter\PresentableTrait; +/** + * Class Credit + */ class Credit extends EntityModel { use SoftDeletes; use PresentableTrait; + /** + * @var array + */ protected $dates = ['deleted_at']; + /** + * @var string + */ protected $presenter = 'App\Ninja\Presenters\CreditPresenter'; + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function account() { return $this->belongsTo('App\Models\Account'); } + /** + * @return mixed + */ public function user() { return $this->belongsTo('App\Models\User')->withTrashed(); } + /** + * @return mixed + */ public function invoice() { return $this->belongsTo('App\Models\Invoice')->withTrashed(); } + /** + * @return mixed + */ public function client() { return $this->belongsTo('App\Models\Client')->withTrashed(); } + /** + * @return string + */ public function getName() { return ''; } + /** + * @return mixed + */ public function getEntityType() { return ENTITY_CREDIT; } + /** + * @param $amount + * @return mixed + */ public function apply($amount) { if ($amount > $this->balance) { diff --git a/app/Models/Currency.php b/app/Models/Currency.php index 944f9f2d8e..c4b55a46c2 100644 --- a/app/Models/Currency.php +++ b/app/Models/Currency.php @@ -2,12 +2,28 @@ use Eloquent; +/** + * Class Currency + */ class Currency extends Eloquent { + /** + * @var bool + */ public $timestamps = false; - public function getName() + /** + * @var array + */ + protected $casts = [ + 'swap_currency_symbol' => 'boolean', + ]; + + /** + * @return mixed + */ + public function getName() { return $this->name; - } + } } diff --git a/app/Models/DateFormat.php b/app/Models/DateFormat.php index b343fd4226..cc421169d2 100644 --- a/app/Models/DateFormat.php +++ b/app/Models/DateFormat.php @@ -2,7 +2,23 @@ use Eloquent; +/** + * Class DateFormat + */ class DateFormat extends Eloquent { + /** + * @var bool + */ public $timestamps = false; + + /** + * @return bool|string + */ + public function __toString() + { + $date = mktime(0, 0, 0, 12, 31, date('Y')); + + return date($this->format, $date); + } } diff --git a/app/Models/DatetimeFormat.php b/app/Models/DatetimeFormat.php index 1d7ba8b936..a7876a29e8 100644 --- a/app/Models/DatetimeFormat.php +++ b/app/Models/DatetimeFormat.php @@ -2,7 +2,23 @@ use Eloquent; +/** + * Class DatetimeFormat + */ class DatetimeFormat extends Eloquent { + /** + * @var bool + */ public $timestamps = false; + + /** + * @return bool|string + */ + public function __toString() + { + $date = mktime(0, 0, 0, 12, 31, date('Y')); + + return date($this->format, $date); + } } diff --git a/app/Models/Document.php b/app/Models/Document.php index efa9426e95..ebf0855df1 100644 --- a/app/Models/Document.php +++ b/app/Models/Document.php @@ -2,72 +2,95 @@ use Illuminate\Support\Facades\Storage; use DB; -use Auth; +/** + * Class Document + */ class Document extends EntityModel { - public static $extraExtensions = array( + /** + * @var array + */ + protected $fillable = [ + 'invoice_id', + 'expense_id', + ]; + + /** + * @var array + */ + public static $extraExtensions = [ 'jpg' => 'jpeg', 'tif' => 'tiff', - ); + ]; - public static $allowedMimes = array(// Used by Dropzone.js; does not affect what the server accepts + /** + * @var array + */ + public static $allowedMimes = [// Used by Dropzone.js; does not affect what the server accepts 'image/png', 'image/jpeg', 'image/tiff', 'application/pdf', 'image/gif', 'image/vnd.adobe.photoshop', 'text/plain', 'application/msword', 'application/excel', 'application/vnd.ms-excel', 'application/x-excel', 'application/x-msexcel', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet','application/postscript', 'image/svg+xml', 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'application/vnd.ms-powerpoint', - ); + ]; - public static $types = array( - 'png' => array( + /** + * @var array + */ + public static $types = [ + 'png' => [ 'mime' => 'image/png', - ), - 'ai' => array( + ], + 'ai' => [ 'mime' => 'application/postscript', - ), - 'svg' => array( + ], + 'svg' => [ 'mime' => 'image/svg+xml', - ), - 'jpeg' => array( + ], + 'jpeg' => [ 'mime' => 'image/jpeg', - ), - 'tiff' => array( + ], + 'tiff' => [ 'mime' => 'image/tiff', - ), - 'pdf' => array( + ], + 'pdf' => [ 'mime' => 'application/pdf', - ), - 'gif' => array( + ], + 'gif' => [ 'mime' => 'image/gif', - ), - 'psd' => array( + ], + 'psd' => [ 'mime' => 'image/vnd.adobe.photoshop', - ), - 'txt' => array( + ], + 'txt' => [ 'mime' => 'text/plain', - ), - 'doc' => array( + ], + 'doc' => [ 'mime' => 'application/msword', - ), - 'xls' => array( + ], + 'xls' => [ 'mime' => 'application/vnd.ms-excel', - ), - 'ppt' => array( + ], + 'ppt' => [ 'mime' => 'application/vnd.ms-powerpoint', - ), - 'xlsx' => array( + ], + 'xlsx' => [ 'mime' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', - ), - 'docx' => array( + ], + 'docx' => [ 'mime' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', - ), - 'pptx' => array( + ], + 'pptx' => [ 'mime' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', - ), - ); + ], + ]; + /** + * @param array $attributes + * @return $this + */ public function fill(array $attributes) { parent::fill($attributes); @@ -79,43 +102,74 @@ class Document extends EntityModel return $this; } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function account() { return $this->belongsTo('App\Models\Account'); } + /** + * @return mixed + */ public function user() { return $this->belongsTo('App\Models\User')->withTrashed(); } + /** + * @return mixed + */ public function expense() { return $this->belongsTo('App\Models\Expense')->withTrashed(); } + /** + * @return mixed + */ public function invoice() { return $this->belongsTo('App\Models\Invoice')->withTrashed(); } + /** + * @return mixed + */ public function getDisk(){ return Storage::disk(!empty($this->disk)?$this->disk:env('DOCUMENT_FILESYSTEM', 'documents')); } + /** + * @param $value + */ public function setDiskAttribute($value) { $this->attributes['disk'] = $value?$value:env('DOCUMENT_FILESYSTEM', 'documents'); } + /** + * @return null|string + */ public function getDirectUrl(){ return static::getDirectFileUrl($this->path, $this->getDisk()); } + /** + * @return null|string + */ public function getDirectPreviewUrl(){ return $this->preview?static::getDirectFileUrl($this->preview, $this->getDisk(), true):null; } + /** + * @param $path + * @param $disk + * @param bool $prioritizeSpeed + * @return null|string + * @throws \OpenCloud\Common\Exceptions\NoNameError + */ public static function getDirectFileUrl($path, $disk, $prioritizeSpeed = false){ $adapter = $disk->getAdapter(); $fullPath = $adapter->applyPathPrefix($path); @@ -151,50 +205,81 @@ class Document extends EntityModel return null; } + /** + * @return mixed + */ public function getRaw(){ $disk = $this->getDisk(); return $disk->get($this->path); } + /** + * @return mixed + */ public function getStream(){ $disk = $this->getDisk(); return $disk->readStream($this->path); } + /** + * @return mixed + */ public function getRawPreview(){ $disk = $this->getDisk(); return $disk->get($this->preview); } + /** + * @return \Illuminate\Contracts\Routing\UrlGenerator|string + */ public function getUrl(){ return url('documents/'.$this->public_id.'/'.$this->name); } + /** + * @param $invitation + * @return \Illuminate\Contracts\Routing\UrlGenerator|string + */ public function getClientUrl($invitation){ return url('client/documents/'.$invitation->invitation_key.'/'.$this->public_id.'/'.$this->name); } + /** + * @return bool + */ public function isPDFEmbeddable(){ return $this->type == 'jpeg' || $this->type == 'png' || $this->preview; } + /** + * @return \Illuminate\Contracts\Routing\UrlGenerator|null|string + */ public function getVFSJSUrl(){ if(!$this->isPDFEmbeddable())return null; return url('documents/js/'.$this->public_id.'/'.$this->name.'.js'); } + /** + * @return \Illuminate\Contracts\Routing\UrlGenerator|null|string + */ public function getClientVFSJSUrl(){ if(!$this->isPDFEmbeddable())return null; return url('client/documents/js/'.$this->public_id.'/'.$this->name.'.js'); } + /** + * @return \Illuminate\Contracts\Routing\UrlGenerator|null|string + */ public function getPreviewUrl(){ return $this->preview?url('documents/preview/'.$this->public_id.'/'.$this->name.'.'.pathinfo($this->preview, PATHINFO_EXTENSION)):null; } + /** + * @return array + */ public function toArray() { $array = parent::toArray(); @@ -205,6 +290,9 @@ class Document extends EntityModel return $array; } + /** + * @return mixed + */ public function cloneDocument(){ $document = Document::createNew($this); $document->path = $this->path; diff --git a/app/Models/EntityModel.php b/app/Models/EntityModel.php index 4b724d3953..4a98ef817e 100644 --- a/app/Models/EntityModel.php +++ b/app/Models/EntityModel.php @@ -4,31 +4,55 @@ use Auth; use Eloquent; use Utils; +/** + * Class EntityModel + */ class EntityModel extends Eloquent { + /** + * @var bool + */ public $timestamps = true; + /** + * @var array + */ protected $hidden = ['id']; + /** + * @var bool + */ + public static $notifySubscriptions = true; + + /** + * @param null $context + * @return mixed + */ public static function createNew($context = null) { $className = get_called_class(); $entity = new $className(); if ($context) { - $entity->user_id = $context instanceof User ? $context->id : $context->user_id; - $entity->account_id = $context->account_id; + $user = $context instanceof User ? $context : $context->user; + $account = $context->account; } elseif (Auth::check()) { - $entity->user_id = Auth::user()->id; - $entity->account_id = Auth::user()->account_id; + $user = Auth::user(); + $account = Auth::user()->account; } else { Utils::fatalError(); } - if(method_exists($className, 'withTrashed')){ - $lastEntity = $className::withTrashed() - ->scope(false, $entity->account_id); + $entity->user_id = $user->id; + $entity->account_id = $account->id; + + // store references to the original user/account to prevent needing to reload them + $entity->setRelation('user', $user); + $entity->setRelation('account', $account); + + if (method_exists($className, 'trashed')){ + $lastEntity = $className::whereAccountId($entity->account_id)->withTrashed(); } else { - $lastEntity = $className::scope(false, $entity->account_id); + $lastEntity = $className::whereAccountId($entity->account_id); } $lastEntity = $lastEntity->orderBy('public_id', 'DESC') @@ -43,6 +67,10 @@ class EntityModel extends Eloquent return $entity; } + /** + * @param $publicId + * @return mixed + */ public static function getPrivateId($publicId) { $className = get_called_class(); @@ -50,6 +78,9 @@ class EntityModel extends Eloquent return $className::scope($publicId)->withTrashed()->value('id'); } + /** + * @return string + */ public function getActivityKey() { return '[' . $this->getEntityType().':'.$this->public_id.':'.$this->getDisplayName() . ']'; @@ -67,6 +98,12 @@ class EntityModel extends Eloquent } */ + /** + * @param $query + * @param bool $publicId + * @param bool $accountId + * @return mixed + */ public function scopeScope($query, $publicId = false, $accountId = false) { if (!$accountId) { @@ -83,38 +120,51 @@ class EntityModel extends Eloquent } } - return $query; - } - - public function scopeViewable($query) - { if (Auth::check() && ! Auth::user()->hasPermission('view_all')) { - $query->where($this->getEntityType(). 's.user_id', '=', Auth::user()->id); + $query->where(Utils::pluralizeEntityType($this->getEntityType()) . '.user_id', '=', Auth::user()->id); } return $query; } + /** + * @param $query + * @return mixed + */ public function scopeWithArchived($query) { return $query->withTrashed()->where('is_deleted', '=', false); } + /** + * @return mixed + */ public function getName() { return $this->public_id; } + /** + * @return mixed + */ public function getDisplayName() { return $this->getName(); } + /** + * @param $entityType + * @return string + */ public static function getClassName($entityType) { return 'App\\Models\\' . ucwords(Utils::toCamelCase($entityType)); } + /** + * @param $entityType + * @return string + */ public static function getTransformerName($entityType) { return 'App\\Ninja\\Transformers\\' . ucwords(Utils::toCamelCase($entityType)) . 'Transformer'; @@ -130,6 +180,9 @@ class EntityModel extends Eloquent } // converts "App\Models\Client" to "client_id" + /** + * @return string + */ public function getKeyField() { $class = get_class($this); diff --git a/app/Models/Expense.php b/app/Models/Expense.php index ccb4ccb684..d5ad0e0405 100644 --- a/app/Models/Expense.php +++ b/app/Models/Expense.php @@ -6,15 +6,27 @@ use App\Events\ExpenseWasCreated; use App\Events\ExpenseWasUpdated; use App\Events\ExpenseWasDeleted; +/** + * Class Expense + */ class Expense extends EntityModel { // Expenses use SoftDeletes; use PresentableTrait; + /** + * @var array + */ protected $dates = ['deleted_at']; + /** + * @var string + */ protected $presenter = 'App\Ninja\Presenters\ExpensePresenter'; + /** + * @var array + */ protected $fillable = [ 'client_id', 'vendor_id', @@ -27,37 +39,72 @@ class Expense extends EntityModel 'public_notes', 'bank_id', 'transaction_id', + 'expense_category_id', + 'tax_rate1', + 'tax_name1', + 'tax_rate2', + 'tax_name2', ]; + + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function expense_category() + { + return $this->belongsTo('App\Models\ExpenseCategory')->withTrashed(); + } + + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function account() { return $this->belongsTo('App\Models\Account'); } + /** + * @return mixed + */ public function user() { return $this->belongsTo('App\Models\User')->withTrashed(); } + /** + * @return mixed + */ public function vendor() { return $this->belongsTo('App\Models\Vendor')->withTrashed(); } + /** + * @return mixed + */ public function client() { return $this->belongsTo('App\Models\Client')->withTrashed(); } + /** + * @return mixed + */ public function invoice() { return $this->belongsTo('App\Models\Invoice')->withTrashed(); } + /** + * @return mixed + */ public function documents() { return $this->hasMany('App\Models\Document')->orderBy('id'); } + /** + * @return mixed + */ public function getName() { if($this->expense_number) @@ -66,31 +113,49 @@ class Expense extends EntityModel return $this->public_id; } + /** + * @return mixed + */ public function getDisplayName() { return $this->getName(); } + /** + * @return string + */ public function getRoute() { return "/expenses/{$this->public_id}"; } + /** + * @return mixed + */ public function getEntityType() { return ENTITY_EXPENSE; } + /** + * @return bool + */ public function isExchanged() { return $this->invoice_currency_id != $this->expense_currency_id; } + /** + * @return float + */ public function convertedAmount() { return round($this->amount * $this->exchange_rate, 2); } + /** + * @return array + */ public function toArray() { $array = parent::toArray(); @@ -99,6 +164,20 @@ class Expense extends EntityModel return $array; } + + /** + * @param $query + * @param null $bankdId + * @return mixed + */ + public function scopeBankId($query, $bankdId = null) + { + if ($bankdId) { + $query->whereBankId($bankId); + } + + return $query; + } } Expense::creating(function ($expense) { diff --git a/app/Models/ExpenseCategory.php b/app/Models/ExpenseCategory.php new file mode 100644 index 0000000000..fd66cdee7f --- /dev/null +++ b/app/Models/ExpenseCategory.php @@ -0,0 +1,44 @@ +belongsTo('App\Models\Expense'); + } + + /** + * @return string + */ + public function getRoute() + { + return "/expense_categories/{$this->public_id}/edit"; + } + +} diff --git a/app/Models/Font.php b/app/Models/Font.php index b9518a91ba..442daeaae2 100644 --- a/app/Models/Font.php +++ b/app/Models/Font.php @@ -2,7 +2,13 @@ use Eloquent; +/** + * Class Font + */ class Font extends Eloquent { + /** + * @var bool + */ public $timestamps = false; } diff --git a/app/Models/Frequency.php b/app/Models/Frequency.php index b4a7b5c339..d4072f3b80 100644 --- a/app/Models/Frequency.php +++ b/app/Models/Frequency.php @@ -2,7 +2,13 @@ use Eloquent; +/** + * Class Frequency + */ class Frequency extends Eloquent { + /** + * @var bool + */ public $timestamps = false; } diff --git a/app/Models/Gateway.php b/app/Models/Gateway.php index 681e8315c5..c13065c73e 100644 --- a/app/Models/Gateway.php +++ b/app/Models/Gateway.php @@ -4,18 +4,57 @@ use Eloquent; use Omnipay; use Utils; +/** + * Class Gateway + */ class Gateway extends Eloquent { + /** + * @var bool + */ public $timestamps = true; - public static $paymentTypes = [ - PAYMENT_TYPE_CREDIT_CARD, - PAYMENT_TYPE_PAYPAL, - PAYMENT_TYPE_BITCOIN, - PAYMENT_TYPE_DIRECT_DEBIT, - PAYMENT_TYPE_DWOLLA, + /** + * @var array + */ + public static $gatewayTypes = [ + GATEWAY_TYPE_CREDIT_CARD, + GATEWAY_TYPE_BANK_TRANSFER, + GATEWAY_TYPE_PAYPAL, + GATEWAY_TYPE_BITCOIN, + GATEWAY_TYPE_DWOLLA, + GATEWAY_TYPE_TOKEN, ]; + // these will appear in the primary gateway select + // the rest are shown when selecting 'more options' + /** + * @var array + */ + public static $preferred = [ + GATEWAY_PAYPAL_EXPRESS, + GATEWAY_BITPAY, + GATEWAY_DWOLLA, + GATEWAY_STRIPE, + GATEWAY_BRAINTREE, + GATEWAY_AUTHORIZE_NET, + GATEWAY_MOLLIE, + ]; + + // allow adding these gateway if another gateway + // is already configured + /** + * @var array + */ + public static $alternate = [ + GATEWAY_PAYPAL_EXPRESS, + GATEWAY_BITPAY, + GATEWAY_DWOLLA, + ]; + + /** + * @var array + */ public static $hiddenFields = [ // PayPal 'headerImageUrl', @@ -28,6 +67,9 @@ class Gateway extends Eloquent 'returnUrl', ]; + /** + * @var array + */ public static $optionalFields = [ // PayPal 'testMode', @@ -36,36 +78,75 @@ class Gateway extends Eloquent 'sandbox', ]; + /** + * @return string + */ public function getLogoUrl() { return '/images/gateways/logo_'.$this->provider.'.png'; } + /** + * @param $gatewayId + * @return bool + */ public function isGateway($gatewayId) { return $this->id == $gatewayId; } + /** + * @param $type + * @return string + */ public static function getPaymentTypeName($type) { return Utils::toCamelCase(strtolower(str_replace('PAYMENT_TYPE_', '', $type))); } - /* - public static function getPaymentTypeLinks() { - $data = []; - foreach (self::$paymentTypes as $type) { - $data[] = Utils::toCamelCase(strtolower(str_replace('PAYMENT_TYPE_', '', $type))); - } - return $data; - } - */ + /** + * @param $gatewayIds + * @return int + */ + public static function hasStandardGateway($gatewayIds) + { + $diff = array_diff($gatewayIds, static::$alternate); + return count($diff); + } + + /** + * @param $query + * @param $accountGatewaysIds + */ + public function scopePrimary($query, $accountGatewaysIds) + { + $query->where('payment_library_id', '=', 1) + ->where('id', '!=', GATEWAY_WEPAY) + ->whereIn('id', static::$preferred) + ->whereIn('id', $accountGatewaysIds); + } + + /** + * @param $query + * @param $accountGatewaysIds + */ + public function scopeSecondary($query, $accountGatewaysIds) + { + $query->where('payment_library_id', '=', 1) + ->where('id', '!=', GATEWAY_WEPAY) + ->whereNotIn('id', static::$preferred) + ->whereIn('id', $accountGatewaysIds); + } + + /** + * @return string|\Symfony\Component\Translation\TranslatorInterface + */ public function getHelp() { $link = ''; - if ($this->id == GATEWAY_AUTHORIZE_NET || $this->id == GATEWAY_AUTHORIZE_NET_SIM) { + if ($this->id == GATEWAY_AUTHORIZE_NET) { $link = 'http://reseller.authorize.net/application/?id=5560364'; } elseif ($this->id == GATEWAY_PAYPAL_EXPRESS) { $link = 'https://www.paypal.com/us/cgi-bin/webscr?cmd=_login-api-run'; @@ -80,31 +161,19 @@ class Gateway extends Eloquent } $key = 'texts.gateway_help_'.$this->id; - $str = trans($key, ['link' => "Click here"]); + $str = trans($key, [ + 'link' => "Click here", + 'complete_link' => url('/complete'), + ]); return $key != $str ? $str : ''; } + /** + * @return mixed + */ public function getFields() { return Omnipay::create($this->provider)->getDefaultParameters(); } - - public static function getPaymentType($gatewayId) { - if ($gatewayId == GATEWAY_PAYPAL_EXPRESS) { - return PAYMENT_TYPE_PAYPAL; - } else if ($gatewayId == GATEWAY_BITPAY) { - return PAYMENT_TYPE_BITCOIN; - } else if ($gatewayId == GATEWAY_DWOLLA) { - return PAYMENT_TYPE_DWOLLA; - }else if ($gatewayId == GATEWAY_GOCARDLESS) { - return PAYMENT_TYPE_DIRECT_DEBIT; - } else { - return PAYMENT_TYPE_CREDIT_CARD; - } - } - - public static function getPrettyPaymentType($gatewayId) { - return trans('texts.' . strtolower(Gateway::getPaymentType($gatewayId))); - } } diff --git a/app/Models/Industry.php b/app/Models/Industry.php index fe2d1fa1e2..be4920b151 100644 --- a/app/Models/Industry.php +++ b/app/Models/Industry.php @@ -2,10 +2,19 @@ use Eloquent; +/** + * Class Industry + */ class Industry extends Eloquent { + /** + * @var bool + */ public $timestamps = false; + /** + * @return mixed + */ public function getName() { return $this->name; diff --git a/app/Models/Invitation.php b/app/Models/Invitation.php index becd0197c9..d2d4abb026 100644 --- a/app/Models/Invitation.php +++ b/app/Models/Invitation.php @@ -4,26 +4,44 @@ use Utils; use Carbon; use Illuminate\Database\Eloquent\SoftDeletes; +/** + * Class Invitation + */ class Invitation extends EntityModel { use SoftDeletes; + /** + * @var array + */ protected $dates = ['deleted_at']; + /** + * @return mixed + */ public function invoice() { return $this->belongsTo('App\Models\Invoice')->withTrashed(); } + /** + * @return mixed + */ public function contact() { return $this->belongsTo('App\Models\Contact')->withTrashed(); } + /** + * @return mixed + */ public function user() { return $this->belongsTo('App\Models\User')->withTrashed(); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function account() { return $this->belongsTo('App\Models\Account'); @@ -31,15 +49,20 @@ class Invitation extends EntityModel // If we're getting the link for PhantomJS to generate the PDF // we need to make sure it's served from our site + /** + * @param string $type + * @param bool $forceOnsite + * @return string + */ public function getLink($type = 'view', $forceOnsite = false) { - if (!$this->account) { + if ( ! $this->account) { $this->load('account'); } - $url = SITE_URL; + $url = trim(SITE_URL, '/'); $iframe_url = $this->account->iframe_url; - + if ($this->account->hasFeature(FEATURE_CUSTOM_URL)) { if ($iframe_url && !$forceOnsite) { return "{$iframe_url}?{$this->invitation_key}"; @@ -47,10 +70,13 @@ class Invitation extends EntityModel $url = Utils::replaceSubdomain($url, $this->account->subdomain); } } - + return "{$url}/{$type}/{$this->invitation_key}"; } + /** + * @return bool|string + */ public function getStatus() { $hasValue = false; @@ -64,17 +90,23 @@ class Invitation extends EntityModel $date = Utils::dateToString($this->$field); $hasValue = true; } - $parts[] = trans('texts.invitation_status.' . $status) . ': ' . $date; + $parts[] = trans('texts.invitation_status_' . $status) . ': ' . $date; } return $hasValue ? implode($parts, '
    ') : false; } + /** + * @return mixed + */ public function getName() { return $this->invitation_key; } + /** + * @param null $messageId + */ public function markSent($messageId = null) { $this->message_id = $messageId; diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php index db0cae513f..432e811bff 100644 --- a/app/Models/Invoice.php +++ b/app/Models/Invoice.php @@ -2,11 +2,8 @@ use Utils; use DateTime; -use URL; use Illuminate\Database\Eloquent\SoftDeletes; use Laracasts\Presenter\PresentableTrait; -use App\Models\BalanceAffecting; -use App\Models\Client; use App\Events\QuoteWasCreated; use App\Events\QuoteWasUpdated; use App\Events\InvoiceWasCreated; @@ -14,6 +11,9 @@ use App\Events\InvoiceWasUpdated; use App\Events\InvoiceInvitationWasEmailed; use App\Events\QuoteInvitationWasEmailed; +/** + * Class Invoice + */ class Invoice extends EntityModel implements BalanceAffecting { use PresentableTrait; @@ -22,9 +22,18 @@ class Invoice extends EntityModel implements BalanceAffecting SoftDeletes::trashed as parentTrashed; } + /** + * @var string + */ protected $presenter = 'App\Ninja\Presenters\InvoicePresenter'; + /** + * @var array + */ protected $dates = ['deleted_at']; + /** + * @var array + */ protected $fillable = [ 'tax_name1', 'tax_rate1', @@ -32,14 +41,20 @@ class Invoice extends EntityModel implements BalanceAffecting 'tax_rate2', ]; + /** + * @var array + */ protected $casts = [ 'is_recurring' => 'boolean', 'has_tasks' => 'boolean', - 'auto_bill' => 'boolean', + 'client_enable_auto_bill' => 'boolean', 'has_expenses' => 'boolean', ]; // used for custom invoice numbers + /** + * @var array + */ public static $patternFields = [ 'counter', 'custom1', @@ -49,14 +64,38 @@ class Invoice extends EntityModel implements BalanceAffecting 'date:', ]; + /** + * @var string + */ public static $fieldInvoiceNumber = 'invoice_number'; + /** + * @var string + */ public static $fieldInvoiceDate = 'invoice_date'; + /** + * @var string + */ public static $fieldDueDate = 'due_date'; + /** + * @var string + */ public static $fieldAmount = 'amount'; + /** + * @var string + */ public static $fieldPaid = 'paid'; + /** + * @var string + */ public static $fieldNotes = 'notes'; + /** + * @var string + */ public static $fieldTerms = 'terms'; + /** + * @return array + */ public static function getImportColumns() { return [ @@ -71,6 +110,9 @@ class Invoice extends EntityModel implements BalanceAffecting ]; } + /** + * @return array + */ public static function getImportMap() { return [ @@ -83,22 +125,35 @@ class Invoice extends EntityModel implements BalanceAffecting 'notes' => 'notes', ]; } + + /** + * @return string + */ public function getRoute() { $entityType = $this->getEntityType(); return "/{$entityType}s/{$this->public_id}/edit"; } + /** + * @return mixed + */ public function getDisplayName() { return $this->is_recurring ? trans('texts.recurring') : $this->invoice_number; } + /** + * @return bool + */ public function affectsBalance() { - return !$this->is_quote && !$this->is_recurring; + return $this->isType(INVOICE_TYPE_STANDARD) && !$this->is_recurring; } + /** + * @return float|int + */ public function getAdjustment() { if (!$this->affectsBalance()) { @@ -108,11 +163,17 @@ class Invoice extends EntityModel implements BalanceAffecting return $this->getRawAdjustment(); } + /** + * @return float + */ private function getRawAdjustment() { return floatval($this->amount) - floatval($this->getOriginal('amount')); } + /** + * @return bool + */ public function isChanged() { if ($this->getRawAdjustment() != 0) { @@ -137,9 +198,13 @@ class Invoice extends EntityModel implements BalanceAffecting return false; } + /** + * @param bool $calculate + * @return int|mixed + */ public function getAmountPaid($calculate = false) { - if ($this->is_quote || $this->is_recurring) { + if ($this->isType(INVOICE_TYPE_QUOTE) || $this->is_recurring) { return 0; } @@ -154,6 +219,9 @@ class Invoice extends EntityModel implements BalanceAffecting } } + /** + * @return bool + */ public function trashed() { if ($this->client && $this->client->trashed()) { @@ -163,77 +231,158 @@ class Invoice extends EntityModel implements BalanceAffecting return self::parentTrashed(); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function account() { return $this->belongsTo('App\Models\Account'); } + /** + * @return mixed + */ public function user() { return $this->belongsTo('App\Models\User')->withTrashed(); } + /** + * @return mixed + */ public function client() { return $this->belongsTo('App\Models\Client')->withTrashed(); } + /** + * @return mixed + */ public function invoice_items() { return $this->hasMany('App\Models\InvoiceItem')->orderBy('id'); } + /** + * @return mixed + */ public function documents() { return $this->hasMany('App\Models\Document')->orderBy('id'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function invoice_status() { return $this->belongsTo('App\Models\InvoiceStatus'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function invoice_design() { return $this->belongsTo('App\Models\InvoiceDesign'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ public function payments() { return $this->hasMany('App\Models\Payment', 'invoice_id', 'id'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function recurring_invoice() { return $this->belongsTo('App\Models\Invoice'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ public function recurring_invoices() { return $this->hasMany('App\Models\Invoice', 'recurring_invoice_id'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function frequency() { return $this->belongsTo('App\Models\Frequency'); } + /** + * @return mixed + */ public function invitations() { return $this->hasMany('App\Models\Invitation')->orderBy('invitations.contact_id'); } + /** + * @return mixed + */ public function expenses() { return $this->hasMany('App\Models\Expense','invoice_id','id')->withTrashed(); } + /** + * @param $query + * @return mixed + */ public function scopeInvoices($query) { - return $query->where('is_quote', '=', false) + return $query->where('invoice_type_id', '=', INVOICE_TYPE_STANDARD) ->where('is_recurring', '=', false); } + /** + * @param $query + * @return mixed + */ + public function scopeQuotes($query) + { + return $query->where('invoice_type_id', '=', INVOICE_TYPE_QUOTE) + ->where('is_recurring', '=', false); + } + + /** + * @param $query + * @param $typeId + * @return mixed + */ + public function scopeInvoiceType($query, $typeId) + { + return $query->where('invoice_type_id', '=', $typeId); + } + + /** + * @param $typeId + * @return bool + */ + public function isType($typeId) { + return $this->invoice_type_id == $typeId; + } + + /** + * @return bool + */ + public function isQuote() { + return $this->isType(INVOICE_TYPE_QUOTE); + } + + /** + * @param bool $notify + */ public function markInvitationsSent($notify = false) { foreach ($this->invitations as $invitation) { @@ -241,6 +390,11 @@ class Invoice extends EntityModel implements BalanceAffecting } } + /** + * @param $invitation + * @param bool $messageId + * @param bool $notify + */ public function markInvitationSent($invitation, $messageId = false, $notify = true) { if (!$this->isSent()) { @@ -256,7 +410,7 @@ class Invoice extends EntityModel implements BalanceAffecting return; } - if ($this->is_quote) { + if ($this->isType(INVOICE_TYPE_QUOTE)) { event(new QuoteInvitationWasEmailed($invitation)); } else { event(new InvoiceInvitationWasEmailed($invitation)); @@ -271,6 +425,9 @@ class Invoice extends EntityModel implements BalanceAffecting } } + /** + * @param bool $save + */ public function updatePaidStatus($save = true) { $statusId = false; @@ -292,12 +449,16 @@ class Invoice extends EntityModel implements BalanceAffecting public function markApproved() { - if ($this->is_quote) { + if ($this->isType(INVOICE_TYPE_QUOTE)) { $this->invoice_status_id = INVOICE_STATUS_APPROVED; $this->save(); } } + /** + * @param $balanceAdjustment + * @param int $partial + */ public function updateBalances($balanceAdjustment, $partial = 0) { if ($this->is_deleted) { @@ -313,57 +474,91 @@ class Invoice extends EntityModel implements BalanceAffecting $this->save(); } + /** + * @return mixed + */ public function getName() { return $this->is_recurring ? trans('texts.recurring') : $this->invoice_number; } + /** + * @return string + */ public function getFileName() { $entityType = $this->getEntityType(); return trans("texts.$entityType") . '_' . $this->invoice_number . '.pdf'; } + /** + * @return string + */ public function getPDFPath() { return storage_path() . '/pdfcache/cache-' . $this->id . '.pdf'; } + /** + * @param $invoice + * @return string + */ public static function calcLink($invoice) { return link_to('invoices/' . $invoice->public_id, $invoice->invoice_number); } + /** + * @return string + */ public function getLink() { return self::calcLink($this); } + /** + * @return mixed + */ public function getEntityType() { - return $this->is_quote ? ENTITY_QUOTE : ENTITY_INVOICE; + return $this->isType(INVOICE_TYPE_QUOTE) ? ENTITY_QUOTE : ENTITY_INVOICE; } + /** + * @return bool + */ public function isSent() { return $this->invoice_status_id >= INVOICE_STATUS_SENT; } + /** + * @return bool + */ public function isViewed() { return $this->invoice_status_id >= INVOICE_STATUS_VIEWED; } + /** + * @return bool + */ public function isPartial() { return $this->invoice_status_id >= INVOICE_STATUS_PARTIAL; } + /** + * @return bool + */ public function isPaid() { return $this->invoice_status_id >= INVOICE_STATUS_PAID; } + /** + * @return bool + */ public function isOverdue() { if ( ! $this->due_date) { @@ -373,11 +568,17 @@ class Invoice extends EntityModel implements BalanceAffecting return time() > strtotime($this->due_date); } + /** + * @return mixed + */ public function getRequestedAmount() { return $this->partial > 0 ? $this->partial : $this->balance; } + /** + * @return string + */ public function getCurrencyCode() { if ($this->client->currency) { @@ -389,6 +590,9 @@ class Invoice extends EntityModel implements BalanceAffecting } } + /** + * @return $this + */ public function hidePrivateFields() { $this->setVisible([ @@ -416,7 +620,7 @@ class Invoice extends EntityModel implements BalanceAffecting 'invoice_design_id', 'invoice_fonts', 'features', - 'is_quote', + 'invoice_type_id', 'custom_value1', 'custom_value2', 'custom_taxes1', @@ -532,6 +736,10 @@ class Invoice extends EntityModel implements BalanceAffecting return $this; } + /** + * @return bool|\Recurr\RecurrenceCollection + * @throws \Recurr\Exception\MissingData + */ public function getSchedule() { if (!$this->start_date || !$this->is_recurring || !$this->frequency_id) { @@ -562,6 +770,9 @@ class Invoice extends EntityModel implements BalanceAffecting return $dates; } + /** + * @return null + */ public function getNextSendDate() { if ($this->start_date && !$this->last_sent_date) { @@ -580,6 +791,10 @@ class Invoice extends EntityModel implements BalanceAffecting return $schedule[1]->getStart(); } + /** + * @param null $invoice_date + * @return mixed|null + */ public function getDueDate($invoice_date = null){ if(!$this->is_recurring) { return $this->due_date ? $this->due_date : null; @@ -640,8 +855,8 @@ class Invoice extends EntityModel implements BalanceAffecting $dueDate = mktime(0, 0, 0, $dueMonth, $dueDay, $dueYear); } else if($monthVal == 2) {// February; day of week - $ordinals = array('first', 'second', 'third', 'fourth'); - $daysOfWeek = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'); + $ordinals = ['first', 'second', 'third', 'fourth']; + $daysOfWeek = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday']; $ordinalIndex = ceil($dayVal / 7) - 1;// 1-7 are "first"; 8-14 are "second", etc. $dayOfWeekIndex = ($dayVal - 1) % 7;// 1,8,15,22 are Sunday, 2,9,16,23 are Monday, etc. @@ -668,6 +883,11 @@ class Invoice extends EntityModel implements BalanceAffecting return null; } + /** + * @param int $min + * @param int $max + * @return null + */ public function getPrettySchedule($min = 1, $max = 10) { if (!$schedule = $this->getSchedule($max)) { @@ -692,6 +912,9 @@ class Invoice extends EntityModel implements BalanceAffecting return implode('
    ', $dates); } + /** + * @return string + */ private function getRecurrenceRule() { $rule = ''; @@ -738,9 +961,16 @@ class Invoice extends EntityModel implements BalanceAffecting } */ + /** + * @return bool + */ public function shouldSendToday() { - if (!$this->start_date || strtotime($this->start_date) > strtotime('now')) { + if ( ! $this->user->confirmed) { + return false; + } + + if ( ! $this->start_date || strtotime($this->start_date) > strtotime('now')) { return false; } @@ -760,7 +990,7 @@ class Invoice extends EntityModel implements BalanceAffecting $date1 = new DateTime($this->last_sent_date); $date2 = new DateTime(); $diff = $date2->diff($date1); - $daysSinceLastSent = $diff->format("%a"); + $daysSinceLastSent = $diff->format('%a'); $monthsSinceLastSent = ($diff->format('%y') * 12) + $diff->format('%m'); if ($daysSinceLastSent == 0) { @@ -790,6 +1020,9 @@ class Invoice extends EntityModel implements BalanceAffecting return false; } + /** + * @return bool|string + */ public function getPDFString() { if (!env('PHANTOMJS_CLOUD_KEY')) { @@ -817,6 +1050,11 @@ class Invoice extends EntityModel implements BalanceAffecting return Utils::decodePDF($pdfString); } + /** + * @param $invoiceItem + * @param $invoiceTotal + * @return float|int + */ public function getItemTaxable($invoiceItem, $invoiceTotal) { $total = $invoiceItem->qty * $invoiceItem->cost; @@ -833,6 +1071,9 @@ class Invoice extends EntityModel implements BalanceAffecting return $total; } + /** + * @return float|int|mixed + */ public function getTaxable() { $total = 0; @@ -863,6 +1104,10 @@ class Invoice extends EntityModel implements BalanceAffecting // if $calculatePaid is true we'll loop through each payment to // determine the sum, otherwise we'll use the cached paid_to_date amount + /** + * @param bool $calculatePaid + * @return array + */ public function getTaxes($calculatePaid = false) { $taxes = []; @@ -899,7 +1144,14 @@ class Invoice extends EntityModel implements BalanceAffecting return $taxes; } - + + /** + * @param $taxes + * @param $name + * @param $rate + * @param $amount + * @param $paid + */ private function calculateTax(&$taxes, $name, $rate, $amount, $paid) { if ( ! $amount) { @@ -923,17 +1175,40 @@ class Invoice extends EntityModel implements BalanceAffecting $taxes[$key]['paid'] += $paid; } + /** + * @return bool + */ public function hasDocuments(){ if(count($this->documents))return true; return $this->hasExpenseDocuments(); } + /** + * @return bool + */ public function hasExpenseDocuments(){ foreach($this->expenses as $expense){ if(count($expense->documents))return true; } return false; } + + /** + * @return bool + */ + public function getAutoBillEnabled() { + if (!$this->is_recurring) { + $recurInvoice = $this->recurring_invoice; + } else { + $recurInvoice = $this; + } + + if (!$recurInvoice) { + return false; + } + + return $recurInvoice->auto_bill == AUTO_BILL_ALWAYS || ($recurInvoice->auto_bill != AUTO_BILL_OFF && $recurInvoice->client_enable_auto_bill); + } } Invoice::creating(function ($invoice) { @@ -943,7 +1218,7 @@ Invoice::creating(function ($invoice) { }); Invoice::created(function ($invoice) { - if ($invoice->is_quote) { + if ($invoice->isType(INVOICE_TYPE_QUOTE)) { event(new QuoteWasCreated($invoice)); } else { event(new InvoiceWasCreated($invoice)); @@ -951,7 +1226,7 @@ Invoice::created(function ($invoice) { }); Invoice::updating(function ($invoice) { - if ($invoice->is_quote) { + if ($invoice->isType(INVOICE_TYPE_QUOTE)) { event(new QuoteWasUpdated($invoice)); } else { event(new InvoiceWasUpdated($invoice)); diff --git a/app/Models/InvoiceDesign.php b/app/Models/InvoiceDesign.php index 51f15b035a..c89c14f38f 100644 --- a/app/Models/InvoiceDesign.php +++ b/app/Models/InvoiceDesign.php @@ -3,12 +3,20 @@ use Eloquent; use Auth; use Cache; -use App\Models\InvoiceDesign; +/** + * Class InvoiceDesign + */ class InvoiceDesign extends Eloquent { + /** + * @var bool + */ public $timestamps = false; + /** + * @return mixed + */ public static function getDesigns() { $account = Auth::user()->account; diff --git a/app/Models/InvoiceItem.php b/app/Models/InvoiceItem.php index e80482bafd..6598a24bed 100644 --- a/app/Models/InvoiceItem.php +++ b/app/Models/InvoiceItem.php @@ -2,11 +2,20 @@ use Illuminate\Database\Eloquent\SoftDeletes; +/** + * Class InvoiceItem + */ class InvoiceItem extends EntityModel { use SoftDeletes; + /** + * @var array + */ protected $dates = ['deleted_at']; + /** + * @var array + */ protected $fillable = [ 'tax_name1', 'tax_rate1', @@ -14,21 +23,33 @@ class InvoiceItem extends EntityModel 'tax_rate2', ]; + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function invoice() { return $this->belongsTo('App\Models\Invoice'); } + /** + * @return mixed + */ public function user() { return $this->belongsTo('App\Models\User')->withTrashed(); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function product() { return $this->belongsTo('App\Models\Product'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function account() { return $this->belongsTo('App\Models\Account'); diff --git a/app/Models/InvoiceStatus.php b/app/Models/InvoiceStatus.php index 36164d26c6..24948f8451 100644 --- a/app/Models/InvoiceStatus.php +++ b/app/Models/InvoiceStatus.php @@ -2,7 +2,13 @@ use Eloquent; +/** + * Class InvoiceStatus + */ class InvoiceStatus extends Eloquent { + /** + * @var bool + */ public $timestamps = false; } diff --git a/app/Models/Language.php b/app/Models/Language.php index 084c2fe86d..efce90844f 100644 --- a/app/Models/Language.php +++ b/app/Models/Language.php @@ -2,10 +2,19 @@ use Eloquent; +/** + * Class Language + */ class Language extends Eloquent { + /** + * @var bool + */ public $timestamps = false; + /** + * @return mixed + */ public function getName() { return $this->name; diff --git a/app/Models/License.php b/app/Models/License.php index 93898f8d7d..39b82b7ecc 100644 --- a/app/Models/License.php +++ b/app/Models/License.php @@ -3,9 +3,18 @@ use Eloquent; use Illuminate\Database\Eloquent\SoftDeletes; +/** + * Class License + */ class License extends Eloquent { + /** + * @var bool + */ public $timestamps = true; use SoftDeletes; + /** + * @var array + */ protected $dates = ['deleted_at']; } diff --git a/app/Models/OwnedByClientTrait.php b/app/Models/OwnedByClientTrait.php index 7f11448324..dc6e6208ae 100644 --- a/app/Models/OwnedByClientTrait.php +++ b/app/Models/OwnedByClientTrait.php @@ -1,7 +1,13 @@ client) { diff --git a/app/Models/Payment.php b/app/Models/Payment.php index a2e8b2591f..c6aa790fac 100644 --- a/app/Models/Payment.php +++ b/app/Models/Payment.php @@ -1,57 +1,114 @@ belongsTo('App\Models\Invoice')->withTrashed(); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function invitation() { return $this->belongsTo('App\Models\Invitation'); } + /** + * @return mixed + */ public function client() { return $this->belongsTo('App\Models\Client')->withTrashed(); } + /** + * @return mixed + */ public function user() { return $this->belongsTo('App\Models\User')->withTrashed(); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function account() { return $this->belongsTo('App\Models\Account'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function contact() { return $this->belongsTo('App\Models\Contact'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function account_gateway() { return $this->belongsTo('App\Models\AccountGateway'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function payment_type() { return $this->belongsTo('App\Models\PaymentType'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function payment_method() + { + return $this->belongsTo('App\Models\PaymentMethod'); + } + + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function payment_status() + { + return $this->belongsTo('App\Models\PaymentStatus'); + } + + /** + * @return string + */ public function getRoute() { return "/payments/{$this->public_id}/edit"; @@ -64,21 +121,181 @@ class Payment extends EntityModel } */ + /** + * @return mixed + */ public function getName() { return trim("payment {$this->transaction_reference}"); } + /** + * @return bool + */ + public function isPending() + { + return $this->payment_status_id == PAYMENT_STATUS_PENDING; + } + + /** + * @return bool + */ + public function isFailed() + { + return $this->payment_status_id == PAYMENT_STATUS_FAILED; + } + + /** + * @return bool + */ + public function isCompleted() + { + return $this->payment_status_id == PAYMENT_STATUS_COMPLETED; + } + + /** + * @return bool + */ + public function isPartiallyRefunded() + { + return $this->payment_status_id == PAYMENT_STATUS_PARTIALLY_REFUNDED; + } + + /** + * @return bool + */ + public function isRefunded() + { + return $this->payment_status_id == PAYMENT_STATUS_REFUNDED; + } + + /** + * @return bool + */ + public function isVoided() + { + return $this->payment_status_id == PAYMENT_STATUS_VOIDED; + } + + /** + * @param null $amount + * @return bool + */ + public function recordRefund($amount = null) + { + if ($this->isRefunded() || $this->isVoided()) { + return false; + } + + if (!$amount) { + $amount = $this->amount; + } + + $new_refund = min($this->amount, $this->refunded + $amount); + $refund_change = $new_refund - $this->refunded; + + if ($refund_change) { + $this->refunded = $new_refund; + $this->payment_status_id = $this->refunded == $this->amount ? PAYMENT_STATUS_REFUNDED : PAYMENT_STATUS_PARTIALLY_REFUNDED; + $this->save(); + + Event::fire(new PaymentWasRefunded($this, $refund_change)); + } + + return true; + } + + /** + * @return bool + */ + public function markVoided() + { + if ($this->isVoided() || $this->isPartiallyRefunded() || $this->isRefunded()) { + return false; + } + + $this->refunded = $this->amount; + $this->payment_status_id = PAYMENT_STATUS_VOIDED; + $this->save(); + + Event::fire(new PaymentWasVoided($this)); + + return true; + } + + public function markComplete() + { + $this->payment_status_id = PAYMENT_STATUS_COMPLETED; + $this->save(); + Event::fire(new PaymentCompleted($this)); + } + + /** + * @param string $failureMessage + */ + public function markFailed($failureMessage = '') + { + $this->payment_status_id = PAYMENT_STATUS_FAILED; + $this->gateway_error = $failureMessage; + $this->save(); + Event::fire(new PaymentFailed($this)); + } + + /** + * @return mixed + */ public function getEntityType() { return ENTITY_PAYMENT; } + + /** + * @return mixed + */ + public function getCompletedAmount() + { + return $this->amount - $this->refunded; + } + + /** + * @return mixed|null|\stdClass|string + */ + public function getBankDataAttribute() + { + if (!$this->routing_number) { + return null; + } + return PaymentMethod::lookupBankData($this->routing_number); + } + + /** + * @param $bank_name + * @return null + */ + public function getBankNameAttribute($bank_name) + { + if ($bank_name) { + return $bank_name; + } + $bankData = $this->bank_data; + + return $bankData?$bankData->name:null; + } + + /** + * @param $value + * @return null|string + */ + public function getLast4Attribute($value) + { + return $value ? str_pad($value, 4, '0', STR_PAD_LEFT) : null; + } } Payment::creating(function ($payment) { - + }); Payment::created(function ($payment) { event(new PaymentWasCreated($payment)); -}); \ No newline at end of file +}); diff --git a/app/Models/PaymentLibrary.php b/app/Models/PaymentLibrary.php index 3f0f5c860d..d9445015d2 100644 --- a/app/Models/PaymentLibrary.php +++ b/app/Models/PaymentLibrary.php @@ -2,11 +2,23 @@ use Eloquent; +/** + * Class PaymentLibrary + */ class PaymentLibrary extends Eloquent { + /** + * @var string + */ protected $table = 'payment_libraries'; + /** + * @var bool + */ public $timestamps = true; + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ public function gateways() { return $this->hasMany('App\Models\Gateway', 'payment_library_id'); diff --git a/app/Models/PaymentMethod.php b/app/Models/PaymentMethod.php new file mode 100644 index 0000000000..1a0f865be1 --- /dev/null +++ b/app/Models/PaymentMethod.php @@ -0,0 +1,240 @@ +belongsTo('App\Models\Account'); + } + + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function contact() + { + return $this->belongsTo('App\Models\Contact'); + } + + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function account_gateway_token() + { + return $this->belongsTo('App\Models\AccountGatewayToken'); + } + + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function payment_type() + { + return $this->belongsTo('App\Models\PaymentType'); + } + + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function currency() + { + return $this->belongsTo('App\Models\Currency'); + } + + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function payments() + { + return $this->hasMany('App\Models\Payments'); + } + + /** + * @return mixed|null|\stdClass|string + */ + public function getBankDataAttribute() + { + if (!$this->routing_number) { + return null; + } + return static::lookupBankData($this->routing_number); + } + + /** + * @param $bank_name + * @return null + */ + public function getBankNameAttribute($bank_name) + { + if ($bank_name) { + return $bank_name; + } + $bankData = $this->bank_data; + + return $bankData?$bankData->name:null; + } + + /** + * @param $value + * @return null|string + */ + public function getLast4Attribute($value) + { + return $value ? str_pad($value, 4, '0', STR_PAD_LEFT) : null; + } + + /** + * @param $query + * @param $clientId + * @return mixed + */ + public function scopeClientId($query, $clientId) + { + return $query->with(['contact' => function($query) use ($clientId) { + return $query->whereClientId($clientId); + }]); + } + + /** + * @param $query + * @param $isBank + */ + public function scopeIsBankAccount($query, $isBank) + { + if ($isBank) { + $query->where('payment_type_id', '=', PAYMENT_TYPE_ACH); + } else { + $query->where('payment_type_id', '!=', PAYMENT_TYPE_ACH); + } + } + + /** + * @return \Illuminate\Contracts\Routing\UrlGenerator|string + */ + public function imageUrl() + { + return url(sprintf('/images/credit_cards/%s.png', str_replace(' ', '', strtolower($this->payment_type->name)))); + } + + /** + * @param $routingNumber + * @return mixed|null|\stdClass|string + */ + public static function lookupBankData($routingNumber) { + $cached = Cache::get('bankData:'.$routingNumber); + + if ($cached != null) { + return $cached == false ? null : $cached; + } + + $dataPath = base_path('vendor/gatepay/FedACHdir/FedACHdir.txt'); + + if (!file_exists($dataPath) || !$size = filesize($dataPath)) { + return 'Invalid data file'; + } + + $lineSize = 157; + $numLines = $size/$lineSize; + + if ($numLines % 1 != 0) { + // The number of lines should be an integer + return 'Invalid data file'; + } + + // Format: http://www.sco.ca.gov/Files-21C/Bank_Master_Interface_Information_Package.pdf + $file = fopen($dataPath, 'r'); + + // Binary search + $low = 0; + $high = $numLines - 1; + while ($low <= $high) { + $mid = floor(($low + $high) / 2); + + fseek($file, $mid * $lineSize); + $thisNumber = fread($file, 9); + + if ($thisNumber > $routingNumber) { + $high = $mid - 1; + } else if ($thisNumber < $routingNumber) { + $low = $mid + 1; + } else { + $data = new \stdClass(); + $data->routing_number = $thisNumber; + + fseek($file, 26, SEEK_CUR); + + $data->name = trim(fread($file, 36)); + $data->address = trim(fread($file, 36)); + $data->city = trim(fread($file, 20)); + $data->state = fread($file, 2); + $data->zip = fread($file, 5).'-'.fread($file, 4); + $data->phone = fread($file, 10); + break; + } + } + + if (!empty($data)) { + Cache::put('bankData:'.$routingNumber, $data, 5); + return $data; + } else { + Cache::put('bankData:'.$routingNumber, false, 5); + return null; + } + } + + /** + * @return bool + */ + public function requiresDelayedAutoBill() + { + return $this->payment_type_id == PAYMENT_TYPE_ACH; + } + + /** + * @return mixed + */ + public function gatewayType() + { + if ($this->payment_type_id == PAYMENT_TYPE_ACH) { + return GATEWAY_TYPE_BANK_TRANSFER; + } elseif ($this->payment_type_id == PAYMENT_TYPE_PAYPAL) { + return GATEWAY_TYPE_PAYPAL; + } else { + return GATEWAY_TYPE_TOKEN; + } + } +} + +PaymentMethod::deleting(function($paymentMethod) { + $accountGatewayToken = $paymentMethod->account_gateway_token; + if ($accountGatewayToken->default_payment_method_id == $paymentMethod->id) { + $newDefault = $accountGatewayToken->payment_methods->first(function($i, $paymentMethdod) use ($accountGatewayToken){ + return $paymentMethdod->id != $accountGatewayToken->default_payment_method_id; + }); + $accountGatewayToken->default_payment_method_id = $newDefault ? $newDefault->id : null; + $accountGatewayToken->save(); + } +}); diff --git a/app/Models/PaymentStatus.php b/app/Models/PaymentStatus.php new file mode 100644 index 0000000000..d4c06899e5 --- /dev/null +++ b/app/Models/PaymentStatus.php @@ -0,0 +1,14 @@ + 'product_key', + 'notes|description|details' => 'notes', + 'cost|amount|price' => 'cost', + ]; + } + + /** + * @return mixed + */ public function getEntityType() { return ENTITY_PRODUCT; } + /** + * @param $key + * @return mixed + */ public static function findProductByKey($key) { return Product::scope()->where('product_key', '=', $key)->first(); } + /** + * @return mixed + */ public function user() { return $this->belongsTo('App\Models\User')->withTrashed(); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function default_tax_rate() { return $this->belongsTo('App\Models\TaxRate'); diff --git a/app/Models/Size.php b/app/Models/Size.php index 99d1b12f5d..16526d83f0 100644 --- a/app/Models/Size.php +++ b/app/Models/Size.php @@ -2,10 +2,19 @@ use Eloquent; +/** + * Class Size + */ class Size extends Eloquent { + /** + * @var bool + */ public $timestamps = false; + /** + * @return mixed + */ public function getName() { return $this->name; diff --git a/app/Models/Subscription.php b/app/Models/Subscription.php index 3592ac8149..d4e0640682 100644 --- a/app/Models/Subscription.php +++ b/app/Models/Subscription.php @@ -1,12 +1,20 @@ belongsTo('App\Models\Account'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function invoice() { return $this->belongsTo('App\Models\Invoice'); } + /** + * @return mixed + */ public function user() { return $this->belongsTo('App\Models\User')->withTrashed(); } + /** + * @return mixed + */ public function client() { return $this->belongsTo('App\Models\Client')->withTrashed(); } + /** + * @param $task + * @return string + */ public static function calcStartTime($task) { $parts = json_decode($task->time_log) ?: []; @@ -43,11 +66,18 @@ class Task extends EntityModel } } + /** + * @return string + */ public function getStartTime() { return self::calcStartTime($this); } + /** + * @param $task + * @return int + */ public static function calcDuration($task) { $duration = 0; @@ -64,11 +94,17 @@ class Task extends EntityModel return $duration; } + /** + * @return int + */ public function getDuration() { return self::calcDuration($this); } + /** + * @return int + */ public function getCurrentDuration() { $parts = json_decode($this->time_log) ?: []; @@ -81,14 +117,39 @@ class Task extends EntityModel } } + /** + * @return bool + */ public function hasPreviousDuration() { $parts = json_decode($this->time_log) ?: []; return count($parts) && (count($parts[0]) && $parts[0][1]); } + /** + * @return float + */ public function getHours() { return round($this->getDuration() / (60 * 60), 2); } + + /** + * Gets the route to the tasks edit action + * + * @return string + */ + public function getRoute() + { + return "/tasks/{$this->public_id}/edit"; + } } + + +Task::created(function ($task) { + event(new TaskWasCreated($task)); +}); + +Task::updated(function ($task) { + event(new TaskWasUpdated($task)); +}); diff --git a/app/Models/TaxRate.php b/app/Models/TaxRate.php index 384ccf933b..f041c735d9 100644 --- a/app/Models/TaxRate.php +++ b/app/Models/TaxRate.php @@ -1,25 +1,48 @@ belongsTo('App\Models\User')->withTrashed(); } + + /** + * @return bool|string + */ + public function __toString() + { + return sprintf('%s: %s%%', $this->name, $this->rate); + } + } diff --git a/app/Models/Theme.php b/app/Models/Theme.php index d9a4d2419d..3cb2255a7e 100644 --- a/app/Models/Theme.php +++ b/app/Models/Theme.php @@ -2,7 +2,13 @@ use Eloquent; +/** + * Class Theme + */ class Theme extends Eloquent { + /** + * @var bool + */ public $timestamps = false; } diff --git a/app/Models/Timezone.php b/app/Models/Timezone.php index 5c00fd12da..20c4479c8b 100644 --- a/app/Models/Timezone.php +++ b/app/Models/Timezone.php @@ -2,7 +2,13 @@ use Eloquent; +/** + * Class Timezone + */ class Timezone extends Eloquent { + /** + * @var bool + */ public $timestamps = false; } diff --git a/app/Models/User.php b/app/Models/User.php index 71069d2582..e95459f384 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -1,7 +1,6 @@ 0b0001, 'view_all' => 0b0010, 'edit_all' => 0b0100, - ); - + ]; + use Authenticatable, Authorizable, CanResetPassword; /** @@ -52,28 +57,46 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac protected $hidden = ['password', 'remember_token', 'confirmation_code']; use SoftDeletes; + /** + * @var array + */ protected $dates = ['deleted_at']; + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function account() { return $this->belongsTo('App\Models\Account'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function theme() { return $this->belongsTo('App\Models\Theme'); } + /** + * @param $value + */ public function setEmailAttribute($value) { $this->attributes['email'] = $this->attributes['username'] = $value; } + /** + * @return mixed|string + */ public function getName() { return $this->getDisplayName(); } + /** + * @return mixed + */ public function getPersonType() { return PERSON_USER; @@ -109,36 +132,59 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac return $this->email; } + /** + * @return mixed + */ public function isPro() { return $this->account->isPro(); } + /** + * @param $feature + * @return mixed + */ public function hasFeature($feature) { return $this->account->hasFeature($feature); } + /** + * @return bool + */ public function isPaidPro() { return $this->isPro($accountDetails) && !$accountDetails['trial']; } + /** + * @return mixed + */ public function isTrial() { return $this->account->isTrial(); } + /** + * @param null $plan + * @return mixed + */ public function isEligibleForTrial($plan = null) { return $this->account->isEligibleForTrial($plan); } + /** + * @return int + */ public function maxInvoiceDesignId() { return $this->hasFeature(FEATURE_MORE_INVOICE_DESIGNS) ? 11 : (Utils::isNinja() ? COUNT_FREE_DESIGNS : COUNT_FREE_DESIGNS_SELF_HOST); } + /** + * @return mixed|string + */ public function getDisplayName() { if ($this->getFullName()) { @@ -150,6 +196,9 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac } } + /** + * @return string + */ public function getFullName() { if ($this->first_name || $this->last_name) { @@ -159,16 +208,27 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac } } + /** + * @return bool + */ public function showGreyBackground() { return !$this->theme_id || in_array($this->theme_id, [2, 3, 5, 6, 7, 8, 10, 11, 12]); } + /** + * @return mixed + */ public function getRequestsCount() { return Session::get(SESSION_COUNTER, 0); } - + + /** + * @param bool $success + * @param bool $forced + * @return bool + */ public function afterSave($success = true, $forced = false) { if ($this->email) { @@ -178,6 +238,9 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac } } + /** + * @return mixed + */ public function getMaxNumClients() { if ($this->hasFeature(FEATURE_MORE_CLIENTS)) { @@ -191,6 +254,9 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac return MAX_NUM_CLIENTS; } + /** + * @return mixed + */ public function getMaxNumVendors() { if ($this->hasFeature(FEATURE_MORE_CLIENTS)) { @@ -199,18 +265,27 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac return MAX_NUM_VENDORS; } - - + + + /** + * @return mixed + */ public function getRememberToken() { return $this->remember_token; } + /** + * @param string $value + */ public function setRememberToken($value) { $this->remember_token = $value; } + /** + * @return string + */ public function getRememberTokenName() { return 'remember_token'; @@ -234,6 +309,9 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac } } + /** + * @param $user + */ public static function onUpdatingUser($user) { if ($user->password != $user->getOriginal('password')) { @@ -247,6 +325,9 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac } } + /** + * @param $user + */ public static function onUpdatedUser($user) { if (!$user->getOriginal('email') @@ -259,15 +340,18 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac event(new UserSettingsChanged($user)); } + /** + * @return bool + */ public function isEmailBeingChanged() { return Utils::isNinjaProd() && $this->email != $this->getOriginal('email') && $this->getOriginal('confirmed'); } - - - + + + /** * Set the permissions attribute on the model. * @@ -277,18 +361,21 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac protected function setPermissionsAttribute($value){ if(empty($value)) { $this->attributes['permissions'] = 0; - } else { + } else { $bitmask = 0; foreach($value as $permission){ + if ( ! $permission) { + continue; + } $bitmask = $bitmask | static::$all_permissions[$permission]; } $this->attributes['permissions'] = $bitmask; } - + return $this; } - + /** * Expands the value of the permissions attribute * @@ -296,16 +383,16 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac * @return mixed */ protected function getPermissionsAttribute($value){ - $permissions = array(); + $permissions = []; foreach(static::$all_permissions as $permission => $bitmask){ if(($value & $bitmask) == $bitmask) { $permissions[$permission] = $permission; } } - + return $permissions; } - + /** * Checks to see if the user has the required permission * @@ -325,13 +412,41 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac return count(array_intersect($permission, $this->permissions)) > 0; } } - + return false; } - + + /** + * @param $entity + * @return bool + */ public function owns($entity) { return !empty($entity->user_id) && $entity->user_id == $this->id; } + + /** + * @return bool|mixed + */ + public function filterId() { + return $this->hasPermission('view_all') ? false : $this->id; + } + + + public function caddAddUsers() { + if ( ! $this->hasFeature(FEATURE_USERS)) { + return false; + } + + $account = $this->account; + $company = $account->company; + + $numUsers = 1; + foreach ($company->accounts as $account) { + $numUsers += $account->users->count() - 1; + } + + return $numUsers < $company->num_users; + } } User::updating(function ($user) { diff --git a/app/Models/UserAccount.php b/app/Models/UserAccount.php index a1cd15f89b..63200eb25f 100644 --- a/app/Models/UserAccount.php +++ b/app/Models/UserAccount.php @@ -2,10 +2,20 @@ use Eloquent; +/** + * Class UserAccount + */ class UserAccount extends Eloquent { + /** + * @var bool + */ public $timestamps = false; + /** + * @param $userId + * @return bool + */ public function hasUserId($userId) { if (!$userId) { @@ -21,6 +31,9 @@ class UserAccount extends Eloquent return false; } + /** + * @param $userId + */ public function setUserId($userId) { if (self::hasUserId($userId)) { @@ -36,6 +49,9 @@ class UserAccount extends Eloquent } } + /** + * @param $userId + */ public function removeUserId($userId) { if (!$userId || !self::hasUserId($userId)) { diff --git a/app/Models/Vendor.php b/app/Models/Vendor.php index d537b1ca9d..6a387e9246 100644 --- a/app/Models/Vendor.php +++ b/app/Models/Vendor.php @@ -2,20 +2,31 @@ use Utils; use DB; -use Carbon; use App\Events\VendorWasCreated; use App\Events\VendorWasUpdated; use App\Events\VendorWasDeleted; use Laracasts\Presenter\PresentableTrait; use Illuminate\Database\Eloquent\SoftDeletes; +/** + * Class Vendor + */ class Vendor extends EntityModel { use PresentableTrait; use SoftDeletes; + /** + * @var string + */ protected $presenter = 'App\Ninja\Presenters\VendorPresenter'; + /** + * @var array + */ protected $dates = ['deleted_at']; + /** + * @var array + */ protected $fillable = [ 'name', 'id_number', @@ -33,16 +44,46 @@ class Vendor extends EntityModel 'transaction_name', ]; + /** + * @var string + */ public static $fieldName = 'name'; + /** + * @var string + */ public static $fieldPhone = 'work_phone'; + /** + * @var string + */ public static $fieldAddress1 = 'address1'; + /** + * @var string + */ public static $fieldAddress2 = 'address2'; + /** + * @var string + */ public static $fieldCity = 'city'; + /** + * @var string + */ public static $fieldState = 'state'; + /** + * @var string + */ public static $fieldPostalCode = 'postal_code'; + /** + * @var string + */ public static $fieldNotes = 'notes'; + /** + * @var string + */ public static $fieldCountry = 'country'; + /** + * @return array + */ public static function getImportColumns() { return [ @@ -62,6 +103,9 @@ class Vendor extends EntityModel ]; } + /** + * @return array + */ public static function getImportMap() { return [ @@ -80,56 +124,91 @@ class Vendor extends EntityModel ]; } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function account() { return $this->belongsTo('App\Models\Account'); } + /** + * @return mixed + */ public function user() { return $this->belongsTo('App\Models\User')->withTrashed(); } + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ public function payments() { return $this->hasMany('App\Models\Payment'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ public function vendor_contacts() { return $this->hasMany('App\Models\VendorContact'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function country() { return $this->belongsTo('App\Models\Country'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function currency() { return $this->belongsTo('App\Models\Currency'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function language() { return $this->belongsTo('App\Models\Language'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function size() { return $this->belongsTo('App\Models\Size'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function industry() { return $this->belongsTo('App\Models\Industry'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ public function expenses() { return $this->hasMany('App\Models\Expense','vendor_id','id'); } + /** + * @param $data + * @param bool $isPrimary + * @return \Illuminate\Database\Eloquent\Model + */ public function addVendorContact($data, $isPrimary = false) { $publicId = isset($data['public_id']) ? $data['public_id'] : false; @@ -146,32 +225,50 @@ class Vendor extends EntityModel return $this->vendor_contacts()->save($contact); } + /** + * @return string + */ public function getRoute() { return "/vendors/{$this->public_id}"; } + /** + * @return mixed + */ public function getName() { return $this->name; } + /** + * @return mixed + */ public function getDisplayName() { return $this->getName(); } + /** + * @return string + */ public function getCityState() { $swap = $this->country && $this->country->swap_postal_code; return Utils::cityStateZip($this->city, $this->state, $this->postal_code, $swap); } + /** + * @return string + */ public function getEntityType() { return 'vendor'; } + /** + * @return bool + */ public function hasAddress() { $fields = [ @@ -192,6 +289,9 @@ class Vendor extends EntityModel return false; } + /** + * @return string + */ public function getDateCreated() { if ($this->created_at == '0000-00-00 00:00:00') { @@ -201,6 +301,9 @@ class Vendor extends EntityModel } } + /** + * @return mixed + */ public function getCurrencyId() { if ($this->currency_id) { @@ -214,6 +317,9 @@ class Vendor extends EntityModel return $this->account->currency_id ?: DEFAULT_CURRENCY; } + /** + * @return float|int + */ public function getTotalExpense() { return DB::table('expenses') diff --git a/app/Models/VendorContact.php b/app/Models/VendorContact.php index 6b2ad12c80..abcf4f097f 100644 --- a/app/Models/VendorContact.php +++ b/app/Models/VendorContact.php @@ -1,15 +1,26 @@ belongsTo('App\Models\Account'); } + /** + * @return mixed + */ public function user() { return $this->belongsTo('App\Models\User')->withTrashed(); } + /** + * @return mixed + */ public function vendor() { return $this->belongsTo('App\Models\Vendor')->withTrashed(); } + /** + * @return mixed + */ public function getPersonType() { return PERSON_VENDOR_CONTACT; } + /** + * @return mixed|string + */ public function getName() { return $this->getDisplayName(); } + /** + * @return mixed|string + */ public function getDisplayName() { if ($this->getFullName()) { @@ -57,6 +98,9 @@ class VendorContact extends EntityModel } } + /** + * @return string + */ public function getFullName() { if ($this->first_name || $this->last_name) { diff --git a/app/Ninja/Datatables/AccountGatewayDatatable.php b/app/Ninja/Datatables/AccountGatewayDatatable.php new file mode 100644 index 0000000000..5c7a84d3ea --- /dev/null +++ b/app/Ninja/Datatables/AccountGatewayDatatable.php @@ -0,0 +1,95 @@ +deleted_at) { + return $model->name; + } elseif ($model->gateway_id != GATEWAY_WEPAY) { + return link_to("gateways/{$model->public_id}/edit", $model->name)->toHtml(); + } else { + $accountGateway = AccountGateway::find($model->id); + $config = $accountGateway->getConfig(); + $endpoint = WEPAY_ENVIRONMENT == WEPAY_STAGE ? 'https://stage.wepay.com/' : 'https://www.wepay.com/'; + $wepayAccountId = $config->accountId; + $wepayState = isset($config->state)?$config->state:null; + $linkText = $model->name; + $url = $endpoint.'account/'.$wepayAccountId; + $html = link_to($url, $linkText, ['target'=>'_blank'])->toHtml(); + + try { + if ($wepayState == 'action_required') { + $updateUri = $endpoint.'api/account_update/'.$wepayAccountId.'?redirect_uri='.urlencode(URL::to('gateways')); + $linkText .= ' ('.trans('texts.action_required').')'; + $url = $updateUri; + $html = "{$linkText}"; + $model->setupUrl = $url; + } elseif ($wepayState == 'pending') { + $linkText .= ' ('.trans('texts.resend_confirmation_email').')'; + $model->resendConfirmationUrl = $url = URL::to("gateways/{$accountGateway->public_id}/resend_confirmation"); + $html = link_to($url, $linkText)->toHtml(); + } + } catch(\WePayException $ex){} + + return $html; + } + } + ], + ]; + } + + public function actions() + { + return [ + [ + uctrans('texts.resend_confirmation_email'), + function ($model) { + return $model->resendConfirmationUrl; + }, + function($model) { + return !$model->deleted_at && $model->gateway_id == GATEWAY_WEPAY && !empty($model->resendConfirmationUrl); + } + ], [ + uctrans('texts.finish_setup'), + function ($model) { + return $model->setupUrl; + }, + function($model) { + return !$model->deleted_at && $model->gateway_id == GATEWAY_WEPAY && !empty($model->setupUrl); + } + ] , [ + uctrans('texts.edit_gateway'), + function ($model) { + return URL::to("gateways/{$model->public_id}/edit"); + }, + function($model) { + return !$model->deleted_at; + } + ], [ + uctrans('texts.manage_wepay_account'), + function ($model) { + $accountGateway = AccountGateway::find($model->id); + $endpoint = WEPAY_ENVIRONMENT == WEPAY_STAGE ? 'https://stage.wepay.com/' : 'https://www.wepay.com/'; + return [ + 'url' => $endpoint.'account/'.$accountGateway->getConfig()->accountId, + 'attributes' => 'target="_blank"' + ]; + }, + function($model) { + return !$model->deleted_at && $model->gateway_id == GATEWAY_WEPAY; + } + ] + ]; + } + +} diff --git a/app/Ninja/Datatables/ActivityDatatable.php b/app/Ninja/Datatables/ActivityDatatable.php new file mode 100644 index 0000000000..cb87c26ae6 --- /dev/null +++ b/app/Ninja/Datatables/ActivityDatatable.php @@ -0,0 +1,50 @@ +created_at)); + } + ], + [ + 'activity_type_id', + function ($model) { + $data = [ + 'client' => link_to('/clients/' . $model->client_public_id, Utils::getClientDisplayName($model))->toHtml(), + 'user' => $model->is_system ? '' . trans('texts.system') . '' : Utils::getPersonDisplayName($model->user_first_name, $model->user_last_name, $model->user_email), + 'invoice' => $model->invoice ? link_to('/invoices/' . $model->invoice_public_id, $model->is_recurring ? trans('texts.recurring_invoice') : $model->invoice)->toHtml() : null, + 'quote' => $model->invoice ? link_to('/quotes/' . $model->invoice_public_id, $model->invoice)->toHtml() : null, + 'contact' => $model->contact_id ? link_to('/clients/' . $model->client_public_id, Utils::getClientDisplayName($model))->toHtml() : Utils::getPersonDisplayName($model->user_first_name, $model->user_last_name, $model->user_email), + 'payment' => $model->payment ?: '', + 'credit' => $model->payment_amount ? Utils::formatMoney($model->credit, $model->currency_id, $model->country_id) : '', + 'payment_amount' => $model->payment_amount ? Utils::formatMoney($model->payment_amount, $model->currency_id, $model->country_id) : null, + 'adjustment' => $model->adjustment ? Utils::formatMoney($model->adjustment, $model->currency_id, $model->country_id) : null + ]; + + return trans("texts.activity_{$model->activity_type_id}", $data); + } + ], + [ + 'balance', + function ($model) { + return Utils::formatMoney($model->balance, $model->currency_id, $model->country_id); + } + ], + [ + 'adjustment', + function ($model) { + return $model->adjustment != 0 ? Utils::wrapAdjustment($model->adjustment, $model->currency_id, $model->country_id) : ''; + } + ] + ]; + } +} diff --git a/app/Ninja/Datatables/BankAccountDatatable.php b/app/Ninja/Datatables/BankAccountDatatable.php new file mode 100644 index 0000000000..6f0eb1c00e --- /dev/null +++ b/app/Ninja/Datatables/BankAccountDatatable.php @@ -0,0 +1,40 @@ +public_id}/edit", $model->bank_name)->toHtml(); + }, + ], + [ + 'bank_library_id', + function ($model) { + return 'OFX'; + } + ], + ]; + } + + public function actions() + { + return [ + [ + uctrans('texts.edit_bank_account'), + function ($model) { + return URL::to("bank_accounts/{$model->public_id}/edit"); + }, + ] + ]; + } + + +} diff --git a/app/Ninja/Datatables/ClientDatatable.php b/app/Ninja/Datatables/ClientDatatable.php new file mode 100644 index 0000000000..4b0ca68b05 --- /dev/null +++ b/app/Ninja/Datatables/ClientDatatable.php @@ -0,0 +1,136 @@ +public_id}", $model->name ?: '')->toHtml(); + } + ], + [ + 'first_name', + function ($model) { + return link_to("clients/{$model->public_id}", $model->first_name.' '.$model->last_name)->toHtml(); + } + ], + [ + 'email', + function ($model) { + return link_to("clients/{$model->public_id}", $model->email ?: '')->toHtml(); + } + ], + [ + 'clients.created_at', + function ($model) { + return Utils::timestampToDateString(strtotime($model->created_at)); + } + ], + [ + 'last_login', + function ($model) { + return Utils::timestampToDateString(strtotime($model->last_login)); + } + ], + [ + 'balance', + function ($model) { + return Utils::formatMoney($model->balance, $model->currency_id, $model->country_id); + } + ] + ]; + } + + public function actions() + { + return [ + [ + trans('texts.edit_client'), + function ($model) { + return URL::to("clients/{$model->public_id}/edit"); + }, + function ($model) { + return Auth::user()->can('editByOwner', [ENTITY_CLIENT, $model->user_id]); + } + ], + [ + '--divider--', function(){return false;}, + function ($model) { + $user = Auth::user(); + return $user->can('editByOwner', [ENTITY_CLIENT, $model->user_id]) && ($user->can('create', ENTITY_TASK) || $user->can('create', ENTITY_INVOICE)); + } + ], + [ + trans('texts.new_task'), + function ($model) { + return URL::to("tasks/create/{$model->public_id}"); + }, + function ($model) { + return Auth::user()->can('create', ENTITY_TASK); + } + ], + [ + trans('texts.new_invoice'), + function ($model) { + return URL::to("invoices/create/{$model->public_id}"); + }, + function ($model) { + return Auth::user()->can('create', ENTITY_INVOICE); + } + ], + [ + trans('texts.new_quote'), + function ($model) { + return URL::to("quotes/create/{$model->public_id}"); + }, + function ($model) { + return Auth::user()->hasFeature(FEATURE_QUOTES) && Auth::user()->can('create', ENTITY_INVOICE); + } + ], + [ + '--divider--', function(){return false;}, + function ($model) { + $user = Auth::user(); + return ($user->can('create', ENTITY_TASK) || $user->can('create', ENTITY_INVOICE)) && ($user->can('create', ENTITY_PAYMENT) || $user->can('create', ENTITY_CREDIT) || $user->can('create', ENTITY_EXPENSE)); + } + ], + [ + trans('texts.enter_payment'), + function ($model) { + return URL::to("payments/create/{$model->public_id}"); + }, + function ($model) { + return Auth::user()->can('create', ENTITY_PAYMENT); + } + ], + [ + trans('texts.enter_credit'), + function ($model) { + return URL::to("credits/create/{$model->public_id}"); + }, + function ($model) { + return Auth::user()->can('create', ENTITY_CREDIT); + } + ], + [ + trans('texts.enter_expense'), + function ($model) { + return URL::to("expenses/create/0/{$model->public_id}"); + }, + function ($model) { + return Auth::user()->can('create', ENTITY_EXPENSE); + } + ] + ]; + } + +} diff --git a/app/Ninja/Datatables/CreditDatatable.php b/app/Ninja/Datatables/CreditDatatable.php new file mode 100644 index 0000000000..7f258e377d --- /dev/null +++ b/app/Ninja/Datatables/CreditDatatable.php @@ -0,0 +1,66 @@ +can('viewByOwner', [ENTITY_CLIENT, $model->client_user_id])){ + return Utils::getClientDisplayName($model); + } + + return $model->client_public_id ? link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml() : ''; + }, + ! $this->hideClient + ], + [ + 'amount', + function ($model) { + return Utils::formatMoney($model->amount, $model->currency_id, $model->country_id) . ''; + } + ], + [ + 'balance', + function ($model) { + return Utils::formatMoney($model->balance, $model->currency_id, $model->country_id); + } + ], + [ + 'credit_date', + function ($model) { + return Utils::fromSqlDate($model->credit_date); + } + ], + [ + 'private_notes', + function ($model) { + return $model->private_notes; + } + ] + ]; + } + + public function actions() + { + return [ + [ + trans('texts.apply_credit'), + function ($model) { + return URL::to("payments/create/{$model->client_public_id}") . '?paymentTypeId=1'; + }, + function ($model) { + return Auth::user()->can('create', ENTITY_PAYMENT); + } + ] + ]; + } +} diff --git a/app/Ninja/Datatables/EntityDatatable.php b/app/Ninja/Datatables/EntityDatatable.php new file mode 100644 index 0000000000..085645ff20 --- /dev/null +++ b/app/Ninja/Datatables/EntityDatatable.php @@ -0,0 +1,24 @@ +isBulkEdit = $isBulkEdit; + $this->hideClient = $hideClient; + } + + public function columns() + { + return []; + } + + public function actions() + { + return []; + } +} diff --git a/app/Ninja/Datatables/ExpenseCategoryDatatable.php b/app/Ninja/Datatables/ExpenseCategoryDatatable.php new file mode 100644 index 0000000000..7ef850b0a4 --- /dev/null +++ b/app/Ninja/Datatables/ExpenseCategoryDatatable.php @@ -0,0 +1,43 @@ +can('editByOwner', [ENTITY_EXPENSE_CATEGORY, $model->user_id])) { + return $model->category; + } + + return link_to("expense_categories/{$model->public_id}/edit", $model->category)->toHtml(); + } + ], + ]; + } + + public function actions() + { + return [ + [ + trans('texts.edit_category'), + function ($model) { + return URL::to("expense_categories/{$model->public_id}/edit") ; + }, + function ($model) { + return Auth::user()->can('editByOwner', [ENTITY_EXPENSE_CATEGORY, $model->user_id]); + } + ], + ]; + } + +} diff --git a/app/Ninja/Datatables/ExpenseDatatable.php b/app/Ninja/Datatables/ExpenseDatatable.php new file mode 100644 index 0000000000..3b398a5184 --- /dev/null +++ b/app/Ninja/Datatables/ExpenseDatatable.php @@ -0,0 +1,145 @@ +vendor_public_id) { + if(!Auth::user()->can('viewByOwner', [ENTITY_VENDOR, $model->vendor_user_id])){ + return $model->vendor_name; + } + + return link_to("vendors/{$model->vendor_public_id}", $model->vendor_name)->toHtml(); + } else { + return ''; + } + }, + ! $this->hideClient + ], + [ + 'client_name', + function ($model) + { + if ($model->client_public_id) { + if(!Auth::user()->can('viewByOwner', [ENTITY_CLIENT, $model->client_user_id])){ + return Utils::getClientDisplayName($model); + } + + return link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml(); + } else { + return ''; + } + }, + ! $this->hideClient + ], + [ + 'expense_date', + function ($model) { + if(!Auth::user()->can('editByOwner', [ENTITY_EXPENSE, $model->user_id])){ + return Utils::fromSqlDate($model->expense_date); + } + + return link_to("expenses/{$model->public_id}/edit", Utils::fromSqlDate($model->expense_date))->toHtml(); + } + ], + [ + 'amount', + function ($model) { + // show both the amount and the converted amount + if ($model->exchange_rate != 1) { + $converted = round($model->amount * $model->exchange_rate, 2); + return Utils::formatMoney($model->amount, $model->expense_currency_id) . ' | ' . + Utils::formatMoney($converted, $model->invoice_currency_id); + } else { + return Utils::formatMoney($model->amount, $model->expense_currency_id); + } + } + ], + [ + 'category', + function ($model) { + return $model->category != null ? substr($model->category, 0, 100) : ''; + } + ], + [ + 'public_notes', + function ($model) { + return $model->public_notes != null ? substr($model->public_notes, 0, 100) : ''; + } + ], + [ + 'expense_status_id', + function ($model) { + return self::getStatusLabel($model->invoice_id, $model->should_be_invoiced, $model->balance); + } + ], + ]; + } + + public function actions() + { + return [ + [ + trans('texts.edit_expense'), + function ($model) { + return URL::to("expenses/{$model->public_id}/edit") ; + }, + function ($model) { + return Auth::user()->can('editByOwner', [ENTITY_EXPENSE, $model->user_id]); + } + ], + [ + trans('texts.view_invoice'), + function ($model) { + return URL::to("/invoices/{$model->invoice_public_id}/edit"); + }, + function ($model) { + return $model->invoice_public_id && Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->invoice_user_id]); + } + ], + [ + trans('texts.invoice_expense'), + function ($model) { + return "javascript:invoiceEntity({$model->public_id})"; + }, + function ($model) { + return ! $model->invoice_id && (!$model->deleted_at || $model->deleted_at == '0000-00-00') && Auth::user()->can('create', ENTITY_INVOICE); + } + ], + ]; + } + + + private function getStatusLabel($invoiceId, $shouldBeInvoiced, $balance) + { + if ($invoiceId) { + if (floatval($balance)) { + $label = trans('texts.invoiced'); + $class = 'default'; + } else { + $label = trans('texts.paid'); + $class = 'success'; + } + } elseif ($shouldBeInvoiced) { + $label = trans('texts.pending'); + $class = 'warning'; + } else { + $label = trans('texts.logged'); + $class = 'primary'; + } + + return "

    $label

    "; + } + +} diff --git a/app/Ninja/Datatables/InvoiceDatatable.php b/app/Ninja/Datatables/InvoiceDatatable.php new file mode 100644 index 0000000000..b9fa70aa0a --- /dev/null +++ b/app/Ninja/Datatables/InvoiceDatatable.php @@ -0,0 +1,193 @@ +entityType; + + return [ + [ + 'invoice_number', + function ($model) use ($entityType) { + if(!Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id])){ + return $model->invoice_number; + } + + return link_to("{$entityType}s/{$model->public_id}/edit", $model->invoice_number, ['class' => Utils::getEntityRowClass($model)])->toHtml(); + } + ], + [ + 'client_name', + function ($model) { + if(!Auth::user()->can('viewByOwner', [ENTITY_CLIENT, $model->client_user_id])){ + return Utils::getClientDisplayName($model); + } + return link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml(); + }, + ! $this->hideClient + ], + [ + 'invoice_date', + function ($model) { + return Utils::fromSqlDate($model->invoice_date); + } + ], + [ + 'amount', + function ($model) { + return Utils::formatMoney($model->amount, $model->currency_id, $model->country_id); + } + ], + [ + 'balance', + function ($model) { + return $model->partial > 0 ? + trans('texts.partial_remaining', [ + 'partial' => Utils::formatMoney($model->partial, $model->currency_id, $model->country_id), + 'balance' => Utils::formatMoney($model->balance, $model->currency_id, $model->country_id)] + ) : + Utils::formatMoney($model->balance, $model->currency_id, $model->country_id); + }, + $entityType == ENTITY_INVOICE + ], + [ + 'due_date', + function ($model) { + return Utils::fromSqlDate($model->due_date); + }, + ], + [ + 'invoice_status_name', + function ($model) use ($entityType) { + return $model->quote_invoice_id ? link_to("invoices/{$model->quote_invoice_id}/edit", trans('texts.converted'))->toHtml() : self::getStatusLabel($model); + } + ] + ]; + } + + public function actions() + { + $entityType = $this->entityType; + + return [ + [ + trans("texts.edit_{$entityType}"), + function ($model) use ($entityType) { + return URL::to("{$entityType}s/{$model->public_id}/edit"); + }, + function ($model) { + return Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]); + } + ], + [ + trans("texts.clone_{$entityType}"), + function ($model) use ($entityType) { + return URL::to("{$entityType}s/{$model->public_id}/clone"); + }, + function ($model) { + return Auth::user()->can('create', ENTITY_INVOICE); + } + ], + [ + trans('texts.view_history'), + function ($model) use ($entityType) { + return URL::to("{$entityType}s/{$entityType}_history/{$model->public_id}"); + } + ], + [ + '--divider--', function(){return false;}, + function ($model) { + return Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]) || Auth::user()->can('create', ENTITY_PAYMENT); + } + ], + [ + trans('texts.mark_sent'), + function ($model) { + return "javascript:markEntity({$model->public_id})"; + }, + function ($model) { + return $model->invoice_status_id < INVOICE_STATUS_SENT && Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]); + } + ], + [ + trans('texts.enter_payment'), + function ($model) { + return URL::to("payments/create/{$model->client_public_id}/{$model->public_id}"); + }, + function ($model) use ($entityType) { + return $entityType == ENTITY_INVOICE && $model->balance > 0 && Auth::user()->can('create', ENTITY_PAYMENT); + } + ], + [ + trans('texts.view_quote'), + function ($model) { + return URL::to("quotes/{$model->quote_id}/edit"); + }, + function ($model) use ($entityType) { + return $entityType == ENTITY_INVOICE && $model->quote_id && Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]); + } + ], + [ + trans('texts.view_invoice'), + function ($model) { + return URL::to("invoices/{$model->quote_invoice_id}/edit"); + }, + function ($model) use ($entityType) { + return $entityType == ENTITY_QUOTE && $model->quote_invoice_id && Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]); + } + ], + [ + trans('texts.convert_to_invoice'), + function ($model) { + return "javascript:convertEntity({$model->public_id})"; + }, + function ($model) use ($entityType) { + return $entityType == ENTITY_QUOTE && ! $model->quote_invoice_id && Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]); + } + ] + ]; + } + + private function getStatusLabel($model) + { + $entityType = $this->entityType; + + // check if invoice is overdue + if (Utils::parseFloat($model->balance) && $model->due_date && $model->due_date != '0000-00-00') { + if (\DateTime::createFromFormat('Y-m-d', $model->due_date) < new \DateTime('now')) { + $label = $entityType == ENTITY_INVOICE ? trans('texts.overdue') : trans('texts.expired'); + return '

    ' . $label . '

    '; + } + } + + $label = trans('texts.status_' . strtolower($model->invoice_status_name)); + $class = 'default'; + switch ($model->invoice_status_id) { + case INVOICE_STATUS_SENT: + $class = 'info'; + break; + case INVOICE_STATUS_VIEWED: + $class = 'warning'; + break; + case INVOICE_STATUS_APPROVED: + $class = 'success'; + break; + case INVOICE_STATUS_PARTIAL: + $class = 'primary'; + break; + case INVOICE_STATUS_PAID: + $class = 'success'; + break; + } + + return "

    $label

    "; + } + +} diff --git a/app/Ninja/Datatables/PaymentDatatable.php b/app/Ninja/Datatables/PaymentDatatable.php new file mode 100644 index 0000000000..20f2cd0258 --- /dev/null +++ b/app/Ninja/Datatables/PaymentDatatable.php @@ -0,0 +1,164 @@ +can('editByOwner', [ENTITY_INVOICE, $model->invoice_user_id])){ + return $model->invoice_number; + } + + return link_to("invoices/{$model->invoice_public_id}/edit", $model->invoice_number, ['class' => Utils::getEntityRowClass($model)])->toHtml(); + } + ], + [ + 'client_name', + function ($model) { + if(!Auth::user()->can('viewByOwner', [ENTITY_CLIENT, $model->client_user_id])){ + return Utils::getClientDisplayName($model); + } + + return $model->client_public_id ? link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml() : ''; + }, + ! $this->hideClient + ], + [ + 'transaction_reference', + function ($model) { + return $model->transaction_reference ? $model->transaction_reference : ''.trans('texts.manual_entry').''; + } + ], + [ + 'payment_type', + function ($model) { + return ($model->payment_type && !$model->last4) ? $model->payment_type : ($model->account_gateway_id ? $model->gateway_name : ''); + } + ], + [ + 'source', + function ($model) { + $code = str_replace(' ', '', strtolower($model->payment_type)); + $card_type = trans('texts.card_' . $code); + if ($model->payment_type_id != PAYMENT_TYPE_ACH) { + if($model->last4) { + $expiration = Utils::fromSqlDate($model->expiration, false)->format('m/y'); + return '' . htmlentities($card_type) . '  •••' . $model->last4 . ' ' . $expiration; + } elseif ($model->email) { + return $model->email; + } + } elseif ($model->last4) { + if($model->bank_name) { + $bankName = $model->bank_name; + } else { + $bankData = PaymentMethod::lookupBankData($model->routing_number); + if($bankData) { + $bankName = $bankData->name; + } + } + if (!empty($bankName)) { + return $bankName.'  •••' . $model->last4; + } elseif($model->last4) { + return '' . htmlentities($card_type) . '  •••' . $model->last4; + } + } + } + ], + [ + 'amount', + function ($model) { + return Utils::formatMoney($model->amount, $model->currency_id, $model->country_id); + } + ], + [ + 'payment_date', + function ($model) { + return Utils::dateToString($model->payment_date); + } + ], + [ + 'payment_status_name', + function ($model) { + return self::getStatusLabel($model); + } + ] + ]; + } + + + public function actions() + { + return [ + [ + trans('texts.edit_payment'), + function ($model) { + return URL::to("payments/{$model->public_id}/edit"); + }, + function ($model) { + return Auth::user()->can('editByOwner', [ENTITY_PAYMENT, $model->user_id]); + } + ], + [ + trans('texts.refund_payment'), + function ($model) { + $max_refund = number_format($model->amount - $model->refunded, 2); + $formatted = Utils::formatMoney($max_refund, $model->currency_id, $model->country_id); + $symbol = Utils::getFromCache($model->currency_id ? $model->currency_id : 1, 'currencies')->symbol ; + return "javascript:showRefundModal({$model->public_id}, '{$max_refund}', '{$formatted}', '{$symbol}')"; + }, + function ($model) { + return Auth::user()->can('editByOwner', [ENTITY_PAYMENT, $model->user_id]) && $model->payment_status_id >= PAYMENT_STATUS_COMPLETED && + $model->refunded < $model->amount && + ( + ($model->transaction_reference && in_array($model->gateway_id , static::$refundableGateways)) + || $model->payment_type_id == PAYMENT_TYPE_CREDIT + ); + } + ] + ]; + } + + private function getStatusLabel($model) + { + $label = trans('texts.status_' . strtolower($model->payment_status_name)); + $class = 'default'; + switch ($model->payment_status_id) { + case PAYMENT_STATUS_PENDING: + $class = 'info'; + break; + case PAYMENT_STATUS_COMPLETED: + $class = 'success'; + break; + case PAYMENT_STATUS_FAILED: + $class = 'danger'; + break; + case PAYMENT_STATUS_PARTIALLY_REFUNDED: + $label = trans('texts.status_partially_refunded_amount', [ + 'amount' => Utils::formatMoney($model->refunded, $model->currency_id, $model->country_id), + ]); + $class = 'primary'; + break; + case PAYMENT_STATUS_VOIDED: + case PAYMENT_STATUS_REFUNDED: + $class = 'default'; + break; + } + return "

    $label

    "; + } +} diff --git a/app/Ninja/Datatables/ProductDatatable.php b/app/Ninja/Datatables/ProductDatatable.php new file mode 100644 index 0000000000..a5b3cbfc21 --- /dev/null +++ b/app/Ninja/Datatables/ProductDatatable.php @@ -0,0 +1,55 @@ +public_id.'/edit', $model->product_key)->toHtml(); + } + ], + [ + 'notes', + function ($model) { + return nl2br(Str::limit($model->notes, 100)); + } + ], + [ + 'cost', + function ($model) { + return Utils::formatMoney($model->cost); + } + ], + [ + 'tax_rate', + function ($model) { + return $model->tax_rate ? ($model->tax_name . ' ' . $model->tax_rate . '%') : ''; + }, + Auth::user()->account->invoice_item_taxes + ] + ]; + } + + public function actions() + { + return [ + [ + uctrans('texts.edit_product'), + function ($model) { + return URL::to("products/{$model->public_id}/edit"); + } + ] + ]; + } + +} diff --git a/app/Ninja/Datatables/RecurringInvoiceDatatable.php b/app/Ninja/Datatables/RecurringInvoiceDatatable.php new file mode 100644 index 0000000000..64a5bc3307 --- /dev/null +++ b/app/Ninja/Datatables/RecurringInvoiceDatatable.php @@ -0,0 +1,65 @@ +frequency); + $frequency = preg_replace('/\s/', '_', $frequency); + return link_to("invoices/{$model->public_id}", trans('texts.freq_'.$frequency))->toHtml(); + } + ], + [ + 'client_name', + function ($model) { + return link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml(); + }, + ! $this->hideClient + ], + [ + 'start_date', + function ($model) { + return Utils::fromSqlDate($model->start_date); + } + ], + [ + 'end_date', + function ($model) { + return Utils::fromSqlDate($model->end_date); + } + ], + [ + 'amount', + function ($model) { + return Utils::formatMoney($model->amount, $model->currency_id, $model->country_id); + } + ] + ]; + } + + public function actions() + { + return [ + [ + trans('texts.edit_invoice'), + function ($model) { + return URL::to("invoices/{$model->public_id}/edit"); + }, + function ($model) { + return Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]); + } + ] + ]; + } + +} diff --git a/app/Ninja/Datatables/TaskDatatable.php b/app/Ninja/Datatables/TaskDatatable.php new file mode 100644 index 0000000000..2184d9c359 --- /dev/null +++ b/app/Ninja/Datatables/TaskDatatable.php @@ -0,0 +1,117 @@ +can('viewByOwner', [ENTITY_CLIENT, $model->client_user_id])){ + return Utils::getClientDisplayName($model); + } + + return $model->client_public_id ? link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml() : ''; + }, + ! $this->hideClient + ], + [ + 'created_at', + function ($model) { + return link_to("tasks/{$model->public_id}/edit", Task::calcStartTime($model))->toHtml(); + } + ], + [ + 'time_log', + function($model) { + return Utils::formatTime(Task::calcDuration($model)); + } + ], + [ + 'description', + function ($model) { + return $model->description; + } + ], + [ + 'invoice_number', + function ($model) { + return self::getStatusLabel($model); + } + ] + ]; + } + + public function actions() + { + return [ + [ + trans('texts.edit_task'), + function ($model) { + return URL::to('tasks/'.$model->public_id.'/edit'); + }, + function ($model) { + return (!$model->deleted_at || $model->deleted_at == '0000-00-00') && Auth::user()->can('editByOwner', [ENTITY_TASK, $model->user_id]); + } + ], + [ + trans('texts.view_invoice'), + function ($model) { + return URL::to("/invoices/{$model->invoice_public_id}/edit"); + }, + function ($model) { + return $model->invoice_number && Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->invoice_user_id]); + } + ], + [ + trans('texts.stop_task'), + function ($model) { + return "javascript:stopTask({$model->public_id})"; + }, + function ($model) { + return $model->is_running && Auth::user()->can('editByOwner', [ENTITY_TASK, $model->user_id]); + } + ], + [ + trans('texts.invoice_task'), + function ($model) { + return "javascript:invoiceEntity({$model->public_id})"; + }, + function ($model) { + return ! $model->invoice_number && (!$model->deleted_at || $model->deleted_at == '0000-00-00') && Auth::user()->can('create', ENTITY_INVOICE); + } + ] + ]; + } + + private function getStatusLabel($model) + { + if ($model->invoice_number) { + if (floatval($model->balance)) { + $label = trans('texts.invoiced'); + $class = 'default'; + } else { + $class = 'success'; + $label = trans('texts.paid'); + } + } elseif ($model->is_running) { + $class = 'primary'; + $label = trans('texts.running'); + } else { + $class = 'warning'; + $label = trans('texts.logged'); + } + + return "

    $label

    "; + } + + +} diff --git a/app/Ninja/Datatables/TaxRateDatatable.php b/app/Ninja/Datatables/TaxRateDatatable.php new file mode 100644 index 0000000000..3e16aba9ee --- /dev/null +++ b/app/Ninja/Datatables/TaxRateDatatable.php @@ -0,0 +1,39 @@ +public_id}/edit", $model->name)->toHtml(); + } + ], + [ + 'rate', + function ($model) { + return $model->rate . '%'; + } + ] + ]; + } + + public function actions() + { + return [ + [ + uctrans('texts.edit_tax_rate'), + function ($model) { + return URL::to("tax_rates/{$model->public_id}/edit"); + } + ] + ]; + } + +} diff --git a/app/Ninja/Datatables/TokenDatatable.php b/app/Ninja/Datatables/TokenDatatable.php new file mode 100644 index 0000000000..7fb77ebc96 --- /dev/null +++ b/app/Ninja/Datatables/TokenDatatable.php @@ -0,0 +1,39 @@ +public_id}/edit", $model->name)->toHtml(); + } + ], + [ + 'token', + function ($model) { + return $model->token; + } + ] + ]; + } + + public function actions() + { + return [ + [ + uctrans('texts.edit_token'), + function ($model) { + return URL::to("tokens/{$model->public_id}/edit"); + } + ] + ]; + } + +} diff --git a/app/Ninja/Datatables/UserDatatable.php b/app/Ninja/Datatables/UserDatatable.php new file mode 100644 index 0000000000..2bf4f7a1cc --- /dev/null +++ b/app/Ninja/Datatables/UserDatatable.php @@ -0,0 +1,94 @@ +public_id ? link_to('users/'.$model->public_id.'/edit', $model->first_name.' '.$model->last_name)->toHtml() : ($model->first_name.' '.$model->last_name); + } + ], + [ + 'email', + function ($model) { + return $model->email; + } + ], + [ + 'confirmed', + function ($model) { + if (!$model->public_id) { + return self::getStatusLabel(USER_STATE_OWNER); + } elseif ($model->deleted_at) { + return self::getStatusLabel(USER_STATE_DISABLED); + } elseif ($model->confirmed) { + if($model->is_admin){ + return self::getStatusLabel(USER_STATE_ADMIN); + } else { + return self::getStatusLabel(USER_STATE_ACTIVE); + } + } else { + return self::getStatusLabel(USER_STATE_PENDING); + } + } + ], + ]; + } + + public function actions() + { + return [ + [ + uctrans('texts.edit_user'), + function ($model) { + return URL::to("users/{$model->public_id}/edit"); + }, + function ($model) { + return $model->public_id; + } + ], + [ + uctrans('texts.send_invite'), + function ($model) { + return URL::to("send_confirmation/{$model->public_id}"); + }, + function ($model) { + return $model->public_id && ! $model->confirmed; + } + ] + ]; + } + + private function getStatusLabel($state) + { + $label = trans("texts.{$state}"); + $class = 'default'; + switch ($state) { + case USER_STATE_PENDING: + $class = 'default'; + break; + case USER_STATE_ACTIVE: + $class = 'info'; + break; + case USER_STATE_DISABLED: + $class = 'warning'; + break; + case USER_STATE_OWNER: + $class = 'success'; + break; + case USER_STATE_ADMIN: + $class = 'primary'; + break; + } + return "

    $label

    "; + } + + +} diff --git a/app/Ninja/Datatables/VendorDatatable.php b/app/Ninja/Datatables/VendorDatatable.php new file mode 100644 index 0000000000..93e059b6ae --- /dev/null +++ b/app/Ninja/Datatables/VendorDatatable.php @@ -0,0 +1,79 @@ +public_id}", $model->name ?: '')->toHtml(); + } + ], + [ + 'city', + function ($model) { + return $model->city; + } + ], + [ + 'work_phone', + function ($model) { + return $model->work_phone; + } + ], + [ + 'email', + function ($model) { + return link_to("vendors/{$model->public_id}", $model->email ?: '')->toHtml(); + } + ], + [ + 'vendors.created_at', + function ($model) { + return Utils::timestampToDateString(strtotime($model->created_at)); + } + ], + ]; + } + + public function actions() + { + return [ + [ + trans('texts.edit_vendor'), + function ($model) { + return URL::to("vendors/{$model->public_id}/edit"); + }, + function ($model) { + return Auth::user()->can('editByOwner', [ENTITY_VENDOR, $model->user_id]); + } + ], + [ + '--divider--', function(){return false;}, + function ($model) { + return Auth::user()->can('editByOwner', [ENTITY_VENDOR, $model->user_id]) && Auth::user()->can('create', ENTITY_EXPENSE); + } + + ], + [ + trans('texts.enter_expense'), + function ($model) { + return URL::to("expenses/create/{$model->public_id}"); + }, + function ($model) { + return Auth::user()->can('create', ENTITY_EXPENSE); + } + ] + ]; + } + + +} diff --git a/app/Ninja/Import/BaseTransformer.php b/app/Ninja/Import/BaseTransformer.php index 8e17bfeec3..c1ad30d34f 100644 --- a/app/Ninja/Import/BaseTransformer.php +++ b/app/Ninja/Import/BaseTransformer.php @@ -4,94 +4,188 @@ use Utils; use DateTime; use League\Fractal\TransformerAbstract; +/** + * Class BaseTransformer + */ class BaseTransformer extends TransformerAbstract { + /** + * @var + */ protected $maps; + /** + * BaseTransformer constructor. + * @param $maps + */ public function __construct($maps) { $this->maps = $maps; } + /** + * @param $name + * @return bool + */ protected function hasClient($name) { - $name = strtolower($name); + $name = trim(strtolower($name)); return isset($this->maps[ENTITY_CLIENT][$name]); } + /** + * @param $key + * @return bool + */ + protected function hasProduct($key) + { + $key = trim(strtolower($key)); + return isset($this->maps[ENTITY_PRODUCT][$key]); + } + + /** + * @param $data + * @param $field + * @return string + */ protected function getString($data, $field) { return (isset($data->$field) && $data->$field) ? $data->$field : ''; } + /** + * @param $data + * @param $field + * @return int + */ + protected function getNumber($data, $field) + { + return (isset($data->$field) && $data->$field) ? $data->$field : 0; + } + + /** + * @param $name + * @return null + */ protected function getClientId($name) { $name = strtolower($name); return isset($this->maps[ENTITY_CLIENT][$name]) ? $this->maps[ENTITY_CLIENT][$name] : null; } + /** + * @param $name + * @return null + */ + protected function getProductId($name) + { + $name = strtolower($name); + return isset($this->maps[ENTITY_PRODUCT][$name]) ? $this->maps[ENTITY_PRODUCT][$name] : null; + } + + /** + * @param $name + * @return null + */ protected function getCountryId($name) { $name = strtolower($name); return isset($this->maps['countries'][$name]) ? $this->maps['countries'][$name] : null; } + /** + * @param $name + * @return null + */ protected function getCountryIdBy2($name) { $name = strtolower($name); return isset($this->maps['countries2'][$name]) ? $this->maps['countries2'][$name] : null; } + /** + * @param $name + * @return mixed + */ protected function getFirstName($name) { $name = Utils::splitName($name); return $name[0]; } + /** + * @param $date + * @param string $format + * @return null + */ protected function getDate($date, $format = 'Y-m-d') { if ( ! $date instanceof DateTime) { $date = DateTime::createFromFormat($format, $date); } - + return $date ? $date->format('Y-m-d') : null; } + /** + * @param $name + * @return mixed + */ protected function getLastName($name) { $name = Utils::splitName($name); return $name[1]; } + /** + * @param $number + * @return string + */ protected function getInvoiceNumber($number) { $number = strtolower($number); return str_pad($number, 4, '0', STR_PAD_LEFT); } + /** + * @param $invoiceNumber + * @return null + */ protected function getInvoiceId($invoiceNumber) { $invoiceNumber = $this->getInvoiceNumber($invoiceNumber); return isset($this->maps[ENTITY_INVOICE][$invoiceNumber]) ? $this->maps[ENTITY_INVOICE][$invoiceNumber] : null; } + /** + * @param $invoiceNumber + * @return bool + */ protected function hasInvoice($invoiceNumber) { $invoiceNumber = $this->getInvoiceNumber($invoiceNumber); return isset($this->maps[ENTITY_INVOICE][$invoiceNumber]); } + /** + * @param $invoiceNumber + * @return null + */ protected function getInvoiceClientId($invoiceNumber) { $invoiceNumber = $this->getInvoiceNumber($invoiceNumber); return isset($this->maps[ENTITY_INVOICE.'_'.ENTITY_CLIENT][$invoiceNumber])? $this->maps[ENTITY_INVOICE.'_'.ENTITY_CLIENT][$invoiceNumber] : null; } - + + /** + * @param $name + * @return null + */ protected function getVendorId($name) { $name = strtolower($name); return isset($this->maps[ENTITY_VENDOR][$name]) ? $this->maps[ENTITY_VENDOR][$name] : null; } - -} \ No newline at end of file + +} diff --git a/app/Ninja/Import/CSV/ClientTransformer.php b/app/Ninja/Import/CSV/ClientTransformer.php index b480d5e88f..b7707081e6 100644 --- a/app/Ninja/Import/CSV/ClientTransformer.php +++ b/app/Ninja/Import/CSV/ClientTransformer.php @@ -3,8 +3,15 @@ use App\Ninja\Import\BaseTransformer; use League\Fractal\Resource\Item; +/** + * Class ClientTransformer + */ class ClientTransformer extends BaseTransformer { + /** + * @param $data + * @return bool|Item + */ public function transform($data) { if (isset($data->name) && $this->hasClient($data->name)) { @@ -20,6 +27,7 @@ class ClientTransformer extends BaseTransformer 'state' => $this->getString($data, 'state'), 'postal_code' => $this->getString($data, 'postal_code'), 'private_notes' => $this->getString($data, 'notes'), + 'website' => $this->getString($data, 'website'), 'contacts' => [ [ 'first_name' => $this->getString($data, 'first_name'), diff --git a/app/Ninja/Import/CSV/InvoiceTransformer.php b/app/Ninja/Import/CSV/InvoiceTransformer.php index e58bfe335e..6095388fdd 100644 --- a/app/Ninja/Import/CSV/InvoiceTransformer.php +++ b/app/Ninja/Import/CSV/InvoiceTransformer.php @@ -3,8 +3,15 @@ use App\Ninja\Import\BaseTransformer; use League\Fractal\Resource\Item; +/** + * Class InvoiceTransformer + */ class InvoiceTransformer extends BaseTransformer { + /** + * @param $data + * @return bool|Item + */ public function transform($data) { if ( ! $this->getClientId($data->name)) { diff --git a/app/Ninja/Import/CSV/PaymentTransformer.php b/app/Ninja/Import/CSV/PaymentTransformer.php index 7acd3d88f8..c8a1a82955 100644 --- a/app/Ninja/Import/CSV/PaymentTransformer.php +++ b/app/Ninja/Import/CSV/PaymentTransformer.php @@ -3,8 +3,15 @@ use App\Ninja\Import\BaseTransformer; use League\Fractal\Resource\Item; +/** + * Class PaymentTransformer + */ class PaymentTransformer extends BaseTransformer { + /** + * @param $data + * @return Item + */ public function transform($data) { return new Item($data, function ($data) { diff --git a/app/Ninja/Import/CSV/ProductTransformer.php b/app/Ninja/Import/CSV/ProductTransformer.php new file mode 100644 index 0000000000..e6c581b727 --- /dev/null +++ b/app/Ninja/Import/CSV/ProductTransformer.php @@ -0,0 +1,29 @@ +product_key) || $this->hasProduct($data->product_key)) { + return false; + } + + return new Item($data, function ($data) { + return [ + 'product_key' => $this->getString($data, 'product_key'), + 'notes' => $this->getString($data, 'notes'), + 'cost' => $this->getNumber($data, 'cost'), + ]; + }); + } +} diff --git a/app/Ninja/Import/CSV/VendorTransformer.php b/app/Ninja/Import/CSV/VendorTransformer.php index 464274e5a4..d589dd8db2 100644 --- a/app/Ninja/Import/CSV/VendorTransformer.php +++ b/app/Ninja/Import/CSV/VendorTransformer.php @@ -2,9 +2,17 @@ use App\Ninja\Import\BaseTransformer; use League\Fractal\Resource\Item; + // vendor +/** + * Class VendorTransformer + */ class VendorTransformer extends BaseTransformer { + /** + * @param $data + * @return bool|Item + */ public function transform($data) { if (isset($data->name) && $this->hasVendor($data->name)) { diff --git a/app/Ninja/Import/FreshBooks/ClientTransformer.php b/app/Ninja/Import/FreshBooks/ClientTransformer.php index d71be4befd..2d5e6b64ed 100644 --- a/app/Ninja/Import/FreshBooks/ClientTransformer.php +++ b/app/Ninja/Import/FreshBooks/ClientTransformer.php @@ -3,8 +3,15 @@ use App\Ninja\Import\BaseTransformer; use League\Fractal\Resource\Item; +/** + * Class ClientTransformer + */ class ClientTransformer extends BaseTransformer { + /** + * @param $data + * @return bool|Item + */ public function transform($data) { if ($this->hasClient($data->organization)) { diff --git a/app/Ninja/Import/FreshBooks/InvoiceTransformer.php b/app/Ninja/Import/FreshBooks/InvoiceTransformer.php index 06c4af9674..ef5e11571d 100644 --- a/app/Ninja/Import/FreshBooks/InvoiceTransformer.php +++ b/app/Ninja/Import/FreshBooks/InvoiceTransformer.php @@ -3,8 +3,15 @@ use App\Ninja\Import\BaseTransformer; use League\Fractal\Resource\Item; +/** + * Class InvoiceTransformer + */ class InvoiceTransformer extends BaseTransformer { + /** + * @param $data + * @return bool|Item + */ public function transform($data) { if ( ! $this->getClientId($data->organization)) { diff --git a/app/Ninja/Import/FreshBooks/PaymentTransformer.php b/app/Ninja/Import/FreshBooks/PaymentTransformer.php index 1f69fdbacf..3cd829f1ea 100644 --- a/app/Ninja/Import/FreshBooks/PaymentTransformer.php +++ b/app/Ninja/Import/FreshBooks/PaymentTransformer.php @@ -3,11 +3,18 @@ use App\Ninja\Import\BaseTransformer; use League\Fractal\Resource\Item; +/** + * Class PaymentTransformer + */ class PaymentTransformer extends BaseTransformer { - public function transform($data, $maps) + /** + * @param $data + * @return Item + */ + public function transform($data) { - return new Item($data, function ($data) use ($maps) { + return new Item($data, function ($data) { return [ 'amount' => $data->paid, 'payment_date_sql' => $data->create_date, @@ -16,4 +23,4 @@ class PaymentTransformer extends BaseTransformer ]; }); } -} \ No newline at end of file +} diff --git a/app/Ninja/Import/FreshBooks/TaskTransformer.php b/app/Ninja/Import/FreshBooks/TaskTransformer.php index 8c1363edcf..09e4095960 100644 --- a/app/Ninja/Import/FreshBooks/TaskTransformer.php +++ b/app/Ninja/Import/FreshBooks/TaskTransformer.php @@ -1,7 +1,6 @@ hasVendor($data->organization)) { diff --git a/app/Ninja/Import/Harvest/ClientTransformer.php b/app/Ninja/Import/Harvest/ClientTransformer.php index fb8200ec3a..20a298709b 100644 --- a/app/Ninja/Import/Harvest/ClientTransformer.php +++ b/app/Ninja/Import/Harvest/ClientTransformer.php @@ -3,8 +3,15 @@ use App\Ninja\Import\BaseTransformer; use League\Fractal\Resource\Item; +/** + * Class ClientTransformer + */ class ClientTransformer extends BaseTransformer { + /** + * @param $data + * @return bool|Item + */ public function transform($data) { if ($this->hasClient($data->client_name)) { diff --git a/app/Ninja/Import/Harvest/ContactTransformer.php b/app/Ninja/Import/Harvest/ContactTransformer.php index 6baf883c95..2e5b667e50 100644 --- a/app/Ninja/Import/Harvest/ContactTransformer.php +++ b/app/Ninja/Import/Harvest/ContactTransformer.php @@ -3,8 +3,15 @@ use App\Ninja\Import\BaseTransformer; use League\Fractal\Resource\Item; +/** + * Class ContactTransformer + */ class ContactTransformer extends BaseTransformer { + /** + * @param $data + * @return bool|Item + */ public function transform($data) { if ( ! $this->hasClient($data->client)) { diff --git a/app/Ninja/Import/Harvest/InvoiceTransformer.php b/app/Ninja/Import/Harvest/InvoiceTransformer.php index 850eeede59..ae47e7a7eb 100644 --- a/app/Ninja/Import/Harvest/InvoiceTransformer.php +++ b/app/Ninja/Import/Harvest/InvoiceTransformer.php @@ -3,8 +3,15 @@ use App\Ninja\Import\BaseTransformer; use League\Fractal\Resource\Item; +/** + * Class InvoiceTransformer + */ class InvoiceTransformer extends BaseTransformer { + /** + * @param $data + * @return bool|Item + */ public function transform($data) { if ( ! $this->getClientId($data->client)) { diff --git a/app/Ninja/Import/Harvest/PaymentTransformer.php b/app/Ninja/Import/Harvest/PaymentTransformer.php index 0efd442886..b8b98e0dc8 100644 --- a/app/Ninja/Import/Harvest/PaymentTransformer.php +++ b/app/Ninja/Import/Harvest/PaymentTransformer.php @@ -3,8 +3,15 @@ use App\Ninja\Import\BaseTransformer; use League\Fractal\Resource\Item; +/** + * Class PaymentTransformer + */ class PaymentTransformer extends BaseTransformer { + /** + * @param $data + * @return Item + */ public function transform($data) { return new Item($data, function ($data) { diff --git a/app/Ninja/Import/Harvest/VendorContactTransformer.php b/app/Ninja/Import/Harvest/VendorContactTransformer.php index 3aa0b0b36a..7f3533fd78 100644 --- a/app/Ninja/Import/Harvest/VendorContactTransformer.php +++ b/app/Ninja/Import/Harvest/VendorContactTransformer.php @@ -2,9 +2,17 @@ use App\Ninja\Import\BaseTransformer; use League\Fractal\Resource\Item; + // vendor +/** + * Class VendorContactTransformer + */ class VendorContactTransformer extends BaseTransformer { + /** + * @param $data + * @return bool|Item + */ public function transform($data) { if ( ! $this->hasVendor($data->vendor)) { diff --git a/app/Ninja/Import/Harvest/VendorTransformer.php b/app/Ninja/Import/Harvest/VendorTransformer.php index efab1e6b66..0bc3ab12cd 100644 --- a/app/Ninja/Import/Harvest/VendorTransformer.php +++ b/app/Ninja/Import/Harvest/VendorTransformer.php @@ -2,9 +2,17 @@ use App\Ninja\Import\BaseTransformer; use League\Fractal\Resource\Item; + // vendor +/** + * Class VendorTransformer + */ class VendorTransformer extends BaseTransformer { + /** + * @param $data + * @return bool|Item + */ public function transform($data) { if ($this->hasVendor($data->vendor_name)) { diff --git a/app/Ninja/Import/Hiveage/ClientTransformer.php b/app/Ninja/Import/Hiveage/ClientTransformer.php index 515eb83535..577872e0b6 100644 --- a/app/Ninja/Import/Hiveage/ClientTransformer.php +++ b/app/Ninja/Import/Hiveage/ClientTransformer.php @@ -3,8 +3,15 @@ use App\Ninja\Import\BaseTransformer; use League\Fractal\Resource\Item; +/** + * Class ClientTransformer + */ class ClientTransformer extends BaseTransformer { + /** + * @param $data + * @return bool|Item + */ public function transform($data) { if ($this->hasClient($data->name)) { diff --git a/app/Ninja/Import/Hiveage/InvoiceTransformer.php b/app/Ninja/Import/Hiveage/InvoiceTransformer.php index e9054f1b87..eab836eed2 100644 --- a/app/Ninja/Import/Hiveage/InvoiceTransformer.php +++ b/app/Ninja/Import/Hiveage/InvoiceTransformer.php @@ -3,8 +3,15 @@ use App\Ninja\Import\BaseTransformer; use League\Fractal\Resource\Item; +/** + * Class InvoiceTransformer + */ class InvoiceTransformer extends BaseTransformer { + /** + * @param $data + * @return bool|Item + */ public function transform($data) { if ( ! $this->getClientId($data->client)) { diff --git a/app/Ninja/Import/Hiveage/PaymentTransformer.php b/app/Ninja/Import/Hiveage/PaymentTransformer.php index d6232d05bc..fe091a5eff 100644 --- a/app/Ninja/Import/Hiveage/PaymentTransformer.php +++ b/app/Ninja/Import/Hiveage/PaymentTransformer.php @@ -3,11 +3,18 @@ use App\Ninja\Import\BaseTransformer; use League\Fractal\Resource\Item; +/** + * Class PaymentTransformer + */ class PaymentTransformer extends BaseTransformer { - public function transform($data, $maps) + /** + * @param $data + * @return Item + */ + public function transform($data) { - return new Item($data, function ($data) use ($maps) { + return new Item($data, function ($data) { return [ 'amount' => $data->paid_total, 'payment_date_sql' => $this->getDate($data->last_paid_on), @@ -16,4 +23,4 @@ class PaymentTransformer extends BaseTransformer ]; }); } -} \ No newline at end of file +} diff --git a/app/Ninja/Import/Hiveage/VendorTransformer.php b/app/Ninja/Import/Hiveage/VendorTransformer.php index dec1b62d1c..a52ad461e3 100644 --- a/app/Ninja/Import/Hiveage/VendorTransformer.php +++ b/app/Ninja/Import/Hiveage/VendorTransformer.php @@ -2,9 +2,17 @@ use App\Ninja\Import\BaseTransformer; use League\Fractal\Resource\Item; + // vendor +/** + * Class VendorTransformer + */ class VendorTransformer extends BaseTransformer { + /** + * @param $data + * @return bool|Item + */ public function transform($data) { if ($this->hasVendor($data->name)) { diff --git a/app/Ninja/Import/Invoiceable/ClientTransformer.php b/app/Ninja/Import/Invoiceable/ClientTransformer.php index 7e462ceef9..2dade2f71d 100644 --- a/app/Ninja/Import/Invoiceable/ClientTransformer.php +++ b/app/Ninja/Import/Invoiceable/ClientTransformer.php @@ -3,8 +3,15 @@ use App\Ninja\Import\BaseTransformer; use League\Fractal\Resource\Item; +/** + * Class ClientTransformer + */ class ClientTransformer extends BaseTransformer { + /** + * @param $data + * @return bool|Item + */ public function transform($data) { if ($this->hasClient($data->client_name)) { diff --git a/app/Ninja/Import/Invoiceable/InvoiceTransformer.php b/app/Ninja/Import/Invoiceable/InvoiceTransformer.php index f6697a7e90..23644d81ff 100644 --- a/app/Ninja/Import/Invoiceable/InvoiceTransformer.php +++ b/app/Ninja/Import/Invoiceable/InvoiceTransformer.php @@ -3,8 +3,15 @@ use App\Ninja\Import\BaseTransformer; use League\Fractal\Resource\Item; +/** + * Class InvoiceTransformer + */ class InvoiceTransformer extends BaseTransformer { + /** + * @param $data + * @return bool|Item + */ public function transform($data) { if ( ! $this->getClientId($data->client_name)) { diff --git a/app/Ninja/Import/Invoiceable/PaymentTransformer.php b/app/Ninja/Import/Invoiceable/PaymentTransformer.php index c52494cdc6..6ad823f037 100644 --- a/app/Ninja/Import/Invoiceable/PaymentTransformer.php +++ b/app/Ninja/Import/Invoiceable/PaymentTransformer.php @@ -3,11 +3,18 @@ use App\Ninja\Import\BaseTransformer; use League\Fractal\Resource\Item; +/** + * Class PaymentTransformer + */ class PaymentTransformer extends BaseTransformer { - public function transform($data, $maps) + /** + * @param $data + * @return Item + */ + public function transform($data) { - return new Item($data, function ($data) use ($maps) { + return new Item($data, function ($data) { return [ 'amount' => $data->paid, 'payment_date_sql' => $data->date_paid, @@ -16,4 +23,4 @@ class PaymentTransformer extends BaseTransformer ]; }); } -} \ No newline at end of file +} diff --git a/app/Ninja/Import/Invoiceable/VendorTransformer.php b/app/Ninja/Import/Invoiceable/VendorTransformer.php index 1ec4a28768..5125c3dfea 100644 --- a/app/Ninja/Import/Invoiceable/VendorTransformer.php +++ b/app/Ninja/Import/Invoiceable/VendorTransformer.php @@ -2,9 +2,17 @@ use App\Ninja\Import\BaseTransformer; use League\Fractal\Resource\Item; + // vendor +/** + * Class VendorTransformer + */ class VendorTransformer extends BaseTransformer { + /** + * @param $data + * @return bool|Item + */ public function transform($data) { if ($this->hasVendor($data->vendor_name)) { diff --git a/app/Ninja/Import/Nutcache/ClientTransformer.php b/app/Ninja/Import/Nutcache/ClientTransformer.php index 74705a597a..835049212a 100644 --- a/app/Ninja/Import/Nutcache/ClientTransformer.php +++ b/app/Ninja/Import/Nutcache/ClientTransformer.php @@ -3,8 +3,15 @@ use App\Ninja\Import\BaseTransformer; use League\Fractal\Resource\Item; +/** + * Class ClientTransformer + */ class ClientTransformer extends BaseTransformer { + /** + * @param $data + * @return bool|Item + */ public function transform($data) { if ($this->hasClient($data->name)) { diff --git a/app/Ninja/Import/Nutcache/InvoiceTransformer.php b/app/Ninja/Import/Nutcache/InvoiceTransformer.php index a3e3bc9137..227a4f5878 100644 --- a/app/Ninja/Import/Nutcache/InvoiceTransformer.php +++ b/app/Ninja/Import/Nutcache/InvoiceTransformer.php @@ -3,8 +3,15 @@ use App\Ninja\Import\BaseTransformer; use League\Fractal\Resource\Item; +/** + * Class InvoiceTransformer + */ class InvoiceTransformer extends BaseTransformer { + /** + * @param $data + * @return bool|Item + */ public function transform($data) { if ( ! $this->getClientId($data->client)) { diff --git a/app/Ninja/Import/Nutcache/PaymentTransformer.php b/app/Ninja/Import/Nutcache/PaymentTransformer.php index 04e783361f..fcdf139e6d 100644 --- a/app/Ninja/Import/Nutcache/PaymentTransformer.php +++ b/app/Ninja/Import/Nutcache/PaymentTransformer.php @@ -3,11 +3,18 @@ use App\Ninja\Import\BaseTransformer; use League\Fractal\Resource\Item; +/** + * Class PaymentTransformer + */ class PaymentTransformer extends BaseTransformer { - public function transform($data, $maps) + /** + * @param $data + * @return Item + */ + public function transform($data) { - return new Item($data, function ($data) use ($maps) { + return new Item($data, function ($data) { return [ 'amount' => (float) $data->paid_to_date, 'payment_date_sql' => $this->getDate($data->date), @@ -16,4 +23,4 @@ class PaymentTransformer extends BaseTransformer ]; }); } -} \ No newline at end of file +} diff --git a/app/Ninja/Import/Nutcache/TaskTransformer.php b/app/Ninja/Import/Nutcache/TaskTransformer.php index 8c1363edcf..09e4095960 100644 --- a/app/Ninja/Import/Nutcache/TaskTransformer.php +++ b/app/Ninja/Import/Nutcache/TaskTransformer.php @@ -1,7 +1,6 @@ hasVendor($data->name)) { diff --git a/app/Ninja/Import/Ronin/ClientTransformer.php b/app/Ninja/Import/Ronin/ClientTransformer.php index f79523830e..4015a305a4 100644 --- a/app/Ninja/Import/Ronin/ClientTransformer.php +++ b/app/Ninja/Import/Ronin/ClientTransformer.php @@ -3,8 +3,15 @@ use App\Ninja\Import\BaseTransformer; use League\Fractal\Resource\Item; +/** + * Class ClientTransformer + */ class ClientTransformer extends BaseTransformer { + /** + * @param $data + * @return bool|Item + */ public function transform($data) { if ($this->hasClient($data->company)) { diff --git a/app/Ninja/Import/Ronin/InvoiceTransformer.php b/app/Ninja/Import/Ronin/InvoiceTransformer.php index 5a4ff6ce2a..4f3ed70817 100644 --- a/app/Ninja/Import/Ronin/InvoiceTransformer.php +++ b/app/Ninja/Import/Ronin/InvoiceTransformer.php @@ -3,8 +3,15 @@ use App\Ninja\Import\BaseTransformer; use League\Fractal\Resource\Item; +/** + * Class InvoiceTransformer + */ class InvoiceTransformer extends BaseTransformer { + /** + * @param $data + * @return bool|Item + */ public function transform($data) { if ( ! $this->getClientId($data->client)) { diff --git a/app/Ninja/Import/Ronin/PaymentTransformer.php b/app/Ninja/Import/Ronin/PaymentTransformer.php index c041014562..b8f7cf0562 100644 --- a/app/Ninja/Import/Ronin/PaymentTransformer.php +++ b/app/Ninja/Import/Ronin/PaymentTransformer.php @@ -3,11 +3,18 @@ use App\Ninja\Import\BaseTransformer; use League\Fractal\Resource\Item; +/** + * Class PaymentTransformer + */ class PaymentTransformer extends BaseTransformer { - public function transform($data, $maps) + /** + * @param $data + * @return Item + */ + public function transform($data) { - return new Item($data, function ($data) use ($maps) { + return new Item($data, function ($data) { return [ 'amount' => (float) $data->total - (float) $data->balance, 'payment_date_sql' => $data->date_paid, @@ -16,4 +23,4 @@ class PaymentTransformer extends BaseTransformer ]; }); } -} \ No newline at end of file +} diff --git a/app/Ninja/Import/Ronin/VendorTransformer.php b/app/Ninja/Import/Ronin/VendorTransformer.php index 817de03d66..7a606226c2 100644 --- a/app/Ninja/Import/Ronin/VendorTransformer.php +++ b/app/Ninja/Import/Ronin/VendorTransformer.php @@ -2,9 +2,17 @@ use App\Ninja\Import\BaseTransformer; use League\Fractal\Resource\Item; + // vendor +/** + * Class VendorTransformer + */ class VendorTransformer extends BaseTransformer { + /** + * @param $data + * @return bool|Item + */ public function transform($data) { if ($this->hasVendor($data->company)) { diff --git a/app/Ninja/Import/Wave/ClientTransformer.php b/app/Ninja/Import/Wave/ClientTransformer.php index f76ba9c48a..4a4178336e 100644 --- a/app/Ninja/Import/Wave/ClientTransformer.php +++ b/app/Ninja/Import/Wave/ClientTransformer.php @@ -3,8 +3,15 @@ use App\Ninja\Import\BaseTransformer; use League\Fractal\Resource\Item; +/** + * Class ClientTransformer + */ class ClientTransformer extends BaseTransformer { + /** + * @param $data + * @return bool|Item + */ public function transform($data) { if ($this->hasClient($data->customer_name)) { diff --git a/app/Ninja/Import/Wave/InvoiceTransformer.php b/app/Ninja/Import/Wave/InvoiceTransformer.php index b10585aa72..0ae418ebaa 100644 --- a/app/Ninja/Import/Wave/InvoiceTransformer.php +++ b/app/Ninja/Import/Wave/InvoiceTransformer.php @@ -3,8 +3,15 @@ use App\Ninja\Import\BaseTransformer; use League\Fractal\Resource\Item; +/** + * Class InvoiceTransformer + */ class InvoiceTransformer extends BaseTransformer { + /** + * @param $data + * @return bool|Item + */ public function transform($data) { if ( ! $this->getClientId($data->customer)) { diff --git a/app/Ninja/Import/Wave/PaymentTransformer.php b/app/Ninja/Import/Wave/PaymentTransformer.php index 522fe8ff92..dbfbf6741e 100644 --- a/app/Ninja/Import/Wave/PaymentTransformer.php +++ b/app/Ninja/Import/Wave/PaymentTransformer.php @@ -3,15 +3,22 @@ use App\Ninja\Import\BaseTransformer; use League\Fractal\Resource\Item; +/** + * Class PaymentTransformer + */ class PaymentTransformer extends BaseTransformer { - public function transform($data, $maps) + /** + * @param $data + * @return bool|Item + */ + public function transform($data) { if ( ! $this->getInvoiceClientId($data->invoice_num)) { return false; } - - return new Item($data, function ($data) use ($maps) { + + return new Item($data, function ($data) { return [ 'amount' => (float) $data->amount, 'payment_date_sql' => $this->getDate($data->payment_date), @@ -20,4 +27,4 @@ class PaymentTransformer extends BaseTransformer ]; }); } -} \ No newline at end of file +} diff --git a/app/Ninja/Import/Wave/VendorTransformer.php b/app/Ninja/Import/Wave/VendorTransformer.php index f2fe2f43e3..a63a12407e 100644 --- a/app/Ninja/Import/Wave/VendorTransformer.php +++ b/app/Ninja/Import/Wave/VendorTransformer.php @@ -2,9 +2,17 @@ use App\Ninja\Import\BaseTransformer; use League\Fractal\Resource\Item; + // vendor +/** + * Class VendorTransformer + */ class VendorTransformer extends BaseTransformer { + /** + * @param $data + * @return bool|Item + */ public function transform($data) { if ($this->hasVendor($data->customer_name)) { diff --git a/app/Ninja/Import/Zoho/ClientTransformer.php b/app/Ninja/Import/Zoho/ClientTransformer.php index 689bd1cf1a..4c2f7ef9ed 100644 --- a/app/Ninja/Import/Zoho/ClientTransformer.php +++ b/app/Ninja/Import/Zoho/ClientTransformer.php @@ -3,8 +3,15 @@ use App\Ninja\Import\BaseTransformer; use League\Fractal\Resource\Item; +/** + * Class ClientTransformer + */ class ClientTransformer extends BaseTransformer { + /** + * @param $data + * @return bool|Item + */ public function transform($data) { if ($this->hasClient($data->customer_name)) { diff --git a/app/Ninja/Import/Zoho/InvoiceTransformer.php b/app/Ninja/Import/Zoho/InvoiceTransformer.php index f6fc3c44a7..9db0bc4ceb 100644 --- a/app/Ninja/Import/Zoho/InvoiceTransformer.php +++ b/app/Ninja/Import/Zoho/InvoiceTransformer.php @@ -3,8 +3,15 @@ use App\Ninja\Import\BaseTransformer; use League\Fractal\Resource\Item; +/** + * Class InvoiceTransformer + */ class InvoiceTransformer extends BaseTransformer { + /** + * @param $data + * @return bool|Item + */ public function transform($data) { if ( ! $this->getClientId($data->customer_name)) { diff --git a/app/Ninja/Import/Zoho/PaymentTransformer.php b/app/Ninja/Import/Zoho/PaymentTransformer.php index a8fc749623..c9684bebb4 100644 --- a/app/Ninja/Import/Zoho/PaymentTransformer.php +++ b/app/Ninja/Import/Zoho/PaymentTransformer.php @@ -3,11 +3,18 @@ use App\Ninja\Import\BaseTransformer; use League\Fractal\Resource\Item; +/** + * Class PaymentTransformer + */ class PaymentTransformer extends BaseTransformer { - public function transform($data, $maps) + /** + * @param $data + * @return Item + */ + public function transform($data) { - return new Item($data, function ($data) use ($maps) { + return new Item($data, function ($data) { return [ 'amount' => (float) $data->total - (float) $data->balance, 'payment_date_sql' => $data->last_payment_date, @@ -16,4 +23,4 @@ class PaymentTransformer extends BaseTransformer ]; }); } -} \ No newline at end of file +} diff --git a/app/Ninja/Import/Zoho/VendorTransformer.php b/app/Ninja/Import/Zoho/VendorTransformer.php index 811a9f7ff2..58633a538e 100644 --- a/app/Ninja/Import/Zoho/VendorTransformer.php +++ b/app/Ninja/Import/Zoho/VendorTransformer.php @@ -2,9 +2,17 @@ use App\Ninja\Import\BaseTransformer; use League\Fractal\Resource\Item; + // vendor +/** + * Class VendorTransformer + */ class VendorTransformer extends BaseTransformer { + /** + * @param $data + * @return bool|Item + */ public function transform($data) { if ($this->hasVendor($data->customer_name)) { diff --git a/app/Ninja/Mailers/ContactMailer.php b/app/Ninja/Mailers/ContactMailer.php index fbebd0c5fd..1845582ae2 100644 --- a/app/Ninja/Mailers/ContactMailer.php +++ b/app/Ninja/Mailers/ContactMailer.php @@ -1,18 +1,20 @@ templateService = $templateService; } + /** + * @param Invoice $invoice + * @param bool $reminder + * @param bool $pdfString + * @return bool|null|string + */ public function sendInvoice(Invoice $invoice, $reminder = false, $pdfString = false) { $invoice->load('invitations', 'client.language', 'account'); @@ -48,9 +68,9 @@ class ContactMailer extends Mailer $response = null; if ($client->trashed()) { - return trans('texts.email_errors.inactive_client'); + return trans('texts.email_error_inactive_client'); } elseif ($invoice->trashed()) { - return trans('texts.email_errors.inactive_invoice'); + return trans('texts.email_error_inactive_invoice'); } $account->loadLocalizationSettings($client); @@ -59,30 +79,30 @@ class ContactMailer extends Mailer $sent = false; - if ($account->attatchPDF() && !$pdfString) { + if ($account->attachPDF() && !$pdfString) { $pdfString = $invoice->getPDFString(); } - - $documentStrings = array(); + + $documentStrings = []; if ($account->document_email_attachment && $invoice->hasDocuments()) { $documents = $invoice->documents; - + foreach($invoice->expenses as $expense){ $documents = $documents->merge($expense->documents); } $documents = $documents->sortBy('size'); - + $size = 0; $maxSize = MAX_EMAIL_DOCUMENTS_SIZE * 1000; foreach($documents as $document){ $size += $document->size; if($size > $maxSize)break; - - $documentStrings[] = array( + + $documentStrings[] = [ 'name' => $document->name, 'data' => $document->getRaw(), - ); + ]; } } @@ -92,11 +112,11 @@ class ContactMailer extends Mailer $sent = true; } } - + $account->loadLocalizationSettings(); if ($sent === true) { - if ($invoice->is_quote) { + if ($invoice->isType(INVOICE_TYPE_QUOTE)) { event(new QuoteWasEmailed($invoice)); } else { event(new InvoiceWasEmailed($invoice)); @@ -106,11 +126,29 @@ class ContactMailer extends Mailer return $response; } - private function sendInvitation($invitation, $invoice, $body, $subject, $pdfString, $documentStrings) + /** + * @param Invitation $invitation + * @param Invoice $invoice + * @param $body + * @param $subject + * @param $pdfString + * @param $documentStrings + * @return bool|string + * @throws \Laracasts\Presenter\Exceptions\PresenterException + */ + private function sendInvitation( + Invitation$invitation, + Invoice $invoice, + $body, + $subject, + $pdfString, + $documentStrings + ) { + $client = $invoice->client; $account = $invoice->account; - + if (Auth::check()) { $user = Auth::user(); } else { @@ -121,13 +159,13 @@ class ContactMailer extends Mailer } if (!$user->email || !$user->registered) { - return trans('texts.email_errors.user_unregistered'); + return trans('texts.email_error_user_unregistered'); } elseif (!$user->confirmed) { - return trans('texts.email_errors.user_unconfirmed'); + return trans('texts.email_error_user_unconfirmed'); } elseif (!$invitation->contact->email) { - return trans('texts.email_errors.invalid_contact_email'); + return trans('texts.email_error_invalid_contact_email'); } elseif ($invitation->contact->trashed()) { - return trans('texts.email_errors.inactive_contact'); + return trans('texts.email_error_inactive_contact'); } $variables = [ @@ -136,8 +174,13 @@ class ContactMailer extends Mailer 'invitation' => $invitation, 'amount' => $invoice->getRequestedAmount() ]; - - if (empty($invitation->contact->password) && $account->hasFeature(FEATURE_CLIENT_PORTAL_PASSWORD) && $account->enable_portal_password && $account->send_portal_password) { + + // Let the client know they'll be billed later + if ($client->autoBillLater()) { + $variables['autobill'] = $invoice->present()->autoBillEmailMessage(); + } + + if (empty($invitation->contact->password) && $account->hasFeature(FEATURE_CLIENT_PORTAL_PASSWORD) && $account->enable_portal_password && $account->send_portal_password) { // The contact needs a password $variables['password'] = $password = $this->generatePassword(); $invitation->contact->password = bcrypt($password); @@ -156,7 +199,7 @@ class ContactMailer extends Mailer 'documents' => $documentStrings, ]; - if ($account->attatchPDF()) { + if ($account->attachPDF()) { $data['pdfString'] = $pdfString; $data['pdfFileName'] = $invoice->getFileName(); } @@ -164,7 +207,7 @@ class ContactMailer extends Mailer $subject = $this->templateService->processVariables($subject, $variables); $fromEmail = $user->email; $view = $account->getTemplateView(ENTITY_INVOICE); - + $response = $this->sendTo($invitation->contact->email, $fromEmail, $account->getDisplayName(), $subject, $view, $data); if ($response === true) { @@ -173,14 +216,18 @@ class ContactMailer extends Mailer return $response; } } - + + /** + * @param int $length + * @return string + */ protected function generatePassword($length = 9) { - $sets = array( + $sets = [ 'abcdefghjkmnpqrstuvwxyz', 'ABCDEFGHJKMNPQRSTUVWXYZ', '23456789', - ); + ]; $all = ''; $password = ''; foreach($sets as $set) @@ -192,10 +239,13 @@ class ContactMailer extends Mailer for($i = 0; $i < $length - count($sets); $i++) $password .= $all[array_rand($all)]; $password = str_shuffle($password); - + return $password; } + /** + * @param Payment $payment + */ public function sendPaymentConfirmation(Payment $payment) { $account = $payment->account; @@ -235,7 +285,7 @@ class ContactMailer extends Mailer 'entityType' => ENTITY_INVOICE, ]; - if ($account->attatchPDF()) { + if ($account->attachPDF()) { $data['pdfString'] = $invoice->getPDFString(); $data['pdfFileName'] = $invoice->getFileName(); } @@ -252,11 +302,18 @@ class ContactMailer extends Mailer $account->loadLocalizationSettings(); } + /** + * @param $name + * @param $email + * @param $amount + * @param $license + * @param $productId + */ public function sendLicensePaymentConfirmation($name, $email, $amount, $license, $productId) { $view = 'license_confirmation'; $subject = trans('texts.payment_subject'); - + if ($productId == PRODUCT_ONE_CLICK_INSTALL) { $license = "Softaculous install license: $license"; } elseif ($productId == PRODUCT_INVOICE_DESIGNS) { @@ -264,13 +321,14 @@ class ContactMailer extends Mailer } elseif ($productId == PRODUCT_WHITE_LABEL) { $license = "White label license: $license"; } - + $data = [ 'client' => $name, 'amount' => Utils::formatMoney($amount, DEFAULT_CURRENCY, DEFAULT_COUNTRY), 'license' => $license ]; - + $this->sendTo($email, CONTACT_EMAIL, CONTACT_NAME, $subject, $view, $data); } + } diff --git a/app/Ninja/Mailers/Mailer.php b/app/Ninja/Mailers/Mailer.php index d655e4945e..8e5b213367 100644 --- a/app/Ninja/Mailers/Mailer.php +++ b/app/Ninja/Mailers/Mailer.php @@ -2,11 +2,22 @@ use Exception; use Mail; -use Utils; use App\Models\Invoice; +/** + * Class Mailer + */ class Mailer { + /** + * @param $toEmail + * @param $fromEmail + * @param $fromName + * @param $subject + * @param $view + * @param array $data + * @return bool|string + */ public function sendTo($toEmail, $fromEmail, $fromName, $subject, $view, $data = []) { // check the username is set @@ -59,6 +70,11 @@ class Mailer } } + /** + * @param $response + * @param $data + * @return bool + */ private function handleSuccess($response, $data) { if (isset($data['invitation'])) { @@ -78,6 +94,10 @@ class Mailer return true; } + /** + * @param $exception + * @return string + */ private function handleFailure($exception) { if (isset($_ENV['POSTMARK_API_TOKEN']) && method_exists($exception, 'getResponse')) { @@ -87,8 +107,6 @@ class Mailer } else { $emailError = $exception->getMessage(); } - - //Utils::logError("Email Error: $emailError"); if (isset($data['invitation'])) { $invitation = $data['invitation']; diff --git a/app/Ninja/Mailers/UserMailer.php b/app/Ninja/Mailers/UserMailer.php index 0435a9af62..492a551a9e 100644 --- a/app/Ninja/Mailers/UserMailer.php +++ b/app/Ninja/Mailers/UserMailer.php @@ -1,6 +1,5 @@ email) { @@ -34,7 +37,18 @@ class UserMailer extends Mailer $this->sendTo($user->email, $fromEmail, $fromName, $subject, $view, $data); } - public function sendNotification(User $user, Invoice $invoice, $notificationType, Payment $payment = null) + /** + * @param User $user + * @param Invoice $invoice + * @param $notificationType + * @param Payment|null $payment + */ + public function sendNotification( + User $user, + Invoice $invoice, + $notificationType, + Payment $payment = null + ) { if (! $user->email || $user->cannot('view', $invoice)) { return; @@ -57,6 +71,7 @@ class UserMailer extends Mailer ]; if ($payment) { + $data['payment'] = $payment; $data['paymentAmount'] = $account->formatMoney($payment->amount, $client); } @@ -68,6 +83,9 @@ class UserMailer extends Mailer $this->sendTo($user->email, CONTACT_EMAIL, CONTACT_NAME, $subject, $view, $data); } + /** + * @param Invitation $invitation + */ public function sendEmailBounced(Invitation $invitation) { $user = $invitation->user; diff --git a/app/Ninja/Notifications/PushFactory.php b/app/Ninja/Notifications/PushFactory.php index 723ff824de..e2f34c46be 100644 --- a/app/Ninja/Notifications/PushFactory.php +++ b/app/Ninja/Notifications/PushFactory.php @@ -3,25 +3,16 @@ namespace App\Ninja\Notifications; use Davibennun\LaravelPushNotification\Facades\PushNotification; -use Illuminate\Http\Request; /** * Class PushFactory - * @package App\Ninja\Notifications */ class PushFactory { /** * PushFactory constructor. - * - * @param $this->certificate - Development or production. - * - * Static variables defined in routes.php - * - * IOS_PUSH_CERTIFICATE */ - public function __construct() { $this->certificate = IOS_PUSH_CERTIFICATE; @@ -58,7 +49,6 @@ class PushFactory * @param $message - user specific message * * @return void - * */ public function message($token, $message) @@ -91,5 +81,4 @@ class PushFactory return $feedback->getFeedback(); } - } diff --git a/app/Ninja/PaymentDrivers/AuthorizeNetAIMPaymentDriver.php b/app/Ninja/PaymentDrivers/AuthorizeNetAIMPaymentDriver.php new file mode 100644 index 0000000000..00ba9421ce --- /dev/null +++ b/app/Ninja/PaymentDrivers/AuthorizeNetAIMPaymentDriver.php @@ -0,0 +1,6 @@ +accountGateway = $accountGateway; + $this->invitation = $invitation; + $this->gatewayType = $gatewayType ?: $this->gatewayTypes()[0]; + } + + public function isGateway($gatewayId) + { + return $this->accountGateway->gateway_id == $gatewayId; + } + + // optionally pass a paymentMethod to determine the type from the token + protected function isGatewayType($gatewayType, $paymentMethod = false) + { + if ($paymentMethod) { + return $paymentMethod->gatewayType() == $gatewayType; + } else { + return $this->gatewayType === $gatewayType; + } + } + + public function gatewayTypes() + { + return [ + GATEWAY_TYPE_CREDIT_CARD + ]; + } + + public function handles($type) + { + return in_array($type, $this->gatewayTypes()); + } + + // when set to true we won't pass the card details with the form + public function tokenize() + { + return false; + } + + // set payment method as pending until confirmed + public function isTwoStep() + { + return false; + } + + public function providerName() + { + return strtolower($this->accountGateway->gateway->provider); + } + + protected function invoice() + { + return $this->invitation->invoice; + } + + protected function contact() + { + return $this->invitation->contact; + } + + protected function client() + { + return $this->invoice()->client; + } + + protected function account() + { + return $this->client()->account; + } + + public function startPurchase($input = false, $sourceId = false) + { + $this->input = $input; + $this->sourceId = $sourceId; + + Session::put('invitation_key', $this->invitation->invitation_key); + Session::put($this->invitation->id . 'gateway_type', $this->gatewayType); + Session::put($this->invitation->id . 'payment_ref', $this->invoice()->id . '_' . uniqid()); + + $gateway = $this->accountGateway->gateway; + + if ($this->isGatewayType(GATEWAY_TYPE_TOKEN) || $gateway->is_offsite) { + if (Session::has('error')) { + Session::reflash(); + } else { + $this->completeOnsitePurchase(); + Session::flash('message', trans('texts.applied_payment')); + } + + return redirect()->to('view/' . $this->invitation->invitation_key); + } + + $data = [ + 'details' => ! empty($input['details']) ? json_decode($input['details']) : false, + 'accountGateway' => $this->accountGateway, + 'acceptedCreditCardTypes' => $this->accountGateway->getCreditcardTypes(), + 'gateway' => $gateway, + 'showAddress' => $this->accountGateway->show_address, + 'showBreadcrumbs' => false, + 'url' => 'payment/' . $this->invitation->invitation_key, + 'amount' => $this->invoice()->getRequestedAmount(), + 'invoiceNumber' => $this->invoice()->invoice_number, + 'client' => $this->client(), + 'contact' => $this->invitation->contact, + 'gatewayType' => $this->gatewayType, + 'currencyId' => $this->client()->getCurrencyId(), + 'currencyCode' => $this->client()->getCurrencyCode(), + 'account' => $this->account(), + 'sourceId' => $sourceId, + 'clientFontUrl' => $this->account()->getFontsUrl(), + 'tokenize' => $this->tokenize(), + 'transactionToken' => $this->createTransactionToken(), + ]; + + return view($this->paymentView(), $data); + } + + // check if a custom view exists for this provider + protected function paymentView() + { + $file = sprintf('%s/views/payments/%s/%s.blade.php', resource_path(), $this->providerName(), $this->gatewayType); + + if (file_exists($file)) { + return sprintf('payments.%s/%s', $this->providerName(), $this->gatewayType); + } else { + return sprintf('payments.%s', $this->gatewayType); + } + } + + // check if a custom partial exists for this provider + public function partialView() + { + $file = sprintf('%s/views/payments/%s/partial.blade.php', resource_path(), $this->providerName()); + + if (file_exists($file)) { + return sprintf('payments.%s.partial', $this->providerName()); + } else { + return false; + } + } + + public function rules() + { + $rules = []; + + if ($this->isGatewayType(GATEWAY_TYPE_CREDIT_CARD)) { + + $rules = array_merge($rules, [ + 'first_name' => 'required', + 'last_name' => 'required', + ]); + + // TODO check this is always true + if ( ! $this->tokenize()) { + $rules = array_merge($rules, [ + 'card_number' => 'required', + 'expiration_month' => 'required', + 'expiration_year' => 'required', + 'cvv' => 'required', + ]); + } + + if ($this->accountGateway->show_address) { + $rules = array_merge($rules, [ + 'address1' => 'required', + 'city' => 'required', + 'state' => 'required', + 'postal_code' => 'required', + 'country_id' => 'required', + ]); + } + } + + return $rules; + } + + protected function gateway() + { + if ($this->gateway) { + return $this->gateway; + } + + $this->gateway = Omnipay::create($this->accountGateway->gateway->provider); + $this->gateway->initialize((array) $this->accountGateway->getConfig()); + + return $this->gateway; + } + + public function completeOnsitePurchase($input = false, $paymentMethod = false) + { + $this->input = count($input) ? $input : false; + $gateway = $this->gateway(); + + if ($input) { + $this->updateAddress(); + } + + // load or create token + if ($this->isGatewayType(GATEWAY_TYPE_TOKEN)) { + if ( ! $paymentMethod) { + $paymentMethod = PaymentMethod::clientId($this->client()->id) + ->wherePublicId($this->sourceId) + ->firstOrFail(); + } + } elseif ($this->shouldCreateToken()) { + $paymentMethod = $this->createToken(); + } + + if ($this->isTwoStep()) { + return; + } + + // prepare and process payment + $data = $this->paymentDetails($paymentMethod); + $response = $gateway->purchase($data)->send(); + $this->purchaseResponse = (array) $response->getData(); + + // parse the transaction reference + if ($this->transactionReferenceParam) { + $ref = $this->purchaseResponse[$this->transactionReferenceParam]; + } else { + $ref = $response->getTransactionReference(); + } + + // wrap up + if ($response->isSuccessful() && $ref) { + $payment = $this->createPayment($ref, $paymentMethod); + + // TODO move this to stripe driver + if ($this->invitation->invoice->account->account_key == NINJA_ACCOUNT_KEY) { + Session::flash('trackEventCategory', '/account'); + Session::flash('trackEventAction', '/buy_pro_plan'); + Session::flash('trackEventAmount', $payment->amount); + } + + return $payment; + } elseif ($response->isRedirect()) { + $this->invitation->transaction_reference = $ref; + $this->invitation->save(); + //Session::put('transaction_reference', $ref); + Session::save(); + $response->redirect(); + } else { + throw new Exception($response->getMessage() ?: trans('texts.payment_error')); + } + } + + private function updateAddress() + { + if ( ! $this->isGatewayType(GATEWAY_TYPE_CREDIT_CARD)) { + return; + } + + if ( ! $this->accountGateway->show_address || ! $this->accountGateway->update_address) { + return; + } + + $client = $this->client(); + $client->address1 = trim($this->input['address1']); + $client->address2 = trim($this->input['address2']); + $client->city = trim($this->input['city']); + $client->state = trim($this->input['state']); + $client->postal_code = trim($this->input['postal_code']); + $client->country_id = trim($this->input['country_id']); + $client->save(); + } + + protected function paymentDetails($paymentMethod = false) + { + $invoice = $this->invoice(); + $completeUrl = url('complete/' . $this->invitation->invitation_key . '/' . $this->gatewayType); + + $data = [ + 'amount' => $invoice->getRequestedAmount(), + 'currency' => $invoice->getCurrencyCode(), + 'returnUrl' => $completeUrl, + 'cancelUrl' => $this->invitation->getLink(), + 'description' => trans('texts.' . $invoice->getEntityType()) . " {$invoice->invoice_number}", + 'transactionId' => $invoice->invoice_number, + 'transactionType' => 'Purchase', + 'ip' => Request::ip() + ]; + + if ($paymentMethod) { + if ($this->customerReferenceParam) { + $data[$this->customerReferenceParam] = $paymentMethod->account_gateway_token->token; + } + $data[$this->sourceReferenceParam] = $paymentMethod->source_reference; + } elseif ($this->input) { + $data['card'] = new CreditCard($this->paymentDetailsFromInput($this->input)); + } else { + $data['card'] = new CreditCard($this->paymentDetailsFromClient()); + } + + return $data; + } + + private function paymentDetailsFromInput($input) + { + $invoice = $this->invoice(); + $client = $this->client(); + + $data = [ + 'company' => $client->getDisplayName(), + 'firstName' => isset($input['first_name']) ? $input['first_name'] : null, + 'lastName' => isset($input['last_name']) ? $input['last_name'] : null, + 'email' => isset($input['email']) ? $input['email'] : null, + 'number' => isset($input['card_number']) ? $input['card_number'] : null, + 'expiryMonth' => isset($input['expiration_month']) ? $input['expiration_month'] : null, + 'expiryYear' => isset($input['expiration_year']) ? $input['expiration_year'] : null, + ]; + + // allow space until there's a setting to disable + if (isset($input['cvv']) && $input['cvv'] != ' ') { + $data['cvv'] = $input['cvv']; + } + + if (isset($input['address1'])) { + // TODO use cache instead + $country = Country::find($input['country_id']); + + $data = array_merge($data, [ + 'billingAddress1' => $input['address1'], + 'billingAddress2' => $input['address2'], + 'billingCity' => $input['city'], + 'billingState' => $input['state'], + 'billingPostcode' => $input['postal_code'], + 'billingCountry' => $country->iso_3166_2, + 'shippingAddress1' => $input['address1'], + 'shippingAddress2' => $input['address2'], + 'shippingCity' => $input['city'], + 'shippingState' => $input['state'], + 'shippingPostcode' => $input['postal_code'], + 'shippingCountry' => $country->iso_3166_2 + ]); + } + + return $data; + } + + public function paymentDetailsFromClient() + { + $invoice = $this->invoice(); + $client = $this->client(); + $contact = $this->invitation->contact ?: $client->contacts()->first(); + + return [ + 'email' => $contact->email, + 'company' => $client->getDisplayName(), + 'firstName' => $contact->first_name, + 'lastName' => $contact->last_name, + 'billingAddress1' => $client->address1, + 'billingAddress2' => $client->address2, + 'billingCity' => $client->city, + 'billingPostcode' => $client->postal_code, + 'billingState' => $client->state, + 'billingCountry' => $client->country ? $client->country->iso_3166_2 : '', + 'billingPhone' => $contact->phone, + 'shippingAddress1' => $client->address1, + 'shippingAddress2' => $client->address2, + 'shippingCity' => $client->city, + 'shippingPostcode' => $client->postal_code, + 'shippingState' => $client->state, + 'shippingCountry' => $client->country ? $client->country->iso_3166_2 : '', + 'shippingPhone' => $contact->phone, + ]; + } + + protected function shouldCreateToken() + { + if ($this->isGatewayType(GATEWAY_TYPE_BANK_TRANSFER)) { + return true; + } + + if ( ! $this->handles(GATEWAY_TYPE_TOKEN)) { + return false; + } + + if ($this->account()->token_billing_type_id == TOKEN_BILLING_ALWAYS) { + return true; + } + + return boolval(array_get($this->input, 'token_billing')); + } + + /* + protected function tokenDetails() + { + $details = []; + + if ($customer = $this->customer()) { + $details['customerReference'] = $customer->token; + } + + return $details; + } + */ + + public function customer($clientId = false) + { + if ($this->customer) { + return $this->customer; + } + + if ( ! $clientId) { + $clientId = $this->client()->id; + } + + $this->customer = AccountGatewayToken::clientAndGateway($clientId, $this->accountGateway->id) + ->with('payment_methods') + ->first(); + + if ($this->customer) { + $this->customer = $this->checkCustomerExists($this->customer) ? $this->customer : null; + } + + return $this->customer; + } + + protected function checkCustomerExists($customer) + { + return true; + } + + public function verifyBankAccount($client, $publicId, $amount1, $amount2) + { + throw new Exception('verifyBankAccount not implemented'); + } + + public function removePaymentMethod($paymentMethod) + { + $paymentMethod->delete(); + } + + // Some gateways (ie, Checkout.com and Braintree) require generating a token before paying for the invoice + public function createTransactionToken() + { + return null; + } + + public function createToken() + { + $account = $this->account(); + + if ( ! $customer = $this->customer()) { + $customer = new AccountGatewayToken(); + $customer->account_id = $account->id; + $customer->contact_id = $this->invitation->contact_id; + $customer->account_gateway_id = $this->accountGateway->id; + $customer->client_id = $this->client()->id; + $customer = $this->creatingCustomer($customer); + $customer->save(); + } + + /* + // archive the old payment method + $paymentMethod = PaymentMethod::clientId($this->client()->id) + ->isBankAccount($this->isGatewayType(GATEWAY_TYPE_BANK_TRANSFER)) + ->first(); + + if ($paymentMethod) { + $paymentMethod->delete(); + } + */ + + $paymentMethod = $this->createPaymentMethod($customer); + + if ($paymentMethod && ! $customer->default_payment_method_id) { + $customer->default_payment_method_id = $paymentMethod->id; + $customer->save(); + } + + return $paymentMethod; + } + + protected function creatingCustomer($customer) + { + return $customer; + } + + public function createPaymentMethod($customer) + { + $paymentMethod = PaymentMethod::createNew($this->invitation); + $paymentMethod->ip = Request::ip(); + $paymentMethod->account_gateway_token_id = $customer->id; + $paymentMethod->setRelation('account_gateway_token', $customer); + $paymentMethod = $this->creatingPaymentMethod($paymentMethod); + + if ($paymentMethod) { + $paymentMethod->save(); + } + + return $paymentMethod; + } + + protected function creatingPaymentMethod($paymentMethod) + { + return $paymentMethod; + } + + public function deleteToken() + { + + } + + public function createPayment($ref = false, $paymentMethod = null) + { + $invitation = $this->invitation; + $invoice = $this->invoice(); + + $payment = Payment::createNew($invitation); + $payment->invitation_id = $invitation->id; + $payment->account_gateway_id = $this->accountGateway->id; + $payment->invoice_id = $invoice->id; + $payment->amount = $invoice->getRequestedAmount(); + $payment->client_id = $invoice->client_id; + $payment->contact_id = $invitation->contact_id; + $payment->transaction_reference = $ref; + $payment->payment_date = date_create()->format('Y-m-d'); + $payment->ip = Request::ip(); + + $payment = $this->creatingPayment($payment, $paymentMethod); + + if ($paymentMethod) { + $payment->last4 = $paymentMethod->last4; + $payment->expiration = $paymentMethod->expiration; + $payment->routing_number = $paymentMethod->routing_number; + $payment->payment_type_id = $paymentMethod->payment_type_id; + $payment->email = $paymentMethod->email; + $payment->bank_name = $paymentMethod->bank_name; + $payment->payment_method_id = $paymentMethod->id; + } + + $payment->save(); + + // TODO move this code + // enable pro plan for hosted users + if ($invoice->account->account_key == NINJA_ACCOUNT_KEY) { + foreach ($invoice->invoice_items as $invoice_item) { + // Hacky, but invoices don't have meta fields to allow us to store this easily + if (1 == preg_match('/^Plan - (.+) \((.+)\)$/', $invoice_item->product_key, $matches)) { + $plan = strtolower($matches[1]); + $term = strtolower($matches[2]); + if ($plan == PLAN_ENTERPRISE) { + preg_match('/###[\d] [\w]* (\d*)/', $invoice_item->notes, $matches); + $numUsers = $matches[1]; + } else { + $numUsers = 1; + } + } elseif ($invoice_item->product_key == 'Pending Monthly') { + $pending_monthly = true; + } + } + + if (!empty($plan)) { + $account = Account::with('users')->find($invoice->client->public_id); + + if( + $account->company->plan != $plan + || DateTime::createFromFormat('Y-m-d', $account->company->plan_expires) >= date_create('-7 days') + ) { + // Either this is a different plan, or the subscription expired more than a week ago + // Reset any grandfathering + $account->company->plan_started = date_create()->format('Y-m-d'); + } + + if ( + $account->company->plan == $plan + && $account->company->plan_term == $term + && DateTime::createFromFormat('Y-m-d', $account->company->plan_expires) >= date_create() + ) { + // This is a renewal; mark it paid as of when this term expires + $account->company->plan_paid = $account->company->plan_expires; + } else { + $account->company->plan_paid = date_create()->format('Y-m-d'); + } + + $account->company->payment_id = $payment->id; + $account->company->plan = $plan; + $account->company->plan_term = $term; + $account->company->plan_price = $payment->amount; + $account->company->num_users = $numUsers; + $account->company->plan_expires = DateTime::createFromFormat('Y-m-d', $account->company->plan_paid) + ->modify($term == PLAN_TERM_MONTHLY ? '+1 month' : '+1 year')->format('Y-m-d'); + + if (!empty($pending_monthly)) { + $account->company->pending_plan = $plan; + $account->company->pending_term = PLAN_TERM_MONTHLY; + } else { + $account->company->pending_plan = null; + $account->company->pending_term = null; + } + + $account->company->save(); + } + } + + return $payment; + } + + protected function creatingPayment($payment, $paymentMethod) + { + return $payment; + } + + public function refundPayment($payment, $amount = 0) + { + if ($amount) { + $amount = min($amount, $payment->getCompletedAmount()); + } else { + $amount = $payment->getCompletedAmount(); + } + + if ( ! $amount) { + return false; + } + + if ($payment->payment_type_id == PAYMENT_TYPE_CREDIT) { + return $payment->recordRefund($amount); + } + + $details = $this->refundDetails($payment, $amount); + $response = $this->gateway()->refund($details)->send(); + + if ($response->isSuccessful()) { + return $payment->recordRefund($amount); + } elseif ($this->attemptVoidPayment($response, $payment, $amount)) { + $details = ['transactionReference' => $payment->transaction_reference]; + $response = $this->gateway->void($details)->send(); + if ($response->isSuccessful()) { + return $payment->markVoided(); + } + } + + return false; + } + + protected function refundDetails($payment, $amount) + { + return [ + 'amount' => $amount, + 'transactionReference' => $payment->transaction_reference, + ]; + } + + protected function attemptVoidPayment($response, $payment, $amount) + { + // Partial refund not allowed for unsettled transactions + return $amount == $payment->amount; + } + + protected function createLocalPayment($payment) + { + return $payment; + } + + public function completeOffsitePurchase($input) + { + $this->input = $input; + $ref = array_get($this->input, 'token') ?: $this->invitation->transaction_reference; + + if (method_exists($this->gateway(), 'completePurchase')) { + + $details = $this->paymentDetails(); + $response = $this->gateway()->completePurchase($details)->send(); + $ref = $response->getTransactionReference() ?: $ref; + + if ($response->isCancelled()) { + return false; + } elseif ( ! $response->isSuccessful()) { + throw new Exception($response->getMessage()); + } + } + + return $this->createPayment($ref); + } + + public function tokenLinks() + { + if ( ! $this->customer()) { + return []; + } + + $paymentMethods = $this->customer()->payment_methods; + $links = []; + + foreach ($paymentMethods as $paymentMethod) { + if ($paymentMethod->payment_type_id == PAYMENT_TYPE_ACH && $paymentMethod->status != PAYMENT_METHOD_STATUS_VERIFIED) { + continue; + } + + $url = URL::to("/payment/{$this->invitation->invitation_key}/token/".$paymentMethod->public_id); + + if ($paymentMethod->payment_type_id == PAYMENT_TYPE_ACH) { + if ($paymentMethod->bank_name) { + $label = $paymentMethod->bank_name; + } else { + $label = trans('texts.use_bank_on_file'); + } + } elseif ($paymentMethod->payment_type_id == PAYMENT_TYPE_PAYPAL) { + $label = 'PayPal: ' . $paymentMethod->email; + } else { + $label = trans('texts.use_card_on_file'); + } + + $links[] = [ + 'url' => $url, + 'label' => $label, + ]; + } + + return $links; + } + + public function paymentLinks() + { + $links = []; + + foreach ($this->gatewayTypes() as $gatewayType) { + if ($gatewayType === GATEWAY_TYPE_TOKEN) { + continue; + } + + $links[] = [ + 'url' => $this->paymentUrl($gatewayType), + 'label' => trans("texts.{$gatewayType}") + ]; + } + + return $links; + } + + protected function paymentUrl($gatewayType) + { + $account = $this->account(); + $url = URL::to("/payment/{$this->invitation->invitation_key}/{$gatewayType}"); + + // PayPal doesn't allow being run in an iframe so we need to open in new tab + if ($gatewayType === GATEWAY_TYPE_PAYPAL) { + $url .= '#braintree_paypal'; + + if ($account->iframe_url) { + return 'javascript:window.open("' . $url . '", "_blank")'; + } + } + + return $url; + } + + protected function parseCardType($cardName) { + $cardTypes = [ + 'visa' => PAYMENT_TYPE_VISA, + 'americanexpress' => PAYMENT_TYPE_AMERICAN_EXPRESS, + 'amex' => PAYMENT_TYPE_AMERICAN_EXPRESS, + 'mastercard' => PAYMENT_TYPE_MASTERCARD, + 'discover' => PAYMENT_TYPE_DISCOVER, + 'jcb' => PAYMENT_TYPE_JCB, + 'dinersclub' => PAYMENT_TYPE_DINERS, + 'carteblanche' => PAYMENT_TYPE_CARTE_BLANCHE, + 'chinaunionpay' => PAYMENT_TYPE_UNIONPAY, + 'unionpay' => PAYMENT_TYPE_UNIONPAY, + 'laser' => PAYMENT_TYPE_LASER, + 'maestro' => PAYMENT_TYPE_MAESTRO, + 'solo' => PAYMENT_TYPE_SOLO, + 'switch' => PAYMENT_TYPE_SWITCH + ]; + + $cardName = strtolower(str_replace([' ', '-', '_'], '', $cardName)); + + if (empty($cardTypes[$cardName]) && 1 == preg_match('/^('.implode('|', array_keys($cardTypes)).')/', $cardName, $matches)) { + // Some gateways return extra stuff after the card name + $cardName = $matches[1]; + } + + if (!empty($cardTypes[$cardName])) { + return $cardTypes[$cardName]; + } else { + return PAYMENT_TYPE_CREDIT_CARD_OTHER; + } + } + + public function handleWebHook($input) + { + throw new Exception('Unsupported gateway'); + } +} diff --git a/app/Ninja/PaymentDrivers/BitPayPaymentDriver.php b/app/Ninja/PaymentDrivers/BitPayPaymentDriver.php new file mode 100644 index 0000000000..df1821acdb --- /dev/null +++ b/app/Ninja/PaymentDrivers/BitPayPaymentDriver.php @@ -0,0 +1,12 @@ +accountGateway && $this->accountGateway->getPayPalEnabled()) { + $types[] = GATEWAY_TYPE_PAYPAL; + } + + return $types; + } + + public function tokenize() + { + return true; + } + + public function startPurchase($input = false, $sourceId = false) + { + $data = parent::startPurchase($input, $sourceId); + + if ($this->isGatewayType(GATEWAY_TYPE_PAYPAL)) { + /* + if ( ! $sourceId || empty($input['device_data'])) { + throw new Exception(); + } + + Session::put($this->invitation->id . 'device_data', $input['device_data']); + */ + + $data['details'] = ! empty($input['device_data']) ? json_decode($input['device_data']) : false; + } + + return $data; + } + + protected function checkCustomerExists($customer) + { + if ( ! parent::checkCustomerExists($customer)) { + return false; + } + + $customer = $this->gateway()->findCustomer($customer->token) + ->send() + ->getData(); + + return ($customer instanceof Customer); + } + + protected function paymentDetails($paymentMethod = false) + { + $data = parent::paymentDetails($paymentMethod); + + $deviceData = array_get($this->input, 'device_data') ?: Session::get($this->invitation->id . 'device_data'); + + if ($deviceData) { + $data['device_data'] = $deviceData; + } + + if ($this->isGatewayType(GATEWAY_TYPE_PAYPAL, $paymentMethod)) { + $data['ButtonSource'] = 'InvoiceNinja_SP'; + } + + if ( ! $paymentMethod && ! empty($this->input['sourceToken'])) { + $data['token'] = $this->input['sourceToken']; + } + + return $data; + } + + public function createToken() + { + if ($customer = $this->customer()) { + $customerReference = $customer->token; + } else { + $data = $this->paymentDetails(); + $tokenResponse = $this->gateway()->createCustomer(['customerData' => $this->customerData()])->send(); + if ($tokenResponse->isSuccessful()) { + $customerReference = $tokenResponse->getCustomerData()->id; + } else { + return false; + } + } + + if ($customerReference) { + $data['customerId'] = $customerReference; + + if ($this->isGatewayType(GATEWAY_TYPE_PAYPAL)) { + $data['paymentMethodNonce'] = $this->input['sourceToken']; + } + + $tokenResponse = $this->gateway->createPaymentMethod($data)->send(); + if ($tokenResponse->isSuccessful()) { + $this->tokenResponse = $tokenResponse->getData()->paymentMethod; + } else { + return false; + } + } + + return parent::createToken(); + } + + private function customerData() + { + return [ + 'firstName' => array_get($this->input, 'first_name') ?: $this->contact()->first_name, + 'lastName' => array_get($this->input, 'last_name') ?: $this->contact()->last_name, + 'company' => $this->client()->name, + 'email' => $this->contact()->email, + 'phone' => $this->contact()->phone, + 'website' => $this->client()->website + ]; + } + + public function creatingCustomer($customer) + { + $customer->token = $this->tokenResponse->customerId; + + return $customer; + } + + protected function creatingPaymentMethod($paymentMethod) + { + $response = $this->tokenResponse; + + $paymentMethod->source_reference = $response->token; + + if ($this->isGatewayType(GATEWAY_TYPE_CREDIT_CARD)) { + $paymentMethod->payment_type_id = $this->parseCardType($response->cardType); + $paymentMethod->last4 = $response->last4; + $paymentMethod->expiration = $response->expirationYear . '-' . $response->expirationMonth . '-01'; + } elseif ($this->isGatewayType(GATEWAY_TYPE_PAYPAL)) { + $paymentMethod->email = $response->email; + $paymentMethod->payment_type_id = PAYMENT_TYPE_PAYPAL; + } else { + return null; + } + + return $paymentMethod; + } + + public function removePaymentMethod($paymentMethod) + { + parent::removePaymentMethod($paymentMethod); + + $response = $this->gateway()->deletePaymentMethod([ + 'token' => $paymentMethod->source_reference + ])->send(); + + if ($response->isSuccessful()) { + return true; + } else { + throw new Exception($response->getMessage()); + } + } + + protected function attemptVoidPayment($response, $payment, $amount) + { + if ( ! parent::attemptVoidPayment($response, $payment, $amount)) { + return false; + } + + $data = $response->getData(); + + if ($data instanceof \Braintree\Result\Error) { + $error = $data->errors->deepAll()[0]; + if ($error && $error->code == 91506) { + return true; + } + } + + return false; + } + + public function createTransactionToken() + { + return $this->gateway() + ->clientToken() + ->send() + ->getToken(); + } +} diff --git a/app/Ninja/PaymentDrivers/CheckoutComPaymentDriver.php b/app/Ninja/PaymentDrivers/CheckoutComPaymentDriver.php new file mode 100644 index 0000000000..ede0b67823 --- /dev/null +++ b/app/Ninja/PaymentDrivers/CheckoutComPaymentDriver.php @@ -0,0 +1,35 @@ +gateway()->purchase([ + 'amount' => $this->invoice()->getRequestedAmount(), + 'currency' => $this->client()->getCurrencyCode() + ])->send(); + + if ($response->isRedirect()) { + $token = $response->getTransactionReference(); + + $this->invitation->transaction_reference = $token; + $this->invitation->save(); + + return $token; + } + + return false; + } + + protected function paymentDetails($paymentMethod = false) + { + $data = parent::paymentDetails(); + + if ($ref = array_get($this->input, 'token')) { + $data['transactionReference'] = $ref; + } + + return $data; + } + +} diff --git a/app/Ninja/PaymentDrivers/CybersourcePaymentDriver.php b/app/Ninja/PaymentDrivers/CybersourcePaymentDriver.php new file mode 100644 index 0000000000..29299eb94f --- /dev/null +++ b/app/Ninja/PaymentDrivers/CybersourcePaymentDriver.php @@ -0,0 +1,15 @@ +createPayment($input['bill_trans_ref_no']); + } else { + throw new Exception($input['message'] . ': ' . $input['invalid_fields']); + } + } +} diff --git a/app/Ninja/PaymentDrivers/DwollaPaymentDriver.php b/app/Ninja/PaymentDrivers/DwollaPaymentDriver.php new file mode 100644 index 0000000000..26f5626c8c --- /dev/null +++ b/app/Ninja/PaymentDrivers/DwollaPaymentDriver.php @@ -0,0 +1,24 @@ +getSandbox() && isset($_ENV['DWOLLA_SANDBOX_KEY']) && isset($_ENV['DWOLLA_SANSBOX_SECRET'])) { + $gateway->setKey($_ENV['DWOLLA_SANDBOX_KEY']); + $gateway->setSecret($_ENV['DWOLLA_SANSBOX_SECRET']); + } elseif (isset($_ENV['DWOLLA_KEY']) && isset($_ENV['DWOLLA_SECRET'])) { + $gateway->setKey($_ENV['DWOLLA_KEY']); + $gateway->setSecret($_ENV['DWOLLA_SECRET']); + } + + return $gateway; + } +} diff --git a/app/Ninja/PaymentDrivers/EwayRapidSharedPaymentDriver.php b/app/Ninja/PaymentDrivers/EwayRapidSharedPaymentDriver.php new file mode 100644 index 0000000000..fc842919e8 --- /dev/null +++ b/app/Ninja/PaymentDrivers/EwayRapidSharedPaymentDriver.php @@ -0,0 +1,6 @@ +paymentDetails(); + + $details['transactionReference'] = $this->invitation->transaction_reference; + + $response = $this->gateway()->fetchTransaction($details)->send(); + + return $this->createPayment($response->getTransactionReference()); + } + +} diff --git a/app/Ninja/PaymentDrivers/PayFastPaymentDriver.php b/app/Ninja/PaymentDrivers/PayFastPaymentDriver.php new file mode 100644 index 0000000000..79b49b2349 --- /dev/null +++ b/app/Ninja/PaymentDrivers/PayFastPaymentDriver.php @@ -0,0 +1,13 @@ +isGateway(GATEWAY_PAYFAST) && Request::has('pt')) { + $token = Request::query('pt'); + } + } +} diff --git a/app/Ninja/PaymentDrivers/PayPalExpressPaymentDriver.php b/app/Ninja/PaymentDrivers/PayPalExpressPaymentDriver.php new file mode 100644 index 0000000000..ad11a8c128 --- /dev/null +++ b/app/Ninja/PaymentDrivers/PayPalExpressPaymentDriver.php @@ -0,0 +1,28 @@ +payer_id = $this->input['PayerID']; + + return $payment; + } +} diff --git a/app/Ninja/PaymentDrivers/PayPalProPaymentDriver.php b/app/Ninja/PaymentDrivers/PayPalProPaymentDriver.php new file mode 100644 index 0000000000..0c8344cb57 --- /dev/null +++ b/app/Ninja/PaymentDrivers/PayPalProPaymentDriver.php @@ -0,0 +1,20 @@ +accountGateway && $this->accountGateway->getAchEnabled()) { + $types[] = GATEWAY_TYPE_BANK_TRANSFER; + } + + return $types; + } + + public function tokenize() + { + return $this->accountGateway->getPublishableStripeKey(); + } + + public function rules() + { + $rules = parent::rules(); + + if ($this->isGatewayType(GATEWAY_TYPE_BANK_TRANSFER)) { + $rules['authorize_ach'] = 'required'; + } + + return $rules; + } + + protected function checkCustomerExists($customer) + { + $response = $this->gateway() + ->fetchCustomer(['customerReference' => $customer->token]) + ->send(); + + if ( ! $response->isSuccessful()) { + return false; + } + + $this->tokenResponse = $response->getData(); + + // import Stripe tokens created before payment methods table was added + if ( ! count($customer->payment_methods)) { + if ($paymentMethod = $this->createPaymentMethod($customer)) { + $customer->default_payment_method_id = $paymentMethod->id; + $customer->save(); + $customer->load('payment_methods'); + } + } + + return true; + } + + public function isTwoStep() + { + return $this->isGatewayType(GATEWAY_TYPE_BANK_TRANSFER) && empty($this->input['plaidPublicToken']); + } + + protected function paymentDetails($paymentMethod = false) + { + $data = parent::paymentDetails($paymentMethod); + + if ($paymentMethod) { + return $data; + } + + // Stripe complains if the email field is set + unset($data['email']); + + if ( ! empty($this->input['sourceToken'])) { + $data['token'] = $this->input['sourceToken']; + unset($data['card']); + } + + if ( ! empty($this->input['plaidPublicToken'])) { + $data['plaidPublicToken'] = $this->input['plaidPublicToken']; + $data['plaidAccountId'] = $this->input['plaidAccountId']; + unset($data['card']); + } + + return $data; + } + + public function createToken() + { + $invoice = $this->invitation->invoice; + $client = $invoice->client; + + $data = $this->paymentDetails(); + $data['description'] = $client->getDisplayName(); + + if ( ! empty($data['plaidPublicToken'])) { + $plaidResult = $this->getPlaidToken($data['plaidPublicToken'], $data['plaidAccountId']); + unset($data['plaidPublicToken']); + unset($data['plaidAccountId']); + $data['token'] = $plaidResult['stripe_bank_account_token']; + } + + // if a customer already exists link the token to it + if ($customer = $this->customer()) { + $data['customerReference'] = $customer->token; + } + + $tokenResponse = $this->gateway() + ->createCard($data) + ->send(); + + if ($tokenResponse->isSuccessful()) { + $this->tokenResponse = $tokenResponse->getData(); + + return parent::createToken(); + } else { + throw new Exception($tokenResponse->getMessage()); + } + } + + public function creatingCustomer($customer) + { + $customer->token = $this->tokenResponse['id']; + + return $customer; + } + + protected function creatingPaymentMethod($paymentMethod) + { + $data = $this->tokenResponse; + + if (!empty($data['object']) && ($data['object'] == 'card' || $data['object'] == 'bank_account')) { + $source = $data; + } elseif (!empty($data['object']) && $data['object'] == 'customer') { + $sources = !empty($data['sources']) ? $data['sources'] : $data['cards']; + $source = reset($sources['data']); + } else { + $source = !empty($data['source']) ? $data['source'] : $data['card']; + } + + if ( ! $source) { + return false; + } + + $paymentMethod->source_reference = $source['id']; + $paymentMethod->last4 = $source['last4']; + + if ($this->isGatewayType(GATEWAY_TYPE_CREDIT_CARD)) { + + $paymentMethod->expiration = $source['exp_year'] . '-' . $source['exp_month'] . '-01'; + $paymentMethod->payment_type_id = $this->parseCardType($source['brand']); + + } elseif ($this->isGatewayType(GATEWAY_TYPE_BANK_TRANSFER)) { + + $paymentMethod->routing_number = $source['routing_number']; + $paymentMethod->payment_type_id = PAYMENT_TYPE_ACH; + $paymentMethod->status = $source['status']; + $currency = Cache::get('currencies')->where('code', strtoupper($source['currency']))->first(); + + if ($currency) { + $paymentMethod->currency_id = $currency->id; + $paymentMethod->setRelation('currency', $currency); + } + + } + + return $paymentMethod; + } + + protected function creatingPayment($payment, $paymentMethod) + { + if ($this->isGatewayType(GATEWAY_TYPE_BANK_TRANSFER, $paymentMethod)) { + $payment->payment_status_id = $this->purchaseResponse['status'] == 'succeeded' ? PAYMENT_STATUS_COMPLETED : PAYMENT_STATUS_PENDING; + } + + return $payment; + } + + public function removePaymentMethod($paymentMethod) + { + parent::removePaymentMethod($paymentMethod); + + if ( ! $paymentMethod->relationLoaded('account_gateway_token')) { + $paymentMethod->load('account_gateway_token'); + } + + $response = $this->gateway()->deleteCard([ + 'customerReference' => $paymentMethod->account_gateway_token->token, + 'cardReference' => $paymentMethod->source_reference + ])->send(); + + if ($response->isSuccessful()) { + return true; + } else { + throw new Exception($response->getMessage()); + } + } + + private function getPlaidToken($publicToken, $accountId) + { + $clientId = $this->accountGateway->getPlaidClientId(); + $secret = $this->accountGateway->getPlaidSecret(); + + if (!$clientId) { + throw new Exception('plaid client id not set'); // TODO use text strings + } + + if (!$secret) { + throw new Exception('plaid secret not set'); + } + + try { + $subdomain = $this->accountGateway->getPlaidEnvironment() == 'production' ? 'api' : 'tartan'; + $response = (new \GuzzleHttp\Client(['base_uri'=>"https://{$subdomain}.plaid.com"]))->request( + 'POST', + 'exchange_token', + [ + 'allow_redirects' => false, + 'headers' => ['content-type' => 'application/x-www-form-urlencoded'], + 'body' => http_build_query([ + 'client_id' => $clientId, + 'secret' => $secret, + 'public_token' => $publicToken, + 'account_id' => $accountId, + ]) + ] + ); + return json_decode($response->getBody(), true); + } catch (\GuzzleHttp\Exception\BadResponseException $e) { + $response = $e->getResponse(); + $body = json_decode($response->getBody(), true); + + if ($body && !empty($body['message'])) { + throw new Exception($body['message']); + } else { + throw new Exception($e->getMessage()); + } + } + } + + public function verifyBankAccount($client, $publicId, $amount1, $amount2) + { + $customer = $this->customer($client->id); + $paymentMethod = PaymentMethod::clientId($client->id) + ->wherePublicId($publicId) + ->firstOrFail(); + + // Omnipay doesn't support verifying payment methods + // Also, it doesn't want to urlencode without putting numbers inside the brackets + $result = $this->makeStripeCall( + 'POST', + 'customers/' . $customer->token . '/sources/' . $paymentMethod->source_reference . '/verify', + 'amounts[]=' . intval($amount1) . '&amounts[]=' . intval($amount2) + ); + + if (is_string($result)) { + return $result; + } + + $paymentMethod->status = PAYMENT_METHOD_STATUS_VERIFIED; + $paymentMethod->save(); + + if ( ! $customer->default_payment_method_id) { + $customer->default_payment_method_id = $paymentMethod->id; + $customer->save(); + } + + return true; + } + + public function makeStripeCall($method, $url, $body = null) + { + $apiKey = $this->accountGateway->getConfig()->apiKey; + + if (!$apiKey) { + return 'No API key set'; + } + + try{ + $options = [ + 'headers' => ['content-type' => 'application/x-www-form-urlencoded'], + 'auth' => [$apiKey, ''], + ]; + + if ($body) { + $options['body'] = $body; + } + + $response = (new \GuzzleHttp\Client(['base_uri'=>'https://api.stripe.com/v1/']))->request( + $method, + $url, + $options + ); + return json_decode($response->getBody(), true); + } catch (\GuzzleHttp\Exception\BadResponseException $e) { + $response = $e->getResponse(); + + $body = json_decode($response->getBody(), true); + if ($body && $body['error'] && $body['error']['type'] == 'invalid_request_error') { + return $body['error']['message']; + } + + return $e->getMessage(); + } + } + + public function handleWebHook($input) + { + $eventId = array_get($input, 'id'); + $eventType= array_get($input, 'type'); + + $accountGateway = $this->accountGateway; + $accountId = $accountGateway->account_id; + + if (!$eventId) { + throw new Exception('Missing event id'); + } + + if (!$eventType) { + throw new Exception('Missing event type'); + } + + $supportedEvents = [ + 'charge.failed', + 'charge.succeeded', + 'charge.refunded', + 'customer.source.updated', + 'customer.source.deleted', + 'customer.bank_account.deleted', + ]; + + if (!in_array($eventType, $supportedEvents)) { + return ['message' => 'Ignoring event']; + } + + // Fetch the event directly from Stripe for security + $eventDetails = $this->makeStripeCall('GET', 'events/'.$eventId); + + if (is_string($eventDetails) || !$eventDetails) { + throw new Exception('Could not get event details'); + } + + if ($eventType != $eventDetails['type']) { + throw new Exception('Event type mismatch'); + } + + if (!$eventDetails['pending_webhooks']) { + throw new Exception('This is not a pending event'); + } + + if ($eventType == 'charge.failed' || $eventType == 'charge.succeeded' || $eventType == 'charge.refunded') { + $charge = $eventDetails['data']['object']; + $transactionRef = $charge['id']; + + $payment = Payment::scope(false, $accountId)->where('transaction_reference', '=', $transactionRef)->first(); + + if (!$payment) { + throw new Exception('Unknown payment'); + } + + if ($eventType == 'charge.failed') { + if (!$payment->isFailed()) { + $payment->markFailed($charge['failure_message']); + + $userMailer = app('App\Ninja\Mailers\UserMailer'); + $userMailer->sendNotification($payment->user, $payment->invoice, 'payment_failed', $payment); + } + } elseif ($eventType == 'charge.succeeded') { + $payment->markComplete(); + } elseif ($eventType == 'charge.refunded') { + $payment->recordRefund($charge['amount_refunded'] / 100 - $payment->refunded); + } + } elseif($eventType == 'customer.source.updated' || $eventType == 'customer.source.deleted' || $eventType == 'customer.bank_account.deleted') { + $source = $eventDetails['data']['object']; + $sourceRef = $source['id']; + + $paymentMethod = PaymentMethod::scope(false, $accountId)->where('source_reference', '=', $sourceRef)->first(); + + if (!$paymentMethod) { + throw new Exception('Unknown payment method'); + } + + if ($eventType == 'customer.source.deleted' || $eventType == 'customer.bank_account.deleted') { + $paymentMethod->delete(); + } elseif ($eventType == 'customer.source.updated') { + //$this->paymentService->convertPaymentMethodFromStripe($source, null, $paymentMethod)->save(); + } + } + + return 'Processed successfully'; + } +} diff --git a/app/Ninja/PaymentDrivers/TwoCheckoutPaymentDriver.php b/app/Ninja/PaymentDrivers/TwoCheckoutPaymentDriver.php new file mode 100644 index 0000000000..005611d4a0 --- /dev/null +++ b/app/Ninja/PaymentDrivers/TwoCheckoutPaymentDriver.php @@ -0,0 +1,13 @@ +createPayment($input['order_number']); + } + +} diff --git a/app/Ninja/PaymentDrivers/WePayPaymentDriver.php b/app/Ninja/PaymentDrivers/WePayPaymentDriver.php new file mode 100644 index 0000000000..c8865e74d1 --- /dev/null +++ b/app/Ninja/PaymentDrivers/WePayPaymentDriver.php @@ -0,0 +1,308 @@ +accountGateway && $this->accountGateway->getAchEnabled()) { + $types[] = GATEWAY_TYPE_BANK_TRANSFER; + } + + return $types; + } + + /* + public function startPurchase($input = false, $sourceId = false) + { + $data = parent::startPurchase($input, $sourceId); + + if ($this->isGatewayType(GATEWAY_TYPE_BANK_TRANSFER)) { + if ( ! $sourceId) { + throw new Exception(); + } + } + + return $data; + } + */ + + public function tokenize() + { + return true; + } + + protected function checkCustomerExists($customer) + { + return true; + } + + public function rules() + { + $rules = parent::rules(); + + if ($this->isGatewayType(GATEWAY_TYPE_BANK_TRANSFER)) { + $rules = array_merge($rules, [ + 'authorize_ach' => 'required', + 'tos_agree' => 'required', + ]); + } + + return $rules; + } + + protected function paymentDetails($paymentMethod = false) + { + $data = parent::paymentDetails($paymentMethod); + + if ($transactionId = Session::get($this->invitation->id . 'payment_ref')) { + $data['transaction_id'] = $transactionId; + } + + $data['applicationFee'] = $this->calculateApplicationFee($data['amount']); + $data['feePayer'] = WEPAY_FEE_PAYER; + $data['callbackUri'] = $this->accountGateway->getWebhookUrl(); + + if ($this->isGatewayType(GATEWAY_TYPE_BANK_TRANSFER, $paymentMethod)) { + $data['paymentMethodType'] = 'payment_bank'; + } + + return $data; + } + + public function createToken() + { + $wepay = Utils::setupWePay($this->accountGateway); + $token = intval($this->input['sourceToken']); + + if ($this->isGatewayType(GATEWAY_TYPE_BANK_TRANSFER)) { + // Persist bank details + $this->tokenResponse = $wepay->request('/payment_bank/persist', [ + 'client_id' => WEPAY_CLIENT_ID, + 'client_secret' => WEPAY_CLIENT_SECRET, + 'payment_bank_id' => $token, + ]); + } else { + // Authorize credit card + $tokenResponse = $wepay->request('credit_card/authorize', [ + 'client_id' => WEPAY_CLIENT_ID, + 'client_secret' => WEPAY_CLIENT_SECRET, + 'credit_card_id' => $token, + ]); + + // Update the callback uri and get the card details + $tokenResponse = $wepay->request('credit_card/modify', [ + 'client_id' => WEPAY_CLIENT_ID, + 'client_secret' => WEPAY_CLIENT_SECRET, + 'credit_card_id' => $token, + 'auto_update' => WEPAY_AUTO_UPDATE, + 'callback_uri' => $this->accountGateway->getWebhookUrl(), + ]); + + $this->tokenResponse = $wepay->request('credit_card', [ + 'client_id' => WEPAY_CLIENT_ID, + 'client_secret' => WEPAY_CLIENT_SECRET, + 'credit_card_id' => $token, + ]); + } + + return parent::createToken(); + } + + /* + public function creatingCustomer($customer) + { + if ($gatewayResponse instanceof \Omnipay\WePay\Message\CustomCheckoutResponse) { + $wepay = \Utils::setupWePay($accountGateway); + $paymentMethodType = $gatewayResponse->getData()['payment_method']['type']; + + $gatewayResponse = $wepay->request($paymentMethodType, array( + 'client_id' => WEPAY_CLIENT_ID, + 'client_secret' => WEPAY_CLIENT_SECRET, + $paymentMethodType.'_id' => $gatewayResponse->getData()['payment_method'][$paymentMethodType]['id'], + )); + } + } + */ + + protected function creatingPaymentMethod($paymentMethod) + { + $source = $this->tokenResponse; + + if ($this->isGatewayType(GATEWAY_TYPE_BANK_TRANSFER)) { + $paymentMethod->payment_type_id = PAYMENT_TYPE_ACH; + $paymentMethod->last4 = $source->account_last_four; + $paymentMethod->bank_name = $source->bank_name; + $paymentMethod->source_reference = $source->payment_bank_id; + + switch($source->state) { + case 'new': + case 'pending': + $paymentMethod->status = 'new'; + break; + case 'authorized': + $paymentMethod->status = 'verified'; + break; + } + } else { + $paymentMethod->last4 = $source->last_four; + $paymentMethod->payment_type_id = $this->parseCardType($source->credit_card_name); + $paymentMethod->expiration = $source->expiration_year . '-' . $source->expiration_month . '-01'; + $paymentMethod->source_reference = $source->credit_card_id; + } + + return $paymentMethod; + } + + public function removePaymentMethod($paymentMethod) + { + parent::removePaymentMethod($paymentMethod); + + $wepay = Utils::setupWePay($this->accountGateway); + $response = $wepay->request('/credit_card/delete', [ + 'client_id' => WEPAY_CLIENT_ID, + 'client_secret' => WEPAY_CLIENT_SECRET, + 'credit_card_id' => intval($paymentMethod->source_reference), + ]); + + if ($response->state == 'deleted') { + return true; + } else { + throw new Exception(trans('texts.failed_remove_payment_method')); + } + } + + protected function refundDetails($payment, $amount) + { + $data = parent::refundDetails($payment, $amount); + + $data['refund_reason'] = 'Refund issued by merchant.'; + + // WePay issues a full refund when no amount is set. If an amount is set, it will try + // to issue a partial refund without refunding any fees. However, the Stripe driver + // (but not the API) requires the amount parameter to be set no matter what. + if ($data['amount'] == $payment->getCompletedAmount()) { + unset($data['amount']); + } + + return $data; + } + + protected function attemptVoidPayment($response, $payment, $amount) + { + if ( ! parent::attemptVoidPayment($response, $payment, $amount)) { + return false; + } + + return $response->getCode() == 4004; + } + + private function calculateApplicationFee($amount) + { + $fee = (WEPAY_APP_FEE_MULTIPLIER * $amount) + WEPAY_APP_FEE_FIXED; + + return floor(min($fee, $amount * 0.2));// Maximum fee is 20% of the amount. + } + + public function handleWebHook($input) + { + $accountGateway = $this->accountGateway; + $accountId = $accountGateway->account_id; + + foreach (array_keys($input) as $key) { + if ('_id' == substr($key, -3)) { + $objectType = substr($key, 0, -3); + $objectId = $input[$key]; + break; + } + } + + if (!isset($objectType)) { + throw new Exception('Could not find object id parameter'); + } + + if ($objectType == 'credit_card') { + $paymentMethod = PaymentMethod::scope(false, $accountId)->where('source_reference', '=', $objectId)->first(); + + if (!$paymentMethod) { + throw new Exception('Unknown payment method'); + } + + $wepay = Utils::setupWePay($accountGateway); + $source = $wepay->request('credit_card', [ + 'client_id' => WEPAY_CLIENT_ID, + 'client_secret' => WEPAY_CLIENT_SECRET, + 'credit_card_id' => intval($objectId), + ]); + + if ($source->state == 'deleted') { + $paymentMethod->delete(); + } else { + //$this->paymentService->convertPaymentMethodFromWePay($source, null, $paymentMethod)->save(); + } + + return 'Processed successfully'; + } elseif ($objectType == 'account') { + $config = $accountGateway->getConfig(); + if ($config->accountId != $objectId) { + throw new Exception('Unknown account'); + } + + $wepay = Utils::setupWePay($accountGateway); + $wepayAccount = $wepay->request('account', [ + 'account_id' => intval($objectId), + ]); + + if ($wepayAccount->state == 'deleted') { + $accountGateway->delete(); + } else { + $config->state = $wepayAccount->state; + $accountGateway->setConfig($config); + $accountGateway->save(); + } + + return ['message' => 'Processed successfully']; + } elseif ($objectType == 'checkout') { + $payment = Payment::scope(false, $accountId)->where('transaction_reference', '=', $objectId)->first(); + + if (!$payment) { + throw new Exception('Unknown payment'); + } + + $wepay = Utils::setupWePay($accountGateway); + $checkout = $wepay->request('checkout', [ + 'checkout_id' => intval($objectId), + ]); + + if ($checkout->state == 'refunded') { + $payment->recordRefund(); + } elseif (!empty($checkout->refund) && !empty($checkout->refund->amount_refunded) && ($checkout->refund->amount_refunded - $payment->refunded) > 0) { + $payment->recordRefund($checkout->refund->amount_refunded - $payment->refunded); + } + + if ($checkout->state == 'captured') { + $payment->markComplete(); + } elseif ($checkout->state == 'cancelled') { + $payment->markCancelled(); + } elseif ($checkout->state == 'failed') { + $payment->markFailed(); + } + + return 'Processed successfully'; + } else { + return 'Ignoring event'; + } + } + +} diff --git a/app/Ninja/Presenters/AccountPresenter.php b/app/Ninja/Presenters/AccountPresenter.php index dc9cacbb8a..cd829fd4f4 100644 --- a/app/Ninja/Presenters/AccountPresenter.php +++ b/app/Ninja/Presenters/AccountPresenter.php @@ -3,18 +3,31 @@ use Utils; use Laracasts\Presenter\Presenter; -class AccountPresenter extends Presenter { +/** + * Class AccountPresenter + */ +class AccountPresenter extends Presenter +{ + /** + * @return mixed + */ public function name() { return $this->entity->name ?: trans('texts.untitled_account'); } + /** + * @return string + */ public function website() { return Utils::addHttp($this->entity->website); } + /** + * @return mixed + */ public function currencyCode() { $currencyId = $this->entity->getCurrencyId(); diff --git a/app/Ninja/Presenters/ClientPresenter.php b/app/Ninja/Presenters/ClientPresenter.php index bb32a8b62f..44efc20701 100644 --- a/app/Ninja/Presenters/ClientPresenter.php +++ b/app/Ninja/Presenters/ClientPresenter.php @@ -1,10 +1,7 @@ {$text}
    "; } - - public function url() - { - return URL::to('/clients/' . $this->entity->public_id); - } - - public function link() - { - return link_to('/clients/' . $this->entity->public_id, $this->entity->getDisplayName()); - } -} \ No newline at end of file +} diff --git a/app/Ninja/Presenters/CreditPresenter.php b/app/Ninja/Presenters/CreditPresenter.php index 7e38205b10..8bcafe58d7 100644 --- a/app/Ninja/Presenters/CreditPresenter.php +++ b/app/Ninja/Presenters/CreditPresenter.php @@ -1,17 +1,25 @@ entity->client ? $this->entity->client->getDisplayName() : ''; } + /** + * @return \DateTime|string + */ public function credit_date() { return Utils::fromSqlDate($this->entity->credit_date); } -} \ No newline at end of file +} diff --git a/app/Ninja/Presenters/EntityPresenter.php b/app/Ninja/Presenters/EntityPresenter.php new file mode 100644 index 0000000000..7a8255ccb7 --- /dev/null +++ b/app/Ninja/Presenters/EntityPresenter.php @@ -0,0 +1,31 @@ +entity->getEntityType(); + $id = $this->entity->public_id; + $link = sprintf('/%ss/%s', $type, $id); + + return URL::to($link); + } + + /** + * @return mixed + */ + public function link() + { + $name = $this->entity->getDisplayName(); + $link = $this->url(); + + return link_to($link, $name)->toHtml(); + } +} diff --git a/app/Ninja/Presenters/ExpensePresenter.php b/app/Ninja/Presenters/ExpensePresenter.php index 1980480a2f..3de0773625 100644 --- a/app/Ninja/Presenters/ExpensePresenter.php +++ b/app/Ninja/Presenters/ExpensePresenter.php @@ -1,28 +1,35 @@ entity->vendor ? $this->entity->vendor->getDisplayName() : ''; } + /** + * @return \DateTime|string + */ public function expense_date() { return Utils::fromSqlDate($this->entity->expense_date); } + /** + * @return int + */ public function invoiced_amount() { return $this->entity->invoice_id ? $this->entity->convertedAmount() : 0; } - - public function link() - { - return link_to('/expenses/' . $this->entity->public_id, $this->entity->name); - } -} \ No newline at end of file + +} diff --git a/app/Ninja/Presenters/InvoicePresenter.php b/app/Ninja/Presenters/InvoicePresenter.php index 36a2ce2acb..2af94f8060 100644 --- a/app/Ninja/Presenters/InvoicePresenter.php +++ b/app/Ninja/Presenters/InvoicePresenter.php @@ -1,10 +1,8 @@ entity->partial > 0) { return 'partial_due'; - } elseif ($this->entity->is_quote) { + } elseif ($this->entity->isType(INVOICE_TYPE_QUOTE)) { return 'total'; } else { return 'balance_due'; @@ -45,6 +43,8 @@ class InvoicePresenter extends Presenter { return trans('texts.deleted'); } elseif ($this->entity->trashed()) { return trans('texts.archived'); + } elseif ($this->entity->is_recurring) { + return trans('texts.active'); } else { $status = $this->entity->invoice_status ? $this->entity->invoice_status->name : 'draft'; $status = strtolower($status); @@ -64,17 +64,9 @@ class InvoicePresenter extends Presenter { public function frequency() { - return $this->entity->frequency ? $this->entity->frequency->name : ''; - } - - public function url() - { - return URL::to('/invoices/' . $this->entity->public_id); - } - - public function link() - { - return link_to('/invoices/' . $this->entity->public_id, $this->entity->invoice_number); + $frequency = $this->entity->frequency ? $this->entity->frequency->name : ''; + $frequency = strtolower($frequency); + return trans('texts.freq_'.$frequency); } public function email() @@ -82,4 +74,29 @@ class InvoicePresenter extends Presenter { $client = $this->entity->client; return count($client->contacts) ? $client->contacts[0]->email : ''; } -} \ No newline at end of file + + public function autoBillEmailMessage() + { + $client = $this->entity->client; + $paymentMethod = $client->defaultPaymentMethod(); + + if ( ! $paymentMethod) { + return false; + } + + if ($paymentMethod->payment_type_id == PAYMENT_TYPE_ACH) { + $paymentMethodString = trans('texts.auto_bill_payment_method_bank_transfer'); + } elseif ($paymentMethod->payment_type_id == PAYMENT_TYPE_PAYPAL) { + $paymentMethodString = trans('texts.auto_bill_payment_method_paypal'); + } else { + $paymentMethodString = trans('texts.auto_bill_payment_method_credit_card'); + } + + $data = [ + 'payment_method' => $paymentMethodString, + 'due_date' => $this->due_date(), + ]; + + return trans('texts.auto_bill_notification', $data); + } +} diff --git a/app/Ninja/Presenters/PaymentPresenter.php b/app/Ninja/Presenters/PaymentPresenter.php index a1c3692991..8d91a4827d 100644 --- a/app/Ninja/Presenters/PaymentPresenter.php +++ b/app/Ninja/Presenters/PaymentPresenter.php @@ -1,10 +1,8 @@ entity->public_id . '/edit'); - } - - public function link() - { - return link_to('/payments/' . $this->entity->public_id . '/edit', $this->entity->getDisplayName()); - } - -} \ No newline at end of file +} diff --git a/app/Ninja/Presenters/TaskPresenter.php b/app/Ninja/Presenters/TaskPresenter.php index 367e849ca7..d9b96c1e9a 100644 --- a/app/Ninja/Presenters/TaskPresenter.php +++ b/app/Ninja/Presenters/TaskPresenter.php @@ -1,20 +1,30 @@ entity->client ? $this->entity->client->getDisplayName() : ''; } + /** + * @return mixed + */ public function user() { return $this->entity->user->getDisplayName(); } + /** + * @param $account + * @return mixed + */ public function times($account) { $parts = json_decode($this->entity->time_log) ?: []; @@ -37,6 +47,9 @@ class TaskPresenter extends Presenter { return implode("\n", $times); } + /** + * @return string + */ public function status() { $class = $text = ''; @@ -54,5 +67,4 @@ class TaskPresenter extends Presenter { return "{$text}"; } - -} \ No newline at end of file +} diff --git a/app/Ninja/Presenters/VendorPresenter.php b/app/Ninja/Presenters/VendorPresenter.php index d0bef4e0c8..afc02f9065 100644 --- a/app/Ninja/Presenters/VendorPresenter.php +++ b/app/Ninja/Presenters/VendorPresenter.php @@ -1,17 +1,12 @@ entity->country ? $this->entity->country->name : ''; } - - public function link() - { - return link_to('/vendors/' . $this->entity->public_id, $this->entity->name); - } -} \ No newline at end of file +} diff --git a/app/Ninja/Repositories/AccountGatewayRepository.php b/app/Ninja/Repositories/AccountGatewayRepository.php index b61f854f2d..c59b0d77ab 100644 --- a/app/Ninja/Repositories/AccountGatewayRepository.php +++ b/app/Ninja/Repositories/AccountGatewayRepository.php @@ -1,10 +1,6 @@ join('gateways', 'gateways.id', '=', 'account_gateways.gateway_id') - ->where('account_gateways.deleted_at', '=', null) - ->where('account_gateways.account_id', '=', $accountId) - ->select('account_gateways.public_id', 'gateways.name', 'account_gateways.deleted_at', 'account_gateways.gateway_id'); + ->where('account_gateways.account_id', '=', $accountId); + + if (!\Session::get('show_trash:gateway')) { + $query->where('account_gateways.deleted_at', '=', null); + } + + return $query->select('account_gateways.id', 'account_gateways.public_id', 'gateways.name', 'account_gateways.deleted_at', 'account_gateways.gateway_id'); } } diff --git a/app/Ninja/Repositories/AccountRepository.php b/app/Ninja/Repositories/AccountRepository.php index 38753dde9b..1c6f7f30c3 100644 --- a/app/Ninja/Repositories/AccountRepository.php +++ b/app/Ninja/Repositories/AccountRepository.php @@ -4,7 +4,6 @@ use Auth; use Request; use Session; use Utils; -use DB; use URL; use stdClass; use Validator; @@ -28,7 +27,7 @@ class AccountRepository { $company = new Company(); $company->save(); - + $account = new Account(); $account->ip = Request::getClientIp(); $account->account_key = str_random(RANDOM_KEY_LENGTH); @@ -87,7 +86,7 @@ class AccountRepository private function getAccountSearchData($user) { $account = $user->account; - + $data = [ 'clients' => [], 'contacts' => [], @@ -102,7 +101,7 @@ class AccountRepository if ($account->custom_client_label2) { $data[$account->custom_client_label2] = []; } - + if ($user->hasPermission('view_all')) { $clients = Client::scope() ->with('contacts', 'invoices') @@ -114,7 +113,7 @@ class AccountRepository $query->where('user_id', '=', $user->id); }])->get(); } - + foreach ($clients as $client) { if ($client->name) { $data['clients'][] = [ @@ -122,20 +121,20 @@ class AccountRepository 'tokens' => $client->name, 'url' => $client->present()->url, ]; - } + } if ($client->custom_value1) { $data[$account->custom_client_label1][] = [ 'value' => "{$client->custom_value1}: " . $client->getDisplayName(), 'tokens' => $client->custom_value1, - 'url' => $client->present()->url, + 'url' => $client->present()->url, ]; - } + } if ($client->custom_value2) { $data[$account->custom_client_label2][] = [ 'value' => "{$client->custom_value2}: " . $client->getDisplayName(), 'tokens' => $client->custom_value2, - 'url' => $client->present()->url, + 'url' => $client->present()->url, ]; } @@ -177,6 +176,7 @@ class AccountRepository ENTITY_QUOTE, ENTITY_TASK, ENTITY_EXPENSE, + ENTITY_EXPENSE_CATEGORY, ENTITY_VENDOR, ENTITY_RECURRING_INVOICE, ENTITY_PAYMENT, @@ -186,11 +186,11 @@ class AccountRepository foreach ($entityTypes as $entityType) { $features[] = [ "new_{$entityType}", - "/{$entityType}s/create", + Utils::pluralizeEntityType($entityType) . '/create' ]; $features[] = [ - "list_{$entityType}s", - "/{$entityType}s", + 'list_' . Utils::pluralizeEntityType($entityType), + Utils::pluralizeEntityType($entityType) ]; } @@ -228,23 +228,26 @@ class AccountRepository return $data; } - public function enablePlan($plan = PLAN_PRO, $term = PLAN_TERM_MONTHLY, $credit = 0, $pending_monthly = false) + public function enablePlan($plan, $credit = 0, $pending_monthly = false) { $account = Auth::user()->account; $client = $this->getNinjaClient($account); - $invitation = $this->createNinjaInvoice($client, $account, $plan, $term, $credit, $pending_monthly); + $invitation = $this->createNinjaInvoice($client, $account, $plan, $credit, $pending_monthly); return $invitation; } - public function createNinjaInvoice($client, $clientAccount, $plan = PLAN_PRO, $term = PLAN_TERM_MONTHLY, $credit = 0, $pending_monthly = false) + public function createNinjaInvoice($client, $clientAccount, $plan, $credit = 0, $pending_monthly = false) { + $term = $plan['term']; + $plan_cost = $plan['price']; + $num_users = $plan['num_users']; + $plan = $plan['plan']; + if ($credit < 0) { $credit = 0; } - - $plan_cost = Account::$plan_prices[$plan][$term]; - + $account = $this->getNinjaAccount(); $lastInvoice = Invoice::withTrashed()->whereAccountId($account->id)->orderBy('public_id', 'DESC')->first(); $publicId = $lastInvoice ? ($lastInvoice->public_id + 1) : 1; @@ -266,28 +269,33 @@ class AccountRepository $credit_item->product_key = trans('texts.plan_credit_product'); $invoice->invoice_items()->save($credit_item); } - + $item = InvoiceItem::createNew($invoice); $item->qty = 1; $item->cost = $plan_cost; $item->notes = trans("texts.{$plan}_plan_{$term}_description"); - + + if ($plan == PLAN_ENTERPRISE) { + $min = Utils::getMinNumUsers($num_users); + $item->notes .= "\n\n###" . trans('texts.min_to_max_users', ['min' => $min, 'max' => $num_users]); + } + // Don't change this without updating the regex in PaymentService->createPayment() $item->product_key = 'Plan - '.ucfirst($plan).' ('.ucfirst($term).')'; $invoice->invoice_items()->save($item); - + if ($pending_monthly) { $term_end = $term == PLAN_MONTHLY ? date_create('+1 month') : date_create('+1 year'); $pending_monthly_item = InvoiceItem::createNew($invoice); $item->qty = 1; $pending_monthly_item->cost = 0; - $pending_monthly_item->notes = trans("texts.plan_pending_monthly", array('date', Utils::dateToString($term_end))); - + $pending_monthly_item->notes = trans('texts.plan_pending_monthly', ['date', Utils::dateToString($term_end)]); + // Don't change this without updating the text in PaymentService->createPayment() $pending_monthly_item->product_key = 'Pending Monthly'; $invoice->invoice_items()->save($pending_monthly_item); } - + $invitation = new Invitation(); $invitation->account_id = $account->id; @@ -328,12 +336,14 @@ class AccountRepository $user->notify_paid = true; $account->users()->save($user); - $accountGateway = new AccountGateway(); - $accountGateway->user_id = $user->id; - $accountGateway->gateway_id = NINJA_GATEWAY_ID; - $accountGateway->public_id = 1; - $accountGateway->setConfig(json_decode(env(NINJA_GATEWAY_CONFIG))); - $account->account_gateways()->save($accountGateway); + if ($config = env(NINJA_GATEWAY_CONFIG)) { + $accountGateway = new AccountGateway(); + $accountGateway->user_id = $user->id; + $accountGateway->gateway_id = NINJA_GATEWAY_ID; + $accountGateway->public_id = 1; + $accountGateway->setConfig(json_decode($config)); + $account->account_gateways()->save($accountGateway); + } } return $account; @@ -356,11 +366,11 @@ class AccountRepository $client->user_id = $ninjaUser->id; $client->currency_id = 1; } - + foreach (['name', 'address1', 'address2', 'city', 'state', 'postal_code', 'country_id', 'work_phone', 'language_id', 'vat_number'] as $field) { $client->$field = $account->$field; } - + $client->save(); if ($clientExists) { @@ -372,7 +382,7 @@ class AccountRepository $contact->public_id = $account->id; $contact->is_primary = true; } - + $user = $account->getPrimaryUser(); foreach (['first_name', 'last_name', 'email', 'phone'] as $field) { $contact->$field = $user->$field; @@ -513,7 +523,7 @@ class AccountRepository if ($with) { $users->with($with); } - + return $users->get(); } @@ -565,7 +575,7 @@ class AccountRepository $record->save(); $users = $this->getUserAccounts($record); - + // Pick the primary user foreach ($users as $user) { if (!$user->public_id) { @@ -573,16 +583,16 @@ class AccountRepository if(empty($primaryUser)) { $useAsPrimary = true; } - + $planDetails = $user->account->getPlanDetails(false, false); $planLevel = 0; - + if ($planDetails) { $planLevel = 1; if ($planDetails['plan'] == PLAN_ENTERPRISE) { $planLevel = 2; } - + if (!$useAsPrimary && ( $planLevel > $primaryUserPlanLevel || ($planLevel == $primaryUserPlanLevel && $planDetails['expires'] > $primaryUserPlanExpires) @@ -590,7 +600,7 @@ class AccountRepository $useAsPrimary = true; } } - + if ($useAsPrimary) { $primaryUser = $user; $primaryUserPlanLevel = $planLevel; @@ -600,14 +610,14 @@ class AccountRepository } } } - + // Merge other companies into the primary user's company if (!empty($primaryUser)) { foreach ($users as $user) { if ($user == $primaryUser || $user->public_id) { continue; } - + if ($user->account->company_id != $primaryUser->account->company_id) { foreach ($user->account->company->accounts as $account) { $account->company_id = $primaryUser->account->company_id; @@ -636,9 +646,9 @@ class AccountRepository $userAccount->removeUserId($userId); $userAccount->save(); } - + $user = User::whereId($userId)->first(); - + if (!$user->public_id && $user->account->company->accounts->count() > 1) { $company = Company::create(); $company->save(); @@ -660,7 +670,7 @@ class AccountRepository ->withTrashed() ->first(); } while ($match); - + return $code; } @@ -668,7 +678,7 @@ class AccountRepository { $name = trim($name) ?: 'TOKEN'; $users = $this->findUsers($user); - + foreach ($users as $user) { if ($token = AccountToken::whereUserId($user->id)->whereName($name)->first()) { continue; diff --git a/app/Ninja/Repositories/ActivityRepository.php b/app/Ninja/Repositories/ActivityRepository.php index b51c8bbf29..f36812546d 100644 --- a/app/Ninja/Repositories/ActivityRepository.php +++ b/app/Ninja/Repositories/ActivityRepository.php @@ -20,14 +20,14 @@ class ActivityRepository } // init activity and copy over context - $activity = self::getBlank($altEntity ?: $client); + $activity = self::getBlank($altEntity ?: ($client ?: $entity)); $activity = Utils::copyContext($activity, $entity); $activity = Utils::copyContext($activity, $altEntity); - $activity->client_id = $client->id; $activity->activity_type_id = $activityTypeId; $activity->adjustment = $balanceChange; - $activity->balance = $client->balance + $balanceChange; + $activity->client_id = $client ? $client->id : 0; + $activity->balance = $client ? ($client->balance + $balanceChange) : 0; $keyField = $entity->getKeyField(); $activity->$keyField = $entity->id; @@ -35,7 +35,9 @@ class ActivityRepository $activity->ip = Request::getClientIp(); $activity->save(); - $client->updateBalances($balanceChange, $paidToDateChange); + if ($client) { + $client->updateBalances($balanceChange, $paidToDateChange); + } return $activity; } @@ -91,14 +93,16 @@ class ActivityRepository 'invoices.public_id as invoice_public_id', 'invoices.is_recurring', 'clients.name as client_name', + 'accounts.name as account_name', 'clients.public_id as client_public_id', 'contacts.id as contact', 'contacts.first_name as first_name', 'contacts.last_name as last_name', 'contacts.email as email', 'payments.transaction_reference as payment', + 'payments.amount as payment_amount', 'credits.amount as credit' ); } -} \ No newline at end of file +} diff --git a/app/Ninja/Repositories/BankAccountRepository.php b/app/Ninja/Repositories/BankAccountRepository.php index f36499b8a5..3a4186d299 100644 --- a/app/Ninja/Repositories/BankAccountRepository.php +++ b/app/Ninja/Repositories/BankAccountRepository.php @@ -2,11 +2,8 @@ use DB; use Crypt; -use Utils; -use Session; use App\Models\BankAccount; use App\Models\BankSubaccount; -use App\Ninja\Repositories\BaseRepository; class BankAccountRepository extends BaseRepository { diff --git a/app/Ninja/Repositories/BaseRepository.php b/app/Ninja/Repositories/BaseRepository.php index f674c40654..49f296ef1b 100644 --- a/app/Ninja/Repositories/BaseRepository.php +++ b/app/Ninja/Repositories/BaseRepository.php @@ -1,23 +1,40 @@ getClassName(); return new $className(); } + /** + * @param $entity + * @param $type + * @return string + */ private function getEventClass($entity, $type) { return 'App\Events\\' . ucfirst($entity->getEntityType()) . 'Was' . $type; } + /** + * @param $entity + */ public function archive($entity) { if ($entity->trashed()) { @@ -33,6 +50,9 @@ class BaseRepository } } + /** + * @param $entity + */ public function restore($entity) { if ( ! $entity->trashed()) { @@ -55,6 +75,9 @@ class BaseRepository } } + /** + * @param $entity + */ public function delete($entity) { if ($entity->is_deleted) { @@ -73,11 +96,19 @@ class BaseRepository } } + /** + * @param $ids + * @return mixed + */ public function findByPublicIds($ids) { return $this->getInstance()->scope($ids)->get(); } + /** + * @param $ids + * @return mixed + */ public function findByPublicIdsWithTrashed($ids) { return $this->getInstance()->scope($ids)->withTrashed()->get(); diff --git a/app/Ninja/Repositories/ClientRepository.php b/app/Ninja/Repositories/ClientRepository.php index 83f08cd97a..31ca425253 100644 --- a/app/Ninja/Repositories/ClientRepository.php +++ b/app/Ninja/Repositories/ClientRepository.php @@ -2,10 +2,8 @@ use DB; use Cache; -use App\Ninja\Repositories\BaseRepository; use App\Models\Client; use App\Models\Contact; -use App\Models\Activity; use App\Events\ClientWasCreated; use App\Events\ClientWasUpdated; @@ -25,7 +23,7 @@ class ClientRepository extends BaseRepository ->get(); } - public function find($filter = null) + public function find($filter = null, $userId = false) { $query = DB::table('clients') ->join('accounts', 'accounts.id', '=', 'clients.account_id') @@ -63,9 +61,13 @@ class ClientRepository extends BaseRepository }); } + if ($userId) { + $query->where('clients.user_id', '=', $userId); + } + return $query; } - + public function save($data, $client = null) { $publicId = isset($data['public_id']) ? $data['public_id'] : false; @@ -78,7 +80,7 @@ class ClientRepository extends BaseRepository $client = Client::scope($publicId)->with('contacts')->firstOrFail(); \Log::warning('Entity not set in client repo save'); } - + // convert currency code to id if (isset($data['currency_code'])) { $currencyCode = strtolower($data['currency_code']); @@ -98,7 +100,7 @@ class ClientRepository extends BaseRepository return $client; } */ - + $first = true; $contacts = isset($data['contact']) ? [$data['contact']] : $data['contacts']; $contactIds = []; @@ -107,16 +109,18 @@ class ClientRepository extends BaseRepository usort($contacts, function ($left, $right) { return (isset($right['is_primary']) ? $right['is_primary'] : 1) - (isset($left['is_primary']) ? $left['is_primary'] : 0); }); - + foreach ($contacts as $contact) { $contact = $client->addContact($contact, $first); $contactIds[] = $contact->public_id; $first = false; } - foreach ($client->contacts as $contact) { - if (!in_array($contact->public_id, $contactIds)) { - $contact->delete(); + if ( ! $client->wasRecentlyCreated) { + foreach ($client->contacts as $contact) { + if (!in_array($contact->public_id, $contactIds)) { + $contact->delete(); + } } } diff --git a/app/Ninja/Repositories/ContactRepository.php b/app/Ninja/Repositories/ContactRepository.php index 49b73e91a6..6f157c1c40 100644 --- a/app/Ninja/Repositories/ContactRepository.php +++ b/app/Ninja/Repositories/ContactRepository.php @@ -1,6 +1,5 @@ send_invoice = true; $contact->client_id = $data['client_id']; $contact->is_primary = Contact::scope()->where('client_id', '=', $contact->client_id)->count() == 0; + $contact->contact_key = str_random(RANDOM_KEY_LENGTH); } else { $contact = Contact::scope($publicId)->firstOrFail(); } diff --git a/app/Ninja/Repositories/CreditRepository.php b/app/Ninja/Repositories/CreditRepository.php index 068707ace0..c295f56d8c 100644 --- a/app/Ninja/Repositories/CreditRepository.php +++ b/app/Ninja/Repositories/CreditRepository.php @@ -4,7 +4,6 @@ use DB; use Utils; use App\Models\Credit; use App\Models\Client; -use App\Ninja\Repositories\BaseRepository; class CreditRepository extends BaseRepository { diff --git a/app/Ninja/Repositories/DocumentRepository.php b/app/Ninja/Repositories/DocumentRepository.php index a2278b1843..e0308a5ef9 100644 --- a/app/Ninja/Repositories/DocumentRepository.php +++ b/app/Ninja/Repositories/DocumentRepository.php @@ -2,11 +2,8 @@ use DB; use Utils; -use Response; use App\Models\Document; -use App\Ninja\Repositories\BaseRepository; use Intervention\Image\ImageManager; -use Session; use Form; class DocumentRepository extends BaseRepository @@ -30,11 +27,7 @@ class DocumentRepository extends BaseRepository $query = DB::table('clients') ->join('accounts', 'accounts.id', '=', 'clients.account_id') ->leftjoin('clients', 'clients.id', '=', 'clients.client_id') - /*->leftJoin('expenses', 'expenses.id', '=', 'clients.expense_id') - ->leftJoin('invoices', 'invoices.id', '=', 'clients.invoice_id')*/ ->where('documents.account_id', '=', $accountid) - /*->where('vendors.deleted_at', '=', null) - ->where('clients.deleted_at', '=', null)*/ ->select( 'documents.account_id', 'documents.path', @@ -57,8 +50,9 @@ class DocumentRepository extends BaseRepository return $query; } - public function upload($uploaded, &$doc_array=null) + public function upload($data, &$doc_array=null) { + $uploaded = $data['file']; $extension = strtolower($uploaded->getClientOriginalExtension()); if(empty(Document::$types[$extension]) && !empty(Document::$extraExtensions[$extension])){ $documentType = Document::$extraExtensions[$extension]; @@ -81,12 +75,17 @@ class DocumentRepository extends BaseRepository return 'File too large'; } - + // don't allow a document to be linked to both an invoice and an expense + if (array_get($data, 'invoice_id') && array_get($data, 'expense_id')) { + unset($data['expense_id']); + } $hash = sha1_file($filePath); $filename = \Auth::user()->account->account_key.'/'.$hash.'.'.$documentType; $document = Document::createNew(); + $document->fill($data); + $disk = $document->getDisk(); if(!$disk->exists($filename)){// Have we already stored the same file $stream = fopen($filePath, 'r'); @@ -95,20 +94,20 @@ class DocumentRepository extends BaseRepository } // This is an image; check if we need to create a preview - if(in_array($documentType, array('jpeg','png','gif','bmp','tiff','psd'))){ + if(in_array($documentType, ['jpeg','png','gif','bmp','tiff','psd'])){ $makePreview = false; $imageSize = getimagesize($filePath); $width = $imageSize[0]; $height = $imageSize[1]; - $imgManagerConfig = array(); - if(in_array($documentType, array('gif','bmp','tiff','psd'))){ + $imgManagerConfig = []; + if(in_array($documentType, ['gif','bmp','tiff','psd'])){ // Needs to be converted $makePreview = true; } else if($width > DOCUMENT_PREVIEW_SIZE || $height > DOCUMENT_PREVIEW_SIZE){ $makePreview = true; } - if(in_array($documentType,array('bmp','tiff','psd'))){ + if(in_array($documentType,['bmp','tiff','psd'])){ if(!class_exists('Imagick')){ // Cant't read this $makePreview = false; @@ -119,7 +118,7 @@ class DocumentRepository extends BaseRepository if($makePreview){ $previewType = 'jpeg'; - if(in_array($documentType, array('png','gif','tiff','psd'))){ + if(in_array($documentType, ['png','gif','tiff','psd'])){ // Has transparency $previewType = 'png'; } @@ -191,7 +190,7 @@ class DocumentRepository extends BaseRepository ->where('invoices.is_deleted', '=', false) ->where('clients.deleted_at', '=', null) ->where('invoices.is_recurring', '=', false) - // This needs to be a setting to also hide the activity on the dashboard page + // TODO: This needs to be a setting to also hide the activity on the dashboard page //->where('invoices.invoice_status_id', '>=', INVOICE_STATUS_SENT) ->select( 'invitations.invitation_key', diff --git a/app/Ninja/Repositories/ExpenseCategoryRepository.php b/app/Ninja/Repositories/ExpenseCategoryRepository.php new file mode 100644 index 0000000000..90edbd2d74 --- /dev/null +++ b/app/Ninja/Repositories/ExpenseCategoryRepository.php @@ -0,0 +1,52 @@ +where('expense_categories.account_id', '=', Auth::user()->account_id) + ->select( + 'expense_categories.name as category', + 'expense_categories.public_id', + 'expense_categories.user_id', + 'expense_categories.deleted_at' + ); + + if (!\Session::get('show_trash:expense_category')) { + $query->where('expense_categories.deleted_at', '=', null); + } + + if ($filter) { + $query->where(function ($query) use ($filter) { + $query->where('expense_categories.name', 'like', '%'.$filter.'%'); + }); + } + + return $query; + } + + public function save($input, $category = false) + { + $publicId = isset($data['public_id']) ? $data['public_id'] : false; + + if ( ! $category) { + $category = ExpenseCategory::createNew(); + } + + $category->fill($input); + $category->save(); + + return $category; + } +} diff --git a/app/Ninja/Repositories/ExpenseRepository.php b/app/Ninja/Repositories/ExpenseRepository.php index 8836cd65da..b692e03c0e 100644 --- a/app/Ninja/Repositories/ExpenseRepository.php +++ b/app/Ninja/Repositories/ExpenseRepository.php @@ -6,8 +6,6 @@ use Auth; use App\Models\Expense; use App\Models\Vendor; use App\Models\Document; -use App\Ninja\Repositories\BaseRepository; -use Session; class ExpenseRepository extends BaseRepository { @@ -36,22 +34,8 @@ class ExpenseRepository extends BaseRepository public function findVendor($vendorPublicId) { $vendorId = Vendor::getPrivateId($vendorPublicId); - $accountid = \Auth::user()->account_id; - $query = DB::table('expenses') - ->join('accounts', 'accounts.id', '=', 'expenses.account_id') - ->where('expenses.account_id', '=', $accountid) - ->where('expenses.vendor_id', '=', $vendorId) - ->select( - 'expenses.id', - 'expenses.expense_date', - 'expenses.amount', - 'expenses.public_notes', - 'expenses.public_id', - 'expenses.deleted_at', - 'expenses.should_be_invoiced', - 'expenses.created_at', - 'expenses.user_id' - ); + + $query = $this->find()->where('expenses.vendor_id', '=', $vendorId); return $query; } @@ -65,6 +49,7 @@ class ExpenseRepository extends BaseRepository ->leftJoin('contacts', 'contacts.client_id', '=', 'clients.id') ->leftjoin('vendors', 'vendors.id', '=', 'expenses.vendor_id') ->leftJoin('invoices', 'invoices.id', '=', 'expenses.invoice_id') + ->leftJoin('expense_categories', 'expenses.expense_category_id', '=', 'expense_categories.id') ->where('expenses.account_id', '=', $accountid) ->where('contacts.deleted_at', '=', null) ->where('vendors.deleted_at', '=', null) @@ -91,8 +76,10 @@ class ExpenseRepository extends BaseRepository 'expenses.expense_currency_id', 'expenses.invoice_currency_id', 'expenses.user_id', + 'expense_categories.name as category', 'invoices.public_id as invoice_public_id', 'invoices.user_id as invoice_user_id', + 'invoices.balance', 'vendors.name as vendor_name', 'vendors.public_id as vendor_public_id', 'vendors.user_id as vendor_user_id', @@ -115,7 +102,8 @@ class ExpenseRepository extends BaseRepository $query->where(function ($query) use ($filter) { $query->where('expenses.public_notes', 'like', '%'.$filter.'%') ->orWhere('clients.name', 'like', '%'.$filter.'%') - ->orWhere('vendors.name', 'like', '%'.$filter.'%'); + ->orWhere('vendors.name', 'like', '%'.$filter.'%') + ->orWhere('expense_categories.name', 'like', '%'.$filter.'%');; }); } @@ -144,7 +132,7 @@ class ExpenseRepository extends BaseRepository $expense->private_notes = trim($input['private_notes']); } $expense->public_notes = trim($input['public_notes']); - $expense->should_be_invoiced = isset($input['should_be_invoiced']) || $expense->client_id ? true : false; + $expense->should_be_invoiced = isset($input['should_be_invoiced']) && floatval($input['should_be_invoiced']) || $expense->client_id ? true : false; if ( ! $expense->expense_currency_id) { $expense->expense_currency_id = \Auth::user()->account->getCurrencyId(); @@ -160,7 +148,7 @@ class ExpenseRepository extends BaseRepository $expense->save(); // Documents - $document_ids = !empty($input['document_ids'])?array_map('intval', $input['document_ids']):array();; + $document_ids = !empty($input['document_ids'])?array_map('intval', $input['document_ids']):[];; foreach ($document_ids as $document_id){ // check document completed upload before user submitted form if ($document_id) { @@ -173,29 +161,13 @@ class ExpenseRepository extends BaseRepository } } - if(!empty($input['documents']) && Auth::user()->can('create', ENTITY_DOCUMENT)){ - // Fallback upload - $doc_errors = array(); - foreach($input['documents'] as $upload){ - $result = $this->documentRepo->upload($upload); - if(is_string($result)){ - $doc_errors[] = $result; + // prevent loading all of the documents if we don't have to + if ( ! $expense->wasRecentlyCreated) { + foreach ($expense->documents as $document){ + if ( ! in_array($document->public_id, $document_ids)){ + // Not checking permissions; deleting a document is just editing the invoice + $document->delete(); } - else{ - $result->expense_id = $expense->id; - $result->save(); - $document_ids[] = $result->public_id; - } - } - if(!empty($doc_errors)){ - Session::flash('error', implode('
    ',array_map('htmlentities',$doc_errors))); - } - } - - foreach ($expense->documents as $document){ - if(!in_array($document->public_id, $document_ids)){ - // Not checking permissions; deleting a document is just editing the invoice - $document->delete(); } } diff --git a/app/Ninja/Repositories/InvoiceRepository.php b/app/Ninja/Repositories/InvoiceRepository.php index 5d09ec2d74..0249f764b6 100644 --- a/app/Ninja/Repositories/InvoiceRepository.php +++ b/app/Ninja/Repositories/InvoiceRepository.php @@ -1,8 +1,8 @@ invoiceType(INVOICE_TYPE_STANDARD) ->with('user', 'client.contacts', 'invoice_status') ->withTrashed() - ->where('is_quote', '=', false) ->where('is_recurring', '=', false) ->get(); } @@ -106,7 +105,7 @@ class InvoiceRepository extends BaseRepository ->join('frequencies', 'frequencies.id', '=', 'invoices.frequency_id') ->join('contacts', 'contacts.client_id', '=', 'clients.id') ->where('invoices.account_id', '=', $accountId) - ->where('invoices.is_quote', '=', false) + ->where('invoices.invoice_type_id', '=', INVOICE_TYPE_STANDARD) ->where('contacts.deleted_at', '=', null) ->where('invoices.is_recurring', '=', true) ->where('contacts.is_primary', '=', true) @@ -147,6 +146,53 @@ class InvoiceRepository extends BaseRepository return $query; } + public function getClientRecurringDatatable($contactId) + { + $query = DB::table('invitations') + ->join('accounts', 'accounts.id', '=', 'invitations.account_id') + ->join('invoices', 'invoices.id', '=', 'invitations.invoice_id') + ->join('clients', 'clients.id', '=', 'invoices.client_id') + ->join('frequencies', 'frequencies.id', '=', 'invoices.frequency_id') + ->where('invitations.contact_id', '=', $contactId) + ->where('invitations.deleted_at', '=', null) + ->where('invoices.invoice_type_id', '=', INVOICE_TYPE_STANDARD) + ->where('invoices.is_deleted', '=', false) + ->where('clients.deleted_at', '=', null) + ->where('invoices.is_recurring', '=', true) + ->whereIn('invoices.auto_bill', [AUTO_BILL_OPT_IN, AUTO_BILL_OPT_OUT]) + //->where('invoices.start_date', '>=', date('Y-m-d H:i:s')) + ->select( + DB::raw('COALESCE(clients.currency_id, accounts.currency_id) currency_id'), + DB::raw('COALESCE(clients.country_id, accounts.country_id) country_id'), + 'invitations.invitation_key', + 'invoices.invoice_number', + 'invoices.due_date', + 'clients.public_id as client_public_id', + 'clients.name as client_name', + 'invoices.public_id', + 'invoices.amount', + 'invoices.start_date', + 'invoices.end_date', + 'invoices.client_enable_auto_bill', + 'frequencies.name as frequency' + ); + + $table = \Datatable::query($query) + ->addColumn('frequency', function ($model) { return $model->frequency; }) + ->addColumn('start_date', function ($model) { return Utils::fromSqlDate($model->start_date); }) + ->addColumn('end_date', function ($model) { return Utils::fromSqlDate($model->end_date); }) + ->addColumn('amount', function ($model) { return Utils::formatMoney($model->amount, $model->currency_id, $model->country_id); }) + ->addColumn('client_enable_auto_bill', function ($model) { + if ($model->client_enable_auto_bill) { + return trans('texts.enabled') . ' - '.trans('texts.disable').''; + } else { + return trans('texts.disabled') . ' - '.trans('texts.enable').''; + } + }); + + return $table->make(); + } + public function getClientDatatable($contactId, $entityType, $search) { $query = DB::table('invitations') @@ -156,7 +202,7 @@ class InvoiceRepository extends BaseRepository ->join('contacts', 'contacts.client_id', '=', 'clients.id') ->where('invitations.contact_id', '=', $contactId) ->where('invitations.deleted_at', '=', null) - ->where('invoices.is_quote', '=', $entityType == ENTITY_QUOTE) + ->where('invoices.invoice_type_id', '=', $entityType == ENTITY_QUOTE ? INVOICE_TYPE_QUOTE : INVOICE_TYPE_STANDARD) ->where('invoices.is_deleted', '=', false) ->where('clients.deleted_at', '=', null) ->where('contacts.deleted_at', '=', null) @@ -201,8 +247,14 @@ class InvoiceRepository extends BaseRepository ->make(); } - public function save($data, $invoice = null) + /** + * @param array $data + * @param Invoice|null $invoice + * @return Invoice|mixed + */ + public function save(array $data, Invoice $invoice = null) { + /** @var Account $account */ $account = \Auth::user()->account; $publicId = isset($data['public_id']) ? $data['public_id'] : false; @@ -276,7 +328,12 @@ class InvoiceRepository extends BaseRepository $invoice->frequency_id = $data['frequency_id'] ? $data['frequency_id'] : 0; $invoice->start_date = Utils::toSqlDate($data['start_date']); $invoice->end_date = Utils::toSqlDate($data['end_date']); - $invoice->auto_bill = isset($data['auto_bill']) && $data['auto_bill'] ? true : false; + $invoice->client_enable_auto_bill = isset($data['client_enable_auto_bill']) && $data['client_enable_auto_bill'] ? true : false; + $invoice->auto_bill = isset($data['auto_bill']) ? intval($data['auto_bill']) : AUTO_BILL_OFF; + + if ($invoice->auto_bill < AUTO_BILL_OFF || $invoice->auto_bill > AUTO_BILL_ALWAYS ) { + $invoice->auto_bill = AUTO_BILL_OFF; + } if (isset($data['recurring_due_date'])) { $invoice->due_date = $data['recurring_due_date']; @@ -425,7 +482,7 @@ class InvoiceRepository extends BaseRepository $invoice->invoice_items()->forceDelete(); } - $document_ids = !empty($data['document_ids'])?array_map('intval', $data['document_ids']):array();; + $document_ids = !empty($data['document_ids'])?array_map('intval', $data['document_ids']):[];; foreach ($document_ids as $document_id){ $document = Document::scope($document_id)->first(); if($document && Auth::user()->can('edit', $document)){ @@ -442,32 +499,15 @@ class InvoiceRepository extends BaseRepository } } - if(!empty($data['documents']) && Auth::user()->can('create', ENTITY_DOCUMENT)){ - // Fallback upload - $doc_errors = array(); - foreach($data['documents'] as $upload){ - $result = $this->documentRepo->upload($upload); - if(is_string($result)){ - $doc_errors[] = $result; - } - else{ - $result->invoice_id = $invoice->id; - $result->save(); - $document_ids[] = $result->public_id; - } - } - if(!empty($doc_errors)){ - Session::flash('error', implode('
    ',array_map('htmlentities',$doc_errors))); - } - } - - foreach ($invoice->documents as $document){ - if(!in_array($document->public_id, $document_ids)){ - // Removed - // Not checking permissions; deleting a document is just editing the invoice - if($document->invoice_id == $invoice->id){ - // Make sure the document isn't on a clone - $document->delete(); + if ( ! $invoice->wasRecentlyCreated) { + foreach ($invoice->documents as $document){ + if(!in_array($document->public_id, $document_ids)){ + // Removed + // Not checking permissions; deleting a document is just editing the invoice + if($document->invoice_id == $invoice->id){ + // Make sure the document isn't on a clone + $document->delete(); + } } } } @@ -499,7 +539,7 @@ class InvoiceRepository extends BaseRepository } if ($productKey = trim($item['product_key'])) { - if (\Auth::user()->account->update_products && ! strtotime($productKey)) { + if (\Auth::user()->account->update_products && ! strtotime($productKey) && ! $task && ! $expense) { $product = Product::findProductByKey($productKey); if (!$product) { if (Auth::user()->can('create', ENTITY_PRODUCT)) { @@ -546,7 +586,12 @@ class InvoiceRepository extends BaseRepository return $invoice; } - public function cloneInvoice($invoice, $quotePublicId = null) + /** + * @param Invoice $invoice + * @param null $quotePublicId + * @return mixed + */ + public function cloneInvoice(Invoice $invoice, $quotePublicId = null) { $invoice->load('invitations', 'invoice_items'); $account = $invoice->account; @@ -590,7 +635,7 @@ class InvoiceRepository extends BaseRepository 'tax_name2', 'tax_rate2', 'amount', - 'is_quote', + 'invoice_type_id', 'custom_value1', 'custom_value2', 'custom_taxes1', @@ -602,7 +647,7 @@ class InvoiceRepository extends BaseRepository } if ($quotePublicId) { - $clone->is_quote = false; + $clone->invoice_type_id = INVOICE_TYPE_STANDARD; $clone->quote_id = $quotePublicId; } @@ -648,13 +693,21 @@ class InvoiceRepository extends BaseRepository return $clone; } - public function markSent($invoice) + /** + * @param Invoice $invoice + */ + public function markSent(Invoice $invoice) { $invoice->markInvitationsSent(); } + /** + * @param $invitationKey + * @return Invitation|bool + */ public function findInvoiceByInvitation($invitationKey) { + /** @var \App\Models\Invitation $invitation */ $invitation = Invitation::where('invitation_key', '=', $invitationKey)->first(); if (!$invitation) { @@ -676,11 +729,15 @@ class InvoiceRepository extends BaseRepository return $invitation; } + /** + * @param $clientId + * @return mixed + */ public function findOpenInvoices($clientId) { return Invoice::scope() + ->invoiceType(INVOICE_TYPE_STANDARD) ->whereClientId($clientId) - ->whereIsQuote(false) ->whereIsRecurring(false) ->whereDeletedAt(null) ->whereHasTasks(true) @@ -689,7 +746,11 @@ class InvoiceRepository extends BaseRepository ->get(); } - public function createRecurringInvoice($recurInvoice) + /** + * @param Invoice $recurInvoice + * @return mixed + */ + public function createRecurringInvoice(Invoice $recurInvoice) { $recurInvoice->load('account.timezone', 'invoice_items', 'client', 'user'); @@ -706,6 +767,7 @@ class InvoiceRepository extends BaseRepository } $invoice = Invoice::createNew($recurInvoice); + $invoice->invoice_type_id = INVOICE_TYPE_STANDARD; $invoice->client_id = $recurInvoice->client_id; $invoice->recurring_invoice_id = $recurInvoice->id; $invoice->invoice_number = $recurInvoice->account->getNextInvoiceNumber($invoice); @@ -763,7 +825,8 @@ class InvoiceRepository extends BaseRepository $recurInvoice->last_sent_date = date('Y-m-d'); $recurInvoice->save(); - if ($recurInvoice->auto_bill) { + if ($recurInvoice->getAutoBillEnabled() && !$recurInvoice->account->auto_bill_on_due_date) { + // autoBillInvoice will check for ACH, so we're not checking here if ($this->paymentService->autoBillInvoice($invoice)) { // update the invoice reference to match its actual state // this is to ensure a 'payment received' email is sent @@ -774,7 +837,11 @@ class InvoiceRepository extends BaseRepository return $invoice; } - public function findNeedingReminding($account) + /** + * @param Account $account + * @return mixed + */ + public function findNeedingReminding(Account $account) { $dates = []; @@ -786,9 +853,9 @@ class InvoiceRepository extends BaseRepository } $sql = implode(' OR ', $dates); - $invoices = Invoice::whereAccountId($account->id) + $invoices = Invoice::invoiceType(INVOICE_TYPE_STANDARD) + ->whereAccountId($account->id) ->where('balance', '>', 0) - ->where('is_quote', '=', false) ->where('is_recurring', '=', false) ->whereRaw('('.$sql.')') ->get(); diff --git a/app/Ninja/Repositories/PaymentRepository.php b/app/Ninja/Repositories/PaymentRepository.php index dd99fccdfd..f75f9a1867 100644 --- a/app/Ninja/Repositories/PaymentRepository.php +++ b/app/Ninja/Repositories/PaymentRepository.php @@ -5,8 +5,6 @@ use Utils; use App\Models\Payment; use App\Models\Credit; use App\Models\Invoice; -use App\Models\Client; -use App\Ninja\Repositories\BaseRepository; class PaymentRepository extends BaseRepository { @@ -22,6 +20,7 @@ class PaymentRepository extends BaseRepository ->join('clients', 'clients.id', '=', 'payments.client_id') ->join('invoices', 'invoices.id', '=', 'payments.invoice_id') ->join('contacts', 'contacts.client_id', '=', 'clients.id') + ->join('payment_statuses', 'payment_statuses.id', '=', 'payments.payment_status_id') ->leftJoin('payment_types', 'payment_types.id', '=', 'payments.payment_type_id') ->leftJoin('account_gateways', 'account_gateways.id', '=', 'payments.account_gateway_id') ->leftJoin('gateways', 'gateways.id', '=', 'account_gateways.gateway_id') @@ -39,6 +38,8 @@ class PaymentRepository extends BaseRepository 'clients.user_id as client_user_id', 'payments.amount', 'payments.payment_date', + 'payments.payment_status_id', + 'payments.payment_type_id', 'invoices.public_id as invoice_public_id', 'invoices.user_id as invoice_user_id', 'invoices.invoice_number', @@ -50,8 +51,16 @@ class PaymentRepository extends BaseRepository 'payments.deleted_at', 'payments.is_deleted', 'payments.user_id', + 'payments.refunded', + 'payments.expiration', + 'payments.last4', + 'payments.email', + 'payments.routing_number', + 'payments.bank_name', 'invoices.is_deleted as invoice_is_deleted', - 'gateways.name as gateway_name' + 'gateways.name as gateway_name', + 'gateways.id as gateway_id', + 'payment_statuses.name as payment_status_name' ); if (!\Session::get('show_trash:payment')) { @@ -85,6 +94,7 @@ class PaymentRepository extends BaseRepository ->join('clients', 'clients.id', '=', 'payments.client_id') ->join('invoices', 'invoices.id', '=', 'payments.invoice_id') ->join('contacts', 'contacts.client_id', '=', 'clients.id') + ->join('payment_statuses', 'payment_statuses.id', '=', 'payments.payment_status_id') ->leftJoin('invitations', function ($join) { $join->on('invitations.invoice_id', '=', 'invoices.id') ->on('invitations.contact_id', '=', 'contacts.id'); @@ -105,13 +115,22 @@ class PaymentRepository extends BaseRepository 'clients.public_id as client_public_id', 'payments.amount', 'payments.payment_date', + 'payments.payment_type_id', 'invoices.public_id as invoice_public_id', 'invoices.invoice_number', 'contacts.first_name', 'contacts.last_name', 'contacts.email', 'payment_types.name as payment_type', - 'payments.account_gateway_id' + 'payments.account_gateway_id', + 'payments.refunded', + 'payments.expiration', + 'payments.last4', + 'payments.email', + 'payments.routing_number', + 'payments.bank_name', + 'payments.payment_status_id', + 'payment_statuses.name as payment_status_name' ); if ($filter) { @@ -199,6 +218,4 @@ class PaymentRepository extends BaseRepository parent::restore($payment); } - - } diff --git a/app/Ninja/Repositories/PaymentTermRepository.php b/app/Ninja/Repositories/PaymentTermRepository.php index e631e9f162..bde31c20a8 100644 --- a/app/Ninja/Repositories/PaymentTermRepository.php +++ b/app/Ninja/Repositories/PaymentTermRepository.php @@ -1,9 +1,6 @@ withTrashed() + ->get(); + } + public function find($accountId) { return DB::table('products') @@ -30,11 +36,11 @@ class ProductRepository extends BaseRepository 'products.deleted_at' ); } - + public function save($data, $product = null) { $publicId = isset($data['public_id']) ? $data['public_id'] : false; - + if ($product) { // do nothing } elseif ($publicId) { @@ -50,4 +56,4 @@ class ProductRepository extends BaseRepository return $product; } -} \ No newline at end of file +} diff --git a/app/Ninja/Repositories/ReferralRepository.php b/app/Ninja/Repositories/ReferralRepository.php index f6170af296..ca12f960fd 100644 --- a/app/Ninja/Repositories/ReferralRepository.php +++ b/app/Ninja/Repositories/ReferralRepository.php @@ -1,7 +1,6 @@ $data) : $data; } + /** + * @param string $resourceKey + * @param array $data + * @return array + */ public function item($resourceKey, array $data) { return $data; - //return ($resourceKey && $resourceKey !== 'data') ? array($resourceKey => $data) : $data; } } diff --git a/app/Ninja/Transformers/AccountTokenTransformer.php b/app/Ninja/Transformers/AccountTokenTransformer.php index e6ca7e8bfd..22d1407be5 100644 --- a/app/Ninja/Transformers/AccountTokenTransformer.php +++ b/app/Ninja/Transformers/AccountTokenTransformer.php @@ -1,12 +1,18 @@ serializer); + return $this->includeCollection($account->expense_categories, $transformer, 'expense_categories'); + } + + /** + * @param Account $account + * @return \League\Fractal\Resource\Collection + */ public function includeUsers(Account $account) { $transformer = new UserTransformer($account, $this->serializer); return $this->includeCollection($account->users, $transformer, 'users'); } + /** + * @param Account $account + * @return \League\Fractal\Resource\Collection + */ public function includeClients(Account $account) { $transformer = new ClientTransformer($account, $this->serializer); return $this->includeCollection($account->clients, $transformer, 'clients'); } + /** + * @param Account $account + * @return \League\Fractal\Resource\Collection + */ public function includeInvoices(Account $account) { $transformer = new InvoiceTransformer($account, $this->serializer); return $this->includeCollection($account->invoices, $transformer, 'invoices'); } + /** + * @param Account $account + * @return \League\Fractal\Resource\Collection + */ public function includeProducts(Account $account) { $transformer = new ProductTransformer($account, $this->serializer); return $this->includeCollection($account->products, $transformer, 'products'); } + /** + * @param Account $account + * @return \League\Fractal\Resource\Collection + */ public function includeTaxRates(Account $account) { $transformer = new TaxRateTransformer($account, $this->serializer); return $this->includeCollection($account->tax_rates, $transformer, 'taxRates'); } + /** + * @param Account $account + * @return \League\Fractal\Resource\Collection + */ public function includePayments(Account $account) { $transformer = new PaymentTransformer($account, $this->serializer); return $this->includeCollection($account->payments, $transformer, 'payments'); } + /** + * @param Account $account + * @return array + * @throws \Laracasts\Presenter\Exceptions\PresenterException + */ public function transform(Account $account) { return [ @@ -96,7 +139,8 @@ class AccountTransformer extends EntityTransformer 'custom_label1' => $account->custom_label1, 'custom_label2' => $account->custom_label2, 'custom_value1' => $account->custom_value1, - 'custom_value2' => $account->custom_value2 + 'custom_value2' => $account->custom_value2, + 'logo' => $account->logo, ]; } -} \ No newline at end of file +} diff --git a/app/Ninja/Transformers/ClientTransformer.php b/app/Ninja/Transformers/ClientTransformer.php index ea282f74ce..67239fa9b2 100644 --- a/app/Ninja/Transformers/ClientTransformer.php +++ b/app/Ninja/Transformers/ClientTransformer.php @@ -1,9 +1,6 @@ account, $this->serializer); return $this->includeCollection($client->contacts, $transformer, ENTITY_CONTACT); } + /** + * @param Client $client + * @return \League\Fractal\Resource\Collection + */ public function includeInvoices(Client $client) { $transformer = new InvoiceTransformer($this->account, $this->serializer, $client); return $this->includeCollection($client->invoices, $transformer, ENTITY_INVOICE); } + /** + * @param Client $client + * @return \League\Fractal\Resource\Collection + */ public function includeCredits(Client $client) { $transformer = new CreditTransformer($this->account, $this->serializer); return $this->includeCollection($client->credits, $transformer, ENTITY_CREDIT); } + /** + * @param Client $client + * @return \League\Fractal\Resource\Collection + */ public function includeExpenses(Client $client) { $transformer = new ExpenseTransformer($this->account, $this->serializer); @@ -75,6 +90,10 @@ class ClientTransformer extends EntityTransformer } + /** + * @param Client $client + * @return array + */ public function transform(Client $client) { return array_merge($this->getDefaults($client), [ diff --git a/app/Ninja/Transformers/ContactTransformer.php b/app/Ninja/Transformers/ContactTransformer.php index 68172e156c..fa01260116 100644 --- a/app/Ninja/Transformers/ContactTransformer.php +++ b/app/Ninja/Transformers/ContactTransformer.php @@ -1,11 +1,16 @@ getDefaults($contact), [ diff --git a/app/Ninja/Transformers/CreditTransformer.php b/app/Ninja/Transformers/CreditTransformer.php index 39ce5ff1d8..9fb303ded2 100644 --- a/app/Ninja/Transformers/CreditTransformer.php +++ b/app/Ninja/Transformers/CreditTransformer.php @@ -1,11 +1,16 @@ getDefaults($credit), [ diff --git a/app/Ninja/Transformers/DocumentTransformer.php b/app/Ninja/Transformers/DocumentTransformer.php index 4cbfa06191..0ab10d12d4 100644 --- a/app/Ninja/Transformers/DocumentTransformer.php +++ b/app/Ninja/Transformers/DocumentTransformer.php @@ -1,11 +1,16 @@ getDefaults($document), [ @@ -14,6 +19,7 @@ class DocumentTransformer extends EntityTransformer 'type' => $document->type, 'invoice_id' => isset($document->invoice->public_id) ? (int) $document->invoice->public_id : null, 'expense_id' => isset($document->expense->public_id) ? (int) $document->expense->public_id : null, + 'updated_at' => $this->getTimestamp($document->updated_at), ]); } -} \ No newline at end of file +} diff --git a/app/Ninja/Transformers/EntityTransformer.php b/app/Ninja/Transformers/EntityTransformer.php index 691e6ff67f..9fd53235b8 100644 --- a/app/Ninja/Transformers/EntityTransformer.php +++ b/app/Ninja/Transformers/EntityTransformer.php @@ -2,7 +2,6 @@ use Auth; use App\Models\Account; -use App\Models\Client; use League\Fractal\TransformerAbstract; class EntityTransformer extends TransformerAbstract diff --git a/app/Ninja/Transformers/ExpenseCategoryTransformer.php b/app/Ninja/Transformers/ExpenseCategoryTransformer.php new file mode 100644 index 0000000000..7d79f30b10 --- /dev/null +++ b/app/Ninja/Transformers/ExpenseCategoryTransformer.php @@ -0,0 +1,17 @@ +getDefaults($expenseCategory), [ + 'id' => (int) $expenseCategory->public_id, + 'name' => $expenseCategory->name, + 'updated_at' => $this->getTimestamp($expenseCategory->updated_at), + 'archived_at' => $this->getTimestamp($expenseCategory->deleted_at), + ]); + } +} \ No newline at end of file diff --git a/app/Ninja/Transformers/ExpenseTransformer.php b/app/Ninja/Transformers/ExpenseTransformer.php index 46c334cb3e..5a07d962a8 100644 --- a/app/Ninja/Transformers/ExpenseTransformer.php +++ b/app/Ninja/Transformers/ExpenseTransformer.php @@ -1,8 +1,6 @@ client = $client; } @@ -68,6 +67,12 @@ class InvoiceTransformer extends EntityTransformer return $this->includeCollection($invoice->expenses, $transformer, ENTITY_EXPENSE); } + public function includeDocuments(Invoice $invoice) + { + $transformer = new DocumentTransformer($this->account, $this->serializer); + return $this->includeCollection($invoice->documents, $transformer, ENTITY_DOCUMENT); + } + public function transform(Invoice $invoice) { @@ -87,7 +92,7 @@ class InvoiceTransformer extends EntityTransformer 'terms' => $invoice->terms, 'public_notes' => $invoice->public_notes, 'is_deleted' => (bool) $invoice->is_deleted, - 'is_quote' => (bool) $invoice->is_quote, + 'invoice_type_id' => (int) $invoice->invoice_type_id, 'is_recurring' => (bool) $invoice->is_recurring, 'frequency_id' => (int) $invoice->frequency_id, 'start_date' => $invoice->start_date, @@ -113,6 +118,7 @@ class InvoiceTransformer extends EntityTransformer 'quote_invoice_id' => (int) $invoice->quote_invoice_id, 'custom_text_value1' => $invoice->custom_text_value1, 'custom_text_value2' => $invoice->custom_text_value2, + 'is_quote' => (bool) $invoice->isType(INVOICE_TYPE_QUOTE), // Temp to support mobile app ]); } } diff --git a/app/Ninja/Transformers/PaymentTransformer.php b/app/Ninja/Transformers/PaymentTransformer.php index 9f3ef32128..ce8826a6c7 100644 --- a/app/Ninja/Transformers/PaymentTransformer.php +++ b/app/Ninja/Transformers/PaymentTransformer.php @@ -4,8 +4,6 @@ use App\Models\Account; use App\Models\Payment; use App\Models\Invoice; use App\Models\Client; -use League\Fractal; -use App\Ninja\Transformers\InvoiceTransformer; /** * @SWG\Definition(definition="Payment", required={"invoice_id"}, @SWG\Xml(name="Payment")) diff --git a/app/Ninja/Transformers/ProductTransformer.php b/app/Ninja/Transformers/ProductTransformer.php index 309305815f..ac71ae09de 100644 --- a/app/Ninja/Transformers/ProductTransformer.php +++ b/app/Ninja/Transformers/ProductTransformer.php @@ -1,7 +1,6 @@ $user->account->account_key, 'name' => $user->account->present()->name, 'token' => $user->account->getToken($user->id, $this->tokenName), - 'default_url' => SITE_URL + 'default_url' => SITE_URL, + 'logo' => $user->account->logo, ]; } } \ No newline at end of file diff --git a/app/Ninja/Transformers/UserTransformer.php b/app/Ninja/Transformers/UserTransformer.php index 1619deb1f2..905fc669f3 100644 --- a/app/Ninja/Transformers/UserTransformer.php +++ b/app/Ninja/Transformers/UserTransformer.php @@ -2,7 +2,6 @@ use App\Models\Account; use App\Models\User; -use League\Fractal; class UserTransformer extends EntityTransformer { diff --git a/app/Ninja/Transformers/VendorContactTransformer.php b/app/Ninja/Transformers/VendorContactTransformer.php index f277964cec..b06981475f 100644 --- a/app/Ninja/Transformers/VendorContactTransformer.php +++ b/app/Ninja/Transformers/VendorContactTransformer.php @@ -1,8 +1,7 @@ hasPermission('admin'); } - public static function create($user) { + /** + * @param User $user + * @return bool + */ + public static function create(User $user) { return $user->hasPermission('admin'); } } \ No newline at end of file diff --git a/app/Policies/BankAccountPolicy.php b/app/Policies/BankAccountPolicy.php index fa5eeff848..33ca0a22fe 100644 --- a/app/Policies/BankAccountPolicy.php +++ b/app/Policies/BankAccountPolicy.php @@ -2,12 +2,27 @@ namespace App\Policies; -class BankAccountPolicy extends EntityPolicy { - public static function edit($user, $item) { +use App\Models\User; + +/** + * Class BankAccountPolicy + */ +class BankAccountPolicy extends EntityPolicy +{ + /** + * @param User $user + * @param $item + * @return bool + */ + public static function edit(User $user, $item) { return $user->hasPermission('admin'); } - public static function create($user) { + /** + * @param User $user + * @return bool + */ + public static function create(User $user) { return $user->hasPermission('admin'); } } \ No newline at end of file diff --git a/app/Policies/DocumentPolicy.php b/app/Policies/DocumentPolicy.php index 955801f194..e9d67dd341 100644 --- a/app/Policies/DocumentPolicy.php +++ b/app/Policies/DocumentPolicy.php @@ -2,19 +2,43 @@ namespace App\Policies; -class DocumentPolicy extends EntityPolicy { - public static function create($user){ +use App\Models\Document; +use App\Models\User; + +/** + * Class DocumentPolicy + */ +class DocumentPolicy extends EntityPolicy +{ + /** + * @param User $user + * @return bool + */ + public static function create(User $user) + { return !empty($user); } - - public static function view($user, $document) { - if($user->hasPermission('view_all'))return true; - if($document->expense){ - if($document->expense->invoice)return $user->can('view', $document->expense->invoice); - return $user->can('view', $document->expense); - } - if($document->invoice)return $user->can('view', $document->invoice); - - return $user->owns($item); + + /** + * @param User $user + * @param Document $document + * @return bool + */ + public static function view(User $user, Document $document) + { + if ($user->hasPermission('view_all')) { + return true; + } + if ($document->expense) { + if ($document->expense->invoice) { + return $user->can('view', $document->expense->invoice); + } + return $user->can('view', $document->expense); + } + if ($document->invoice) { + return $user->can('view', $document->invoice); + } + + return $user->owns($item); } } \ No newline at end of file diff --git a/app/Policies/EntityPolicy.php b/app/Policies/EntityPolicy.php index 4c5e8ded9d..3eca53333f 100644 --- a/app/Policies/EntityPolicy.php +++ b/app/Policies/EntityPolicy.php @@ -3,31 +3,58 @@ namespace App\Policies; use App\Models\User; -use App\Models\EntityModel; - use Illuminate\Auth\Access\HandlesAuthorization; +/** + * Class EntityPolicy + */ class EntityPolicy { use HandlesAuthorization; - - public static function create($user) { + + /** + * @param User $user + * @return bool + */ + public static function create(User $user) { return $user->hasPermission('create_all'); } - - public static function edit($user, $item) { + + /** + * @param User $user + * @param $item + * + * @return bool + */ + public static function edit(User $user, $item) { return $user->hasPermission('edit_all') || $user->owns($item); } - - public static function view($user, $item) { + + /** + * @param User $user + * @param $item + * + * @return bool + */ + public static function view(User $user, $item) { return $user->hasPermission('view_all') || $user->owns($item); } - - public static function viewByOwner($user, $ownerUserId) { + + /** + * @param User $user + * @param $ownerUserId + * @return bool + */ + public static function viewByOwner(User$user, $ownerUserId) { return $user->hasPermission('view_all') || $user->id == $ownerUserId; } - - public static function editByOwner($user, $ownerUserId) { + + /** + * @param User $user + * @param $ownerUserId + * @return bool + */ + public static function editByOwner(User $user, $ownerUserId) { return $user->hasPermission('edit_all') || $user->id == $ownerUserId; } -} \ No newline at end of file +} diff --git a/app/Policies/ExpenseCategoryPolicy.php b/app/Policies/ExpenseCategoryPolicy.php new file mode 100644 index 0000000000..bac89b183c --- /dev/null +++ b/app/Policies/ExpenseCategoryPolicy.php @@ -0,0 +1,56 @@ +is_admin; + } + + /** + * @param User $user + * @param $item + * + * @return bool + */ + public static function edit(User $user, $item) { + return $user->is_admin; + } + + /** + * @param User $user + * @param $item + * + * @return bool + */ + public static function view(User $user, $item) { + return true; + } + + /** + * @param User $user + * @param $ownerUserId + * @return bool + */ + public static function viewByOwner(User$user, $ownerUserId) { + return true; + } + + /** + * @param User $user + * @param $ownerUserId + * @return bool + */ + public static function editByOwner(User $user, $ownerUserId) { + return $user->is_admin; + } + +} diff --git a/app/Policies/ExpensePolicy.php b/app/Policies/ExpensePolicy.php index 4fdac4d627..d281d2f407 100644 --- a/app/Policies/ExpensePolicy.php +++ b/app/Policies/ExpensePolicy.php @@ -2,4 +2,20 @@ namespace App\Policies; -class ExpensePolicy extends EntityPolicy {} \ No newline at end of file +use App\Models\User; + +class ExpensePolicy extends EntityPolicy +{ + /** + * @param User $user + * @return bool + */ + public static function create(User $user) { + if ( ! parent::create($user)) { + return false; + } + + return $user->hasFeature(FEATURE_EXPENSES); + } + +} diff --git a/app/Policies/GenericEntityPolicy.php b/app/Policies/GenericEntityPolicy.php index ad0e76a6ba..264867a262 100644 --- a/app/Policies/GenericEntityPolicy.php +++ b/app/Policies/GenericEntityPolicy.php @@ -2,37 +2,57 @@ namespace App\Policies; + use App\Models\User; use Utils; - use Illuminate\Auth\Access\HandlesAuthorization; +/** + * Class GenericEntityPolicy + */ class GenericEntityPolicy { use HandlesAuthorization; - - public static function editByOwner($user, $itemType, $ownerUserId) { + + /** + * @param User $user + * @param $itemType + * @param $ownerUserId + * @return bool|mixed + */ + public static function editByOwner(User $user, $itemType, $ownerUserId) { $itemType = Utils::getEntityName($itemType); if (method_exists("App\\Policies\\{$itemType}Policy", 'editByOwner')) { - return call_user_func(array("App\\Policies\\{$itemType}Policy", 'editByOwner'), $user, $ownerUserId); + return call_user_func(["App\\Policies\\{$itemType}Policy", 'editByOwner'], $user, $ownerUserId); } return false; } - - public static function viewByOwner($user, $itemType, $ownerUserId) { + + /** + * @param User $user + * @param $itemType + * @param $ownerUserId + * @return bool|mixed + */ + public static function viewByOwner(User $user, $itemType, $ownerUserId) { $itemType = Utils::getEntityName($itemType); if (method_exists("App\\Policies\\{$itemType}Policy", 'viewByOwner')) { - return call_user_func(array("App\\Policies\\{$itemType}Policy", 'viewByOwner'), $user, $ownerUserId); + return call_user_func(["App\\Policies\\{$itemType}Policy", 'viewByOwner'], $user, $ownerUserId); } return false; } - - public static function create($user, $itemType) { + + /** + * @param User $user + * @param $itemType + * @return bool|mixed + */ + public static function create(User $user, $itemType) { $itemType = Utils::getEntityName($itemType); if (method_exists("App\\Policies\\{$itemType}Policy", 'create')) { - return call_user_func(array("App\\Policies\\{$itemType}Policy", 'create'), $user); + return call_user_func(["App\\Policies\\{$itemType}Policy", 'create'], $user); } return false; diff --git a/app/Policies/InvoicePolicy.php b/app/Policies/InvoicePolicy.php index a51a099a68..aa72b4c053 100644 --- a/app/Policies/InvoicePolicy.php +++ b/app/Policies/InvoicePolicy.php @@ -2,4 +2,4 @@ namespace App\Policies; -class InvoicePolicy extends EntityPolicy {} \ No newline at end of file +class InvoicePolicy extends EntityPolicy {} diff --git a/app/Policies/PaymentTermPolicy.php b/app/Policies/PaymentTermPolicy.php index 7acf8bb9ab..36d1ae210a 100644 --- a/app/Policies/PaymentTermPolicy.php +++ b/app/Policies/PaymentTermPolicy.php @@ -2,12 +2,28 @@ namespace App\Policies; -class PaymentTermPolicy extends EntityPolicy { - public static function edit($user, $item) { +use App\Models\User; + +/** + * Class PaymentTermPolicy + */ +class PaymentTermPolicy extends EntityPolicy +{ + + /** + * @param User $user + * @param $item + * @return mixed + */ + public static function edit(User $user, $item) { return $user->hasPermission('admin'); } - public static function create($user) { + /** + * @param User $user + * @return bool + */ + public static function create(User $user) { return $user->hasPermission('admin'); } } \ No newline at end of file diff --git a/app/Policies/ProductPolicy.php b/app/Policies/ProductPolicy.php index 897fe7404a..10f8b13eee 100644 --- a/app/Policies/ProductPolicy.php +++ b/app/Policies/ProductPolicy.php @@ -2,12 +2,28 @@ namespace App\Policies; -class ProductPolicy extends EntityPolicy { - public static function edit($user, $item) { +use App\Models\User; + +/** + * Class ProductPolicy + */ +class ProductPolicy extends EntityPolicy +{ + + /** + * @param User $user + * @param $item + * @return mixed + */ + public static function edit(User $user, $item) { return $user->hasPermission('admin'); } - public static function create($user) { + /** + * @param User $user + * @return mixed + */ + public static function create(User $user) { return $user->hasPermission('admin'); } } \ No newline at end of file diff --git a/app/Policies/QuotePolicy.php b/app/Policies/QuotePolicy.php new file mode 100644 index 0000000000..8d5f60ea7f --- /dev/null +++ b/app/Policies/QuotePolicy.php @@ -0,0 +1,21 @@ +hasFeature(FEATURE_QUOTES); + } + +} diff --git a/app/Policies/TaskPolicy.php b/app/Policies/TaskPolicy.php index b1fbe29029..6e7391e031 100644 --- a/app/Policies/TaskPolicy.php +++ b/app/Policies/TaskPolicy.php @@ -2,4 +2,20 @@ namespace App\Policies; -class TaskPolicy extends EntityPolicy {} \ No newline at end of file +use App\Models\User; + +class TaskPolicy extends EntityPolicy +{ + /** + * @param User $user + * @return bool + */ + public static function create(User $user) { + if ( ! parent::create($user)) { + return false; + } + + return $user->hasFeature(FEATURE_TASKS); + } + +} diff --git a/app/Policies/TaxRatePolicy.php b/app/Policies/TaxRatePolicy.php index 4de8e6ac7e..0ce64eca79 100644 --- a/app/Policies/TaxRatePolicy.php +++ b/app/Policies/TaxRatePolicy.php @@ -2,12 +2,24 @@ namespace App\Policies; -class TaxRatePolicy extends EntityPolicy { - public static function edit($user, $item) { +use App\Models\User; + +class TaxRatePolicy extends EntityPolicy +{ + /** + * @param User $user + * @param $item + * @return bool + */ + public static function edit(User $user, $item) { return $user->hasPermission('admin'); } - public static function create($user) { + /** + * @param User $user + * @return bool + */ + public static function create(User $user) { return $user->hasPermission('admin'); } } \ No newline at end of file diff --git a/app/Policies/VendorPolicy.php b/app/Policies/VendorPolicy.php index 681cdcb502..8c38819325 100644 --- a/app/Policies/VendorPolicy.php +++ b/app/Policies/VendorPolicy.php @@ -2,4 +2,20 @@ namespace App\Policies; -class VendorPolicy extends EntityPolicy {} \ No newline at end of file +use App\Models\User; + +class VendorPolicy extends EntityPolicy +{ + /** + * @param User $user + * @return bool + */ + public static function create(User $user) { + if ( ! parent::create($user)) { + return false; + } + + return $user->hasFeature(FEATURE_EXPENSES); + } + +} diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index e7587e48b1..9ce79f8554 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -1,19 +1,18 @@ '.trans("texts.$types").''; - + $items = []; - - if($user->can('create', $type))$items[] = '
  • '.trans("texts.new_$type").'
  • '; - + + if ($user->can('create', $type)) { + $items[] = '
  • '.trans("texts.new_$type").'
  • '; + } + if ($type == ENTITY_INVOICE) { if(!empty($items))$items[] = '
  • '; - $items[] = '
  • '.trans("texts.recurring_invoices").'
  • '; - if($user->can('create', ENTITY_INVOICE))$items[] = '
  • '.trans("texts.new_recurring_invoice").'
  • '; - if ($user->hasFeature(FEATURE_QUOTES)) { - $items[] = '
  • '; - $items[] = '
  • '.trans("texts.quotes").'
  • '; - if($user->can('create', ENTITY_INVOICE))$items[] = '
  • '.trans("texts.new_quote").'
  • '; - } + $items[] = '
  • '.trans('texts.recurring_invoices').'
  • '; + if($user->can('create', ENTITY_INVOICE))$items[] = '
  • '.trans('texts.new_recurring_invoice').'
  • '; + $items[] = '
  • '; + $items[] = '
  • '.trans('texts.quotes').'
  • '; + if($user->can('create', ENTITY_QUOTE))$items[] = '
  • '.trans('texts.new_quote').'
  • '; } else if ($type == ENTITY_CLIENT) { if(!empty($items))$items[] = '
  • '; - $items[] = '
  • '.trans("texts.credits").'
  • '; - if($user->can('create', ENTITY_CREDIT))$items[] = '
  • '.trans("texts.new_credit").'
  • '; + $items[] = '
  • '.trans('texts.credits').'
  • '; + if($user->can('create', ENTITY_CREDIT))$items[] = '
  • '.trans('texts.new_credit').'
  • '; } else if ($type == ENTITY_EXPENSE) { if(!empty($items))$items[] = '
  • '; - $items[] = '
  • '.trans("texts.vendors").'
  • '; - if($user->can('create', ENTITY_VENDOR))$items[] = '
  • '.trans("texts.new_vendor").'
  • '; + $items[] = '
  • '.trans('texts.vendors').'
  • '; + if($user->can('create', ENTITY_VENDOR))$items[] = '
  • '.trans('texts.new_vendor').'
  • '; } - + if(!empty($items)){ $str.= ''; } @@ -157,14 +156,14 @@ class AppServiceProvider extends ServiceProvider { return $str . ''; }); - + Form::macro('human_filesize', function($bytes, $decimals = 1) { - $size = array('B','kB','MB','GB','TB','PB','EB','ZB','YB'); + $size = ['B','kB','MB','GB','TB','PB','EB','ZB','YB']; $factor = floor((strlen($bytes) - 1) / 3); if($factor == 0)$decimals=0;// There aren't fractional bytes return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . ' ' . @$size[$factor]; }); - + Validator::extend('positive', function($attribute, $value, $parameters) { return Utils::parseFloat($value) >= 0; }); diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php index 227a1d6df6..bd826f6405 100644 --- a/app/Providers/AuthServiceProvider.php +++ b/app/Providers/AuthServiceProvider.php @@ -17,6 +17,7 @@ class AuthServiceProvider extends ServiceProvider \App\Models\Credit::class => \App\Policies\CreditPolicy::class, \App\Models\Document::class => \App\Policies\DocumentPolicy::class, \App\Models\Expense::class => \App\Policies\ExpensePolicy::class, + \App\Models\ExpenseCategory::class => \App\Policies\ExpenseCategoryPolicy::class, \App\Models\Invoice::class => \App\Policies\InvoicePolicy::class, \App\Models\Payment::class => \App\Policies\PaymentPolicy::class, \App\Models\Task::class => \App\Policies\TaskPolicy::class, @@ -40,7 +41,7 @@ class AuthServiceProvider extends ServiceProvider foreach (get_class_methods(new \App\Policies\GenericEntityPolicy) as $method) { $gate->define($method, "App\Policies\GenericEntityPolicy@{$method}"); } - + $this->registerPolicies($gate); } -} \ No newline at end of file +} diff --git a/app/Providers/BusServiceProvider.php b/app/Providers/BusServiceProvider.php index f0d9be6fe2..d0833ff18c 100644 --- a/app/Providers/BusServiceProvider.php +++ b/app/Providers/BusServiceProvider.php @@ -3,32 +3,30 @@ use Illuminate\Bus\Dispatcher; use Illuminate\Support\ServiceProvider; -class BusServiceProvider extends ServiceProvider { - - /** - * Bootstrap any application services. - * - * @param \Illuminate\Bus\Dispatcher $dispatcher - * @return void - */ - public function boot(Dispatcher $dispatcher) - { - $dispatcher->mapUsing(function($command) - { - return Dispatcher::simpleMapping( - $command, 'App\Commands', 'App\Handlers\Commands' - ); - }); - } - - /** - * Register any application services. - * - * @return void - */ - public function register() - { - // - } +/** + * Class BusServiceProvider + */ +class BusServiceProvider extends ServiceProvider +{ + /** + * Bootstrap any application services. + * + * @param \Illuminate\Bus\Dispatcher $dispatcher + * @return void + */ + public function boot(Dispatcher $dispatcher) + { + $dispatcher->mapUsing(function ($command) { + return Dispatcher::simpleMapping( + $command, 'App\Commands', 'App\Handlers\Commands' + ); + }); + } + /** + * Register any application services. + */ + public function register() + { + } } diff --git a/app/Providers/ComposerServiceProvider.php b/app/Providers/ComposerServiceProvider.php new file mode 100644 index 0000000000..0bd4f0b57c --- /dev/null +++ b/app/Providers/ComposerServiceProvider.php @@ -0,0 +1,31 @@ +composer( + ['accounts.details', 'clients.edit', 'payments.edit', 'invoices.edit', 'accounts.localization'], + 'App\Http\ViewComposers\TranslationComposer' + ); + } + + /** + * Register the service provider. + * + * @return void + */ + public function register() + { + + } +} \ No newline at end of file diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index 45c4a789ca..0e847484ad 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -11,7 +11,6 @@ class EventServiceProvider extends ServiceProvider { * @var array */ protected $listen = [ - // Clients 'App\Events\ClientWasCreated' => [ 'App\Listeners\ActivityListener@createdClient', @@ -43,6 +42,7 @@ class EventServiceProvider extends ServiceProvider { 'App\Events\InvoiceWasDeleted' => [ 'App\Listeners\ActivityListener@deletedInvoice', 'App\Listeners\TaskListener@deletedInvoice', + 'App\Listeners\ExpenseListener@deletedInvoice', ], 'App\Events\InvoiceWasRestored' => [ 'App\Listeners\ActivityListener@restoredInvoice', @@ -108,6 +108,19 @@ class EventServiceProvider extends ServiceProvider { 'App\Listeners\InvoiceListener@deletedPayment', 'App\Listeners\CreditListener@deletedPayment', ], + 'App\Events\PaymentWasRefunded' => [ + 'App\Listeners\ActivityListener@refundedPayment', + 'App\Listeners\InvoiceListener@refundedPayment', + 'App\Listeners\CreditListener@refundedPayment', + ], + 'App\Events\PaymentWasVoided' => [ + 'App\Listeners\ActivityListener@voidedPayment', + 'App\Listeners\InvoiceListener@voidedPayment', + ], + 'App\Events\PaymentFailed' => [ + 'App\Listeners\ActivityListener@failedPayment', + 'App\Listeners\InvoiceListener@failedPayment', + ], 'App\Events\PaymentWasRestored' => [ 'App\Listeners\ActivityListener@restoredPayment', 'App\Listeners\InvoiceListener@restoredPayment', @@ -138,7 +151,14 @@ class EventServiceProvider extends ServiceProvider { 'App\Events\UserSettingsChanged' => [ 'App\Listeners\HandleUserSettingsChanged', ], - + + // Task events + 'App\Events\TaskWasCreated' => [ + 'App\Listeners\ActivityListener@createdTask', + ], + 'App\Events\TaskWasUpdated' => [ + 'App\Listeners\ActivityListener@updatedTask', + ], ]; /** diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 506179d6d4..6bc0e304dd 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -1,46 +1,45 @@ group(['namespace' => $this->namespace], function($router) - { - require app_path('Http/routes.php'); - }); - } + /** + * Define your route model bindings, pattern filters, etc. + * + * @param \Illuminate\Routing\Router $router + * @return void + */ + public function boot(Router $router) + { + parent::boot($router); + } + /** + * Define the routes for the application. + * + * @param \Illuminate\Routing\Router $router + * @return void + */ + public function map(Router $router) + { + $router->group(['namespace' => $this->namespace], function ($router) { + require app_path('Http/routes.php'); + }); + } } diff --git a/app/Services/AccountGatewayService.php b/app/Services/AccountGatewayService.php index bd5635e0dd..758ac8d12e 100644 --- a/app/Services/AccountGatewayService.php +++ b/app/Services/AccountGatewayService.php @@ -1,68 +1,51 @@ accountGatewayRepo = $accountGatewayRepo; $this->datatableService = $datatableService; } + /** + * @return AccountGatewayRepository + */ protected function getRepo() { return $this->accountGatewayRepo; } - /* - public function save() - { - return null; - } - */ - + /** + * @param $accountId + * @return \Illuminate\Http\JsonResponse + */ public function getDatatable($accountId) { $query = $this->accountGatewayRepo->find($accountId); - return $this->createDatatable(ENTITY_ACCOUNT_GATEWAY, $query, false); + return $this->datatableService->createDatatable(new AccountGatewayDatatable(false), $query); } - - protected function getDatatableColumns($entityType, $hideClient) - { - return [ - [ - 'name', - function ($model) { - return link_to("gateways/{$model->public_id}/edit", $model->name)->toHtml(); - } - ], - [ - 'payment_type', - function ($model) { - return Gateway::getPrettyPaymentType($model->gateway_id); - } - ], - ]; - } - - protected function getDatatableActions($entityType) - { - return [ - [ - uctrans('texts.edit_gateway'), - function ($model) { - return URL::to("gateways/{$model->public_id}/edit"); - } - ] - ]; - } - -} \ No newline at end of file +} diff --git a/app/Services/ActivityService.php b/app/Services/ActivityService.php index d3b08b9971..f3a1ec15aa 100644 --- a/app/Services/ActivityService.php +++ b/app/Services/ActivityService.php @@ -1,67 +1,46 @@ activityRepo = $activityRepo; $this->datatableService = $datatableService; } + /** + * @param null $clientPublicId + * @return \Illuminate\Http\JsonResponse + */ public function getDatatable($clientPublicId = null) { $clientId = Client::getPrivateId($clientPublicId); $query = $this->activityRepo->findByClientId($clientId); - return $this->createDatatable(ENTITY_ACTIVITY, $query); + return $this->datatableService->createDatatable(new ActivityDatatable(false), $query); } - - protected function getDatatableColumns($entityType, $hideClient) - { - return [ - [ - 'activities.id', - function ($model) { - return Utils::timestampToDateTimeString(strtotime($model->created_at)); - } - ], - [ - 'activity_type_id', - function ($model) { - $data = [ - 'client' => link_to('/clients/' . $model->client_public_id, Utils::getClientDisplayName($model))->toHtml(), - 'user' => $model->is_system ? '' . trans('texts.system') . '' : Utils::getPersonDisplayName($model->user_first_name, $model->user_last_name, $model->user_email), - 'invoice' => $model->invoice ? link_to('/invoices/' . $model->invoice_public_id, $model->is_recurring ? trans('texts.recurring_invoice') : $model->invoice)->toHtml() : null, - 'quote' => $model->invoice ? link_to('/quotes/' . $model->invoice_public_id, $model->invoice)->toHtml() : null, - 'contact' => $model->contact_id ? link_to('/clients/' . $model->client_public_id, Utils::getClientDisplayName($model))->toHtml() : Utils::getPersonDisplayName($model->user_first_name, $model->user_last_name, $model->user_email), - 'payment' => $model->payment ?: '', - 'credit' => Utils::formatMoney($model->credit, $model->currency_id, $model->country_id) - ]; - - return trans("texts.activity_{$model->activity_type_id}", $data); - } - ], - [ - 'balance', - function ($model) { - return Utils::formatMoney($model->balance, $model->currency_id, $model->country_id); - } - ], - [ - 'adjustment', - function ($model) { - return $model->adjustment != 0 ? Utils::wrapAdjustment($model->adjustment, $model->currency_id, $model->country_id) : ''; - } - ] - ]; - } -} \ No newline at end of file +} diff --git a/app/Services/AuthService.php b/app/Services/AuthService.php index 9b62b1e700..d3a5502080 100644 --- a/app/Services/AuthService.php +++ b/app/Services/AuthService.php @@ -7,12 +7,20 @@ use Input; use Socialite; use App\Ninja\Repositories\AccountRepository; use App\Events\UserLoggedIn; -use App\Events\UserSignedUp; +/** + * Class AuthService + */ class AuthService { + /** + * @var AccountRepository + */ private $accountRepo; + /** + * @var array + */ public static $providers = [ 1 => SOCIAL_GOOGLE, 2 => SOCIAL_FACEBOOK, @@ -20,6 +28,11 @@ class AuthService 4 => SOCIAL_LINKEDIN ]; + /** + * AuthService constructor. + * + * @param AccountRepository $repo + */ public function __construct(AccountRepository $repo) { $this->accountRepo = $repo; @@ -27,11 +40,13 @@ class AuthService public static function getProviders() { - $providers = []; - - } + /** + * @param $provider + * @param $hasCode + * @return \Illuminate\Http\RedirectResponse + */ public function execute($provider, $hasCode) { if (!$hasCode) { @@ -75,16 +90,28 @@ class AuthService return redirect()->to($redirectTo); } + /** + * @param $provider + * @return mixed + */ private function getAuthorization($provider) { return Socialite::driver($provider)->redirect(); } + /** + * @param $provider + * @return mixed + */ public static function getProviderId($provider) { return array_search(strtolower($provider), array_map('strtolower', AuthService::$providers)); } + /** + * @param $providerId + * @return mixed|string + */ public static function getProviderName($providerId) { return $providerId ? AuthService::$providers[$providerId] : ''; diff --git a/app/Services/BankAccountService.php b/app/Services/BankAccountService.php index 4a3551c782..cae345fdac 100644 --- a/app/Services/BankAccountService.php +++ b/app/Services/BankAccountService.php @@ -2,25 +2,50 @@ use stdClass; use Utils; -use URL; use Hash; use App\Models\BankSubaccount; use App\Models\Vendor; use App\Models\Expense; -use App\Services\BaseService; use App\Ninja\Repositories\BankAccountRepository; use App\Ninja\Repositories\ExpenseRepository; use App\Ninja\Repositories\VendorRepository; +use App\Ninja\Datatables\BankAccountDatatable; use App\Libraries\Finance; use App\Libraries\Login; +/** + * Class BankAccountService + */ class BankAccountService extends BaseService { + /** + * @var BankAccountRepository + */ protected $bankAccountRepo; + + /** + * @var ExpenseRepository + */ protected $expenseRepo; + + /** + * @var VendorRepository + */ protected $vendorRepo; + + /** + * @var DatatableService + */ protected $datatableService; + /** + * BankAccountService constructor. + * + * @param BankAccountRepository $bankAccountRepo + * @param ExpenseRepository $expenseRepo + * @param VendorRepository $vendorRepo + * @param DatatableService $datatableService + */ public function __construct(BankAccountRepository $bankAccountRepo, ExpenseRepository $expenseRepo, VendorRepository $vendorRepo, DatatableService $datatableService) { $this->bankAccountRepo = $bankAccountRepo; @@ -29,19 +54,22 @@ class BankAccountService extends BaseService $this->datatableService = $datatableService; } + /** + * @return BankAccountRepository + */ protected function getRepo() { return $this->bankAccountRepo; } - public function loadBankAccounts($bankId, $username, $password, $includeTransactions = true) + /** + * @param null $bankId + * @return array + */ + private function getExpenses($bankId = null) { - if (! $bankId || ! $username || ! $password) { - return false; - } - $expenses = Expense::scope() - ->whereBankId($bankId) + ->bankId($bankId) ->where('transaction_id', '!=', '') ->withTrashed() ->get(['transaction_id']) @@ -50,6 +78,23 @@ class BankAccountService extends BaseService return $val['transaction_id']; }, $expenses)); + return $expenses; + } + + /** + * @param $bankId + * @param $username + * @param $password + * @param bool $includeTransactions + * @return array|bool + */ + public function loadBankAccounts($bankId, $username, $password, $includeTransactions = true) + { + if (! $bankId || ! $username || ! $password) { + return false; + } + + $expenses = $this->getExpenses(); $vendorMap = $this->createVendorMap(); $bankAccounts = BankSubaccount::scope() ->whereHas('bank_account', function ($query) use ($bankId) { @@ -83,6 +128,14 @@ class BankAccountService extends BaseService } } + /** + * @param $account + * @param $bankAccounts + * @param $expenses + * @param $includeTransactions + * @param $vendorMap + * @return bool|stdClass + */ private function parseBankAccount($account, $bankAccounts, $expenses, $includeTransactions, $vendorMap) { $obj = new stdClass(); @@ -106,44 +159,78 @@ class BankAccountService extends BaseService $obj->balance = Utils::formatMoney($account->ledgerBalance, CURRENCY_DOLLAR); if ($includeTransactions) { - $ofxParser = new \OfxParser\Parser(); - $ofx = $ofxParser->loadFromString($account->response); - - $obj->start_date = $ofx->BankAccount->Statement->startDate; - $obj->end_date = $ofx->BankAccount->Statement->endDate; - $obj->transactions = []; - - foreach ($ofx->BankAccount->Statement->transactions as $transaction) { - // ensure transactions aren't imported as expenses twice - if (isset($expenses[$transaction->uniqueId])) { - continue; - } - if ($transaction->amount >= 0) { - continue; - } - - // if vendor has already been imported use current name - $vendorName = trim(substr($transaction->name, 0, 20)); - $key = strtolower($vendorName); - $vendor = isset($vendorMap[$key]) ? $vendorMap[$key] : null; - - $transaction->vendor = $vendor ? $vendor->name : $this->prepareValue($vendorName); - $transaction->info = $this->prepareValue(substr($transaction->name, 20)); - $transaction->memo = $this->prepareValue($transaction->memo); - $transaction->date = \Auth::user()->account->formatDate($transaction->date); - $transaction->amount *= -1; - $obj->transactions[] = $transaction; - } + $obj = $this->parseTransactions($obj, $account->response, $expenses, $vendorMap); } return $obj; } + /** + * @param $account + * @param $data + * @param $expenses + * @param $vendorMap + * @return mixed + */ + private function parseTransactions($account, $data, $expenses, $vendorMap) + { + $ofxParser = new \OfxParser\Parser(); + $ofx = $ofxParser->loadFromString($data); + + $account->start_date = $ofx->BankAccount->Statement->startDate; + $account->end_date = $ofx->BankAccount->Statement->endDate; + $account->transactions = []; + + foreach ($ofx->BankAccount->Statement->transactions as $transaction) { + // ensure transactions aren't imported as expenses twice + if (isset($expenses[$transaction->uniqueId])) { + continue; + } + if ($transaction->amount >= 0) { + continue; + } + + // if vendor has already been imported use current name + $vendorName = trim(substr($transaction->name, 0, 20)); + $key = strtolower($vendorName); + $vendor = isset($vendorMap[$key]) ? $vendorMap[$key] : null; + + $transaction->vendor = $vendor ? $vendor->name : $this->prepareValue($vendorName); + $transaction->info = $this->prepareValue(substr($transaction->name, 20)); + $transaction->memo = $this->prepareValue($transaction->memo); + $transaction->date = \Auth::user()->account->formatDate($transaction->date); + $transaction->amount *= -1; + $account->transactions[] = $transaction; + } + + return $account; + } + + /** + * @param $value + * @return string + */ private function prepareValue($value) { return ucwords(strtolower(trim($value))); } + /** + * @param $data + * @return mixed + */ + public function parseOFX($data) + { + $account = new stdClass; + $expenses = $this->getExpenses(); + $vendorMap = $this->createVendorMap(); + + return $this->parseTransactions($account, $data, $expenses, $vendorMap); + } + + /** + * @return array + */ private function createVendorMap() { $vendorMap = []; @@ -158,7 +245,7 @@ class BankAccountService extends BaseService return $vendorMap; } - public function importExpenses($bankId, $input) + public function importExpenses($bankId = 0, $input) { $vendorMap = $this->createVendorMap(); $countVendors = 0; @@ -219,36 +306,6 @@ class BankAccountService extends BaseService { $query = $this->bankAccountRepo->find($accountId); - return $this->createDatatable(ENTITY_BANK_ACCOUNT, $query, false); - } - - protected function getDatatableColumns($entityType, $hideClient) - { - return [ - [ - 'bank_name', - function ($model) { - return link_to("bank_accounts/{$model->public_id}/edit", $model->bank_name)->toHtml(); - }, - ], - [ - 'bank_library_id', - function ($model) { - return 'OFX'; - } - ], - ]; - } - - protected function getDatatableActions($entityType) - { - return [ - [ - uctrans('texts.edit_bank_account'), - function ($model) { - return URL::to("bank_accounts/{$model->public_id}/edit"); - }, - ] - ]; + return $this->datatableService->createDatatable(new BankAccountDatatable(false), $query); } } diff --git a/app/Services/BaseService.php b/app/Services/BaseService.php index 6bbbc729b2..5eda427119 100644 --- a/app/Services/BaseService.php +++ b/app/Services/BaseService.php @@ -2,17 +2,27 @@ use Auth; use Illuminate\Foundation\Bus\DispatchesJobs; -use App\Services\DatatableService; +/** + * Class BaseService + */ class BaseService { use DispatchesJobs; + /** + * @return null + */ protected function getRepo() { return null; } + /** + * @param $ids + * @param $action + * @return int + */ public function bulk($ids, $action) { if ( ! $ids ) { @@ -29,22 +39,4 @@ class BaseService return count($entities); } - - public function createDatatable($entityType, $query, $showCheckbox = true, $hideClient = false) - { - $columns = $this->getDatatableColumns($entityType, !$showCheckbox); - $actions = $this->getDatatableActions($entityType); - - return $this->datatableService->createDatatable($entityType, $query, $columns, $actions, $showCheckbox); - } - - protected function getDatatableColumns($entityType, $hideClient) - { - return []; - } - - protected function getDatatableActions($entityType) - { - return []; - } } diff --git a/app/Services/ClientService.php b/app/Services/ClientService.php index 96357991c5..2e3ceedafa 100644 --- a/app/Services/ClientService.php +++ b/app/Services/ClientService.php @@ -1,23 +1,31 @@ clientRepo = $clientRepo; @@ -25,11 +33,19 @@ class ClientService extends BaseService $this->datatableService = $datatableService; } + /** + * @return ClientRepository + */ protected function getRepo() { return $this->clientRepo; } + /** + * @param $data + * @param null $client + * @return mixed|null + */ public function save($data, $client = null) { if (Auth::user()->account->isNinjaAccount() && isset($data['plan'])) { @@ -39,139 +55,17 @@ class ClientService extends BaseService return $this->clientRepo->save($data, $client); } - public function getDatatable($search) + /** + * @param $search + * @param $userId + * @return \Illuminate\Http\JsonResponse + */ + public function getDatatable($search, $userId) { - $query = $this->clientRepo->find($search); + $datatable = new ClientDatatable(); - if(!Utils::hasPermission('view_all')){ - $query->where('clients.user_id', '=', Auth::user()->id); - } + $query = $this->clientRepo->find($search, $userId); - return $this->createDatatable(ENTITY_CLIENT, $query); - } - - protected function getDatatableColumns($entityType, $hideClient) - { - return [ - [ - 'name', - function ($model) { - return link_to("clients/{$model->public_id}", $model->name ?: '')->toHtml(); - } - ], - [ - 'first_name', - function ($model) { - return link_to("clients/{$model->public_id}", $model->first_name.' '.$model->last_name)->toHtml(); - } - ], - [ - 'email', - function ($model) { - return link_to("clients/{$model->public_id}", $model->email ?: '')->toHtml(); - } - ], - [ - 'clients.created_at', - function ($model) { - return Utils::timestampToDateString(strtotime($model->created_at)); - } - ], - [ - 'last_login', - function ($model) { - return Utils::timestampToDateString(strtotime($model->last_login)); - } - ], - [ - 'balance', - function ($model) { - return Utils::formatMoney($model->balance, $model->currency_id, $model->country_id); - } - ] - ]; - } - - protected function getDatatableActions($entityType) - { - return [ - [ - trans('texts.edit_client'), - function ($model) { - return URL::to("clients/{$model->public_id}/edit"); - }, - function ($model) { - return Auth::user()->can('editByOwner', [ENTITY_CLIENT, $model->user_id]); - } - ], - [ - '--divider--', function(){return false;}, - function ($model) { - $user = Auth::user(); - return $user->can('editByOwner', [ENTITY_CLIENT, $model->user_id]) && ($user->can('create', ENTITY_TASK) || $user->can('create', ENTITY_INVOICE)); - } - ], - [ - trans('texts.new_task'), - function ($model) { - return URL::to("tasks/create/{$model->public_id}"); - }, - function ($model) { - return Auth::user()->can('create', ENTITY_TASK); - } - ], - [ - trans('texts.new_invoice'), - function ($model) { - return URL::to("invoices/create/{$model->public_id}"); - }, - function ($model) { - return Auth::user()->can('create', ENTITY_INVOICE); - } - ], - [ - trans('texts.new_quote'), - function ($model) { - return URL::to("quotes/create/{$model->public_id}"); - }, - function ($model) { - return Auth::user()->hasFeature(FEATURE_QUOTES) && Auth::user()->can('create', ENTITY_INVOICE); - } - ], - [ - '--divider--', function(){return false;}, - function ($model) { - $user = Auth::user(); - return ($user->can('create', ENTITY_TASK) || $user->can('create', ENTITY_INVOICE)) && ($user->can('create', ENTITY_PAYMENT) || $user->can('create', ENTITY_CREDIT) || $user->can('create', ENTITY_EXPENSE)); - } - ], - [ - trans('texts.enter_payment'), - function ($model) { - return URL::to("payments/create/{$model->public_id}"); - }, - function ($model) { - return Auth::user()->can('create', ENTITY_PAYMENT); - } - ], - [ - trans('texts.enter_credit'), - function ($model) { - return URL::to("credits/create/{$model->public_id}"); - }, - function ($model) { - return Auth::user()->can('create', ENTITY_CREDIT); - } - ], - [ - trans('texts.enter_expense'), - function ($model) { - return URL::to("expenses/create/0/{$model->public_id}"); - }, - function ($model) { - return Auth::user()->can('create', ENTITY_EXPENSE); - } - ] - ]; + return $this->datatableService->createDatatable($datatable, $query); } } diff --git a/app/Services/CreditService.php b/app/Services/CreditService.php index 54ef659f05..b355d5f78c 100644 --- a/app/Services/CreditService.php +++ b/app/Services/CreditService.php @@ -1,99 +1,69 @@ creditRepo = $creditRepo; $this->datatableService = $datatableService; } + /** + * @return CreditRepository + */ protected function getRepo() { return $this->creditRepo; } + /** + * @param $data + * @return mixed|null + */ public function save($data) { return $this->creditRepo->save($data); } + /** + * @param $clientPublicId + * @param $search + * @return \Illuminate\Http\JsonResponse + */ public function getDatatable($clientPublicId, $search) { + // we don't support bulk edit and hide the client on the individual client page + $datatable = new CreditDatatable( ! $clientPublicId, $clientPublicId); $query = $this->creditRepo->find($clientPublicId, $search); - + if(!Utils::hasPermission('view_all')){ $query->where('credits.user_id', '=', Auth::user()->id); } - return $this->createDatatable(ENTITY_CREDIT, $query, !$clientPublicId); + return $this->datatableService->createDatatable($datatable, $query); } - - protected function getDatatableColumns($entityType, $hideClient) - { - return [ - [ - 'client_name', - function ($model) { - if(!Auth::user()->can('viewByOwner', [ENTITY_CLIENT, $model->client_user_id])){ - return Utils::getClientDisplayName($model); - } - - return $model->client_public_id ? link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml() : ''; - }, - ! $hideClient - ], - [ - 'amount', - function ($model) { - return Utils::formatMoney($model->amount, $model->currency_id, $model->country_id) . ''; - } - ], - [ - 'balance', - function ($model) { - return Utils::formatMoney($model->balance, $model->currency_id, $model->country_id); - } - ], - [ - 'credit_date', - function ($model) { - return Utils::fromSqlDate($model->credit_date); - } - ], - [ - 'private_notes', - function ($model) { - return $model->private_notes; - } - ] - ]; - } - - protected function getDatatableActions($entityType) - { - return [ - [ - trans('texts.apply_credit'), - function ($model) { - return URL::to("payments/create/{$model->client_public_id}") . '?paymentTypeId=1'; - }, - function ($model) { - return Auth::user()->can('create', ENTITY_PAYMENT); - } - ] - ]; - } -} \ No newline at end of file +} diff --git a/app/Services/DatatableService.php b/app/Services/DatatableService.php index 2f9af2856c..977ca0c7d0 100644 --- a/app/Services/DatatableService.php +++ b/app/Services/DatatableService.php @@ -1,27 +1,36 @@ isBulkEdit) { $table->addColumn('checkbox', function ($model) { $can_edit = Auth::user()->hasPermission('edit_all') || (isset($model->user_id) && Auth::user()->id == $model->user_id); - + return !$can_edit?'':''; }); } - foreach ($columns as $column) { + foreach ($datatable->columns() as $column) { // set visible to true by default if (count($column) == 2) { $column[] = true; @@ -35,21 +44,25 @@ class DatatableService } } - if ($actions) { - $this->createDropdown($entityType, $table, $actions); + if (count($datatable->actions())) { + $this->createDropdown($datatable, $table); } return $table->orderColumns($orderColumns)->make(); } - private function createDropdown($entityType, $table, $actions) + /** + * @param EntityDatatable $datatable + * @param Table $table + */ + private function createDropdown(EntityDatatable $datatable, $table) { - $table->addColumn('dropdown', function ($model) use ($entityType, $actions) { + $table->addColumn('dropdown', function ($model) use ($datatable) { $hasAction = false; $str = '
    '; $can_edit = Auth::user()->hasPermission('edit_all') || (isset($model->user_id) && Auth::user()->id == $model->user_id); - + if (property_exists($model, 'is_deleted') && $model->is_deleted) { $str .= ''; } elseif ($model->deleted_at && $model->deleted_at !== '0000-00-00') { @@ -58,15 +71,11 @@ class DatatableService $str .= '
    '; } - $str .= '
    '; + if (!empty($dropdown_contents)) { + $str .= ''; }); } - -} \ No newline at end of file +} diff --git a/app/Services/EmailService.php b/app/Services/EmailService.php index 47e1308104..c148dbdede 100644 --- a/app/Services/EmailService.php +++ b/app/Services/EmailService.php @@ -4,19 +4,34 @@ use Carbon; use App\Models\Invitation; use App\Ninja\Mailers\UserMailer; -class EmailService { - +/** + * Class EmailService + */ +class EmailService +{ + /** + * @var UserMailer + */ protected $userMailer; + /** + * EmailService constructor. + * + * @param UserMailer $userMailer + */ public function __construct(UserMailer $userMailer) { $this->userMailer = $userMailer; } + /** + * @param $messageId + * @return bool + */ public function markOpened($messageId) { - $invitation = Invitation::whereMessageId($messageId) - ->first(); + /** @var \App\Models\Invitation $invitation */ + $invitation = Invitation::whereMessageId($messageId)->first(); if (!$invitation) { return false; @@ -28,8 +43,14 @@ class EmailService { return true; } + /** + * @param $messageId + * @param $error + * @return bool + */ public function markBounced($messageId, $error) { + /** @var \App\Models\Invitation $invitation */ $invitation = Invitation::with('user', 'invoice', 'contact') ->whereMessageId($messageId) ->first(); diff --git a/app/Services/ExpenseCategoryService.php b/app/Services/ExpenseCategoryService.php new file mode 100644 index 0000000000..e0b8f3cffa --- /dev/null +++ b/app/Services/ExpenseCategoryService.php @@ -0,0 +1,66 @@ +categoryRepo = $categoryRepo; + $this->datatableService = $datatableService; + } + + /** + * @return CreditRepository + */ + protected function getRepo() + { + return $this->categoryRepo; + } + + /** + * @param $data + * @return mixed|null + */ + public function save($data) + { + return $this->categoryRepo->save($data); + } + + /** + * @param $clientPublicId + * @param $search + * @return \Illuminate\Http\JsonResponse + */ + public function getDatatable($search) + { + // we don't support bulk edit and hide the client on the individual client page + $datatable = new ExpenseCategoryDatatable(); + + $query = $this->categoryRepo->find($search); + + return $this->datatableService->createDatatable($datatable, $query); + } +} diff --git a/app/Services/ExpenseService.php b/app/Services/ExpenseService.php index 671648ea32..040f7a4057 100644 --- a/app/Services/ExpenseService.php +++ b/app/Services/ExpenseService.php @@ -1,33 +1,53 @@ expenseRepo = $expenseRepo; $this->datatableService = $datatableService; } + /** + * @return ExpenseRepository + */ protected function getRepo() { return $this->expenseRepo; } + /** + * @param $data + * @param null $expense + * @return mixed|null + */ public function save($data, $expense = null) { if (isset($data['client_id']) && $data['client_id']) { @@ -41,6 +61,10 @@ class ExpenseService extends BaseService return $this->expenseRepo->save($data, $expense); } + /** + * @param $search + * @return \Illuminate\Http\JsonResponse + */ public function getDatatable($search) { $query = $this->expenseRepo->find($search); @@ -49,172 +73,23 @@ class ExpenseService extends BaseService $query->where('expenses.user_id', '=', Auth::user()->id); } - return $this->createDatatable(ENTITY_EXPENSE, $query); + return $this->datatableService->createDatatable(new ExpenseDatatable(), $query); } + /** + * @param $vendorPublicId + * @return \Illuminate\Http\JsonResponse + */ public function getDatatableVendor($vendorPublicId) { + $datatable = new ExpenseDatatable(false, true); + $query = $this->expenseRepo->findVendor($vendorPublicId); - return $this->datatableService->createDatatable(ENTITY_EXPENSE, - $query, - $this->getDatatableColumnsVendor(ENTITY_EXPENSE,false), - $this->getDatatableActionsVendor(ENTITY_EXPENSE), - false); - } - protected function getDatatableColumns($entityType, $hideClient) - { - return [ - [ - 'vendor_name', - function ($model) - { - if ($model->vendor_public_id) { - if(!Auth::user()->can('viewByOwner', [ENTITY_VENDOR, $model->vendor_user_id])){ - return $model->vendor_name; - } - - return link_to("vendors/{$model->vendor_public_id}", $model->vendor_name)->toHtml(); - } else { - return ''; - } - } - ], - [ - 'client_name', - function ($model) - { - if ($model->client_public_id) { - if(!Auth::user()->can('viewByOwner', [ENTITY_CLIENT, $model->client_user_id])){ - return Utils::getClientDisplayName($model); - } - - return link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml(); - } else { - return ''; - } - } - ], - [ - 'expense_date', - function ($model) { - if(!Auth::user()->can('editByOwner', [ENTITY_EXPENSE, $model->user_id])){ - return Utils::fromSqlDate($model->expense_date); - } - - return link_to("expenses/{$model->public_id}/edit", Utils::fromSqlDate($model->expense_date))->toHtml(); - } - ], - [ - 'amount', - function ($model) { - // show both the amount and the converted amount - if ($model->exchange_rate != 1) { - $converted = round($model->amount * $model->exchange_rate, 2); - return Utils::formatMoney($model->amount, $model->expense_currency_id) . ' | ' . - Utils::formatMoney($converted, $model->invoice_currency_id); - } else { - return Utils::formatMoney($model->amount, $model->expense_currency_id); - } - } - ], - [ - 'public_notes', - function ($model) { - return $model->public_notes != null ? substr($model->public_notes, 0, 100) : ''; - } - ], - [ - 'expense_status_id', - function ($model) { - return self::getStatusLabel($model->invoice_id, $model->should_be_invoiced); - } - ], - ]; - } - - protected function getDatatableColumnsVendor($entityType, $hideClient) - { - return [ - [ - 'expense_date', - function ($model) { - return Utils::dateToString($model->expense_date); - } - ], - [ - 'amount', - function ($model) { - return Utils::formatMoney($model->amount, false, false); - } - ], - [ - 'public_notes', - function ($model) { - return $model->public_notes != null ? $model->public_notes : ''; - } - ], - [ - 'invoice_id', - function ($model) { - return ''; - } - ], - ]; - } - - protected function getDatatableActions($entityType) - { - return [ - [ - trans('texts.edit_expense'), - function ($model) { - return URL::to("expenses/{$model->public_id}/edit") ; - }, - function ($model) { - return Auth::user()->can('editByOwner', [ENTITY_EXPENSE, $model->user_id]); - } - ], - [ - trans('texts.view_invoice'), - function ($model) { - return URL::to("/invoices/{$model->invoice_public_id}/edit"); - }, - function ($model) { - return $model->invoice_public_id && Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->invoice_user_id]); - } - ], - [ - trans('texts.invoice_expense'), - function ($model) { - return "javascript:invoiceEntity({$model->public_id})"; - }, - function ($model) { - return ! $model->invoice_id && (!$model->deleted_at || $model->deleted_at == '0000-00-00') && Auth::user()->can('create', ENTITY_INVOICE); - } - ], - ]; - } - - protected function getDatatableActionsVendor($entityType) - { - return []; - } - - private function getStatusLabel($invoiceId, $shouldBeInvoiced) - { - if ($invoiceId) { - $label = trans('texts.invoiced'); - $class = 'success'; - } elseif ($shouldBeInvoiced) { - $label = trans('texts.pending'); - $class = 'warning'; - } else { - $label = trans('texts.logged'); - $class = 'primary'; + if(!Utils::hasPermission('view_all')){ + $query->where('expenses.user_id', '=', Auth::user()->id); } - return "

    $label

    "; + return $this->datatableService->createDatatable($datatable, $query); } - } diff --git a/app/Services/ImportService.php b/app/Services/ImportService.php index c17a8e359a..4f08976871 100644 --- a/app/Services/ImportService.php +++ b/app/Services/ImportService.php @@ -1,5 +1,6 @@ fractal = $manager; $this->fractal->setSerializer(new ArraySerializer()); @@ -54,12 +120,87 @@ class ImportService $this->invoiceRepo = $invoiceRepo; $this->paymentRepo = $paymentRepo; $this->contactRepo = $contactRepo; + $this->productRepo = $productRepo; } - public function import($source, $files) + /** + * @param $file + * @return array + * @throws Exception + */ + public function importJSON($file) + { + $this->init(); + + $file = file_get_contents($file); + $json = json_decode($file, true); + $json = $this->removeIdFields($json); + + $this->checkClientCount(count($json['clients'])); + + foreach ($json['clients'] as $jsonClient) { + + if ($this->validate($jsonClient, ENTITY_CLIENT) === true) { + $client = $this->clientRepo->save($jsonClient); + $this->addSuccess($client); + } else { + $this->addFailure(ENTITY_CLIENT, $jsonClient); + continue; + } + + foreach ($jsonClient['invoices'] as $jsonInvoice) { + $jsonInvoice['client_id'] = $client->id; + if ($this->validate($jsonInvoice, ENTITY_INVOICE) === true) { + $invoice = $this->invoiceRepo->save($jsonInvoice); + $this->addSuccess($invoice); + } else { + $this->addFailure(ENTITY_INVOICE, $jsonInvoice); + continue; + } + + foreach ($jsonInvoice['payments'] as $jsonPayment) { + $jsonPayment['client_id'] = $jsonPayment['client'] = $client->id; // TODO: change to client_id once views are updated + $jsonPayment['invoice_id'] = $jsonPayment['invoice'] = $invoice->id; // TODO: change to invoice_id once views are updated + if ($this->validate($jsonPayment, ENTITY_PAYMENT) === true) { + $payment = $this->paymentRepo->save($jsonPayment); + $this->addSuccess($payment); + } else { + $this->addFailure(ENTITY_PAYMENT, $jsonPayment); + continue; + } + } + } + } + + return $this->results; + } + + /** + * @param $array + * @return mixed + */ + public function removeIdFields($array) + { + foreach ($array as $key => $val) { + if (is_array($val)) { + $array[$key] = $this->removeIdFields($val); + } elseif ($key === 'id') { + unset($array[$key]); + } + } + return $array; + } + + /** + * @param $source + * @param $files + * @return array + */ + public function importFiles($source, $files) { $results = []; $imported_files = null; + $this->initMaps(); foreach ($files as $entityType => $file) { $results[$entityType] = $this->execute($source, $entityType, $file); @@ -68,6 +209,12 @@ class ImportService return $results; } + /** + * @param $source + * @param $entityType + * @param $file + * @return array + */ private function execute($source, $entityType, $file) { $results = [ @@ -76,18 +223,18 @@ class ImportService ]; // Convert the data - $row_list = array(); - $maps = $this->createMaps(); - Excel::load($file, function ($reader) use ($source, $entityType, $maps, &$row_list, &$results) { + $row_list = []; + + Excel::load($file, function ($reader) use ($source, $entityType, &$row_list, &$results) { $this->checkData($entityType, count($reader->all())); - $reader->each(function ($row) use ($source, $entityType, $maps, &$row_list, &$results) { - $data_index = $this->transformRow($source, $entityType, $row, $maps); + $reader->each(function ($row) use ($source, $entityType, &$row_list, &$results) { + $data_index = $this->transformRow($source, $entityType, $row); if ($data_index !== false) { if ($data_index !== true) { // Wasn't merged with another row - $row_list[] = array('row' => $row, 'data_index' => $data_index); + $row_list[] = ['row' => $row, 'data_index' => $data_index]; } } else { $results[RESULT_FAILURE][] = $row; @@ -97,7 +244,7 @@ class ImportService // Save the data foreach ($row_list as $row_data) { - $result = $this->saveData($source, $entityType, $row_data['row'], $row_data['data_index'], $maps); + $result = $this->saveData($source, $entityType, $row_data['row'], $row_data['data_index']); if ($result) { $results[RESULT_SUCCESS][] = $result; } else { @@ -108,10 +255,16 @@ class ImportService return $results; } - private function transformRow($source, $entityType, $row, $maps) + /** + * @param $source + * @param $entityType + * @param $row + * @return bool|mixed + */ + private function transformRow($source, $entityType, $row) { - $transformer = $this->getTransformer($source, $entityType, $maps); - $resource = $transformer->transform($row, $maps); + $transformer = $this->getTransformer($source, $entityType, $this->maps); + $resource = $transformer->transform($row); if (!$resource) { return false; @@ -126,7 +279,7 @@ class ImportService $data['invoice_number'] = $account->getNextInvoiceNumber($invoice); } - if ($this->validate($source, $data, $entityType) !== true) { + if ($this->validate($data, $entityType) !== true) { return false; } @@ -148,19 +301,35 @@ class ImportService return key($this->processedRows); } - private function saveData($source, $entityType, $row, $data_index, $maps) + /** + * @param $source + * @param $entityType + * @param $row + * @param $data_index + * @return mixed + */ + private function saveData($source, $entityType, $row, $data_index) { $data = $this->processedRows[$data_index]; $entity = $this->{"{$entityType}Repo"}->save($data); + // update the entity maps + $mapFunction = 'add' . ucwords($entity->getEntityType()) . 'ToMaps'; + $this->$mapFunction($entity); + // if the invoice is paid we'll also create a payment record if ($entityType === ENTITY_INVOICE && isset($data['paid']) && $data['paid'] > 0) { - $this->createPayment($source, $row, $maps, $data['client_id'], $entity->id); + $this->createPayment($source, $row, $data['client_id'], $entity->id); } return $entity; } + /** + * @param $entityType + * @param $count + * @throws Exception + */ private function checkData($entityType, $count) { if ($entityType === ENTITY_CLIENT) { @@ -168,6 +337,10 @@ class ImportService } } + /** + * @param $count + * @throws Exception + */ private function checkClientCount($count) { $totalClients = $count + Client::scope()->withTrashed()->count(); @@ -176,11 +349,22 @@ class ImportService } } + /** + * @param $source + * @param $entityType + * @return string + */ public static function getTransformerClassName($source, $entityType) { return 'App\\Ninja\\Import\\'.$source.'\\'.ucwords($entityType).'Transformer'; } + /** + * @param $source + * @param $entityType + * @param $maps + * @return mixed + */ public static function getTransformer($source, $entityType, $maps) { $className = self::getTransformerClassName($source, $entityType); @@ -188,105 +372,59 @@ class ImportService return new $className($maps); } - private function createPayment($source, $data, $maps, $clientId, $invoiceId) + /** + * @param $source + * @param $data + * @param $clientId + * @param $invoiceId + */ + private function createPayment($source, $data, $clientId, $invoiceId) { - $paymentTransformer = $this->getTransformer($source, ENTITY_PAYMENT, $maps); + $paymentTransformer = $this->getTransformer($source, ENTITY_PAYMENT, $this->maps); $data->client_id = $clientId; $data->invoice_id = $invoiceId; - if ($resource = $paymentTransformer->transform($data, $maps)) { + if ($resource = $paymentTransformer->transform($data)) { $data = $this->fractal->createData($resource)->toArray(); $this->paymentRepo->save($data); } } - private function validate($source, $data, $entityType) + /** + * @param $data + * @param $entityType + * @return bool|string + */ + private function validate($data, $entityType) { - // Harvest's contacts are listed separately - if ($entityType === ENTITY_CLIENT && $source != IMPORT_HARVEST) { - $rules = [ - 'contacts' => 'valid_contacts', - ]; - } - if ($entityType === ENTITY_INVOICE) { - $rules = [ - 'client.contacts' => 'valid_contacts', - 'invoice_items' => 'valid_invoice_items', - 'invoice_number' => 'required|unique:invoices,invoice_number,,id,account_id,'.Auth::user()->account_id, - 'discount' => 'positive', - ]; - } else { - return true; - } + $requestClass = 'App\\Http\\Requests\\Create' . ucwords($entityType) . 'Request'; + $request = new $requestClass(); + $request->setUserResolver(function() { return Auth::user(); }); + $request->replace($data); - $validator = Validator::make($data, $rules); + $validator = Validator::make($data, $request->rules()); if ($validator->fails()) { - $messages = $validator->messages(); - - return $messages->first(); + return $validator->messages()->first(); } else { return true; } } - private function createMaps() - { - $clientMap = []; - $clients = $this->clientRepo->all(); - foreach ($clients as $client) { - if ($name = strtolower(trim($client->name))) { - $clientMap[$name] = $client->id; - } - } - - $invoiceMap = []; - $invoiceClientMap = []; - $invoices = $this->invoiceRepo->all(); - foreach ($invoices as $invoice) { - if ($number = strtolower(trim($invoice->invoice_number))) { - $invoiceMap[$number] = $invoice->id; - $invoiceClientMap[$number] = $invoice->client_id; - } - } - - $countryMap = []; - $countryMap2 = []; - $countries = Cache::get('countries'); - foreach ($countries as $country) { - $countryMap[strtolower($country->name)] = $country->id; - $countryMap2[strtolower($country->iso_3166_2)] = $country->id; - } - - $currencyMap = []; - $currencies = Cache::get('currencies'); - foreach ($currencies as $currency) { - $currencyMap[strtolower($currency->code)] = $currency->id; - } - - return [ - ENTITY_CLIENT => $clientMap, - ENTITY_INVOICE => $invoiceMap, - ENTITY_INVOICE.'_'.ENTITY_CLIENT => $invoiceClientMap, - 'countries' => $countryMap, - 'countries2' => $countryMap2, - 'currencies' => $currencyMap, - ]; - } - - public function mapCSV($files) + /** + * @param array $files + * @return array + * @throws Exception + */ + public function mapCSV(array $files) { $data = []; foreach ($files as $entityType => $filename) { - if ($entityType === ENTITY_CLIENT) { - $columns = Client::getImportColumns(); - $map = Client::getImportMap(); - } else { - $columns = Invoice::getImportColumns(); - $map = Invoice::getImportMap(); - } + $class = 'App\\Models\\' . ucwords($entityType); + $columns = $class::getImportColumns(); + $map = $class::getImportMap(); // Lookup field translations foreach ($columns as $key => $value) { @@ -307,6 +445,13 @@ class ImportService return $data; } + /** + * @param $entityType + * @param $filename + * @param $columns + * @param $map + * @return array + */ public function mapFile($entityType, $filename, $columns, $map) { require_once app_path().'/Includes/parsecsv.lib.php'; @@ -318,7 +463,7 @@ class ImportService $headers = false; $hasHeaders = false; - $mapped = array(); + $mapped = []; if (count($csv->data) > 0) { $headers = $csv->data[0]; @@ -344,18 +489,23 @@ class ImportService } } - $data = array( + $data = [ 'entityType' => $entityType, 'data' => $csv->data, 'headers' => $headers, 'hasHeaders' => $hasHeaders, 'columns' => $columns, 'mapped' => $mapped, - ); + ]; return $data; } + /** + * @param $column + * @param $pattern + * @return bool + */ private function checkForMatch($column, $pattern) { if (strpos($column, 'sec') === 0) { @@ -389,7 +539,12 @@ class ImportService return false; } - public function importCSV($maps, $headers) + /** + * @param array $maps + * @param $headers + * @return array + */ + public function importCSV(array $maps, $headers) { $results = []; @@ -400,6 +555,12 @@ class ImportService return $results; } + /** + * @param $entityType + * @param $map + * @param $hasHeaders + * @return array + */ private function executeCSV($entityType, $map, $hasHeaders) { $results = [ @@ -410,10 +571,10 @@ class ImportService $data = Session::get("{$entityType}-data"); $this->checkData($entityType, count($data)); - $maps = $this->createMaps(); + $this->initMaps(); // Convert the data - $row_list = array(); + $row_list = []; foreach ($data as $row) { if ($hasHeaders) { $hasHeaders = false; @@ -421,12 +582,12 @@ class ImportService } $row = $this->convertToObject($entityType, $row, $map); - $data_index = $this->transformRow($source, $entityType, $row, $maps); + $data_index = $this->transformRow($source, $entityType, $row); if ($data_index !== false) { if ($data_index !== true) { // Wasn't merged with another row - $row_list[] = array('row' => $row, 'data_index' => $data_index); + $row_list[] = ['row' => $row, 'data_index' => $data_index]; } } else { $results[RESULT_FAILURE][] = $row; @@ -435,7 +596,7 @@ class ImportService // Save the data foreach ($row_list as $row_data) { - $result = $this->saveData($source, $entityType, $row_data['row'], $row_data['data_index'], $maps); + $result = $this->saveData($source, $entityType, $row_data['row'], $row_data['data_index']); if ($result) { $results[RESULT_SUCCESS][] = $result; @@ -449,15 +610,17 @@ class ImportService return $results; } + /** + * @param $entityType + * @param $data + * @param $map + * @return stdClass + */ private function convertToObject($entityType, $data, $map) { $obj = new stdClass(); - - if ($entityType === ENTITY_CLIENT) { - $columns = Client::getImportColumns(); - } else { - $columns = Invoice::getImportColumns(); - } + $class = 'App\\Models\\' . ucwords($entityType); + $columns = $class::getImportColumns(); foreach ($columns as $column) { $obj->$column = false; @@ -477,4 +640,109 @@ class ImportService return $obj; } + + /** + * @param $entity + */ + private function addSuccess($entity) + { + $this->results[$entity->getEntityType()][RESULT_SUCCESS][] = $entity; + } + + /** + * @param $entityType + * @param $data + */ + private function addFailure($entityType, $data) + { + $this->results[$entityType][RESULT_FAILURE][] = $data; + } + + private function init() + { + EntityModel::$notifySubscriptions = false; + + foreach ([ENTITY_CLIENT, ENTITY_INVOICE, ENTITY_PAYMENT] as $entityType) { + $this->results[$entityType] = [ + RESULT_SUCCESS => [], + RESULT_FAILURE => [], + ]; + } + } + + private function initMaps() + { + $this->init(); + + $this->maps = [ + 'client' => [], + 'invoice' => [], + 'invoice_client' => [], + 'product' => [], + 'countries' => [], + 'countries2' => [], + 'currencies' => [], + 'client_ids' => [], + 'invoice_ids' => [], + ]; + + $clients = $this->clientRepo->all(); + foreach ($clients as $client) { + $this->addClientToMaps($client); + } + + $invoices = $this->invoiceRepo->all(); + foreach ($invoices as $invoice) { + $this->addInvoiceToMaps($invoice); + } + + $products = $this->productRepo->all(); + foreach ($products as $product) { + $this->addProductToMaps($product); + } + + $countries = Cache::get('countries'); + foreach ($countries as $country) { + $this->maps['countries'][strtolower($country->name)] = $country->id; + $this->maps['countries2'][strtolower($country->iso_3166_2)] = $country->id; + } + + $currencies = Cache::get('currencies'); + foreach ($currencies as $currency) { + $this->maps['currencies'][strtolower($currency->code)] = $currency->id; + } + } + + /** + * @param Invoice $invoice + */ + private function addInvoiceToMaps(Invoice $invoice) + { + if ($number = strtolower(trim($invoice->invoice_number))) { + $this->maps['invoice'][$number] = $invoice->id; + $this->maps['invoice_client'][$number] = $invoice->client_id; + $this->maps['invoice_ids'][$invoice->public_id] = $invoice->id; + } + } + + /** + * @param Client $client + */ + private function addClientToMaps(Client $client) + { + if ($name = strtolower(trim($client->name))) { + $this->maps['client'][$name] = $client->id; + $this->maps['client_ids'][$client->public_id] = $client->id; + } + } + + /** + * @param Product $product + */ + private function addProductToMaps(Product $product) + { + if ($key = strtolower(trim($product->product_key))) { + $this->maps['product'][$key] = $product->id; + } + } } diff --git a/app/Services/InvoiceService.php b/app/Services/InvoiceService.php index edbee8caf8..7238d51553 100644 --- a/app/Services/InvoiceService.php +++ b/app/Services/InvoiceService.php @@ -1,47 +1,80 @@ clientRepo = $clientRepo; $this->invoiceRepo = $invoiceRepo; $this->datatableService = $datatableService; } + /** + * @return InvoiceRepository + */ protected function getRepo() { return $this->invoiceRepo; } - public function save($data, $invoice = null) + /** + * @param array $data + * @param Invoice|null $invoice + * @return \App\Models\Invoice|Invoice|mixed + */ + public function save(array $data, Invoice $invoice = null) { if (isset($data['client'])) { $canSaveClient = false; - $clientPublicId = array_get($data, 'client.public_id') ?: array_get($data, 'client.id'); + $canViewClient = false; + $clientPublicId = array_get($data, 'client.public_id') ?: array_get($data, 'client.id'); if (empty($clientPublicId) || $clientPublicId == '-1') { $canSaveClient = Auth::user()->can('create', ENTITY_CLIENT); } else { - $canSaveClient = Auth::user()->can('edit', Client::scope($clientPublicId)->first()); - } + $client = Client::scope($clientPublicId)->first(); + $canSaveClient = Auth::user()->can('edit', $client); + $canViewClient = Auth::user()->can('view', $client); + } if ($canSaveClient) { $client = $this->clientRepo->save($data['client']); + } + if ($canSaveClient || $canViewClient) { $data['client_id'] = $client->id; } } @@ -75,30 +108,37 @@ class InvoiceService extends BaseService return $invoice; } - public function convertQuote($quote, $invitation = null) + /** + * @param $quote + * @param Invitation|null $invitation + * @return mixed + */ + public function convertQuote($quote) { - $invoice = $this->invoiceRepo->cloneInvoice($quote, $quote->id); - if (!$invitation) { - return $invoice; - } - - foreach ($invoice->invitations as $invoiceInvitation) { - if ($invitation->contact_id == $invoiceInvitation->contact_id) { - return $invoiceInvitation->invitation_key; - } - } + return $this->invoiceRepo->cloneInvoice($quote, $quote->id); } - public function approveQuote($quote, $invitation = null) + /** + * @param $quote + * @param Invitation|null $invitation + * @return mixed|null + */ + public function approveQuote($quote, Invitation $invitation = null) { $account = $quote->account; - - if (!$quote->is_quote || $quote->quote_invoice_id) { + + if (!$quote->isType(INVOICE_TYPE_QUOTE) || $quote->quote_invoice_id) { return null; } if ($account->auto_convert_quote || ! $account->hasFeature(FEATURE_QUOTES)) { - $invoice = $this->convertQuote($quote, $invitation); + $invoice = $this->convertQuote($quote); + + foreach ($invoice->invitations as $invoiceInvitation) { + if ($invitation->contact_id == $invoiceInvitation->contact_id) { + $invitation = $invoiceInvitation; + } + } event(new QuoteInvitationWasApproved($quote, $invoice, $invitation)); @@ -118,189 +158,17 @@ class InvoiceService extends BaseService public function getDatatable($accountId, $clientPublicId = null, $entityType, $search) { + $datatable = new InvoiceDatatable( ! $clientPublicId, $clientPublicId); + $datatable->entityType = $entityType; + $query = $this->invoiceRepo->getInvoices($accountId, $clientPublicId, $entityType, $search) - ->where('invoices.is_quote', '=', $entityType == ENTITY_QUOTE ? true : false); + ->where('invoices.invoice_type_id', '=', $entityType == ENTITY_QUOTE ? INVOICE_TYPE_QUOTE : INVOICE_TYPE_STANDARD); if(!Utils::hasPermission('view_all')){ $query->where('invoices.user_id', '=', Auth::user()->id); } - - return $this->createDatatable($entityType, $query, !$clientPublicId); - } - protected function getDatatableColumns($entityType, $hideClient) - { - return [ - [ - 'invoice_number', - function ($model) use ($entityType) { - if(!Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id])){ - return $model->invoice_number; - } - - return link_to("{$entityType}s/{$model->public_id}/edit", $model->invoice_number, ['class' => Utils::getEntityRowClass($model)])->toHtml(); - } - ], - [ - 'client_name', - function ($model) { - if(!Auth::user()->can('viewByOwner', [ENTITY_CLIENT, $model->client_user_id])){ - return Utils::getClientDisplayName($model); - } - return link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml(); - }, - ! $hideClient - ], - [ - 'invoice_date', - function ($model) { - return Utils::fromSqlDate($model->invoice_date); - } - ], - [ - 'amount', - function ($model) { - return Utils::formatMoney($model->amount, $model->currency_id, $model->country_id); - } - ], - [ - 'balance', - function ($model) { - return $model->partial > 0 ? - trans('texts.partial_remaining', [ - 'partial' => Utils::formatMoney($model->partial, $model->currency_id, $model->country_id), - 'balance' => Utils::formatMoney($model->balance, $model->currency_id, $model->country_id)] - ) : - Utils::formatMoney($model->balance, $model->currency_id, $model->country_id); - }, - $entityType == ENTITY_INVOICE - ], - [ - 'due_date', - function ($model) { - return Utils::fromSqlDate($model->due_date); - }, - ], - [ - 'invoice_status_name', - function ($model) use ($entityType) { - return $model->quote_invoice_id ? link_to("invoices/{$model->quote_invoice_id}/edit", trans('texts.converted'))->toHtml() : self::getStatusLabel($entityType, $model); - } - ] - ]; - } - - protected function getDatatableActions($entityType) - { - return [ - [ - trans("texts.edit_{$entityType}"), - function ($model) use ($entityType) { - return URL::to("{$entityType}s/{$model->public_id}/edit"); - }, - function ($model) { - return Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]); - } - ], - [ - trans("texts.clone_{$entityType}"), - function ($model) use ($entityType) { - return URL::to("{$entityType}s/{$model->public_id}/clone"); - }, - function ($model) { - return Auth::user()->can('create', ENTITY_INVOICE); - } - ], - [ - trans("texts.view_history"), - function ($model) use ($entityType) { - return URL::to("{$entityType}s/{$entityType}_history/{$model->public_id}"); - } - ], - [ - '--divider--', function(){return false;}, - function ($model) { - return Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]) || Auth::user()->can('create', ENTITY_PAYMENT); - } - ], - [ - trans("texts.mark_sent"), - function ($model) { - return "javascript:markEntity({$model->public_id})"; - }, - function ($model) { - return $model->invoice_status_id < INVOICE_STATUS_SENT && Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]); - } - ], - [ - trans('texts.enter_payment'), - function ($model) { - return URL::to("payments/create/{$model->client_public_id}/{$model->public_id}"); - }, - function ($model) use ($entityType) { - return $entityType == ENTITY_INVOICE && $model->balance > 0 && Auth::user()->can('create', ENTITY_PAYMENT); - } - ], - [ - trans("texts.view_quote"), - function ($model) { - return URL::to("quotes/{$model->quote_id}/edit"); - }, - function ($model) use ($entityType) { - return $entityType == ENTITY_INVOICE && $model->quote_id && Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]); - } - ], - [ - trans("texts.view_invoice"), - function ($model) { - return URL::to("invoices/{$model->quote_invoice_id}/edit"); - }, - function ($model) use ($entityType) { - return $entityType == ENTITY_QUOTE && $model->quote_invoice_id && Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]); - } - ], - [ - trans("texts.convert_to_invoice"), - function ($model) { - return "javascript:convertEntity({$model->public_id})"; - }, - function ($model) use ($entityType) { - return $entityType == ENTITY_QUOTE && ! $model->quote_invoice_id && Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]); - } - ] - ]; - } - - private function getStatusLabel($entityType, $model) - { - // check if invoice is overdue - if (Utils::parseFloat($model->balance) && $model->due_date && $model->due_date != '0000-00-00') { - if (\DateTime::createFromFormat('Y-m-d', $model->due_date) < new \DateTime("now")) { - $label = $entityType == ENTITY_INVOICE ? trans('texts.overdue') : trans('texts.expired'); - return "

    " . $label . "

    "; - } - } - - $label = trans("texts.status_" . strtolower($model->invoice_status_name)); - $class = 'default'; - switch ($model->invoice_status_id) { - case INVOICE_STATUS_SENT: - $class = 'info'; - break; - case INVOICE_STATUS_VIEWED: - $class = 'warning'; - break; - case INVOICE_STATUS_APPROVED: - $class = 'success'; - break; - case INVOICE_STATUS_PARTIAL: - $class = 'primary'; - break; - case INVOICE_STATUS_PAID: - $class = 'success'; - break; - } - return "

    $label

    "; + return $this->datatableService->createDatatable($datatable, $query); } } diff --git a/app/Services/PaymentService.php b/app/Services/PaymentService.php index 23b5f4e8f1..107fec533d 100644 --- a/app/Services/PaymentService.php +++ b/app/Services/PaymentService.php @@ -1,402 +1,161 @@ datatableService = $datatableService; $this->paymentRepo = $paymentRepo; $this->accountRepo = $accountRepo; } + /** + * @return PaymentRepository + */ protected function getRepo() { return $this->paymentRepo; } - public function createGateway($accountGateway) + /** + * @param Invoice $invoice + * @return bool + */ + public function autoBillInvoice(Invoice $invoice) { - $gateway = Omnipay::create($accountGateway->gateway->provider); - $gateway->initialize((array) $accountGateway->getConfig()); - - if ($accountGateway->isGateway(GATEWAY_DWOLLA)) { - if ($gateway->getSandbox() && isset($_ENV['DWOLLA_SANDBOX_KEY']) && isset($_ENV['DWOLLA_SANSBOX_SECRET'])) { - $gateway->setKey($_ENV['DWOLLA_SANDBOX_KEY']); - $gateway->setSecret($_ENV['DWOLLA_SANSBOX_SECRET']); - } elseif (isset($_ENV['DWOLLA_KEY']) && isset($_ENV['DWOLLA_SECRET'])) { - $gateway->setKey($_ENV['DWOLLA_KEY']); - $gateway->setSecret($_ENV['DWOLLA_SECRET']); - } - } - - return $gateway; - } - - public function getPaymentDetails($invitation, $accountGateway, $input = null) - { - $invoice = $invitation->invoice; - $account = $invoice->account; - $key = $invoice->account_id.'-'.$invoice->invoice_number; - $currencyCode = $invoice->client->currency ? $invoice->client->currency->code : ($invoice->account->currency ? $invoice->account->currency->code : 'USD'); - - if ($input) { - $data = self::convertInputForOmnipay($input); - Session::put($key, $data); - } elseif (Session::get($key)) { - $data = Session::get($key); - } else { - $data = $this->createDataForClient($invitation); - } - - $card = new CreditCard($data); - $data = [ - 'amount' => $invoice->getRequestedAmount(), - 'card' => $card, - 'currency' => $currencyCode, - 'returnUrl' => URL::to('complete'), - 'cancelUrl' => $invitation->getLink(), - 'description' => trans('texts.' . $invoice->getEntityType()) . " {$invoice->invoice_number}", - 'transactionId' => $invoice->invoice_number, - 'transactionType' => 'Purchase', - ]; - - if ($accountGateway->isGateway(GATEWAY_PAYPAL_EXPRESS) || $accountGateway->isGateway(GATEWAY_PAYPAL_PRO)) { - $data['ButtonSource'] = 'InvoiceNinja_SP'; - }; - - return $data; - } - - public function convertInputForOmnipay($input) - { - $data = [ - 'firstName' => $input['first_name'], - 'lastName' => $input['last_name'], - 'email' => $input['email'], - 'number' => isset($input['card_number']) ? $input['card_number'] : null, - 'expiryMonth' => isset($input['expiration_month']) ? $input['expiration_month'] : null, - 'expiryYear' => isset($input['expiration_year']) ? $input['expiration_year'] : null, - ]; - - // allow space until there's a setting to disable - if (isset($input['cvv']) && $input['cvv'] != ' ') { - $data['cvv'] = $input['cvv']; - } - - if (isset($input['country_id'])) { - $country = Country::find($input['country_id']); - - $data = array_merge($data, [ - 'billingAddress1' => $input['address1'], - 'billingAddress2' => $input['address2'], - 'billingCity' => $input['city'], - 'billingState' => $input['state'], - 'billingPostcode' => $input['postal_code'], - 'billingCountry' => $country->iso_3166_2, - 'shippingAddress1' => $input['address1'], - 'shippingAddress2' => $input['address2'], - 'shippingCity' => $input['city'], - 'shippingState' => $input['state'], - 'shippingPostcode' => $input['postal_code'], - 'shippingCountry' => $country->iso_3166_2 - ]); - } - - return $data; - } - - public function createDataForClient($invitation) - { - $invoice = $invitation->invoice; + /** @var \App\Models\Client $client */ $client = $invoice->client; - $contact = $invitation->contact ?: $client->contacts()->first(); - return [ - 'email' => $contact->email, - 'company' => $client->getDisplayName(), - 'firstName' => $contact->first_name, - 'lastName' => $contact->last_name, - 'billingAddress1' => $client->address1, - 'billingAddress2' => $client->address2, - 'billingCity' => $client->city, - 'billingPostcode' => $client->postal_code, - 'billingState' => $client->state, - 'billingCountry' => $client->country ? $client->country->iso_3166_2 : '', - 'billingPhone' => $contact->phone, - 'shippingAddress1' => $client->address1, - 'shippingAddress2' => $client->address2, - 'shippingCity' => $client->city, - 'shippingPostcode' => $client->postal_code, - 'shippingState' => $client->state, - 'shippingCountry' => $client->country ? $client->country->iso_3166_2 : '', - 'shippingPhone' => $contact->phone, - ]; - } + /** @var \App\Models\Account $account */ + $account = $client->account; - public function createToken($gateway, $details, $accountGateway, $client, $contactId) - { - $tokenResponse = $gateway->createCard($details)->send(); - $cardReference = $tokenResponse->getCustomerReference(); - - if ($cardReference) { - $token = AccountGatewayToken::where('client_id', '=', $client->id) - ->where('account_gateway_id', '=', $accountGateway->id)->first(); - - if (!$token) { - $token = new AccountGatewayToken(); - $token->account_id = $client->account->id; - $token->contact_id = $contactId; - $token->account_gateway_id = $accountGateway->id; - $token->client_id = $client->id; - } - - $token->token = $cardReference; - $token->save(); - } else { - $this->lastError = $tokenResponse->getMessage(); - } - - return $cardReference; - } - - public function getCheckoutComToken($invitation) - { - $token = false; - $invoice = $invitation->invoice; - $client = $invoice->client; - $account = $invoice->account; - - $accountGateway = $account->getGatewayConfig(GATEWAY_CHECKOUT_COM); - $gateway = $this->createGateway($accountGateway); - - $response = $gateway->purchase([ - 'amount' => $invoice->getRequestedAmount(), - 'currency' => $client->currency ? $client->currency->code : ($account->currency ? $account->currency->code : 'USD') - ])->send(); - - if ($response->isRedirect()) { - $token = $response->getTransactionReference(); - } - - Session::set($invitation->id . 'payment_type', PAYMENT_TYPE_CREDIT_CARD); - - return $token; - } - - public function createPayment($invitation, $accountGateway, $ref, $payerId = null) - { - $invoice = $invitation->invoice; - - $payment = Payment::createNew($invitation); - $payment->invitation_id = $invitation->id; - $payment->account_gateway_id = $accountGateway->id; - $payment->invoice_id = $invoice->id; - $payment->amount = $invoice->getRequestedAmount(); - $payment->client_id = $invoice->client_id; - $payment->contact_id = $invitation->contact_id; - $payment->transaction_reference = $ref; - $payment->payment_date = date_create()->format('Y-m-d'); - - if ($payerId) { - $payment->payer_id = $payerId; - } - - $payment->save(); - - // enable pro plan for hosted users - if ($invoice->account->account_key == NINJA_ACCOUNT_KEY) { - foreach ($invoice->invoice_items as $invoice_item) { - // Hacky, but invoices don't have meta fields to allow us to store this easily - if (1 == preg_match('/^Plan - (.+) \((.+)\)$/', $invoice_item->product_key, $matches)) { - $plan = strtolower($matches[1]); - $term = strtolower($matches[2]); - } elseif ($invoice_item->product_key == 'Pending Monthly') { - $pending_monthly = true; - } - } - - if (!empty($plan)) { - $account = Account::with('users')->find($invoice->client->public_id); - - if( - $account->company->plan != $plan - || DateTime::createFromFormat('Y-m-d', $account->company->plan_expires) >= date_create('-7 days') - ) { - // Either this is a different plan, or the subscription expired more than a week ago - // Reset any grandfathering - $account->company->plan_started = date_create()->format('Y-m-d'); - } - - if ( - $account->company->plan == $plan - && $account->company->plan_term == $term - && DateTime::createFromFormat('Y-m-d', $account->company->plan_expires) >= date_create() - ) { - // This is a renewal; mark it paid as of when this term expires - $account->company->plan_paid = $account->company->plan_expires; - } else { - $account->company->plan_paid = date_create()->format('Y-m-d'); - } - - $account->company->payment_id = $payment->id; - $account->company->plan = $plan; - $account->company->plan_term = $term; - $account->company->plan_expires = DateTime::createFromFormat('Y-m-d', $account->company->plan_paid) - ->modify($term == PLAN_TERM_MONTHLY ? '+1 month' : '+1 year')->format('Y-m-d'); - - if (!empty($pending_monthly)) { - $account->company->pending_plan = $plan; - $account->company->pending_term = PLAN_TERM_MONTHLY; - } else { - $account->company->pending_plan = null; - $account->company->pending_term = null; - } - - $account->company->save(); - } - } - - return $payment; - } - - public function completePurchase($gateway, $accountGateway, $details, $token) - { - if ($accountGateway->isGateway(GATEWAY_MOLLIE)) { - $details['transactionReference'] = $token; - $response = $gateway->fetchTransaction($details)->send(); - return $gateway->fetchTransaction($details)->send(); - } else { - - return $gateway->completePurchase($details)->send(); - } - } - - public function autoBillInvoice($invoice) - { - $client = $invoice->client; - $account = $invoice->account; + /** @var \App\Models\Invitation $invitation */ $invitation = $invoice->invitations->first(); - $accountGateway = $account->getGatewayConfig(GATEWAY_STRIPE); - $token = $client->getGatewayToken(); - if (!$invitation || !$accountGateway || !$token) { + if ( ! $invitation) { return false; } - // setup the gateway/payment info - $gateway = $this->createGateway($accountGateway); - $details = $this->getPaymentDetails($invitation, $accountGateway); - $details['customerReference'] = $token; + $paymentDriver = $account->paymentDriver($invitation, GATEWAY_TYPE_TOKEN); + $customer = $paymentDriver->customer(); - // submit purchase/get response - $response = $gateway->purchase($details)->send(); - - if ($response->isSuccessful()) { - $ref = $response->getTransactionReference(); - return $this->createPayment($invitation, $accountGateway, $ref); - } else { + if ( ! $customer) { return false; } + + $paymentMethod = $customer->default_payment_method; + + if ($paymentMethod->requiresDelayedAutoBill()) { + $invoiceDate = \DateTime::createFromFormat('Y-m-d', $invoice->invoice_date); + $minDueDate = clone $invoiceDate; + $minDueDate->modify('+10 days'); + + if (date_create() < $minDueDate) { + // Can't auto bill now + return false; + } + + if ($invoice->partial > 0) { + // The amount would be different than the amount in the email + return false; + } + + $firstUpdate = Activity::where('invoice_id', '=', $invoice->id) + ->where('activity_type_id', '=', ACTIVITY_TYPE_UPDATE_INVOICE) + ->first(); + + if ($firstUpdate) { + $backup = json_decode($firstUpdate->json_backup); + + if ($backup->balance != $invoice->balance || $backup->due_date != $invoice->due_date) { + // It's changed since we sent the email can't bill now + return false; + } + } + + if ($invoice->payments->count()) { + // ACH requirements are strict; don't auto bill this + return false; + } + } + + return $paymentDriver->completeOnsitePurchase(false, $paymentMethod); } public function getDatatable($clientPublicId, $search) { + $datatable = new PaymentDatatable( ! $clientPublicId, $clientPublicId); $query = $this->paymentRepo->find($clientPublicId, $search); if(!Utils::hasPermission('view_all')){ $query->where('payments.user_id', '=', Auth::user()->id); } - return $this->createDatatable(ENTITY_PAYMENT, $query, !$clientPublicId); + return $this->datatableService->createDatatable($datatable, $query); } - protected function getDatatableColumns($entityType, $hideClient) + + public function bulk($ids, $action, $params = []) { - return [ - [ - 'invoice_number', - function ($model) { - if(!Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->invoice_user_id])){ - return $model->invoice_number; - } - - return link_to("invoices/{$model->invoice_public_id}/edit", $model->invoice_number, ['class' => Utils::getEntityRowClass($model)])->toHtml(); - } - ], - [ - 'client_name', - function ($model) { - if(!Auth::user()->can('viewByOwner', [ENTITY_CLIENT, $model->client_user_id])){ - return Utils::getClientDisplayName($model); - } - - return $model->client_public_id ? link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml() : ''; - }, - ! $hideClient - ], - [ - 'transaction_reference', - function ($model) { - return $model->transaction_reference ? $model->transaction_reference : 'Manual entry'; - } - ], - [ - 'payment_type', - function ($model) { - return $model->payment_type ? $model->payment_type : ($model->account_gateway_id ? $model->gateway_name : ''); - } - ], - [ - 'amount', - function ($model) { - return Utils::formatMoney($model->amount, $model->currency_id, $model->country_id); - } - ], - [ - 'payment_date', - function ($model) { - return Utils::dateToString($model->payment_date); - } - ] - ]; - } + if ($action == 'refund') { + if ( ! $ids ) { + return 0; + } - protected function getDatatableActions($entityType) - { - return [ - [ - trans('texts.edit_payment'), - function ($model) { - return URL::to("payments/{$model->public_id}/edit"); - }, - function ($model) { - return Auth::user()->can('editByOwner', [ENTITY_PAYMENT, $model->user_id]); - } - ] - ]; - } + $payments = $this->getRepo()->findByPublicIdsWithTrashed($ids); + $successful = 0; + foreach ($payments as $payment) { + if (Auth::user()->can('edit', $payment)) { + $amount = !empty($params['amount']) ? floatval($params['amount']) : null; + $accountGateway = $payment->account_gateway; + $paymentDriver = $accountGateway->paymentDriver(); + if ($paymentDriver->refundPayment($payment, $amount)) { + $successful++; + } + } + } + + return $successful; + } else { + return parent::bulk($ids, $action); + } + } } diff --git a/app/Services/PaymentTermService.php b/app/Services/PaymentTermService.php index 1371d20c2c..c3d49a2360 100644 --- a/app/Services/PaymentTermService.php +++ b/app/Services/PaymentTermService.php @@ -1,8 +1,6 @@ paymentTermRepo = $paymentTermRepo; $this->datatableService = $datatableService; } + /** + * @return PaymentTermRepository + */ protected function getRepo() { return $this->paymentTermRepo; } + /** + * @param int $accountId + * @return \Illuminate\Http\JsonResponse + */ public function getDatatable($accountId = 0) { $query = $this->paymentTermRepo->find(); - return $this->createDatatable(ENTITY_PAYMENT_TERM, $query, false); + return $this->datatableService->createDatatable(ENTITY_PAYMENT_TERM, $query, false); } - protected function getDatatableColumns($entityType, $hideClient) + public function columns($entityType, $hideClient) { return [ [ @@ -46,7 +57,7 @@ class PaymentTermService extends BaseService ]; } - protected function getDatatableActions($entityType) + public function actions($entityType) { return [ [ @@ -57,4 +68,4 @@ class PaymentTermService extends BaseService ] ]; } -} \ No newline at end of file +} diff --git a/app/Services/ProductService.php b/app/Services/ProductService.php index f8ec6e1131..220ac08a60 100644 --- a/app/Services/ProductService.php +++ b/app/Services/ProductService.php @@ -1,84 +1,49 @@ datatableService = $datatableService; $this->productRepo = $productRepo; } + /** + * @return ProductRepository + */ protected function getRepo() { return $this->productRepo; } - /* - public function save() - { - return null; - } - */ - + /** + * @param $accountId + * @return \Illuminate\Http\JsonResponse + */ public function getDatatable($accountId) { + $datatable = new ProductDatatable(false); $query = $this->productRepo->find($accountId); - return $this->createDatatable(ENTITY_PRODUCT, $query, false); + return $this->datatableService->createDatatable($datatable, $query); } - - protected function getDatatableColumns($entityType, $hideClient) - { - return [ - [ - 'product_key', - function ($model) { - return link_to('products/'.$model->public_id.'/edit', $model->product_key)->toHtml(); - } - ], - [ - 'notes', - function ($model) { - return nl2br(Str::limit($model->notes, 100)); - } - ], - [ - 'cost', - function ($model) { - return Utils::formatMoney($model->cost); - } - ], - [ - 'tax_rate', - function ($model) { - return $model->tax_rate ? ($model->tax_name . ' ' . $model->tax_rate . '%') : ''; - }, - Auth::user()->account->invoice_item_taxes - ] - ]; - } - - protected function getDatatableActions($entityType) - { - return [ - [ - uctrans('texts.edit_product'), - function ($model) { - return URL::to("products/{$model->public_id}/edit"); - } - ] - ]; - } - -} \ No newline at end of file +} diff --git a/app/Services/PushService.php b/app/Services/PushService.php index a96042b924..533563fed3 100644 --- a/app/Services/PushService.php +++ b/app/Services/PushService.php @@ -2,28 +2,18 @@ namespace App\Services; -use Illuminate\Http\Request; +use App\Models\Account; +use App\Models\Invoice; use App\Ninja\Notifications\PushFactory; + /** * Class PushService - * @package App\Ninja\Notifications */ - - -/** - * $account->devices Definition - * - * @param string token (push notification device token) - * @param string email (user email address - required for use as key) - * @param string device (ios, gcm etc etc) - * @param bool notify_sent - * @param bool notify_paid - * @param bool notify_approved - * @param bool notify_viewed - */ - class PushService { + /** + * @var PushFactory + */ protected $pushFactory; /** @@ -35,11 +25,10 @@ class PushService } /** - * @param $invoice - Invoice object - * @param $type - Type of notification, ie. Quote APPROVED, Invoice PAID, Invoice/Quote SENT, Invoice/Quote VIEWED + * @param Invoice $invoice + * @param $type */ - - public function sendNotification($invoice, $type) + public function sendNotification(Invoice $invoice, $type) { if (! IOS_PUSH_CERTIFICATE) { return; @@ -57,35 +46,32 @@ class PushService if(($device["notify_{$type}"] == TRUE) && ($device['device'] == 'ios')) $this->pushMessage($invoice, $device['token'], $type); } - - } - /** * pushMessage function * * method to dispatch iOS notifications * - * @param $invoice + * @param Invoice $invoice * @param $token * @param $type */ - private function pushMessage($invoice, $token, $type) + private function pushMessage(Invoice $invoice, $token, $type) { $this->pushFactory->message($token, $this->messageType($invoice, $type)); } - /** * checkDeviceExists function * * Returns a boolean if this account has devices registered for PUSH notifications * - * @param $account + * @param Account $account + * * @return bool */ - private function checkDeviceExists($account) + private function checkDeviceExists(Account $account) { $devices = json_decode($account->devices, TRUE); @@ -100,11 +86,12 @@ class PushService * * method which formats an appropriate message depending on message type * - * @param $invoice + * @param Invoice $invoice * @param $type + * * @return string */ - private function messageType($invoice, $type) + private function messageType(Invoice $invoice, $type) { switch($type) { @@ -127,49 +114,44 @@ class PushService } /** - * @param $invoice + * @param Invoice $invoice * @return string */ - private function entitySentMessage($invoice) + private function entitySentMessage(Invoice $invoice) { - if($invoice->is_quote) - return trans("texts.notification_quote_sent_subject", ['invoice' => $invoice->invoice_number, 'client' => $invoice->client->name]); + if($invoice->isType(INVOICE_TYPE_QUOTE)) + return trans('texts.notification_quote_sent_subject', ['invoice' => $invoice->invoice_number, 'client' => $invoice->client->name]); else - return trans("texts.notification_invoice_sent_subject", ['invoice' => $invoice->invoice_number, 'client' => $invoice->client->name]); - + return trans('texts.notification_invoice_sent_subject', ['invoice' => $invoice->invoice_number, 'client' => $invoice->client->name]); } /** - * @param $invoice + * @param Invoice $invoice * @return string */ - private function invoicePaidMessage($invoice) + private function invoicePaidMessage(Invoice $invoice) { - return trans("texts.notification_invoice_paid_subject", ['invoice' => $invoice->invoice_number, 'client' => $invoice->client->name]); + return trans('texts.notification_invoice_paid_subject', ['invoice' => $invoice->invoice_number, 'client' => $invoice->client->name]); } /** - * @param $invoice + * @param Invoice $invoice * @return string */ - private function quoteApprovedMessage($invoice) + private function quoteApprovedMessage(Invoice $invoice) { - return trans("texts.notification_quote_approved_subject", ['invoice' => $invoice->invoice_number, 'client' => $invoice->client->name]); + return trans('texts.notification_quote_approved_subject', ['invoice' => $invoice->invoice_number, 'client' => $invoice->client->name]); } /** - * @param $invoice + * @param Invoice $invoice * @return string */ - private function entityViewedMessage($invoice) + private function entityViewedMessage(Invoice $invoice) { - if($invoice->is_quote) - return trans("texts.notification_quote_viewed_subject", ['invoice' => $invoice->invoice_number, 'client' => $invoice->client->name]); + if($invoice->isType(INVOICE_TYPE_QUOTE)) + return trans('texts.notification_quote_viewed_subject', ['invoice' => $invoice->invoice_number, 'client' => $invoice->client->name]); else - return trans("texts.notification_invoice_viewed_subject", ['invoice' => $invoice->invoice_number, 'client' => $invoice->client->name]); - + return trans('texts.notification_invoice_viewed_subject', ['invoice' => $invoice->invoice_number, 'client' => $invoice->client->name]); } - - - } diff --git a/app/Services/RecurringInvoiceService.php b/app/Services/RecurringInvoiceService.php index b003455abd..659870f60b 100644 --- a/app/Services/RecurringInvoiceService.php +++ b/app/Services/RecurringInvoiceService.php @@ -1,10 +1,9 @@ invoiceRepo->getRecurringInvoices($accountId, $clientPublicId, $search); if(!Utils::hasPermission('view_all')){ $query->where('invoices.user_id', '=', Auth::user()->id); } - - return $this->createDatatable(ENTITY_RECURRING_INVOICE, $query, !$clientPublicId); + + return $this->datatableService->createDatatable($datatable, $query); } - protected function getDatatableColumns($entityType, $hideClient) - { - return [ - [ - 'frequency', - function ($model) { - return link_to("invoices/{$model->public_id}", $model->frequency)->toHtml(); - } - ], - [ - 'client_name', - function ($model) { - return link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml(); - }, - ! $hideClient - ], - [ - 'start_date', - function ($model) { - return Utils::fromSqlDate($model->start_date); - } - ], - [ - 'end_date', - function ($model) { - return Utils::fromSqlDate($model->end_date); - } - ], - [ - 'amount', - function ($model) { - return Utils::formatMoney($model->amount, $model->currency_id, $model->country_id); - } - ] - ]; - } - - protected function getDatatableActions($entityType) - { - return [ - [ - trans('texts.edit_invoice'), - function ($model) { - return URL::to("invoices/{$model->public_id}/edit"); - }, - function ($model) { - return Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]); - } - ] - ]; - } -} \ No newline at end of file +} diff --git a/app/Services/TaskService.php b/app/Services/TaskService.php index e07793b2f8..812848ac1b 100644 --- a/app/Services/TaskService.php +++ b/app/Services/TaskService.php @@ -1,145 +1,52 @@ taskRepo = $taskRepo; $this->datatableService = $datatableService; } + /** + * @return TaskRepository + */ protected function getRepo() { return $this->taskRepo; } - /* - public function save() - { - return null; - } - */ - + /** + * @param $clientPublicId + * @param $search + * @return \Illuminate\Http\JsonResponse + */ public function getDatatable($clientPublicId, $search) { + $datatable = new TaskDatatable( ! $clientPublicId, $clientPublicId); $query = $this->taskRepo->find($clientPublicId, $search); if(!Utils::hasPermission('view_all')){ $query->where('tasks.user_id', '=', Auth::user()->id); } - return $this->createDatatable(ENTITY_TASK, $query, !$clientPublicId); + return $this->datatableService->createDatatable($datatable, $query); } - - protected function getDatatableColumns($entityType, $hideClient) - { - return [ - [ - 'client_name', - function ($model) { - if(!Auth::user()->can('viewByOwner', [ENTITY_CLIENT, $model->client_user_id])){ - return Utils::getClientDisplayName($model); - } - - return $model->client_public_id ? link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml() : ''; - }, - ! $hideClient - ], - [ - 'created_at', - function ($model) { - return link_to("tasks/{$model->public_id}/edit", Task::calcStartTime($model))->toHtml(); - } - ], - [ - 'time_log', - function($model) { - return Utils::formatTime(Task::calcDuration($model)); - } - ], - [ - 'description', - function ($model) { - return $model->description; - } - ], - [ - 'invoice_number', - function ($model) { - return self::getStatusLabel($model); - } - ] - ]; - } - - protected function getDatatableActions($entityType) - { - return [ - [ - trans('texts.edit_task'), - function ($model) { - return URL::to('tasks/'.$model->public_id.'/edit'); - }, - function ($model) { - return (!$model->deleted_at || $model->deleted_at == '0000-00-00') && Auth::user()->can('editByOwner', [ENTITY_TASK, $model->user_id]); - } - ], - [ - trans('texts.view_invoice'), - function ($model) { - return URL::to("/invoices/{$model->invoice_public_id}/edit"); - }, - function ($model) { - return $model->invoice_number && Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->invoice_user_id]); - } - ], - [ - trans('texts.stop_task'), - function ($model) { - return "javascript:stopTask({$model->public_id})"; - }, - function ($model) { - return $model->is_running && Auth::user()->can('editByOwner', [ENTITY_TASK, $model->user_id]); - } - ], - [ - trans('texts.invoice_task'), - function ($model) { - return "javascript:invoiceEntity({$model->public_id})"; - }, - function ($model) { - return ! $model->invoice_number && (!$model->deleted_at || $model->deleted_at == '0000-00-00') && Auth::user()->can('create', ENTITY_INVOICE); - } - ] - ]; - } - - private function getStatusLabel($model) - { - if ($model->invoice_number) { - $class = 'success'; - $label = trans('texts.invoiced'); - } elseif ($model->is_running) { - $class = 'primary'; - $label = trans('texts.running'); - } else { - $class = 'default'; - $label = trans('texts.logged'); - } - - return "

    $label

    "; - } - -} \ No newline at end of file +} diff --git a/app/Services/TaxRateService.php b/app/Services/TaxRateService.php index db5b041395..7b16132827 100644 --- a/app/Services/TaxRateService.php +++ b/app/Services/TaxRateService.php @@ -1,68 +1,52 @@ taxRateRepo = $taxRateRepo; $this->datatableService = $datatableService; } + /** + * @return TaxRateRepository + */ protected function getRepo() { return $this->taxRateRepo; } - /* - public function save() - { - return null; - } - */ - + /** + * @param $accountId + * @return \Illuminate\Http\JsonResponse + */ public function getDatatable($accountId) { + $datatable = new TaxRateDatatable(false); $query = $this->taxRateRepo->find($accountId); - return $this->createDatatable(ENTITY_TAX_RATE, $query, false); + return $this->datatableService->createDatatable($datatable, $query); } - - protected function getDatatableColumns($entityType, $hideClient) - { - return [ - [ - 'name', - function ($model) { - return link_to("tax_rates/{$model->public_id}/edit", $model->name)->toHtml(); - } - ], - [ - 'rate', - function ($model) { - return $model->rate . '%'; - } - ] - ]; - } - - protected function getDatatableActions($entityType) - { - return [ - [ - uctrans('texts.edit_tax_rate'), - function ($model) { - return URL::to("tax_rates/{$model->public_id}/edit"); - } - ] - ]; - } - -} \ No newline at end of file +} diff --git a/app/Services/TemplateService.php b/app/Services/TemplateService.php index 5a41c70535..bcc371304e 100644 --- a/app/Services/TemplateService.php +++ b/app/Services/TemplateService.php @@ -7,11 +7,22 @@ use App\Models\Gateway; class TemplateService { - public function processVariables($template, $data) + /** + * @param $template + * @param array $data + * @return mixed|string + */ + public function processVariables($template, array $data) { + /** @var \App\Models\Account $account */ $account = $data['account']; + + /** @var \App\Models\Client $client */ $client = $data['client']; + + /** @var \App\Models\Invitation $invitation */ $invitation = $data['invitation']; + $invoice = $invitation->invoice; $passwordHTML = isset($data['password'])?'

    '.trans('texts.password').': '.$data['password'].'

    ':false; $documentsHTML = ''; @@ -28,7 +39,7 @@ class TemplateService } $documentsHTML .= ''; } - + $variables = [ '$footer' => $account->getEmailFooter(), '$client' => $client->getDisplayName(), @@ -51,18 +62,20 @@ class TemplateService '$customInvoice1' => $account->custom_invoice_text_label1, '$customInvoice2' => $account->custom_invoice_text_label2, '$documents' => $documentsHTML, + '$autoBill' => empty($data['autobill'])?'':$data['autobill'], + '$portalLink' => $invitation->contact->link, + '$portalButton' => Form::emailViewButton($invitation->contact->link, 'portal'), ]; // Add variables for available payment types - foreach (Gateway::$paymentTypes as $type) { - $camelType = Gateway::getPaymentTypeName($type); - $type = Utils::toSnakeCase($camelType); + foreach (Gateway::$gatewayTypes as $type) { + $camelType = Utils::toCamelCase($type); $variables["\${$camelType}Link"] = $invitation->getLink('payment') . "/{$type}"; $variables["\${$camelType}Button"] = Form::emailPaymentButton($invitation->getLink('payment') . "/{$type}"); } - + $includesPasswordPlaceholder = strpos($template, '$password') !== false; - + $str = str_replace(array_keys($variables), array_values($variables), $template); if (!$includesPasswordPlaceholder && $passwordHTML) { @@ -71,10 +84,10 @@ class TemplateService { $str = substr_replace($str, $passwordHTML, $pos, 9/* length of "$password" */); } - } + } $str = str_replace('$password', '', $str); $str = autolink($str, 100); - + return $str; - } -} \ No newline at end of file + } +} diff --git a/app/Services/TokenService.php b/app/Services/TokenService.php index 092f3995d3..c090235901 100644 --- a/app/Services/TokenService.php +++ b/app/Services/TokenService.php @@ -1,67 +1,52 @@ tokenRepo = $tokenRepo; $this->datatableService = $datatableService; } + /** + * @return TokenRepository + */ protected function getRepo() { return $this->tokenRepo; } - /* - public function save() - { - return null; - } - */ - + /** + * @param $userId + * @return \Illuminate\Http\JsonResponse + */ public function getDatatable($userId) { + $datatable = new TokenDatatable(false); $query = $this->tokenRepo->find($userId); - return $this->createDatatable(ENTITY_TOKEN, $query, false); + return $this->datatableService->createDatatable($datatable, $query); } - - protected function getDatatableColumns($entityType, $hideClient) - { - return [ - [ - 'name', - function ($model) { - return link_to("tokens/{$model->public_id}/edit", $model->name)->toHtml(); - } - ], - [ - 'token', - function ($model) { - return $model->token; - } - ] - ]; - } - - protected function getDatatableActions($entityType) - { - return [ - [ - uctrans('texts.edit_token'), - function ($model) { - return URL::to("tokens/{$model->public_id}/edit"); - } - ] - ]; - } - -} \ No newline at end of file +} diff --git a/app/Services/UserService.php b/app/Services/UserService.php index 8e31b4c30d..f01764510a 100644 --- a/app/Services/UserService.php +++ b/app/Services/UserService.php @@ -1,121 +1,52 @@ userRepo = $userRepo; $this->datatableService = $datatableService; } + /** + * @return UserRepository + */ protected function getRepo() { return $this->userRepo; } - /* - public function save() - { - return null; - } - */ - + /** + * @param $accountId + * @return \Illuminate\Http\JsonResponse + */ public function getDatatable($accountId) { + $datatable = new UserDatatable(false); $query = $this->userRepo->find($accountId); - return $this->createDatatable(ENTITY_USER, $query, false); + return $this->datatableService->createDatatable($datatable, $query); } - - protected function getDatatableColumns($entityType, $hideClient) - { - return [ - [ - 'first_name', - function ($model) { - return $model->public_id ? link_to('users/'.$model->public_id.'/edit', $model->first_name.' '.$model->last_name)->toHtml() : ($model->first_name.' '.$model->last_name); - } - ], - [ - 'email', - function ($model) { - return $model->email; - } - ], - [ - 'confirmed', - function ($model) { - if (!$model->public_id) { - return self::getStatusLabel(USER_STATE_OWNER); - } elseif ($model->deleted_at) { - return self::getStatusLabel(USER_STATE_DISABLED); - } elseif ($model->confirmed) { - if($model->is_admin){ - return self::getStatusLabel(USER_STATE_ADMIN); - } else { - return self::getStatusLabel(USER_STATE_ACTIVE); - } - } else { - return self::getStatusLabel(USER_STATE_PENDING); - } - } - ], - ]; - } - - protected function getDatatableActions($entityType) - { - return [ - [ - uctrans('texts.edit_user'), - function ($model) { - return URL::to("users/{$model->public_id}/edit"); - }, - function ($model) { - return $model->public_id; - } - ], - [ - uctrans('texts.send_invite'), - function ($model) { - return URL::to("send_confirmation/{$model->public_id}"); - }, - function ($model) { - return $model->public_id && ! $model->confirmed; - } - ] - ]; - } - - private function getStatusLabel($state) - { - $label = trans("texts.{$state}"); - $class = 'default'; - switch ($state) { - case USER_STATE_PENDING: - $class = 'default'; - break; - case USER_STATE_ACTIVE: - $class = 'info'; - break; - case USER_STATE_DISABLED: - $class = 'warning'; - break; - case USER_STATE_OWNER: - $class = 'success'; - break; - case USER_STATE_ADMIN: - $class = 'primary'; - break; - } - return "

    $label

    "; - } - -} \ No newline at end of file +} diff --git a/app/Services/VendorService.php b/app/Services/VendorService.php index 41f5fd4664..51f81d33d6 100644 --- a/app/Services/VendorService.php +++ b/app/Services/VendorService.php @@ -1,32 +1,59 @@ vendorRepo = $vendorRepo; $this->ninjaRepo = $ninjaRepo; $this->datatableService = $datatableService; } + /** + * @return VendorRepository + */ protected function getRepo() { return $this->vendorRepo; } - public function save($data, $vendor = null) + /** + * @param array $data + * @param Vendor|null $vendor + * @return mixed|null + */ + public function save(array $data, Vendor $vendor = null) { if (Auth::user()->account->isNinjaAccount() && isset($data['plan'])) { $this->ninjaRepo->updatePlanDetails($data['public_id'], $data); @@ -35,81 +62,19 @@ class VendorService extends BaseService return $this->vendorRepo->save($data, $vendor); } + /** + * @param $search + * @return \Illuminate\Http\JsonResponse + */ public function getDatatable($search) { + $datatable = new VendorDatatable(); $query = $this->vendorRepo->find($search); - + if(!Utils::hasPermission('view_all')){ $query->where('vendors.user_id', '=', Auth::user()->id); } - return $this->createDatatable(ENTITY_VENDOR, $query); - } - - protected function getDatatableColumns($entityType, $hideVendor) - { - return [ - [ - 'name', - function ($model) { - return link_to("vendors/{$model->public_id}", $model->name ?: '')->toHtml(); - } - ], - [ - 'city', - function ($model) { - return $model->city; - } - ], - [ - 'work_phone', - function ($model) { - return $model->work_phone; - } - ], - [ - 'email', - function ($model) { - return link_to("vendors/{$model->public_id}", $model->email ?: '')->toHtml(); - } - ], - [ - 'vendors.created_at', - function ($model) { - return Utils::timestampToDateString(strtotime($model->created_at)); - } - ], - ]; - } - - protected function getDatatableActions($entityType) - { - return [ - [ - trans('texts.edit_vendor'), - function ($model) { - return URL::to("vendors/{$model->public_id}/edit"); - }, - function ($model) { - return Auth::user()->can('editByOwner', [ENTITY_VENDOR, $model->user_id]); - } - ], - [ - '--divider--', function(){return false;}, - function ($model) { - return Auth::user()->can('editByOwner', [ENTITY_VENDOR, $model->user_id]) && Auth::user()->can('create', ENTITY_EXPENSE); - } - - ], - [ - trans('texts.enter_expense'), - function ($model) { - return URL::to("expenses/create/{$model->public_id}"); - }, - function ($model) { - return Auth::user()->can('create', ENTITY_EXPENSE); - } - ] - ]; + return $this->datatableService->createDatatable($datatable, $query); } } diff --git a/composer.json b/composer.json index 56b8c0d1aa..7af865f891 100644 --- a/composer.json +++ b/composer.json @@ -17,21 +17,18 @@ "omnipay/mollie": "dev-master#22956c1a62a9662afa5f5d119723b413770ac525", "omnipay/2checkout": "dev-master#e9c079c2dde0d7ba461903b3b7bd5caf6dee1248", "omnipay/gocardless": "dev-master", - "omnipay/stripe": "2.3.0", + "omnipay/stripe": "dev-master", + "doctrine/dbal": "2.5.x", + "laravelcollective/bus": "5.2.*", "laravel/framework": "5.2.*", "laravelcollective/html": "5.2.*", - "laravelcollective/bus": "5.2.*", "symfony/css-selector": "~3.0", "patricktalmadge/bootstrapper": "5.5.x", "anahkiasen/former": "4.0.*@dev", - "barryvdh/laravel-debugbar": "~2.0", "chumper/datatable": "dev-develop#04ef2bf", "omnipay/omnipay": "~2.3", "intervention/image": "dev-master", "webpatser/laravel-countries": "dev-master", - "barryvdh/laravel-ide-helper": "dev-master", - "doctrine/dbal": "2.5.x", - "jsanc623/phpbenchtime": "2.x", "lokielse/omnipay-alipay": "dev-master", "coatesap/omnipay-datacash": "~2.0", "mfauveau/omnipay-pacnet": "~2.0", @@ -63,7 +60,6 @@ "meebio/omnipay-secure-trading": "dev-master", "justinbusschau/omnipay-secpay": "~2.0", "labs7in0/omnipay-wechat": "dev-master", - "collizo4sky/omnipay-wepay": "~1.0", "laracasts/presenter": "dev-master", "jlapp/swaggervel": "master-dev", "maatwebsite/excel": "~2.0", @@ -73,15 +69,21 @@ "league/flysystem-aws-s3-v3": "~1.0", "league/flysystem-rackspace": "~1.0", "barracudanetworks/archivestream-php": "^1.0", + "omnipay/braintree": "~2.0@dev", + "gatepay/FedACHdir": "dev-master@dev", "websight/l5-google-cloud-storage": "^1.0", - "fzaninotto/faker": "^1.5" + "wepay/php-sdk": "^0.2", + "collizo4sky/omnipay-wepay": "dev-additional-calls" }, "require-dev": { "phpunit/phpunit": "~4.0", "phpspec/phpspec": "~2.1", "codeception/codeception": "*", "codeception/c3": "~2.0", - "symfony/dom-crawler": "~3.0" + "symfony/dom-crawler": "~3.0", + "barryvdh/laravel-ide-helper": "~2.2", + "barryvdh/laravel-debugbar": "~2.2", + "fzaninotto/faker": "^1.5" }, "autoload": { "classmap": [ @@ -122,5 +124,27 @@ }, "config": { "preferred-install": "dist" - } + }, + "repositories": [ + { + "type": "package", + "package": { + "name": "gatepay/FedACHdir", + "version": "dev-master", + "dist": { + "url": "https://github.com/gatepay/FedACHdir/archive/master.zip", + "type": "zip" + }, + "source": { + "url": "git@github.com:gatepay/FedACHdir.git", + "type": "git", + "reference": "origin/master" + } + } + }, + { + "type": "vcs", + "url": "https://github.com/sometechie/omnipay-wepay" + } + ] } diff --git a/composer.lock b/composer.lock index 894c25f76d..d91a366996 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": "959e373ec2049b8d396f90b313da08b5", - "content-hash": "0a191e645db4d3edd709ec706c26503d", + "hash": "96184bcd2d0fb39c87a98b223efc5c1c", + "content-hash": "361daf07da39682d74bdc2bfead14fb9", "packages": [ { "name": "agmscode/omnipay-agms", @@ -123,12 +123,12 @@ "source": { "type": "git", "url": "https://github.com/formers/former.git", - "reference": "d97f907741323b390f43954a90a227921ecc6b96" + "reference": "37f6876a5d211427b5c445cd64f0eb637f42f685" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/formers/former/zipball/d97f907741323b390f43954a90a227921ecc6b96", - "reference": "d97f907741323b390f43954a90a227921ecc6b96", + "url": "https://api.github.com/repos/formers/former/zipball/37f6876a5d211427b5c445cd64f0eb637f42f685", + "reference": "37f6876a5d211427b5c445cd64f0eb637f42f685", "shasum": "" }, "require": { @@ -174,7 +174,7 @@ "foundation", "laravel" ], - "time": "2016-03-16 01:43:45" + "time": "2016-04-18 15:33:06" }, { "name": "anahkiasen/html-object", @@ -323,22 +323,22 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.17.1", + "version": "3.18.27", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "f8c0cc9357e10896a5c57104f2c79d1b727d97d0" + "reference": "8cc3d3231d9fb9da528205f3b905097a37ac3df3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/f8c0cc9357e10896a5c57104f2c79d1b727d97d0", - "reference": "f8c0cc9357e10896a5c57104f2c79d1b727d97d0", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/8cc3d3231d9fb9da528205f3b905097a37ac3df3", + "reference": "8cc3d3231d9fb9da528205f3b905097a37ac3df3", "shasum": "" }, "require": { "guzzlehttp/guzzle": "~5.3|~6.0.1|~6.1", "guzzlehttp/promises": "~1.0", - "guzzlehttp/psr7": "~1.0", + "guzzlehttp/psr7": "~1.3.1", "mtdowling/jmespath.php": "~2.2", "php": ">=5.5" }, @@ -399,20 +399,20 @@ "s3", "sdk" ], - "time": "2016-03-22 19:19:22" + "time": "2016-07-07 23:09:15" }, { "name": "barracudanetworks/archivestream-php", - "version": "1.0.2", + "version": "1.0.3", "source": { "type": "git", "url": "https://github.com/barracudanetworks/ArchiveStream-php.git", - "reference": "9a81c7de7f0cd5ea2150fc3dc00f1c43178362b6" + "reference": "c4e10449abde2c3283d2bda378cfb458dec08ca1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/barracudanetworks/ArchiveStream-php/zipball/9a81c7de7f0cd5ea2150fc3dc00f1c43178362b6", - "reference": "9a81c7de7f0cd5ea2150fc3dc00f1c43178362b6", + "url": "https://api.github.com/repos/barracudanetworks/ArchiveStream-php/zipball/c4e10449abde2c3283d2bda378cfb458dec08ca1", + "reference": "c4e10449abde2c3283d2bda378cfb458dec08ca1", "shasum": "" }, "require": { @@ -439,99 +439,40 @@ "tar", "zip" ], - "time": "2016-01-07 06:02:26" + "time": "2016-05-18 21:28:06" }, { - "name": "barryvdh/laravel-debugbar", - "version": "v2.2.0", + "name": "braintree/braintree_php", + "version": "3.14.0", "source": { "type": "git", - "url": "https://github.com/barryvdh/laravel-debugbar.git", - "reference": "13b7058d2120c8d5af7f1ada21b7c44dd87b666a" + "url": "https://github.com/braintree/braintree_php.git", + "reference": "0c13b6235bc99c287d18e8cfc02359e66abaa3fb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/13b7058d2120c8d5af7f1ada21b7c44dd87b666a", - "reference": "13b7058d2120c8d5af7f1ada21b7c44dd87b666a", + "url": "https://api.github.com/repos/braintree/braintree_php/zipball/0c13b6235bc99c287d18e8cfc02359e66abaa3fb", + "reference": "0c13b6235bc99c287d18e8cfc02359e66abaa3fb", "shasum": "" }, "require": { - "illuminate/support": "5.1.*|5.2.*", - "maximebf/debugbar": "~1.11.0", - "php": ">=5.5.9", - "symfony/finder": "~2.7|~3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.2-dev" - } - }, - "autoload": { - "psr-4": { - "Barryvdh\\Debugbar\\": "src/" - }, - "files": [ - "src/helpers.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Barry vd. Heuvel", - "email": "barryvdh@gmail.com" - } - ], - "description": "PHP Debugbar integration for Laravel", - "keywords": [ - "debug", - "debugbar", - "laravel", - "profiler", - "webprofiler" - ], - "time": "2016-02-17 08:32:21" - }, - { - "name": "barryvdh/laravel-ide-helper", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/barryvdh/laravel-ide-helper.git", - "reference": "e97ed532f09e290b91ff7713b785ed7ab11d0812" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/barryvdh/laravel-ide-helper/zipball/e97ed532f09e290b91ff7713b785ed7ab11d0812", - "reference": "e97ed532f09e290b91ff7713b785ed7ab11d0812", - "shasum": "" - }, - "require": { - "illuminate/console": "5.0.x|5.1.x|5.2.x", - "illuminate/filesystem": "5.0.x|5.1.x|5.2.x", - "illuminate/support": "5.0.x|5.1.x|5.2.x", - "php": ">=5.4.0", - "phpdocumentor/reflection-docblock": "^2.0.4", - "symfony/class-loader": "~2.3|~3.0" + "ext-curl": "*", + "ext-dom": "*", + "ext-hash": "*", + "ext-openssl": "*", + "ext-xmlwriter": "*", + "php": ">=5.4.0" }, "require-dev": { - "doctrine/dbal": "~2.3" - }, - "suggest": { - "doctrine/dbal": "Load information from the database about models for phpdocs (~2.3)" + "phpunit/phpunit": "3.7.*" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.1-dev" - } - }, "autoload": { + "psr-0": { + "Braintree": "lib/" + }, "psr-4": { - "Barryvdh\\LaravelIdeHelper\\": "src" + "Braintree\\": "lib/Braintree" } }, "notification-url": "https://packagist.org/downloads/", @@ -540,23 +481,12 @@ ], "authors": [ { - "name": "Barry vd. Heuvel", - "email": "barryvdh@gmail.com" + "name": "Braintree", + "homepage": "http://www.braintreepayments.com" } ], - "description": "Laravel IDE Helper, generates correct PHPDocs for all Facade classes, to improve auto-completion.", - "keywords": [ - "autocomplete", - "codeintel", - "helper", - "ide", - "laravel", - "netbeans", - "phpdoc", - "phpstorm", - "sublime" - ], - "time": "2016-03-03 14:38:04" + "description": "Braintree PHP Client Library", + "time": "2016-06-23 15:36:49" }, { "name": "cardgate/omnipay-cardgate", @@ -926,16 +856,16 @@ }, { "name": "collizo4sky/omnipay-wepay", - "version": "1.2.1", + "version": "dev-additional-calls", "source": { "type": "git", - "url": "https://github.com/collizo4sky/omnipay-wepay.git", - "reference": "6a74cc5ea56cb63c74483b1799628ca34c90a6de" + "url": "https://github.com/sometechie/omnipay-wepay.git", + "reference": "a341b9997d71803d0f774d86908cb49a8bc4c405" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/collizo4sky/omnipay-wepay/zipball/6a74cc5ea56cb63c74483b1799628ca34c90a6de", - "reference": "6a74cc5ea56cb63c74483b1799628ca34c90a6de", + "url": "https://api.github.com/repos/sometechie/omnipay-wepay/zipball/a341b9997d71803d0f774d86908cb49a8bc4c405", + "reference": "a341b9997d71803d0f774d86908cb49a8bc4c405", "shasum": "" }, "require": { @@ -943,7 +873,7 @@ }, "require-dev": { "omnipay/tests": "~2.0", - "satooshi/php-coveralls": "dev-master" + "satooshi/php-coveralls": "1.*" }, "type": "library", "autoload": { @@ -951,7 +881,6 @@ "Omnipay\\WePay\\": "src/" } }, - "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], @@ -965,7 +894,10 @@ "payment", "wepay" ], - "time": "2015-12-15 20:31:39" + "support": { + "source": "https://github.com/sometechie/omnipay-wepay/tree/additional-calls" + }, + "time": "2016-05-25 19:18:42" }, { "name": "container-interop/container-interop", @@ -1104,12 +1036,12 @@ "source": { "type": "git", "url": "https://github.com/dercoder/omnipay-paysafecard.git", - "reference": "2f538e119ae6244176a3603b0d00ac29484ee142" + "reference": "9fce03e372d7bdccde96a32aaa6dca5ab29d1ea8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dercoder/omnipay-paysafecard/zipball/2f538e119ae6244176a3603b0d00ac29484ee142", - "reference": "2f538e119ae6244176a3603b0d00ac29484ee142", + "url": "https://api.github.com/repos/dercoder/omnipay-paysafecard/zipball/9fce03e372d7bdccde96a32aaa6dca5ab29d1ea8", + "reference": "9fce03e372d7bdccde96a32aaa6dca5ab29d1ea8", "shasum": "" }, "require": { @@ -1118,7 +1050,7 @@ }, "require-dev": { "omnipay/tests": "~2.0", - "satooshi/php-coveralls": "dev-master" + "satooshi/php-coveralls": "~1.0" }, "type": "library", "extra": { @@ -1151,7 +1083,7 @@ "payment", "paysafecard" ], - "time": "2015-10-09 09:33:10" + "time": "2016-06-21 10:42:41" }, { "name": "descubraomundo/omnipay-pagarme", @@ -1965,52 +1897,15 @@ "time": "2015-01-16 08:41:13" }, { - "name": "fzaninotto/faker", - "version": "v1.6.0", + "name": "gatepay/FedACHdir", + "version": "dev-master", "source": { "type": "git", - "url": "https://github.com/fzaninotto/Faker.git", - "reference": "44f9a286a04b80c76a4e5fb7aad8bb539b920123" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/44f9a286a04b80c76a4e5fb7aad8bb539b920123", - "reference": "44f9a286a04b80c76a4e5fb7aad8bb539b920123", - "shasum": "" - }, - "require": { - "php": "^5.3.3|^7.0" - }, - "require-dev": { - "ext-intl": "*", - "phpunit/phpunit": "~4.0", - "squizlabs/php_codesniffer": "~1.5" + "url": "git@github.com:gatepay/FedACHdir.git", + "reference": "origin/master" }, "type": "library", - "extra": { - "branch-alias": [] - }, - "autoload": { - "psr-4": { - "Faker\\": "src/Faker/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "François Zaninotto" - } - ], - "description": "Faker is a PHP library that generates fake data for you.", - "keywords": [ - "data", - "faker", - "fixtures" - ], - "time": "2016-04-29 12:21:54" + "time": "2016-06-03 12:00:26" }, { "name": "google/apiclient", @@ -2057,22 +1952,22 @@ }, { "name": "guzzle/guzzle", - "version": "v3.8.1", + "version": "v3.9.3", "source": { "type": "git", - "url": "https://github.com/guzzle/guzzle.git", - "reference": "4de0618a01b34aa1c8c33a3f13f396dcd3882eba" + "url": "https://github.com/guzzle/guzzle3.git", + "reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/4de0618a01b34aa1c8c33a3f13f396dcd3882eba", - "reference": "4de0618a01b34aa1c8c33a3f13f396dcd3882eba", + "url": "https://api.github.com/repos/guzzle/guzzle3/zipball/0645b70d953bc1c067bbc8d5bc53194706b628d9", + "reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9", "shasum": "" }, "require": { "ext-curl": "*", "php": ">=5.3.3", - "symfony/event-dispatcher": ">=2.1" + "symfony/event-dispatcher": "~2.1" }, "replace": { "guzzle/batch": "self.version", @@ -2099,18 +1994,21 @@ "guzzle/stream": "self.version" }, "require-dev": { - "doctrine/cache": "*", - "monolog/monolog": "1.*", + "doctrine/cache": "~1.3", + "monolog/monolog": "~1.0", "phpunit/phpunit": "3.7.*", - "psr/log": "1.0.*", - "symfony/class-loader": "*", - "zendframework/zend-cache": "<2.3", - "zendframework/zend-log": "<2.3" + "psr/log": "~1.0", + "symfony/class-loader": "~2.1", + "zendframework/zend-cache": "2.*,<2.3", + "zendframework/zend-log": "2.*,<2.3" + }, + "suggest": { + "guzzlehttp/guzzle": "Guzzle 5 has moved to a new package name. The package you have installed, Guzzle 3, is deprecated." }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.8-dev" + "dev-master": "3.9-dev" } }, "autoload": { @@ -2134,7 +2032,7 @@ "homepage": "https://github.com/guzzle/guzzle/contributors" } ], - "description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients", + "description": "PHP HTTP client. This library is deprecated in favor of https://packagist.org/packages/guzzlehttp/guzzle", "homepage": "http://guzzlephp.org/", "keywords": [ "client", @@ -2145,7 +2043,8 @@ "rest", "web service" ], - "time": "2014-01-28 22:29:15" + "abandoned": "guzzlehttp/guzzle", + "time": "2015-03-18 18:23:50" }, { "name": "guzzlehttp/guzzle", @@ -2211,16 +2110,16 @@ }, { "name": "guzzlehttp/promises", - "version": "1.1.0", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "bb9024c526b22f3fe6ae55a561fd70653d470aa8" + "reference": "c10d860e2a9595f8883527fa0021c7da9e65f579" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/bb9024c526b22f3fe6ae55a561fd70653d470aa8", - "reference": "bb9024c526b22f3fe6ae55a561fd70653d470aa8", + "url": "https://api.github.com/repos/guzzle/promises/zipball/c10d860e2a9595f8883527fa0021c7da9e65f579", + "reference": "c10d860e2a9595f8883527fa0021c7da9e65f579", "shasum": "" }, "require": { @@ -2258,20 +2157,20 @@ "keywords": [ "promise" ], - "time": "2016-03-08 01:15:46" + "time": "2016-05-18 16:56:05" }, { "name": "guzzlehttp/psr7", - "version": "1.2.3", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "2e89629ff057ebb49492ba08e6995d3a6a80021b" + "reference": "5c6447c9df362e8f8093bda8f5d8873fe5c7f65b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/2e89629ff057ebb49492ba08e6995d3a6a80021b", - "reference": "2e89629ff057ebb49492ba08e6995d3a6a80021b", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/5c6447c9df362e8f8093bda8f5d8873fe5c7f65b", + "reference": "5c6447c9df362e8f8093bda8f5d8873fe5c7f65b", "shasum": "" }, "require": { @@ -2287,7 +2186,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.4-dev" } }, "autoload": { @@ -2316,7 +2215,7 @@ "stream", "uri" ], - "time": "2016-02-18 21:54:00" + "time": "2016-06-24 23:00:38" }, { "name": "illuminate/html", @@ -2362,6 +2261,7 @@ "email": "taylorotwell@gmail.com" } ], + "abandoned": "laravelcollective/html", "time": "2015-01-01 16:31:18" }, { @@ -2425,12 +2325,12 @@ "source": { "type": "git", "url": "https://github.com/Intervention/image.git", - "reference": "e368d262887dbb2fdfaf710880571ede51e9c0e6" + "reference": "6886d43f5babe6900c29c59640ca81401fe71c80" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Intervention/image/zipball/e368d262887dbb2fdfaf710880571ede51e9c0e6", - "reference": "e368d262887dbb2fdfaf710880571ede51e9c0e6", + "url": "https://api.github.com/repos/Intervention/image/zipball/6886d43f5babe6900c29c59640ca81401fe71c80", + "reference": "6886d43f5babe6900c29c59640ca81401fe71c80", "shasum": "" }, "require": { @@ -2479,7 +2379,7 @@ "thumbnail", "watermark" ], - "time": "2016-02-26 18:18:19" + "time": "2016-06-22 08:03:11" }, { "name": "ircmaxell/password-compat", @@ -2713,46 +2613,6 @@ ], "time": "2016-01-25 15:38:17" }, - { - "name": "jsanc623/phpbenchtime", - "version": "2.1.0", - "source": { - "type": "git", - "url": "https://github.com/jsanc623/PHPBenchTime.git", - "reference": "dc9980ffd85ef42a23183dda75ab4684801a5564" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/jsanc623/PHPBenchTime/zipball/dc9980ffd85ef42a23183dda75ab4684801a5564", - "reference": "dc9980ffd85ef42a23183dda75ab4684801a5564", - "shasum": "" - }, - "type": "library", - "autoload": { - "psr-0": { - "": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Juan Sanchez", - "email": "juan.sanchez@juanleonardosanchez.com" - } - ], - "description": "A light benchmark timer class for PHP.", - "keywords": [ - "benchmark", - "benchtime", - "profiler", - "stopwatch", - "timer" - ], - "time": "2015-07-06 16:36:27" - }, { "name": "justinbusschau/omnipay-secpay", "version": "2.0.6", @@ -2814,12 +2674,12 @@ "source": { "type": "git", "url": "https://github.com/labs7in0/omnipay-wechat.git", - "reference": "40c9f86df6573ad98ae1dd0d29712ccbc789a74e" + "reference": "c8d80c3b48bae2bab071f283f75b1cd8624ed3c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/labs7in0/omnipay-wechat/zipball/40c9f86df6573ad98ae1dd0d29712ccbc789a74e", - "reference": "40c9f86df6573ad98ae1dd0d29712ccbc789a74e", + "url": "https://api.github.com/repos/labs7in0/omnipay-wechat/zipball/c8d80c3b48bae2bab071f283f75b1cd8624ed3c7", + "reference": "c8d80c3b48bae2bab071f283f75b1cd8624ed3c7", "shasum": "" }, "require": { @@ -2855,7 +2715,7 @@ "purchase", "wechat" ], - "time": "2016-03-18 09:59:11" + "time": "2016-05-10 08:43:41" }, { "name": "laracasts/presenter", @@ -2905,16 +2765,16 @@ }, { "name": "laravel/framework", - "version": "v5.2.24", + "version": "v5.2.39", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "396297a5fd3c70c2fc1af68f09ee574a2380175c" + "reference": "c2a77050269b4e03bd9a735a9f24e573a7598b8a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/396297a5fd3c70c2fc1af68f09ee574a2380175c", - "reference": "396297a5fd3c70c2fc1af68f09ee574a2380175c", + "url": "https://api.github.com/repos/laravel/framework/zipball/c2a77050269b4e03bd9a735a9f24e573a7598b8a", + "reference": "c2a77050269b4e03bd9a735a9f24e573a7598b8a", "shasum": "" }, "require": { @@ -2975,7 +2835,7 @@ }, "require-dev": { "aws/aws-sdk-php": "~3.0", - "mockery/mockery": "~0.9.2", + "mockery/mockery": "~0.9.4", "pda/pheanstalk": "~3.0", "phpunit/phpunit": "~4.1", "predis/predis": "~1.0", @@ -2993,7 +2853,8 @@ "predis/predis": "Required to use the redis cache and queue drivers (~1.0).", "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (~2.0).", "symfony/css-selector": "Required to use some of the crawler integration testing tools (2.8.*|3.0.*).", - "symfony/dom-crawler": "Required to use most of the crawler integration testing tools (2.8.*|3.0.*)." + "symfony/dom-crawler": "Required to use most of the crawler integration testing tools (2.8.*|3.0.*).", + "symfony/psr-http-message-bridge": "Required to psr7 bridging features (0.2.*)." }, "type": "library", "extra": { @@ -3029,20 +2890,20 @@ "framework", "laravel" ], - "time": "2016-03-22 13:45:19" + "time": "2016-06-17 19:25:12" }, { "name": "laravel/socialite", - "version": "v2.0.14", + "version": "v2.0.18", "source": { "type": "git", "url": "https://github.com/laravel/socialite.git", - "reference": "b15f4be0ac739405120d74b837af423aa71502d9" + "reference": "76ee5397fcdea5a062361392abca4eb397e519a3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/socialite/zipball/b15f4be0ac739405120d74b837af423aa71502d9", - "reference": "b15f4be0ac739405120d74b837af423aa71502d9", + "url": "https://api.github.com/repos/laravel/socialite/zipball/76ee5397fcdea5a062361392abca4eb397e519a3", + "reference": "76ee5397fcdea5a062361392abca4eb397e519a3", "shasum": "" }, "require": { @@ -3055,7 +2916,7 @@ }, "require-dev": { "mockery/mockery": "~0.9", - "phpunit/phpunit": "~4.0" + "phpunit/phpunit": "~4.0|~5.0" }, "type": "library", "extra": { @@ -3083,7 +2944,7 @@ "laravel", "oauth" ], - "time": "2015-10-16 15:39:46" + "time": "2016-06-22 12:40:16" }, { "name": "laravelcollective/bus", @@ -3186,16 +3047,16 @@ }, { "name": "league/flysystem", - "version": "1.0.20", + "version": "1.0.24", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "e87a786e3ae12a25cf78a71bb07b4b384bfaa83a" + "reference": "9aca859a303fdca30370f42b8c611d9cf0dedf4b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/e87a786e3ae12a25cf78a71bb07b4b384bfaa83a", - "reference": "e87a786e3ae12a25cf78a71bb07b4b384bfaa83a", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/9aca859a303fdca30370f42b8c611d9cf0dedf4b", + "reference": "9aca859a303fdca30370f42b8c611d9cf0dedf4b", "shasum": "" }, "require": { @@ -3265,20 +3126,20 @@ "sftp", "storage" ], - "time": "2016-03-14 21:54:11" + "time": "2016-06-03 19:11:39" }, { "name": "league/flysystem-aws-s3-v3", - "version": "1.0.9", + "version": "1.0.13", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem-aws-s3-v3.git", - "reference": "595e24678bf78f8107ebc9355d8376ae0eb712c6" + "reference": "dc56a8faf3aff0841f9eae04b6af94a50657896c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/595e24678bf78f8107ebc9355d8376ae0eb712c6", - "reference": "595e24678bf78f8107ebc9355d8376ae0eb712c6", + "url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/dc56a8faf3aff0841f9eae04b6af94a50657896c", + "reference": "dc56a8faf3aff0841f9eae04b6af94a50657896c", "shasum": "" }, "require": { @@ -3312,7 +3173,7 @@ } ], "description": "Flysystem adapter for the AWS S3 SDK v3.x", - "time": "2015-11-19 08:44:16" + "time": "2016-06-21 21:34:35" }, { "name": "league/flysystem-rackspace", @@ -3659,67 +3520,6 @@ ], "time": "2016-03-01 17:45:44" }, - { - "name": "maximebf/debugbar", - "version": "v1.11.1", - "source": { - "type": "git", - "url": "https://github.com/maximebf/php-debugbar.git", - "reference": "d9302891c1f0a0ac5a4f66725163a00537c6359f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/d9302891c1f0a0ac5a4f66725163a00537c6359f", - "reference": "d9302891c1f0a0ac5a4f66725163a00537c6359f", - "shasum": "" - }, - "require": { - "php": ">=5.3.0", - "psr/log": "^1.0", - "symfony/var-dumper": "^2.6|^3.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.0|^5.0" - }, - "suggest": { - "kriswallsmith/assetic": "The best way to manage assets", - "monolog/monolog": "Log using Monolog", - "predis/predis": "Redis storage" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.11-dev" - } - }, - "autoload": { - "psr-4": { - "DebugBar\\": "src/DebugBar/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Maxime Bouroumeau-Fuseau", - "email": "maxime.bouroumeau@gmail.com", - "homepage": "http://maximebf.com" - }, - { - "name": "Barry vd. Heuvel", - "email": "barryvdh@gmail.com" - } - ], - "description": "Debug bar in the browser for php application", - "homepage": "https://github.com/maximebf/php-debugbar", - "keywords": [ - "debug", - "debugbar" - ], - "time": "2016-01-22 12:22:23" - }, { "name": "meebio/omnipay-creditcall", "version": "dev-master", @@ -3920,16 +3720,16 @@ }, { "name": "monolog/monolog", - "version": "1.18.1", + "version": "1.20.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "a5f2734e8c16f3aa21b3da09715d10e15b4d2d45" + "reference": "55841909e2bcde01b5318c35f2b74f8ecc86e037" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/a5f2734e8c16f3aa21b3da09715d10e15b4d2d45", - "reference": "a5f2734e8c16f3aa21b3da09715d10e15b4d2d45", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/55841909e2bcde01b5318c35f2b74f8ecc86e037", + "reference": "55841909e2bcde01b5318c35f2b74f8ecc86e037", "shasum": "" }, "require": { @@ -3944,13 +3744,13 @@ "doctrine/couchdb": "~1.0@dev", "graylog2/gelf-php": "~1.0", "jakub-onderka/php-parallel-lint": "0.9", + "php-amqplib/php-amqplib": "~2.4", "php-console/php-console": "^3.1.3", "phpunit/phpunit": "~4.5", "phpunit/phpunit-mock-objects": "2.3.0", - "raven/raven": "^0.13", "ruflin/elastica": ">=0.90 <3.0", - "swiftmailer/swiftmailer": "~5.3", - "videlalvaro/php-amqplib": "~2.4" + "sentry/sentry": "^0.13", + "swiftmailer/swiftmailer": "~5.3" }, "suggest": { "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", @@ -3959,11 +3759,11 @@ "ext-mongo": "Allow sending log messages to a MongoDB server", "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", "php-console/php-console": "Allow sending log messages to Google Chrome", - "raven/raven": "Allow sending log messages to a Sentry server", "rollbar/rollbar": "Allow sending log messages to Rollbar", "ruflin/elastica": "Allow sending log messages to an Elastic Search server", - "videlalvaro/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib" + "sentry/sentry": "Allow sending log messages to a Sentry server" }, "type": "library", "extra": { @@ -3994,7 +3794,7 @@ "logging", "psr-3" ], - "time": "2016-03-13 16:08:35" + "time": "2016-07-02 14:02:10" }, { "name": "mtdowling/cron-expression", @@ -4144,16 +3944,16 @@ }, { "name": "nikic/php-parser", - "version": "v2.0.1", + "version": "v2.1.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "ce5be709d59b32dd8a88c80259028759991a4206" + "reference": "47b254ea51f1d6d5dc04b9b299e88346bf2369e3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ce5be709d59b32dd8a88c80259028759991a4206", - "reference": "ce5be709d59b32dd8a88c80259028759991a4206", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/47b254ea51f1d6d5dc04b9b299e88346bf2369e3", + "reference": "47b254ea51f1d6d5dc04b9b299e88346bf2369e3", "shasum": "" }, "require": { @@ -4169,7 +3969,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "2.1-dev" } }, "autoload": { @@ -4191,7 +3991,7 @@ "parser", "php" ], - "time": "2016-02-28 19:48:28" + "time": "2016-04-19 13:41:41" }, { "name": "omnipay/2checkout", @@ -4254,20 +4054,20 @@ }, { "name": "omnipay/authorizenet", - "version": "2.3.1", + "version": "2.4.1", "source": { "type": "git", "url": "https://github.com/thephpleague/omnipay-authorizenet.git", - "reference": "e2e813b0b6306ef97b8763037f05476456546b3e" + "reference": "439bb6e649a4c57cddc24d6d704301a8ee5c3c3f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/omnipay-authorizenet/zipball/e2e813b0b6306ef97b8763037f05476456546b3e", - "reference": "e2e813b0b6306ef97b8763037f05476456546b3e", + "url": "https://api.github.com/repos/thephpleague/omnipay-authorizenet/zipball/439bb6e649a4c57cddc24d6d704301a8ee5c3c3f", + "reference": "439bb6e649a4c57cddc24d6d704301a8ee5c3c3f", "shasum": "" }, "require": { - "omnipay/common": "~2.0" + "omnipay/common": "~2.2" }, "require-dev": { "omnipay/tests": "~2.0" @@ -4309,7 +4109,7 @@ "pay", "payment" ], - "time": "2016-03-10 11:35:24" + "time": "2016-06-16 10:06:24" }, { "name": "omnipay/bitpay", @@ -4317,12 +4117,12 @@ "source": { "type": "git", "url": "https://github.com/thephpleague/omnipay-bitpay.git", - "reference": "cf813f1d5436a1d2f942d3df6666695d1e2b5280" + "reference": "9cadfb7955bd361d1a00ac8f0570aee4c05c6bb4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/omnipay-bitpay/zipball/cf813f1d5436a1d2f942d3df6666695d1e2b5280", - "reference": "cf813f1d5436a1d2f942d3df6666695d1e2b5280", + "url": "https://api.github.com/repos/thephpleague/omnipay-bitpay/zipball/9cadfb7955bd361d1a00ac8f0570aee4c05c6bb4", + "reference": "9cadfb7955bd361d1a00ac8f0570aee4c05c6bb4", "shasum": "" }, "require": { @@ -4367,20 +4167,83 @@ "pay", "payment" ], - "time": "2016-03-10 03:16:04" + "time": "2016-04-07 02:53:36" }, { - "name": "omnipay/buckaroo", - "version": "v2.0.1", + "name": "omnipay/braintree", + "version": "dev-master", "source": { "type": "git", - "url": "https://github.com/thephpleague/omnipay-buckaroo.git", - "reference": "76a4fdc4af46a2eeff58036bcb16af7d077363b9" + "url": "https://github.com/thephpleague/omnipay-braintree.git", + "reference": "54846f2d148b2b6163a37b05d19bf5479c2bf855" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/omnipay-buckaroo/zipball/76a4fdc4af46a2eeff58036bcb16af7d077363b9", - "reference": "76a4fdc4af46a2eeff58036bcb16af7d077363b9", + "url": "https://api.github.com/repos/thephpleague/omnipay-braintree/zipball/54846f2d148b2b6163a37b05d19bf5479c2bf855", + "reference": "54846f2d148b2b6163a37b05d19bf5479c2bf855", + "shasum": "" + }, + "require": { + "braintree/braintree_php": "^2.39|^3.0", + "omnipay/common": "~2.0" + }, + "require-dev": { + "omnipay/tests": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Omnipay\\Braintree\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Barry vd. Heuvel", + "email": "barryvdh@gmail.com" + }, + { + "name": "Kayla Daniels", + "email": "kayladnls@gmail.com" + }, + { + "name": "Omnipay Contributors", + "homepage": "https://github.com/thephpleague/omnipay-braintree/contributors" + } + ], + "description": "Braintree gateway for Omnipay payment processing library", + "homepage": "https://github.com/thephpleague/omnipay-braintree", + "keywords": [ + "braintree", + "gateway", + "merchant", + "omnipay", + "pay", + "payment", + "purchase" + ], + "time": "2016-06-22 07:44:48" + }, + { + "name": "omnipay/buckaroo", + "version": "v2.0.2", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/omnipay-buckaroo.git", + "reference": "aeadff6281fb4ecba1ff341bb8288e3e4a54d50e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/omnipay-buckaroo/zipball/aeadff6281fb4ecba1ff341bb8288e3e4a54d50e", + "reference": "aeadff6281fb4ecba1ff341bb8288e3e4a54d50e", "shasum": "" }, "require": { @@ -4424,7 +4287,7 @@ "pay", "payment" ], - "time": "2014-09-17 00:35:28" + "time": "2016-06-22 07:37:02" }, { "name": "omnipay/cardsave", @@ -4543,20 +4406,20 @@ }, { "name": "omnipay/common", - "version": "v2.3.3", + "version": "v2.3.4", "source": { "type": "git", "url": "https://github.com/thephpleague/omnipay-common.git", - "reference": "e4c54a314a2529c1008ad3f77e9eef26ed1f311b" + "reference": "fcd5a606713d11536c89315a5ae02d965a737c21" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/omnipay-common/zipball/e4c54a314a2529c1008ad3f77e9eef26ed1f311b", - "reference": "e4c54a314a2529c1008ad3f77e9eef26ed1f311b", + "url": "https://api.github.com/repos/thephpleague/omnipay-common/zipball/fcd5a606713d11536c89315a5ae02d965a737c21", + "reference": "fcd5a606713d11536c89315a5ae02d965a737c21", "shasum": "" }, "require": { - "guzzle/http": "~3.1", + "guzzle/guzzle": "~3.9", "php": ">=5.3.2", "symfony/http-foundation": "~2.1" }, @@ -4655,7 +4518,7 @@ "payment", "purchase" ], - "time": "2015-01-11 04:54:29" + "time": "2015-03-30 14:34:46" }, { "name": "omnipay/dummy", @@ -4889,16 +4752,16 @@ }, { "name": "omnipay/manual", - "version": "v2.1.1", + "version": "v2.2.0", "source": { "type": "git", "url": "https://github.com/thephpleague/omnipay-manual.git", - "reference": "ddbe7e8cfdb03b102219185aeb7dd91823275c71" + "reference": "db31b81dc3a9ccbc61a805dd9f922b7bfd0eb0e9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/omnipay-manual/zipball/ddbe7e8cfdb03b102219185aeb7dd91823275c71", - "reference": "ddbe7e8cfdb03b102219185aeb7dd91823275c71", + "url": "https://api.github.com/repos/thephpleague/omnipay-manual/zipball/db31b81dc3a9ccbc61a805dd9f922b7bfd0eb0e9", + "reference": "db31b81dc3a9ccbc61a805dd9f922b7bfd0eb0e9", "shasum": "" }, "require": { @@ -4942,7 +4805,7 @@ "pay", "payment" ], - "time": "2014-09-17 00:37:01" + "time": "2016-03-29 17:52:49" }, { "name": "omnipay/migs", @@ -5061,16 +4924,16 @@ }, { "name": "omnipay/multisafepay", - "version": "v2.3.0", + "version": "v2.3.1", "source": { "type": "git", "url": "https://github.com/thephpleague/omnipay-multisafepay.git", - "reference": "342d0a3ba1a5ef0d788f20d23d0c70ce04ec3de1" + "reference": "01cfa7115ab7b3c79633e8137f802891c02640f2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/omnipay-multisafepay/zipball/342d0a3ba1a5ef0d788f20d23d0c70ce04ec3de1", - "reference": "342d0a3ba1a5ef0d788f20d23d0c70ce04ec3de1", + "url": "https://api.github.com/repos/thephpleague/omnipay-multisafepay/zipball/01cfa7115ab7b3c79633e8137f802891c02640f2", + "reference": "01cfa7115ab7b3c79633e8137f802891c02640f2", "shasum": "" }, "require": { @@ -5115,7 +4978,7 @@ "pay", "payment" ], - "time": "2016-02-18 00:06:08" + "time": "2016-03-21 02:10:38" }, { "name": "omnipay/netaxept", @@ -5459,16 +5322,16 @@ }, { "name": "omnipay/paymentexpress", - "version": "v2.1.2", + "version": "v2.2.0", "source": { "type": "git", "url": "https://github.com/thephpleague/omnipay-paymentexpress.git", - "reference": "bd417f02bacb2128c168956739cd3a902d3ee48c" + "reference": "5707f016cd2a6fa735f325c40ff3b5fbe29452ea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/omnipay-paymentexpress/zipball/bd417f02bacb2128c168956739cd3a902d3ee48c", - "reference": "bd417f02bacb2128c168956739cd3a902d3ee48c", + "url": "https://api.github.com/repos/thephpleague/omnipay-paymentexpress/zipball/5707f016cd2a6fa735f325c40ff3b5fbe29452ea", + "reference": "5707f016cd2a6fa735f325c40ff3b5fbe29452ea", "shasum": "" }, "require": { @@ -5518,20 +5381,20 @@ "pxpay", "pxpost" ], - "time": "2015-04-03 00:20:28" + "time": "2016-05-02 13:46:54" }, { "name": "omnipay/paypal", - "version": "v2.5.3", + "version": "v2.5.4", "source": { "type": "git", "url": "https://github.com/thephpleague/omnipay-paypal.git", - "reference": "97fc3b1ff43e130ee911b35e139dcc853488d07a" + "reference": "3d39ab63f9c1e31893ec61bbab9eda98df5f1a6f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/omnipay-paypal/zipball/97fc3b1ff43e130ee911b35e139dcc853488d07a", - "reference": "97fc3b1ff43e130ee911b35e139dcc853488d07a", + "url": "https://api.github.com/repos/thephpleague/omnipay-paypal/zipball/3d39ab63f9c1e31893ec61bbab9eda98df5f1a6f", + "reference": "3d39ab63f9c1e31893ec61bbab9eda98df5f1a6f", "shasum": "" }, "require": { @@ -5576,20 +5439,20 @@ "paypal", "purchase" ], - "time": "2016-02-29 00:06:43" + "time": "2016-03-25 10:40:17" }, { "name": "omnipay/pin", - "version": "v2.2.1", + "version": "v2.2.2", "source": { "type": "git", "url": "https://github.com/thephpleague/omnipay-pin.git", - "reference": "c2252e41f3674267b2bbe79eaeec73b6b1e4ee58" + "reference": "8c859bc71de8def70623eacd1b3ec6da1829a445" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/omnipay-pin/zipball/c2252e41f3674267b2bbe79eaeec73b6b1e4ee58", - "reference": "c2252e41f3674267b2bbe79eaeec73b6b1e4ee58", + "url": "https://api.github.com/repos/thephpleague/omnipay-pin/zipball/8c859bc71de8def70623eacd1b3ec6da1829a445", + "reference": "8c859bc71de8def70623eacd1b3ec6da1829a445", "shasum": "" }, "require": { @@ -5633,7 +5496,7 @@ "payment", "pin" ], - "time": "2016-01-13 07:00:17" + "time": "2016-03-25 18:06:33" }, { "name": "omnipay/sagepay", @@ -5753,16 +5616,16 @@ }, { "name": "omnipay/stripe", - "version": "v2.3.0", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/thephpleague/omnipay-stripe.git", - "reference": "54b816a5e95e34c988d71fb805b0232cfd7c1ce5" + "reference": "cb2d26a95db2105b7a054bd7e84d26c4051cd68f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/omnipay-stripe/zipball/54b816a5e95e34c988d71fb805b0232cfd7c1ce5", - "reference": "54b816a5e95e34c988d71fb805b0232cfd7c1ce5", + "url": "https://api.github.com/repos/thephpleague/omnipay-stripe/zipball/cb2d26a95db2105b7a054bd7e84d26c4051cd68f", + "reference": "cb2d26a95db2105b7a054bd7e84d26c4051cd68f", "shasum": "" }, "require": { @@ -5806,7 +5669,7 @@ "payment", "stripe" ], - "time": "2015-11-10 16:17:35" + "time": "2016-06-01 03:31:03" }, { "name": "omnipay/targetpay", @@ -6029,55 +5892,6 @@ ], "time": "2015-02-28 17:09:35" }, - { - "name": "phpdocumentor/reflection-docblock", - "version": "2.0.4", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d68dbdc53dc358a816f00b300704702b2eaff7b8", - "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.0" - }, - "suggest": { - "dflydev/markdown": "~1.0", - "erusev/parsedown": "~1.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "psr-0": { - "phpDocumentor": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "mike.vanriel@naenius.com" - } - ], - "time": "2015-02-03 12:10:50" - }, { "name": "phpoffice/phpexcel", "version": "1.8.1", @@ -6353,16 +6167,16 @@ }, { "name": "samvaughton/omnipay-barclays-epdq", - "version": "2.2.0", + "version": "2.2.3", "source": { "type": "git", "url": "https://github.com/samvaughton/omnipay-barclays-epdq.git", - "reference": "b7f9263afa73b8e6c3c5e8bb2bf04a82548a41da" + "reference": "ee90e438ce7cb46ef8c1001d102b5711872dabae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/samvaughton/omnipay-barclays-epdq/zipball/b7f9263afa73b8e6c3c5e8bb2bf04a82548a41da", - "reference": "b7f9263afa73b8e6c3c5e8bb2bf04a82548a41da", + "url": "https://api.github.com/repos/samvaughton/omnipay-barclays-epdq/zipball/ee90e438ce7cb46ef8c1001d102b5711872dabae", + "reference": "ee90e438ce7cb46ef8c1001d102b5711872dabae", "shasum": "" }, "require": { @@ -6391,13 +6205,13 @@ "name": "Adrian Macneil", "email": "adrian@adrianmacneil.com" }, - { - "name": "Omnipay Contributors", - "homepage": "https://github.com/barclays-epdq/contributors" - }, { "name": "Sam Vaughton", "email": "samvaughton@gmail.com" + }, + { + "name": "Omnipay Contributors", + "homepage": "https://github.com/samvaughton/omnipay-barclays-epdq/graphs/contributors" } ], "description": "Barclays ePDQ driver for the Omnipay payment processing library.", @@ -6411,7 +6225,7 @@ "pay", "payment" ], - "time": "2016-03-03 14:40:27" + "time": "2016-06-09 16:42:25" }, { "name": "simshaun/recurr", @@ -6419,12 +6233,12 @@ "source": { "type": "git", "url": "https://github.com/simshaun/recurr.git", - "reference": "4d875b0237dcef75ee0de80d9bd63609349568d4" + "reference": "9839002cf916eaad4c3172185349360a555374c1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/simshaun/recurr/zipball/4d875b0237dcef75ee0de80d9bd63609349568d4", - "reference": "4d875b0237dcef75ee0de80d9bd63609349568d4", + "url": "https://api.github.com/repos/simshaun/recurr/zipball/9839002cf916eaad4c3172185349360a555374c1", + "reference": "9839002cf916eaad4c3172185349360a555374c1", "shasum": "" }, "require": { @@ -6465,39 +6279,41 @@ "recurring", "rrule" ], - "time": "2016-02-22 17:40:00" + "time": "2016-07-06 18:49:34" }, { "name": "sly/notification-pusher", - "version": "v2.2.2", + "version": "v2.2.12", "source": { "type": "git", "url": "https://github.com/Ph3nol/NotificationPusher.git", - "reference": "6112841c4b679bc4f6cf01f6cf655e24794bc670" + "reference": "f9a99edb4e26254baf1f7fb1354aa5a3f2c3b0ae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Ph3nol/NotificationPusher/zipball/6112841c4b679bc4f6cf01f6cf655e24794bc670", - "reference": "6112841c4b679bc4f6cf01f6cf655e24794bc670", + "url": "https://api.github.com/repos/Ph3nol/NotificationPusher/zipball/f9a99edb4e26254baf1f7fb1354aa5a3f2c3b0ae", + "reference": "f9a99edb4e26254baf1f7fb1354aa5a3f2c3b0ae", "shasum": "" }, "require": { - "php": ">=5.3.2", - "symfony/console": ">=2.3", - "symfony/options-resolver": ">=2.3", - "symfony/process": ">=2.3", - "zendframework/zendservice-apple-apns": "1.*", + "doctrine/inflector": "~1.0", + "php": ">=5.5", + "symfony/console": "~2.3", + "symfony/options-resolver": "~2.3", + "symfony/process": "~2.3", + "zendframework/zendservice-apple-apns": "^1.1.0", "zendframework/zendservice-google-gcm": "1.*" }, "require-dev": { "atoum/atoum": "dev-master" }, + "bin": [ + "np" + ], "type": "standalone", "autoload": { "psr-0": { - "Sly": [ - "src/" - ] + "Sly": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -6527,7 +6343,7 @@ "push", "pusher" ], - "time": "2013-12-08 20:35:03" + "time": "2015-10-01 07:56:41" }, { "name": "softcommerce/omnipay-paytrace", @@ -6583,20 +6399,20 @@ }, { "name": "superbalist/flysystem-google-storage", - "version": "1.0.3", + "version": "1.0.4", "source": { "type": "git", "url": "https://github.com/Superbalist/flysystem-google-storage.git", - "reference": "441a8529680986a2d2063a268ee2918f51db1b79" + "reference": "8ae35803a102ed6ce58aa87bf7534d4396513765" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Superbalist/flysystem-google-storage/zipball/441a8529680986a2d2063a268ee2918f51db1b79", - "reference": "441a8529680986a2d2063a268ee2918f51db1b79", + "url": "https://api.github.com/repos/Superbalist/flysystem-google-storage/zipball/8ae35803a102ed6ce58aa87bf7534d4396513765", + "reference": "8ae35803a102ed6ce58aa87bf7534d4396513765", "shasum": "" }, "require": { - "google/apiclient": "~1.1|^2.0.0@RC", + "google/apiclient": "~1.1", "league/flysystem": "~1.0", "php": ">=5.4.0" }, @@ -6626,27 +6442,27 @@ } ], "description": "Flysystem adapter for Google Cloud Storage", - "time": "2016-04-12 14:56:22" + "time": "2016-05-19 14:33:03" }, { "name": "swiftmailer/swiftmailer", - "version": "v5.4.1", + "version": "v5.4.3", "source": { "type": "git", "url": "https://github.com/swiftmailer/swiftmailer.git", - "reference": "0697e6aa65c83edf97bb0f23d8763f94e3f11421" + "reference": "4cc92842069c2bbc1f28daaaf1d2576ec4dfe153" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/0697e6aa65c83edf97bb0f23d8763f94e3f11421", - "reference": "0697e6aa65c83edf97bb0f23d8763f94e3f11421", + "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/4cc92842069c2bbc1f28daaaf1d2576ec4dfe153", + "reference": "4cc92842069c2bbc1f28daaaf1d2576ec4dfe153", "shasum": "" }, "require": { "php": ">=5.3.3" }, "require-dev": { - "mockery/mockery": "~0.9.1,<0.9.4" + "mockery/mockery": "~0.9.1" }, "type": "library", "extra": { @@ -6679,86 +6495,30 @@ "mail", "mailer" ], - "time": "2015-06-06 14:19:39" - }, - { - "name": "symfony/class-loader", - "version": "v3.0.3", - "source": { - "type": "git", - "url": "https://github.com/symfony/class-loader.git", - "reference": "92e7cf1af2bc1695daabb4ac972db169606e9030" - }, - "dist": { - "type": "zip", - "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/polyfill-apcu": "~1.1" - }, - "suggest": { - "symfony/polyfill-apcu": "For using ApcClassLoader on HHVM" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\ClassLoader\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony ClassLoader Component", - "homepage": "https://symfony.com", - "time": "2016-02-03 09:33:23" + "time": "2016-07-08 11:51:25" }, { "name": "symfony/console", - "version": "v3.0.3", + "version": "v2.8.8", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "2ed5e2706ce92313d120b8fe50d1063bcfd12e04" + "reference": "c392a6ec72f2122748032c2ad6870420561ffcfa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/2ed5e2706ce92313d120b8fe50d1063bcfd12e04", - "reference": "2ed5e2706ce92313d120b8fe50d1063bcfd12e04", + "url": "https://api.github.com/repos/symfony/console/zipball/c392a6ec72f2122748032c2ad6870420561ffcfa", + "reference": "c392a6ec72f2122748032c2ad6870420561ffcfa", "shasum": "" }, "require": { - "php": ">=5.5.9", + "php": ">=5.3.9", "symfony/polyfill-mbstring": "~1.0" }, "require-dev": { "psr/log": "~1.0", - "symfony/event-dispatcher": "~2.8|~3.0", - "symfony/process": "~2.8|~3.0" + "symfony/event-dispatcher": "~2.1|~3.0.0", + "symfony/process": "~2.1|~3.0.0" }, "suggest": { "psr/log": "For using the console logger", @@ -6768,7 +6528,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "2.8-dev" } }, "autoload": { @@ -6795,20 +6555,20 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2016-02-28 16:24:34" + "time": "2016-06-29 07:02:14" }, { "name": "symfony/css-selector", - "version": "v3.0.3", + "version": "v3.1.2", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "6605602690578496091ac20ec7a5cbd160d4dff4" + "reference": "2851e1932d77ce727776154d659b232d061e816a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/6605602690578496091ac20ec7a5cbd160d4dff4", - "reference": "6605602690578496091ac20ec7a5cbd160d4dff4", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/2851e1932d77ce727776154d659b232d061e816a", + "reference": "2851e1932d77ce727776154d659b232d061e816a", "shasum": "" }, "require": { @@ -6817,7 +6577,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "3.1-dev" } }, "autoload": { @@ -6848,20 +6608,20 @@ ], "description": "Symfony CssSelector Component", "homepage": "https://symfony.com", - "time": "2016-01-27 05:14:46" + "time": "2016-06-29 05:41:56" }, { "name": "symfony/debug", - "version": "v3.0.3", + "version": "v3.0.8", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", - "reference": "29606049ced1ec715475f88d1bbe587252a3476e" + "reference": "c54bc3539c3b87e86799533801e8ae0e971d78c2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/29606049ced1ec715475f88d1bbe587252a3476e", - "reference": "29606049ced1ec715475f88d1bbe587252a3476e", + "url": "https://api.github.com/repos/symfony/debug/zipball/c54bc3539c3b87e86799533801e8ae0e971d78c2", + "reference": "c54bc3539c3b87e86799533801e8ae0e971d78c2", "shasum": "" }, "require": { @@ -6905,31 +6665,31 @@ ], "description": "Symfony Debug Component", "homepage": "https://symfony.com", - "time": "2016-01-27 05:14:46" + "time": "2016-06-29 05:40:00" }, { "name": "symfony/event-dispatcher", - "version": "v3.0.3", + "version": "v2.8.8", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "4dd5df31a28c0f82b41cb1e1599b74b5dcdbdafa" + "reference": "b180b70439dca70049b6b9b7e21d75e6e5d7aca9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/4dd5df31a28c0f82b41cb1e1599b74b5dcdbdafa", - "reference": "4dd5df31a28c0f82b41cb1e1599b74b5dcdbdafa", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b180b70439dca70049b6b9b7e21d75e6e5d7aca9", + "reference": "b180b70439dca70049b6b9b7e21d75e6e5d7aca9", "shasum": "" }, "require": { - "php": ">=5.5.9" + "php": ">=5.3.9" }, "require-dev": { "psr/log": "~1.0", - "symfony/config": "~2.8|~3.0", - "symfony/dependency-injection": "~2.8|~3.0", - "symfony/expression-language": "~2.8|~3.0", - "symfony/stopwatch": "~2.8|~3.0" + "symfony/config": "~2.0,>=2.0.5|~3.0.0", + "symfony/dependency-injection": "~2.6|~3.0.0", + "symfony/expression-language": "~2.6|~3.0.0", + "symfony/stopwatch": "~2.3|~3.0.0" }, "suggest": { "symfony/dependency-injection": "", @@ -6938,7 +6698,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "2.8-dev" } }, "autoload": { @@ -6965,20 +6725,20 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2016-01-27 05:14:46" + "time": "2016-06-29 05:29:29" }, { "name": "symfony/finder", - "version": "v3.0.3", + "version": "v3.0.8", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "623bda0abd9aa29e529c8e9c08b3b84171914723" + "reference": "3eb4e64c6145ef8b92adefb618a74ebdde9e3fe9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/623bda0abd9aa29e529c8e9c08b3b84171914723", - "reference": "623bda0abd9aa29e529c8e9c08b3b84171914723", + "url": "https://api.github.com/repos/symfony/finder/zipball/3eb4e64c6145ef8b92adefb618a74ebdde9e3fe9", + "reference": "3eb4e64c6145ef8b92adefb618a74ebdde9e3fe9", "shasum": "" }, "require": { @@ -7014,24 +6774,25 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2016-01-27 05:14:46" + "time": "2016-06-29 05:40:00" }, { "name": "symfony/http-foundation", - "version": "v2.8.3", + "version": "v2.8.8", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "6f4e41c41e7d352ed9adf71ff6f2ec1756490a1b" + "reference": "7a55440a2bebd37b8bd06f99f5def1ddf0aa9249" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/6f4e41c41e7d352ed9adf71ff6f2ec1756490a1b", - "reference": "6f4e41c41e7d352ed9adf71ff6f2ec1756490a1b", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/7a55440a2bebd37b8bd06f99f5def1ddf0aa9249", + "reference": "7a55440a2bebd37b8bd06f99f5def1ddf0aa9249", "shasum": "" }, "require": { "php": ">=5.3.9", + "symfony/polyfill-mbstring": "~1.1", "symfony/polyfill-php54": "~1.0", "symfony/polyfill-php55": "~1.0" }, @@ -7068,20 +6829,20 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", - "time": "2016-02-28 16:20:50" + "time": "2016-06-29 07:02:14" }, { "name": "symfony/http-kernel", - "version": "v3.0.3", + "version": "v3.0.8", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "59c0a1972e9aad87b7a56bbe1ccee26b7535a0db" + "reference": "177b63b2d50b63fa6d82ea41359ed9928cc7a1fb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/59c0a1972e9aad87b7a56bbe1ccee26b7535a0db", - "reference": "59c0a1972e9aad87b7a56bbe1ccee26b7535a0db", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/177b63b2d50b63fa6d82ea41359ed9928cc7a1fb", + "reference": "177b63b2d50b63fa6d82ea41359ed9928cc7a1fb", "shasum": "" }, "require": { @@ -7089,7 +6850,7 @@ "psr/log": "~1.0", "symfony/debug": "~2.8|~3.0", "symfony/event-dispatcher": "~2.8|~3.0", - "symfony/http-foundation": "~2.8|~3.0" + "symfony/http-foundation": "~2.8.8|~3.0.8|~3.1.2|~3.2" }, "conflict": { "symfony/config": "<2.8" @@ -7150,29 +6911,29 @@ ], "description": "Symfony HttpKernel Component", "homepage": "https://symfony.com", - "time": "2016-02-28 21:33:13" + "time": "2016-06-30 16:30:17" }, { "name": "symfony/options-resolver", - "version": "v3.0.3", + "version": "v2.8.8", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "bc7ee3ef3905f7c21fbed4e921cb39d6518b1300" + "reference": "b6f982782a0624d37b5416c2c96fb99ce5ab74d5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/bc7ee3ef3905f7c21fbed4e921cb39d6518b1300", - "reference": "bc7ee3ef3905f7c21fbed4e921cb39d6518b1300", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/b6f982782a0624d37b5416c2c96fb99ce5ab74d5", + "reference": "b6f982782a0624d37b5416c2c96fb99ce5ab74d5", "shasum": "" }, "require": { - "php": ">=5.5.9" + "php": ">=5.3.9" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "2.8-dev" } }, "autoload": { @@ -7204,20 +6965,20 @@ "configuration", "options" ], - "time": "2016-01-21 09:38:31" + "time": "2016-06-29 05:29:29" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.1.1", + "version": "v1.2.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "1289d16209491b584839022f29257ad859b8532d" + "reference": "dff51f72b0706335131b00a7f49606168c582594" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/1289d16209491b584839022f29257ad859b8532d", - "reference": "1289d16209491b584839022f29257ad859b8532d", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/dff51f72b0706335131b00a7f49606168c582594", + "reference": "dff51f72b0706335131b00a7f49606168c582594", "shasum": "" }, "require": { @@ -7229,7 +6990,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1-dev" + "dev-master": "1.2-dev" } }, "autoload": { @@ -7263,20 +7024,20 @@ "portable", "shim" ], - "time": "2016-01-20 09:13:37" + "time": "2016-05-18 14:26:46" }, { "name": "symfony/polyfill-php54", - "version": "v1.1.1", + "version": "v1.2.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php54.git", - "reference": "9ba741ca01c77282ecf5796c2c1d667f03454ffb" + "reference": "34d761992f6f2cc6092cc0e5e93f38b53ba5e4f1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php54/zipball/9ba741ca01c77282ecf5796c2c1d667f03454ffb", - "reference": "9ba741ca01c77282ecf5796c2c1d667f03454ffb", + "url": "https://api.github.com/repos/symfony/polyfill-php54/zipball/34d761992f6f2cc6092cc0e5e93f38b53ba5e4f1", + "reference": "34d761992f6f2cc6092cc0e5e93f38b53ba5e4f1", "shasum": "" }, "require": { @@ -7285,7 +7046,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1-dev" + "dev-master": "1.2-dev" } }, "autoload": { @@ -7321,20 +7082,20 @@ "portable", "shim" ], - "time": "2016-01-25 19:13:00" + "time": "2016-05-18 14:26:46" }, { "name": "symfony/polyfill-php55", - "version": "v1.1.1", + "version": "v1.2.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php55.git", - "reference": "b4f3f07d91702f8f926339fc4fcf81671d8c27e6" + "reference": "bf2ff9ad6be1a4772cb873e4eea94d70daa95c6d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php55/zipball/b4f3f07d91702f8f926339fc4fcf81671d8c27e6", - "reference": "b4f3f07d91702f8f926339fc4fcf81671d8c27e6", + "url": "https://api.github.com/repos/symfony/polyfill-php55/zipball/bf2ff9ad6be1a4772cb873e4eea94d70daa95c6d", + "reference": "bf2ff9ad6be1a4772cb873e4eea94d70daa95c6d", "shasum": "" }, "require": { @@ -7344,7 +7105,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1-dev" + "dev-master": "1.2-dev" } }, "autoload": { @@ -7377,20 +7138,20 @@ "portable", "shim" ], - "time": "2016-01-20 09:13:37" + "time": "2016-05-18 14:26:46" }, { "name": "symfony/polyfill-php56", - "version": "v1.1.1", + "version": "v1.2.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php56.git", - "reference": "4d891fff050101a53a4caabb03277284942d1ad9" + "reference": "3edf57a8fbf9a927533344cef65ad7e1cf31030a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/4d891fff050101a53a4caabb03277284942d1ad9", - "reference": "4d891fff050101a53a4caabb03277284942d1ad9", + "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/3edf57a8fbf9a927533344cef65ad7e1cf31030a", + "reference": "3edf57a8fbf9a927533344cef65ad7e1cf31030a", "shasum": "" }, "require": { @@ -7400,7 +7161,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1-dev" + "dev-master": "1.2-dev" } }, "autoload": { @@ -7433,20 +7194,20 @@ "portable", "shim" ], - "time": "2016-01-20 09:13:37" + "time": "2016-05-18 14:26:46" }, { "name": "symfony/polyfill-util", - "version": "v1.1.1", + "version": "v1.2.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-util.git", - "reference": "8de62801aa12bc4dfcf85eef5d21981ae7bb3cc4" + "reference": "ef830ce3d218e622b221d6bfad42c751d974bf99" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-util/zipball/8de62801aa12bc4dfcf85eef5d21981ae7bb3cc4", - "reference": "8de62801aa12bc4dfcf85eef5d21981ae7bb3cc4", + "url": "https://api.github.com/repos/symfony/polyfill-util/zipball/ef830ce3d218e622b221d6bfad42c751d974bf99", + "reference": "ef830ce3d218e622b221d6bfad42c751d974bf99", "shasum": "" }, "require": { @@ -7455,7 +7216,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1-dev" + "dev-master": "1.2-dev" } }, "autoload": { @@ -7485,29 +7246,29 @@ "polyfill", "shim" ], - "time": "2016-01-20 09:13:37" + "time": "2016-05-18 14:26:46" }, { "name": "symfony/process", - "version": "v3.0.3", + "version": "v2.8.8", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "dfecef47506179db2501430e732adbf3793099c8" + "reference": "89f33c16796415ccfd8bb3cf8d520cbb79899bfe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/dfecef47506179db2501430e732adbf3793099c8", - "reference": "dfecef47506179db2501430e732adbf3793099c8", + "url": "https://api.github.com/repos/symfony/process/zipball/89f33c16796415ccfd8bb3cf8d520cbb79899bfe", + "reference": "89f33c16796415ccfd8bb3cf8d520cbb79899bfe", "shasum": "" }, "require": { - "php": ">=5.5.9" + "php": ">=5.3.9" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "2.8-dev" } }, "autoload": { @@ -7534,20 +7295,20 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2016-02-02 13:44:19" + "time": "2016-06-29 05:29:29" }, { "name": "symfony/routing", - "version": "v3.0.3", + "version": "v3.0.8", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "fa1e9a8173cf0077dd995205da453eacd758fdf6" + "reference": "9038984bd9c05ab07280121e9e10f61a7231457b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/fa1e9a8173cf0077dd995205da453eacd758fdf6", - "reference": "fa1e9a8173cf0077dd995205da453eacd758fdf6", + "url": "https://api.github.com/repos/symfony/routing/zipball/9038984bd9c05ab07280121e9e10f61a7231457b", + "reference": "9038984bd9c05ab07280121e9e10f61a7231457b", "shasum": "" }, "require": { @@ -7609,20 +7370,20 @@ "uri", "url" ], - "time": "2016-02-04 13:53:13" + "time": "2016-06-29 05:40:00" }, { "name": "symfony/translation", - "version": "v3.0.3", + "version": "v3.0.8", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "2de0b6f7ebe43cffd8a06996ebec6aab79ea9e91" + "reference": "6bf844e1ee3c820c012386c10427a5c67bbefec8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/2de0b6f7ebe43cffd8a06996ebec6aab79ea9e91", - "reference": "2de0b6f7ebe43cffd8a06996ebec6aab79ea9e91", + "url": "https://api.github.com/repos/symfony/translation/zipball/6bf844e1ee3c820c012386c10427a5c67bbefec8", + "reference": "6bf844e1ee3c820c012386c10427a5c67bbefec8", "shasum": "" }, "require": { @@ -7673,20 +7434,20 @@ ], "description": "Symfony Translation Component", "homepage": "https://symfony.com", - "time": "2016-02-02 13:44:19" + "time": "2016-06-29 05:40:00" }, { "name": "symfony/var-dumper", - "version": "v3.0.3", + "version": "v3.0.8", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "9a6a883c48acb215d4825ce9de61dccf93d62074" + "reference": "2f046e9a9d571f22cc8b26783564876713b06579" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/9a6a883c48acb215d4825ce9de61dccf93d62074", - "reference": "9a6a883c48acb215d4825ce9de61dccf93d62074", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/2f046e9a9d571f22cc8b26783564876713b06579", + "reference": "2f046e9a9d571f22cc8b26783564876713b06579", "shasum": "" }, "require": { @@ -7736,7 +7497,7 @@ "debug", "dump" ], - "time": "2016-02-13 09:23:44" + "time": "2016-06-29 05:40:00" }, { "name": "tijsverkoyen/css-to-inline-styles", @@ -7787,16 +7548,16 @@ }, { "name": "true/punycode", - "version": "v2.0.2", + "version": "v2.0.3", "source": { "type": "git", "url": "https://github.com/true/php-punycode.git", - "reference": "74fa01d4de396c40e239794123b3874cb594a30c" + "reference": "6853ce218b6115ec749607e14ac51338920c9d81" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/true/php-punycode/zipball/74fa01d4de396c40e239794123b3874cb594a30c", - "reference": "74fa01d4de396c40e239794123b3874cb594a30c", + "url": "https://api.github.com/repos/true/php-punycode/zipball/6853ce218b6115ec749607e14ac51338920c9d81", + "reference": "6853ce218b6115ec749607e14ac51338920c9d81", "shasum": "" }, "require": { @@ -7829,7 +7590,7 @@ "idna", "punycode" ], - "time": "2016-01-07 17:12:58" + "time": "2016-05-23 08:20:50" }, { "name": "turbo124/laravel-push-notification", @@ -7974,28 +7735,28 @@ }, { "name": "vlucas/phpdotenv", - "version": "v2.2.0", + "version": "v2.3.0", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "9caf304153dc2288e4970caec6f1f3b3bc205412" + "reference": "9ca5644c536654e9509b9d257f53c58630eb2a6a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/9caf304153dc2288e4970caec6f1f3b3bc205412", - "reference": "9caf304153dc2288e4970caec6f1f3b3bc205412", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/9ca5644c536654e9509b9d257f53c58630eb2a6a", + "reference": "9ca5644c536654e9509b9d257f53c58630eb2a6a", "shasum": "" }, "require": { "php": ">=5.3.9" }, "require-dev": { - "phpunit/phpunit": "^4.8|^5.0" + "phpunit/phpunit": "^4.8 || ^5.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.2-dev" + "dev-master": "2.3-dev" } }, "autoload": { @@ -8005,7 +7766,7 @@ }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD" + "BSD-3-Clause-Attribution" ], "authors": [ { @@ -8015,13 +7776,12 @@ } ], "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", - "homepage": "http://github.com/vlucas/phpdotenv", "keywords": [ "dotenv", "env", "environment" ], - "time": "2015-12-29 15:10:30" + "time": "2016-06-14 14:14:52" }, { "name": "webpatser/laravel-countries", @@ -8118,6 +7878,53 @@ ], "time": "2016-03-04 11:57:00" }, + { + "name": "wepay/php-sdk", + "version": "0.2.7", + "source": { + "type": "git", + "url": "https://github.com/wepay/PHP-SDK.git", + "reference": "31bfcdd97d2c9c33c9c09129638ae31840822182" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/wepay/PHP-SDK/zipball/31bfcdd97d2c9c33c9c09129638ae31840822182", + "reference": "31bfcdd97d2c9c33c9c09129638ae31840822182", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "wepay.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "WePay", + "email": "api@wepay.com" + } + ], + "description": "WePay APIv2 SDK for PHP", + "keywords": [ + "payment", + "sdk", + "wepay" + ], + "time": "2015-08-14 19:42:37" + }, { "name": "wildbit/laravel-postmark-provider", "version": "3.0.0", @@ -8194,20 +8001,20 @@ }, { "name": "zendframework/zend-escaper", - "version": "2.5.1", + "version": "2.5.2", "source": { "type": "git", "url": "https://github.com/zendframework/zend-escaper.git", - "reference": "a4b227d8a477f4e7e9073f8e0a7ae7dbd3104a73" + "reference": "2dcd14b61a72d8b8e27d579c6344e12c26141d4e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-escaper/zipball/a4b227d8a477f4e7e9073f8e0a7ae7dbd3104a73", - "reference": "a4b227d8a477f4e7e9073f8e0a7ae7dbd3104a73", + "url": "https://api.github.com/repos/zendframework/zend-escaper/zipball/2dcd14b61a72d8b8e27d579c6344e12c26141d4e", + "reference": "2dcd14b61a72d8b8e27d579c6344e12c26141d4e", "shasum": "" }, "require": { - "php": ">=5.3.23" + "php": ">=5.5" }, "require-dev": { "fabpot/php-cs-fixer": "1.7.*", @@ -8234,7 +8041,7 @@ "escaper", "zf2" ], - "time": "2015-06-03 14:05:37" + "time": "2016-06-30 19:48:38" }, { "name": "zendframework/zend-http", @@ -8387,16 +8194,16 @@ }, { "name": "zendframework/zend-stdlib", - "version": "3.0.0", + "version": "3.0.1", "source": { "type": "git", "url": "https://github.com/zendframework/zend-stdlib.git", - "reference": "22eb098958980fbbe6b9a06f209f5a4b496cc0c1" + "reference": "8bafa58574204bdff03c275d1d618aaa601588ae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-stdlib/zipball/22eb098958980fbbe6b9a06f209f5a4b496cc0c1", - "reference": "22eb098958980fbbe6b9a06f209f5a4b496cc0c1", + "url": "https://api.github.com/repos/zendframework/zend-stdlib/zipball/8bafa58574204bdff03c275d1d618aaa601588ae", + "reference": "8bafa58574204bdff03c275d1d618aaa601588ae", "shasum": "" }, "require": { @@ -8428,7 +8235,7 @@ "stdlib", "zf2" ], - "time": "2016-02-03 16:53:37" + "time": "2016-04-12 21:19:36" }, { "name": "zendframework/zend-uri", @@ -8479,16 +8286,16 @@ }, { "name": "zendframework/zend-validator", - "version": "2.6.0", + "version": "2.8.1", "source": { "type": "git", "url": "https://github.com/zendframework/zend-validator.git", - "reference": "1315fead53358054e3f5fcf440c1a4cd5f0724db" + "reference": "8ec9f57a717dd37340308aa632f148a2c2be1cfc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-validator/zipball/1315fead53358054e3f5fcf440c1a4cd5f0724db", - "reference": "1315fead53358054e3f5fcf440c1a4cd5f0724db", + "url": "https://api.github.com/repos/zendframework/zend-validator/zipball/8ec9f57a717dd37340308aa632f148a2c2be1cfc", + "reference": "8ec9f57a717dd37340308aa632f148a2c2be1cfc", "shasum": "" }, "require": { @@ -8501,13 +8308,13 @@ "phpunit/phpunit": "^4.0", "zendframework/zend-cache": "^2.6.1", "zendframework/zend-config": "^2.6", - "zendframework/zend-db": "^2.5", + "zendframework/zend-db": "^2.7", "zendframework/zend-filter": "^2.6", "zendframework/zend-http": "^2.5.4", "zendframework/zend-i18n": "^2.6", "zendframework/zend-math": "^2.6", "zendframework/zend-servicemanager": "^2.7.5 || ^3.0.3", - "zendframework/zend-session": "^2.5", + "zendframework/zend-session": "^2.6.2", "zendframework/zend-uri": "^2.5" }, "suggest": { @@ -8523,8 +8330,12 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.6-dev", - "dev-develop": "2.7-dev" + "dev-master": "2.8-dev", + "dev-develop": "2.9-dev" + }, + "zf": { + "component": "Zend\\Validator", + "config-provider": "Zend\\Validator\\ConfigProvider" } }, "autoload": { @@ -8542,7 +8353,7 @@ "validator", "zf2" ], - "time": "2016-02-17 17:59:34" + "time": "2016-06-23 13:44:31" }, { "name": "zendframework/zendservice-apple-apns", @@ -8633,16 +8444,16 @@ }, { "name": "zircote/swagger-php", - "version": "2.0.6", + "version": "2.0.7", "source": { "type": "git", "url": "https://github.com/zircote/swagger-php.git", - "reference": "0dfc289d53bad4a2bd193adc8d4bd058029ab417" + "reference": "299df0b51f641225ed50ba5199b21e8cfc34e4f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zircote/swagger-php/zipball/0dfc289d53bad4a2bd193adc8d4bd058029ab417", - "reference": "0dfc289d53bad4a2bd193adc8d4bd058029ab417", + "url": "https://api.github.com/repos/zircote/swagger-php/zipball/299df0b51f641225ed50ba5199b21e8cfc34e4f4", + "reference": "299df0b51f641225ed50ba5199b21e8cfc34e4f4", "shasum": "" }, "require": { @@ -8652,7 +8463,7 @@ }, "require-dev": { "squizlabs/php_codesniffer": "2.*", - "zendframework/zend-form": "*" + "zendframework/zend-form": "<2.8" }, "bin": [ "bin/swagger" @@ -8690,10 +8501,237 @@ "rest", "service discovery" ], - "time": "2016-02-13 15:39:11" + "time": "2016-05-27 09:35:51" } ], "packages-dev": [ + { + "name": "barryvdh/laravel-debugbar", + "version": "v2.2.2", + "source": { + "type": "git", + "url": "https://github.com/barryvdh/laravel-debugbar.git", + "reference": "c291e58d0a13953e0f68d99182ee77ebc693edc0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/c291e58d0a13953e0f68d99182ee77ebc693edc0", + "reference": "c291e58d0a13953e0f68d99182ee77ebc693edc0", + "shasum": "" + }, + "require": { + "illuminate/support": "5.1.*|5.2.*", + "maximebf/debugbar": "~1.11.0", + "php": ">=5.5.9", + "symfony/finder": "~2.7|~3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2-dev" + } + }, + "autoload": { + "psr-4": { + "Barryvdh\\Debugbar\\": "src/" + }, + "files": [ + "src/helpers.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Barry vd. Heuvel", + "email": "barryvdh@gmail.com" + } + ], + "description": "PHP Debugbar integration for Laravel", + "keywords": [ + "debug", + "debugbar", + "laravel", + "profiler", + "webprofiler" + ], + "time": "2016-05-11 13:54:43" + }, + { + "name": "barryvdh/laravel-ide-helper", + "version": "v2.2.1", + "source": { + "type": "git", + "url": "https://github.com/barryvdh/laravel-ide-helper.git", + "reference": "28af7cd19ca41cc0c63dd1de2b46c2b84d31c463" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/barryvdh/laravel-ide-helper/zipball/28af7cd19ca41cc0c63dd1de2b46c2b84d31c463", + "reference": "28af7cd19ca41cc0c63dd1de2b46c2b84d31c463", + "shasum": "" + }, + "require": { + "barryvdh/reflection-docblock": "^2.0.4", + "illuminate/console": "^5.0,<5.4", + "illuminate/filesystem": "^5.0,<5.4", + "illuminate/support": "^5.0,<5.4", + "php": ">=5.4.0", + "symfony/class-loader": "^2.3|^3.0" + }, + "require-dev": { + "doctrine/dbal": "~2.3", + "phpunit/phpunit": "4.*", + "scrutinizer/ocular": "~1.1", + "squizlabs/php_codesniffer": "~2.3" + }, + "suggest": { + "doctrine/dbal": "Load information from the database about models for phpdocs (~2.3)" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2-dev" + } + }, + "autoload": { + "psr-4": { + "Barryvdh\\LaravelIdeHelper\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Barry vd. Heuvel", + "email": "barryvdh@gmail.com" + } + ], + "description": "Laravel IDE Helper, generates correct PHPDocs for all Facade classes, to improve auto-completion.", + "keywords": [ + "autocomplete", + "codeintel", + "helper", + "ide", + "laravel", + "netbeans", + "phpdoc", + "phpstorm", + "sublime" + ], + "time": "2016-07-04 11:52:48" + }, + { + "name": "barryvdh/reflection-docblock", + "version": "v2.0.4", + "source": { + "type": "git", + "url": "https://github.com/barryvdh/ReflectionDocBlock.git", + "reference": "3dcbd98b5d9384a5357266efba8fd29884458e5c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/barryvdh/ReflectionDocBlock/zipball/3dcbd98b5d9384a5357266efba8fd29884458e5c", + "reference": "3dcbd98b5d9384a5357266efba8fd29884458e5c", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.0,<4.5" + }, + "suggest": { + "dflydev/markdown": "~1.0", + "erusev/parsedown": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Barryvdh": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "mike.vanriel@naenius.com" + } + ], + "time": "2016-06-13 19:28:20" + }, + { + "name": "behat/gherkin", + "version": "v4.4.1", + "source": { + "type": "git", + "url": "https://github.com/Behat/Gherkin.git", + "reference": "1576b485c0f92ef6d27da9c4bbfc57ee30cf6911" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Behat/Gherkin/zipball/1576b485c0f92ef6d27da9c4bbfc57ee30cf6911", + "reference": "1576b485c0f92ef6d27da9c4bbfc57ee30cf6911", + "shasum": "" + }, + "require": { + "php": ">=5.3.1" + }, + "require-dev": { + "phpunit/phpunit": "~4.0", + "symfony/yaml": "~2.1" + }, + "suggest": { + "symfony/yaml": "If you want to parse features, represented in YAML files" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-0": { + "Behat\\Gherkin": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + } + ], + "description": "Gherkin DSL parser for PHP 5.3", + "homepage": "http://behat.org/", + "keywords": [ + "BDD", + "Behat", + "Cucumber", + "DSL", + "gherkin", + "parser" + ], + "time": "2015-12-30 14:47:00" + }, { "name": "codeception/c3", "version": "2.0.6", @@ -8746,19 +8784,20 @@ }, { "name": "codeception/codeception", - "version": "2.1.7", + "version": "2.2.2", "source": { "type": "git", "url": "https://github.com/Codeception/Codeception.git", - "reference": "65971b0dee4972710365b6102154cd412a9bf7b1" + "reference": "8d80bb4ec7470e8df5de0e4c401785bc3fa1f4f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/Codeception/zipball/65971b0dee4972710365b6102154cd412a9bf7b1", - "reference": "65971b0dee4972710365b6102154cd412a9bf7b1", + "url": "https://api.github.com/repos/Codeception/Codeception/zipball/8d80bb4ec7470e8df5de0e4c401785bc3fa1f4f6", + "reference": "8d80bb4ec7470e8df5de0e4c401785bc3fa1f4f6", "shasum": "" }, "require": { + "behat/gherkin": "~4.4.0", "ext-json": "*", "ext-mbstring": "*", "facebook/webdriver": ">=1.0.1 <2.0", @@ -8766,29 +8805,38 @@ "guzzlehttp/psr7": "~1.0", "php": ">=5.4.0 <8.0", "phpunit/php-code-coverage": ">=2.1.3", - "phpunit/phpunit": ">4.8.20 <6.0", - "symfony/browser-kit": ">=2.5 <3.1", - "symfony/console": ">=2.5 <3.1", - "symfony/css-selector": ">=2.5 <3.1", - "symfony/dom-crawler": ">=2.5 <3.1", - "symfony/event-dispatcher": ">=2.5 <3.1", - "symfony/finder": ">=2.5 <3.1", - "symfony/yaml": ">=2.5 <3.1" + "phpunit/phpunit": ">4.8.20 <5.5", + "sebastian/comparator": "~1.1", + "sebastian/diff": "^1.4", + "symfony/browser-kit": ">=2.7 <4.0", + "symfony/console": ">=2.7 <4.0", + "symfony/css-selector": ">=2.7 <4.0", + "symfony/dom-crawler": ">=2.7 <4.0", + "symfony/event-dispatcher": ">=2.7 <4.0", + "symfony/finder": ">=2.7 <4.0", + "symfony/yaml": ">=2.7 <4.0" }, "require-dev": { "codeception/specify": "~0.3", "facebook/php-sdk-v4": "~5.0", "flow/jsonpath": "~0.2", + "league/factory-muffin": "^3.0", + "league/factory-muffin-faker": "^1.0", + "mongodb/mongodb": "^1.0", "monolog/monolog": "~1.8", - "pda/pheanstalk": "~2.0", - "php-amqplib/php-amqplib": "~2.4" + "pda/pheanstalk": "~3.0", + "php-amqplib/php-amqplib": "~2.4", + "predis/predis": "^1.0", + "squizlabs/php_codesniffer": "~2.0" }, "suggest": { - "codeception/phpbuiltinserver": "Extension to start and stop PHP built-in web server for your tests", "codeception/specify": "BDD-style code blocks", "codeception/verify": "BDD-style assertions", - "monolog/monolog": "Log test steps", - "phpseclib/phpseclib": "Extension required to use the SFTP option in the FTP Module." + "flow/jsonpath": "For using JSONPath in REST module", + "league/factory-muffin": "For DataFactory module", + "league/factory-muffin-faker": "For Faker support in DataFactory module", + "phpseclib/phpseclib": "for SFTP option in FTP Module", + "symfony/phpunit-bridge": "For phpunit-bridge support" }, "bin": [ "codecept" @@ -8823,7 +8871,7 @@ "functional testing", "unit testing" ], - "time": "2016-03-12 01:15:25" + "time": "2016-06-29 00:59:28" }, { "name": "doctrine/instantiator", @@ -8881,19 +8929,20 @@ }, { "name": "facebook/webdriver", - "version": "1.1.1", + "version": "1.1.2", "source": { "type": "git", "url": "https://github.com/facebook/php-webdriver.git", - "reference": "1c98108ba3eb435b681655764de11502a0653705" + "reference": "0b889d7de7461439f8a3bbcca46e0f696cb27986" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/facebook/php-webdriver/zipball/1c98108ba3eb435b681655764de11502a0653705", - "reference": "1c98108ba3eb435b681655764de11502a0653705", + "url": "https://api.github.com/repos/facebook/php-webdriver/zipball/0b889d7de7461439f8a3bbcca46e0f696cb27986", + "reference": "0b889d7de7461439f8a3bbcca46e0f696cb27986", "shasum": "" }, "require": { + "ext-curl": "*", "php": ">=5.3.19" }, "require-dev": { @@ -8920,7 +8969,262 @@ "selenium", "webdriver" ], - "time": "2015-12-31 15:58:49" + "time": "2016-06-04 00:02:34" + }, + { + "name": "fzaninotto/faker", + "version": "v1.6.0", + "source": { + "type": "git", + "url": "https://github.com/fzaninotto/Faker.git", + "reference": "44f9a286a04b80c76a4e5fb7aad8bb539b920123" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/44f9a286a04b80c76a4e5fb7aad8bb539b920123", + "reference": "44f9a286a04b80c76a4e5fb7aad8bb539b920123", + "shasum": "" + }, + "require": { + "php": "^5.3.3|^7.0" + }, + "require-dev": { + "ext-intl": "*", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~1.5" + }, + "type": "library", + "extra": { + "branch-alias": [] + }, + "autoload": { + "psr-4": { + "Faker\\": "src/Faker/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "François Zaninotto" + } + ], + "description": "Faker is a PHP library that generates fake data for you.", + "keywords": [ + "data", + "faker", + "fixtures" + ], + "time": "2016-04-29 12:21:54" + }, + { + "name": "maximebf/debugbar", + "version": "v1.11.1", + "source": { + "type": "git", + "url": "https://github.com/maximebf/php-debugbar.git", + "reference": "d9302891c1f0a0ac5a4f66725163a00537c6359f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/d9302891c1f0a0ac5a4f66725163a00537c6359f", + "reference": "d9302891c1f0a0ac5a4f66725163a00537c6359f", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "psr/log": "^1.0", + "symfony/var-dumper": "^2.6|^3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0|^5.0" + }, + "suggest": { + "kriswallsmith/assetic": "The best way to manage assets", + "monolog/monolog": "Log using Monolog", + "predis/predis": "Redis storage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.11-dev" + } + }, + "autoload": { + "psr-4": { + "DebugBar\\": "src/DebugBar/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Maxime Bouroumeau-Fuseau", + "email": "maxime.bouroumeau@gmail.com", + "homepage": "http://maximebf.com" + }, + { + "name": "Barry vd. Heuvel", + "email": "barryvdh@gmail.com" + } + ], + "description": "Debug bar in the browser for php application", + "homepage": "https://github.com/maximebf/php-debugbar", + "keywords": [ + "debug", + "debugbar" + ], + "time": "2016-01-22 12:22:23" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "1.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c", + "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "time": "2015-12-27 11:43:31" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "3.1.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "9270140b940ff02e58ec577c237274e92cd40cdd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/9270140b940ff02e58ec577c237274e92cd40cdd", + "reference": "9270140b940ff02e58ec577c237274e92cd40cdd", + "shasum": "" + }, + "require": { + "php": ">=5.5", + "phpdocumentor/reflection-common": "^1.0@dev", + "phpdocumentor/type-resolver": "^0.2.0", + "webmozart/assert": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^4.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "time": "2016-06-10 09:48:41" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "0.2", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b39c7a5b194f9ed7bd0dd345c751007a41862443", + "reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443", + "shasum": "" + }, + "require": { + "php": ">=5.5", + "phpdocumentor/reflection-common": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^5.2||^4.8.24" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "time": "2016-06-10 07:14:17" }, { "name": "phpspec/php-diff", @@ -9036,32 +9340,32 @@ }, { "name": "phpspec/prophecy", - "version": "v1.6.0", + "version": "v1.6.1", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "3c91bdf81797d725b14cb62906f9a4ce44235972" + "reference": "58a8137754bc24b25740d4281399a4a3596058e0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/3c91bdf81797d725b14cb62906f9a4ce44235972", - "reference": "3c91bdf81797d725b14cb62906f9a4ce44235972", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/58a8137754bc24b25740d4281399a4a3596058e0", + "reference": "58a8137754bc24b25740d4281399a4a3596058e0", "shasum": "" }, "require": { "doctrine/instantiator": "^1.0.2", "php": "^5.3|^7.0", - "phpdocumentor/reflection-docblock": "~2.0", - "sebastian/comparator": "~1.1", - "sebastian/recursion-context": "~1.0" + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2", + "sebastian/comparator": "^1.1", + "sebastian/recursion-context": "^1.0" }, "require-dev": { - "phpspec/phpspec": "~2.0" + "phpspec/phpspec": "^2.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.5.x-dev" + "dev-master": "1.6.x-dev" } }, "autoload": { @@ -9094,7 +9398,7 @@ "spy", "stub" ], - "time": "2016-02-15 07:46:21" + "time": "2016-06-07 08:13:47" }, { "name": "phpunit/php-code-coverage", @@ -9248,21 +9552,24 @@ }, { "name": "phpunit/php-timer", - "version": "1.0.7", + "version": "1.0.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b" + "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3e82f4e9fc92665fafd9157568e4dcb01d014e5b", - "reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260", + "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260", "shasum": "" }, "require": { "php": ">=5.3.3" }, + "require-dev": { + "phpunit/phpunit": "~4|~5" + }, "type": "library", "autoload": { "classmap": [ @@ -9285,7 +9592,7 @@ "keywords": [ "timer" ], - "time": "2015-06-21 08:01:12" + "time": "2016-05-12 18:03:57" }, { "name": "phpunit/php-token-stream", @@ -9338,16 +9645,16 @@ }, { "name": "phpunit/phpunit", - "version": "4.8.24", + "version": "4.8.26", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "a1066c562c52900a142a0e2bbf0582994671385e" + "reference": "fc1d8cd5b5de11625979125c5639347896ac2c74" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a1066c562c52900a142a0e2bbf0582994671385e", - "reference": "a1066c562c52900a142a0e2bbf0582994671385e", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/fc1d8cd5b5de11625979125c5639347896ac2c74", + "reference": "fc1d8cd5b5de11625979125c5639347896ac2c74", "shasum": "" }, "require": { @@ -9361,7 +9668,7 @@ "phpunit/php-code-coverage": "~2.1", "phpunit/php-file-iterator": "~1.4", "phpunit/php-text-template": "~1.2", - "phpunit/php-timer": ">=1.0.6", + "phpunit/php-timer": "^1.0.6", "phpunit/phpunit-mock-objects": "~2.3", "sebastian/comparator": "~1.1", "sebastian/diff": "~1.2", @@ -9406,7 +9713,7 @@ "testing", "xunit" ], - "time": "2016-03-14 06:16:08" + "time": "2016-05-17 03:09:28" }, { "name": "phpunit/phpunit-mock-objects", @@ -9582,16 +9889,16 @@ }, { "name": "sebastian/environment", - "version": "1.3.5", + "version": "1.3.7", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf" + "reference": "4e8f0da10ac5802913afc151413bc8c53b6c2716" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf", - "reference": "dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/4e8f0da10ac5802913afc151413bc8c53b6c2716", + "reference": "4e8f0da10ac5802913afc151413bc8c53b6c2716", "shasum": "" }, "require": { @@ -9628,20 +9935,20 @@ "environment", "hhvm" ], - "time": "2016-02-26 18:40:46" + "time": "2016-05-17 03:18:57" }, { "name": "sebastian/exporter", - "version": "1.2.1", + "version": "1.2.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "7ae5513327cb536431847bcc0c10edba2701064e" + "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/7ae5513327cb536431847bcc0c10edba2701064e", - "reference": "7ae5513327cb536431847bcc0c10edba2701064e", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4", + "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4", "shasum": "" }, "require": { @@ -9649,12 +9956,13 @@ "sebastian/recursion-context": "~1.0" }, "require-dev": { + "ext-mbstring": "*", "phpunit/phpunit": "~4.4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2.x-dev" + "dev-master": "1.3.x-dev" } }, "autoload": { @@ -9694,7 +10002,7 @@ "export", "exporter" ], - "time": "2015-06-21 07:55:53" + "time": "2016-06-17 09:04:28" }, { "name": "sebastian/global-state", @@ -9837,16 +10145,16 @@ }, { "name": "symfony/browser-kit", - "version": "v3.0.3", + "version": "v3.1.2", "source": { "type": "git", "url": "https://github.com/symfony/browser-kit.git", - "reference": "dde849a0485b70a24b36f826ed3fb95b904d80c3" + "reference": "dcf41ed026b0499254385b5c88f03247b2ba010b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/browser-kit/zipball/dde849a0485b70a24b36f826ed3fb95b904d80c3", - "reference": "dde849a0485b70a24b36f826ed3fb95b904d80c3", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/dcf41ed026b0499254385b5c88f03247b2ba010b", + "reference": "dcf41ed026b0499254385b5c88f03247b2ba010b", "shasum": "" }, "require": { @@ -9863,7 +10171,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "3.1-dev" } }, "autoload": { @@ -9890,20 +10198,76 @@ ], "description": "Symfony BrowserKit Component", "homepage": "https://symfony.com", - "time": "2016-01-27 11:34:55" + "time": "2016-06-29 05:41:56" }, { - "name": "symfony/dom-crawler", - "version": "v3.0.3", + "name": "symfony/class-loader", + "version": "v3.1.2", "source": { "type": "git", - "url": "https://github.com/symfony/dom-crawler.git", - "reference": "981c8edb4538f88ba976ed44bdcaa683fce3d6c6" + "url": "https://github.com/symfony/class-loader.git", + "reference": "0d0ac77c336eb73f35bebdf3e1f3695ac741bbc9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/981c8edb4538f88ba976ed44bdcaa683fce3d6c6", - "reference": "981c8edb4538f88ba976ed44bdcaa683fce3d6c6", + "url": "https://api.github.com/repos/symfony/class-loader/zipball/0d0ac77c336eb73f35bebdf3e1f3695ac741bbc9", + "reference": "0d0ac77c336eb73f35bebdf3e1f3695ac741bbc9", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "require-dev": { + "symfony/finder": "~2.8|~3.0", + "symfony/polyfill-apcu": "~1.1" + }, + "suggest": { + "symfony/polyfill-apcu": "For using ApcClassLoader on HHVM" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\ClassLoader\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony ClassLoader Component", + "homepage": "https://symfony.com", + "time": "2016-06-29 05:41:56" + }, + { + "name": "symfony/dom-crawler", + "version": "v3.1.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/dom-crawler.git", + "reference": "99ec4a23330fcd0c8667095f3ef7aa204ffd9dc0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/99ec4a23330fcd0c8667095f3ef7aa204ffd9dc0", + "reference": "99ec4a23330fcd0c8667095f3ef7aa204ffd9dc0", "shasum": "" }, "require": { @@ -9919,7 +10283,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "3.1-dev" } }, "autoload": { @@ -9946,20 +10310,20 @@ ], "description": "Symfony DomCrawler Component", "homepage": "https://symfony.com", - "time": "2016-02-28 16:24:34" + "time": "2016-06-29 05:41:56" }, { "name": "symfony/yaml", - "version": "v3.0.3", + "version": "v3.1.2", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "b5ba64cd67ecd6887f63868fa781ca094bd1377c" + "reference": "2884c26ce4c1d61aebf423a8b912950fe7c764de" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/b5ba64cd67ecd6887f63868fa781ca094bd1377c", - "reference": "b5ba64cd67ecd6887f63868fa781ca094bd1377c", + "url": "https://api.github.com/repos/symfony/yaml/zipball/2884c26ce4c1d61aebf423a8b912950fe7c764de", + "reference": "2884c26ce4c1d61aebf423a8b912950fe7c764de", "shasum": "" }, "require": { @@ -9968,7 +10332,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "3.1-dev" } }, "autoload": { @@ -9995,7 +10359,56 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2016-02-23 15:16:06" + "time": "2016-06-29 05:41:56" + }, + { + "name": "webmozart/assert", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/webmozart/assert.git", + "reference": "30eed06dd6bc88410a4ff7f77b6d22f3ce13dbde" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/assert/zipball/30eed06dd6bc88410a4ff7f77b6d22f3ce13dbde", + "reference": "30eed06dd6bc88410a4ff7f77b6d22f3ce13dbde", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "^4.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "time": "2015-08-24 13:29:44" } ], "aliases": [], @@ -10005,11 +10418,11 @@ "omnipay/mollie": 20, "omnipay/2checkout": 20, "omnipay/gocardless": 20, + "omnipay/stripe": 20, "anahkiasen/former": 20, "chumper/datatable": 20, "intervention/image": 20, "webpatser/laravel-countries": 20, - "barryvdh/laravel-ide-helper": 20, "lokielse/omnipay-alipay": 20, "alfaproject/omnipay-skrill": 20, "omnipay/bitpay": 20, @@ -10024,7 +10437,10 @@ "meebio/omnipay-secure-trading": 20, "labs7in0/omnipay-wechat": 20, "laracasts/presenter": 20, - "jlapp/swaggervel": 20 + "jlapp/swaggervel": 20, + "omnipay/braintree": 20, + "gatepay/fedachdir": 20, + "collizo4sky/omnipay-wepay": 20 }, "prefer-stable": false, "prefer-lowest": false, diff --git a/config/app.php b/config/app.php index d9b9aa916b..4068375778 100644 --- a/config/app.php +++ b/config/app.php @@ -82,9 +82,9 @@ return [ | */ - 'key' => env('APP_KEY', ''), + 'key' => env('APP_KEY', 'SomeRandomString'), - 'cipher' => env('APP_CIPHER', MCRYPT_RIJNDAEL_128), + 'cipher' => env('APP_CIPHER', 'AES-256-CBC'), /* |-------------------------------------------------------------------------- @@ -160,7 +160,7 @@ return [ */ 'App\Providers\AuthServiceProvider', 'App\Providers\AppServiceProvider', - //'App\Providers\BusServiceProvider', + 'App\Providers\ComposerServiceProvider', 'App\Providers\ConfigServiceProvider', 'App\Providers\EventServiceProvider', 'App\Providers\RouteServiceProvider', diff --git a/config/former.php b/config/former.php index b9c729e2f9..110fffe8ae 100644 --- a/config/former.php +++ b/config/former.php @@ -27,7 +27,7 @@ // Whether checkboxes should always be present in the POST data, // no matter if you checked them or not - 'push_checkboxes' => false, + 'push_checkboxes' => true, // The value a checkbox will have in the POST array if unchecked 'unchecked_value' => 0, @@ -181,4 +181,4 @@ ), -); \ No newline at end of file +); diff --git a/config/mail.php b/config/mail.php index 6b08e8efb3..d8b32dea17 100644 --- a/config/mail.php +++ b/config/mail.php @@ -80,7 +80,7 @@ return [ | */ - 'username' => env('MAIL_USERNAME'), + 'username' => env('MAIL_USERNAME', ''), /* |-------------------------------------------------------------------------- @@ -93,7 +93,7 @@ return [ | */ - 'password' => env('MAIL_PASSWORD'), + 'password' => env('MAIL_PASSWORD', ''), /* |-------------------------------------------------------------------------- diff --git a/config/services.php b/config/services.php index 45df4553e3..99b5f0b647 100644 --- a/config/services.php +++ b/config/services.php @@ -17,8 +17,8 @@ return [ 'postmark' => env('POSTMARK_API_TOKEN', ''), 'mailgun' => [ - 'domain' => '', - 'secret' => '', + 'domain' => env('MAILGUN_DOMAIN',''), + 'secret' => env('MAILGUN_SECRET',''), ], 'mandrill' => [ diff --git a/database/migrations/2014_03_19_201454_add_language_support.php b/database/migrations/2014_03_19_201454_add_language_support.php index cdb092a9a4..97bb13fc5b 100644 --- a/database/migrations/2014_03_19_201454_add_language_support.php +++ b/database/migrations/2014_03_19_201454_add_language_support.php @@ -15,18 +15,18 @@ class AddLanguageSupport extends Migration { Schema::create('languages', function($table) { $table->increments('id'); - $table->string('name'); - $table->string('locale'); + $table->string('name'); + $table->string('locale'); }); - DB::table('languages')->insert(['name' => 'English', 'locale' => 'en']); - DB::table('languages')->insert(['name' => 'Italian', 'locale' => 'it']); - DB::table('languages')->insert(['name' => 'German', 'locale' => 'de']); - DB::table('languages')->insert(['name' => 'French', 'locale' => 'fr']); - DB::table('languages')->insert(['name' => 'Brazilian Portuguese', 'locale' => 'pt_BR']); - DB::table('languages')->insert(['name' => 'Dutch', 'locale' => 'nl']); - DB::table('languages')->insert(['name' => 'Spanish', 'locale' => 'es']); - DB::table('languages')->insert(['name' => 'Norwegian', 'locale' => 'nb_NO']); + //DB::table('languages')->insert(['name' => 'English', 'locale' => 'en']); + //DB::table('languages')->insert(['name' => 'Italian', 'locale' => 'it']); + //DB::table('languages')->insert(['name' => 'German', 'locale' => 'de']); + //DB::table('languages')->insert(['name' => 'French', 'locale' => 'fr']); + //DB::table('languages')->insert(['name' => 'Brazilian Portuguese', 'locale' => 'pt_BR']); + //DB::table('languages')->insert(['name' => 'Dutch', 'locale' => 'nl']); + //DB::table('languages')->insert(['name' => 'Spanish', 'locale' => 'es']); + //DB::table('languages')->insert(['name' => 'Norwegian', 'locale' => 'nb_NO']); Schema::table('accounts', function($table) { diff --git a/database/migrations/2014_05_17_175626_add_quotes.php b/database/migrations/2014_05_17_175626_add_quotes.php index ae26c640fc..a75ca8ba76 100644 --- a/database/migrations/2014_05_17_175626_add_quotes.php +++ b/database/migrations/2014_05_17_175626_add_quotes.php @@ -14,7 +14,7 @@ class AddQuotes extends Migration { { Schema::table('invoices', function($table) { - $table->boolean('is_quote')->default(0); + $table->boolean('invoice_type_id')->default(0); $table->unsignedInteger('quote_id')->nullable(); $table->unsignedInteger('quote_invoice_id')->nullable(); }); @@ -29,7 +29,7 @@ class AddQuotes extends Migration { { Schema::table('invoices', function($table) { - $table->dropColumn('is_quote'); + $table->dropColumn('invoice_type_id'); $table->dropColumn('quote_id'); $table->dropColumn('quote_invoice_id'); }); diff --git a/database/migrations/2014_10_14_225227_add_danish_translation.php b/database/migrations/2014_10_14_225227_add_danish_translation.php index 226ac9b961..6da361b2a3 100644 --- a/database/migrations/2014_10_14_225227_add_danish_translation.php +++ b/database/migrations/2014_10_14_225227_add_danish_translation.php @@ -12,7 +12,7 @@ class AddDanishTranslation extends Migration { */ public function up() { - DB::table('languages')->insert(['name' => 'Danish', 'locale' => 'da']); + //DB::table('languages')->insert(['name' => 'Danish', 'locale' => 'da']); } /** @@ -22,8 +22,8 @@ class AddDanishTranslation extends Migration { */ public function down() { - $language = \App\Models\Language::whereLocale('da')->first(); - $language->delete(); + //$language = \App\Models\Language::whereLocale('da')->first(); + //$language->delete(); } } diff --git a/database/migrations/2015_04_12_093447_add_sv_language.php b/database/migrations/2015_04_12_093447_add_sv_language.php index ed11361ac1..fc3342f727 100644 --- a/database/migrations/2015_04_12_093447_add_sv_language.php +++ b/database/migrations/2015_04_12_093447_add_sv_language.php @@ -12,10 +12,10 @@ class AddSvLanguage extends Migration { */ public function up() { - DB::table('languages')->insert(['name' => 'Swedish', 'locale' => 'sv']); - DB::table('languages')->insert(['name' => 'Spanish - Spain', 'locale' => 'es_ES']); - DB::table('languages')->insert(['name' => 'French - Canada', 'locale' => 'fr_CA']); - DB::table('languages')->insert(['name' => 'Lithuanian', 'locale' => 'lt']); + //DB::table('languages')->insert(['name' => 'Swedish', 'locale' => 'sv']); + //DB::table('languages')->insert(['name' => 'Spanish - Spain', 'locale' => 'es_ES']); + //DB::table('languages')->insert(['name' => 'French - Canada', 'locale' => 'fr_CA']); + //DB::table('languages')->insert(['name' => 'Lithuanian', 'locale' => 'lt']); } /** diff --git a/database/migrations/2016_04_23_182223_payments_changes.php b/database/migrations/2016_04_23_182223_payments_changes.php new file mode 100644 index 0000000000..844555942b --- /dev/null +++ b/database/migrations/2016_04_23_182223_payments_changes.php @@ -0,0 +1,153 @@ +increments('id'); + $table->string('name'); + }); + + (new \PaymentStatusSeeder())->run(); + + Schema::dropIfExists('payment_methods'); + + Schema::create('payment_methods', function($table) + { + $table->increments('id'); + $table->unsignedInteger('account_id'); + $table->unsignedInteger('user_id'); + $table->unsignedInteger('contact_id')->nullable(); + $table->unsignedInteger('account_gateway_token_id'); + $table->unsignedInteger('payment_type_id'); + $table->string('source_reference'); + + $table->unsignedInteger('routing_number')->nullable(); + $table->smallInteger('last4')->unsigned()->nullable(); + $table->date('expiration')->nullable(); + $table->string('email')->nullable(); + $table->unsignedInteger('currency_id')->nullable(); + $table->string('status')->nullable(); + + $table->timestamps(); + $table->softDeletes(); + + $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + $table->foreign('contact_id')->references('id')->on('contacts')->onDelete('cascade'); + $table->foreign('account_gateway_token_id')->references('id')->on('account_gateway_tokens'); + $table->foreign('payment_type_id')->references('id')->on('payment_types'); + $table->foreign('currency_id')->references('id')->on('currencies'); + + $table->unsignedInteger('public_id')->index(); + $table->unique( array('account_id','public_id') ); + }); + + Schema::table('payments', function($table) + { + $table->decimal('refunded', 13, 2); + $table->unsignedInteger('payment_status_id')->default(PAYMENT_STATUS_COMPLETED); + $table->foreign('payment_status_id')->references('id')->on('payment_statuses'); + + $table->unsignedInteger('routing_number')->nullable(); + $table->smallInteger('last4')->unsigned()->nullable(); + $table->date('expiration')->nullable(); + $table->text('gateway_error')->nullable(); + $table->string('email')->nullable(); + + $table->unsignedInteger('payment_method_id')->nullable(); + $table->foreign('payment_method_id')->references('id')->on('payment_methods'); + }); + + Schema::table('invoices', function($table) + { + $table->boolean('client_enable_auto_bill')->default(false); + }); + + \DB::table('invoices') + ->where('auto_bill', '=', 1) + ->update(array('client_enable_auto_bill' => 1, 'auto_bill' => AUTO_BILL_OPT_OUT)); + + \DB::table('invoices') + ->where('auto_bill', '=', 0) + ->where('is_recurring', '=', 1) + ->update(array('auto_bill' => AUTO_BILL_OFF)); + + + Schema::table('account_gateway_tokens', function($table) + { + $table->unsignedInteger('default_payment_method_id')->nullable(); + $table->foreign('default_payment_method_id')->references('id')->on('payment_methods'); + + }); + + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('payments', function($table) + { + $table->dropColumn('refunded'); + $table->dropForeign('payments_payment_status_id_foreign'); + $table->dropColumn('payment_status_id'); + + $table->dropColumn('routing_number'); + $table->dropColumn('last4'); + $table->dropColumn('expiration'); + $table->dropColumn('gateway_error'); + $table->dropColumn('email'); + + $table->dropForeign('payments_payment_method_id_foreign'); + $table->dropColumn('payment_method_id'); + }); + + \DB::table('invoices') + ->where('auto_bill', '=', AUTO_BILL_OFF) + ->update(array('auto_bill' => 0)); + + \DB::table('invoices') + ->where(function($query){ + $query->where('auto_bill', '=', AUTO_BILL_ALWAYS); + $query->orwhere(function($query){ + $query->where('auto_bill', '!=', 0); + $query->where('client_enable_auto_bill', '=', 1); + }); + }) + ->update(array('auto_bill' => 1)); + + \DB::table('invoices') + ->where('auto_bill', '!=', 1) + ->update(array('auto_bill' => 0)); + + Schema::table('invoices', function ($table) { + $table->dropColumn('client_enable_auto_bill'); + }); + + Schema::dropIfExists('payment_statuses'); + + Schema::table('account_gateway_tokens', function($table) + { + $table->dropForeign('account_gateway_tokens_default_payment_method_id_foreign'); + $table->dropColumn('default_payment_method_id'); + }); + + Schema::dropIfExists('payment_methods'); + } +} diff --git a/database/migrations/2016_05_16_102925_add_swap_currency_symbol_to_currency.php b/database/migrations/2016_05_16_102925_add_swap_currency_symbol_to_currency.php new file mode 100644 index 0000000000..d331b54cf7 --- /dev/null +++ b/database/migrations/2016_05_16_102925_add_swap_currency_symbol_to_currency.php @@ -0,0 +1,53 @@ +boolean('swap_currency_symbol')->default(false); + }); + + Schema::table('expenses', function(Blueprint $table) { + $table->string('tax_name1')->nullable(); + $table->decimal('tax_rate1', 13, 3); + $table->string('tax_name2')->nullable(); + $table->decimal('tax_rate2', 13, 3); + }); + + Schema::table('account_gateways', function(Blueprint $table) { + $table->boolean('require_cvv')->default(true)->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('currencies', function(Blueprint $table) { + $table->dropColumn('swap_currency_symbol'); + }); + + Schema::table('expenses', function(Blueprint $table) { + $table->dropColumn('tax_name1'); + $table->dropColumn('tax_rate1'); + $table->dropColumn('tax_name2'); + $table->dropColumn('tax_rate2'); + }); + + Schema::table('account_gateways', function(Blueprint $table) { + $table->dropColumn('require_cvv'); + }); + } +} diff --git a/database/migrations/2016_05_18_085739_add_invoice_type_support.php b/database/migrations/2016_05_18_085739_add_invoice_type_support.php new file mode 100644 index 0000000000..bc4834df96 --- /dev/null +++ b/database/migrations/2016_05_18_085739_add_invoice_type_support.php @@ -0,0 +1,47 @@ +renameColumn('is_quote', 'invoice_type_id'); + }); + } + + Schema::table('accounts', function($table) + { + $table->boolean('enable_second_tax_rate')->default(false); + }); + + + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + if (Schema::hasColumn('invoices', 'invoice_type_id')) { + DB::update('update invoices set invoice_type_id = invoice_type_id - 1'); + } + + Schema::table('accounts', function($table) + { + $table->dropColumn('enable_second_tax_rate'); + }); + } +} diff --git a/database/migrations/2016_05_24_164847_wepay_ach.php b/database/migrations/2016_05_24_164847_wepay_ach.php new file mode 100644 index 0000000000..088e9225d0 --- /dev/null +++ b/database/migrations/2016_05_24_164847_wepay_ach.php @@ -0,0 +1,62 @@ +string('contact_key')->nullable()->default(null)->index()->unique(); + }); + + Schema::table('payment_methods', function($table) + { + $table->string('bank_name')->nullable(); + $table->string('ip')->nullable(); + }); + + Schema::table('payments', function($table) + { + $table->string('bank_name')->nullable(); + $table->string('ip')->nullable(); + }); + + Schema::table('accounts', function($table) + { + $table->boolean('auto_bill_on_due_date')->default(false); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('contacts', function(Blueprint $table) { + $table->dropColumn('contact_key'); + }); + + Schema::table('payments', function($table) { + $table->dropColumn('bank_name'); + $table->dropColumn('ip'); + }); + + Schema::table('payment_methods', function($table) { + $table->dropColumn('bank_name'); + $table->dropColumn('ip'); + }); + + Schema::table('accounts', function($table) { + $table->dropColumn('auto_bill_on_due_date'); + }); + } +} diff --git a/database/migrations/2016_07_08_083802_support_new_pricing.php b/database/migrations/2016_07_08_083802_support_new_pricing.php new file mode 100644 index 0000000000..cfb9413456 --- /dev/null +++ b/database/migrations/2016_07_08_083802_support_new_pricing.php @@ -0,0 +1,89 @@ +decimal('plan_price', 7, 2)->nullable(); + $table->decimal('pending_plan_price', 7, 2)->nullable(); + $table->smallInteger('num_users')->default(1); + $table->smallInteger('pending_num_users')->default(1); + }); + + // lock in existing prices + DB::table('companies')->where('plan', 'pro')->where('plan_term', 'month')->update(['plan_price' => 5]); + DB::table('companies')->where('plan', 'pro')->where('plan_term', 'year')->update(['plan_price' => 50]); + DB::table('companies')->where('plan', 'enterprise')->where('plan_term', 'month')->update(['plan_price' => 10]); + DB::table('companies')->where('plan', 'enterprise')->where('plan_term', 'year')->update(['plan_price' => 100]); + DB::table('companies')->where('plan', 'enterprise')->update(['num_users' => 5]); + + // https://github.com/invoiceninja/invoiceninja/pull/955 + Schema::table('activities', function (Blueprint $table) { + $table->integer('task_id')->after('invitation_id')->nullable(); + $table->dropForeign('activities_client_id_foreign'); + }); + + // https://github.com/invoiceninja/invoiceninja/pull/950 + Schema::table('accounts', function (Blueprint $table) { + $table->integer('start_of_week'); + }); + + // https://github.com/invoiceninja/invoiceninja/pull/959 + Schema::create('jobs', function (Blueprint $table) { + $table->bigIncrements('id'); + $table->string('queue'); + $table->longText('payload'); + $table->tinyInteger('attempts')->unsigned(); + $table->tinyInteger('reserved')->unsigned(); + $table->unsignedInteger('reserved_at')->nullable(); + $table->unsignedInteger('available_at'); + $table->unsignedInteger('created_at'); + $table->index(['queue', 'reserved', 'reserved_at']); + }); + + Schema::create('failed_jobs', function (Blueprint $table) { + $table->increments('id'); + $table->text('connection'); + $table->text('queue'); + $table->longText('payload'); + $table->timestamp('failed_at')->useCurrent(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('companies', function (Blueprint $table) + { + $table->dropColumn('plan_price'); + $table->dropColumn('pending_plan_price'); + $table->dropColumn('num_users'); + $table->dropColumn('pending_num_users'); + }); + + Schema::table('activities', function (Blueprint $table) { + $table->dropColumn('task_id'); + }); + + Schema::table('accounts', function (Blueprint $table) { + $table->dropColumn('start_of_week'); + }); + + Schema::drop('jobs'); + Schema::drop('failed_jobs'); + } +} diff --git a/database/seeds/ConstantsSeeder.php b/database/seeds/ConstantsSeeder.php index e027416843..0200af1ee3 100644 --- a/database/seeds/ConstantsSeeder.php +++ b/database/seeds/ConstantsSeeder.php @@ -20,23 +20,6 @@ class ConstantsSeeder extends Seeder public function run() { - PaymentType::create(array('name' => 'Apply Credit')); - PaymentType::create(array('name' => 'Bank Transfer')); - PaymentType::create(array('name' => 'Cash')); - PaymentType::create(array('name' => 'Debit')); - PaymentType::create(array('name' => 'ACH')); - PaymentType::create(array('name' => 'Visa Card')); - PaymentType::create(array('name' => 'MasterCard')); - PaymentType::create(array('name' => 'American Express')); - PaymentType::create(array('name' => 'Discover Card')); - PaymentType::create(array('name' => 'Diners Card')); - PaymentType::create(array('name' => 'EuroCard')); - PaymentType::create(array('name' => 'Nova')); - PaymentType::create(array('name' => 'Credit Card Other')); - PaymentType::create(array('name' => 'PayPal')); - PaymentType::create(array('name' => 'Google Wallet')); - PaymentType::create(array('name' => 'Check')); - Theme::create(array('name' => 'amelia')); Theme::create(array('name' => 'cerulean')); Theme::create(array('name' => 'cosmo')); @@ -95,7 +78,7 @@ class ConstantsSeeder extends Seeder Size::create(array('name' => '11 - 50')); Size::create(array('name' => '51 - 100')); Size::create(array('name' => '101 - 500')); - Size::create(array('name' => '500+')); + Size::create(array('name' => '500+')); PaymentTerm::create(array('num_days' => 7, 'name' => 'Net 7', 'public_id' => 1)); PaymentTerm::create(array('num_days' => 10, 'name' => 'Net 10', 'public_id' => 2)); @@ -104,11 +87,11 @@ class ConstantsSeeder extends Seeder PaymentTerm::create(array('num_days' => 30, 'name' => 'Net 30', 'public_id' => 5)); PaymentTerm::create(array('num_days' => 60, 'name' => 'Net 60', 'public_id' => 6)); PaymentTerm::create(array('num_days' => 90, 'name' => 'Net 90', 'public_id' => 7)); - + PaymentLibrary::create(['name' => 'Omnipay']); PaymentLibrary::create(['name' => 'PHP-Payments [Deprecated]']); - /* + /* d, dd: Numeric date, no leading zero and leading zero, respectively. Eg, 5, 05. D, DD: Abbreviated and full weekday names, respectively. Eg, Mon, Monday. m, mm: Numeric month, no leading zero and leading zero, respectively. Eg, 7, 07. @@ -116,42 +99,6 @@ class ConstantsSeeder extends Seeder yy, yyyy: 2- and 4-digit years, respectively. Eg, 12, 2012.) */ - $gateways = [ - array('name'=>'Authorize.Net AIM', 'provider'=>'AuthorizeNet_AIM'), - array('name'=>'Authorize.Net SIM', 'provider'=>'AuthorizeNet_SIM'), - array('name'=>'CardSave', 'provider'=>'CardSave'), - array('name'=>'Eway Rapid', 'provider'=>'Eway_Rapid'), - array('name'=>'FirstData Connect', 'provider'=>'FirstData_Connect'), - array('name'=>'GoCardless', 'provider'=>'GoCardless'), - array('name'=>'Migs ThreeParty', 'provider'=>'Migs_ThreeParty'), - array('name'=>'Migs TwoParty', 'provider'=>'Migs_TwoParty'), - array('name'=>'Mollie', 'provider'=>'Mollie'), - array('name'=>'MultiSafepay', 'provider'=>'MultiSafepay'), - array('name'=>'Netaxept', 'provider'=>'Netaxept'), - array('name'=>'NetBanx', 'provider'=>'NetBanx'), - array('name'=>'PayFast', 'provider'=>'PayFast'), - array('name'=>'Payflow Pro', 'provider'=>'Payflow_Pro'), - array('name'=>'PaymentExpress PxPay', 'provider'=>'PaymentExpress_PxPay'), - array('name'=>'PaymentExpress PxPost', 'provider'=>'PaymentExpress_PxPost'), - array('name'=>'PayPal Express', 'provider'=>'PayPal_Express'), - array('name'=>'PayPal Pro', 'provider'=>'PayPal_Pro'), - array('name'=>'Pin', 'provider'=>'Pin'), - array('name'=>'SagePay Direct', 'provider'=>'SagePay_Direct'), - array('name'=>'SagePay Server', 'provider'=>'SagePay_Server'), - array('name'=>'SecurePay DirectPost', 'provider'=>'SecurePay_DirectPost'), - array('name'=>'Stripe', 'provider'=>'Stripe'), - array('name'=>'TargetPay Direct eBanking', 'provider'=>'TargetPay_Directebanking'), - array('name'=>'TargetPay Ideal', 'provider'=>'TargetPay_Ideal'), - array('name'=>'TargetPay Mr Cash', 'provider'=>'TargetPay_Mrcash'), - array('name'=>'TwoCheckout', 'provider'=>'TwoCheckout'), - array('name'=>'WorldPay', 'provider'=>'WorldPay'), - ]; - - foreach ($gateways as $gateway) - { - Gateway::create($gateway); - } - $timezones = array( 'Pacific/Midway' => "(GMT-11:00) Midway Island", 'US/Samoa' => "(GMT-11:00) Samoa", @@ -267,7 +214,7 @@ class ConstantsSeeder extends Seeder 'Pacific/Auckland' => "(GMT+12:00) Auckland", 'Pacific/Fiji' => "(GMT+12:00) Fiji", ); - + foreach ($timezones as $name => $location) { Timezone::create(array('name'=>$name, 'location'=>$location)); } diff --git a/database/seeds/CurrenciesSeeder.php b/database/seeds/CurrenciesSeeder.php index 3b44d55d8d..c7b1420bc6 100644 --- a/database/seeds/CurrenciesSeeder.php +++ b/database/seeds/CurrenciesSeeder.php @@ -14,7 +14,7 @@ class CurrenciesSeeder extends Seeder ['name' => 'Pound Sterling', 'code' => 'GBP', 'symbol' => '£', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], ['name' => 'Euro', 'code' => 'EUR', 'symbol' => '€', 'precision' => '2', 'thousand_separator' => '.', 'decimal_separator' => ','], ['name' => 'South African Rand', 'code' => 'ZAR', 'symbol' => 'R', 'precision' => '2', 'thousand_separator' => '.', 'decimal_separator' => ','], - ['name' => 'Danish Krone', 'code' => 'DKK', 'symbol' => 'kr ', 'precision' => '2', 'thousand_separator' => '.', 'decimal_separator' => ','], + ['name' => 'Danish Krone', 'code' => 'DKK', 'symbol' => 'kr ', 'precision' => '2', 'thousand_separator' => '.', 'decimal_separator' => ',', 'swap_currency_symbol' => true], ['name' => 'Israeli Shekel', 'code' => 'ILS', 'symbol' => 'NIS ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], ['name' => 'Swedish Krona', 'code' => 'SEK', 'symbol' => 'kr ', 'precision' => '2', 'thousand_separator' => '.', 'decimal_separator' => ','], ['name' => 'Kenyan Shilling', 'code' => 'KES', 'symbol' => 'KSh ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], @@ -58,6 +58,8 @@ class CurrenciesSeeder extends Seeder ['name' => 'Maldivian Rufiyaa', 'code' => 'MVR', 'symbol' => '', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], ['name' => 'Costa Rican Colón', 'code' => 'CRC', 'symbol' => '', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], ['name' => 'Pakistani Rupee', 'code' => 'PKR', 'symbol' => 'Rs ', 'precision' => '0', 'thousand_separator' => ',', 'decimal_separator' => '.'], + ['name' => 'Polish Zloty', 'code' => 'PLN', 'symbol' => 'zł', 'precision' => '2', 'thousand_separator' => ' ', 'decimal_separator' => ',', 'swap_currency_symbol' => true], + ['name' => 'Sri Lankan Rupee', 'code' => 'LKR', 'symbol' => 'LKR', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.', 'swap_currency_symbol' => true], ]; foreach ($currencies as $currency) { @@ -67,6 +69,9 @@ class CurrenciesSeeder extends Seeder $record->symbol = $currency['symbol']; $record->thousand_separator = $currency['thousand_separator']; $record->decimal_separator = $currency['decimal_separator']; + if(isset($currency['swap_currency_symbol'])){ + $record->swap_currency_symbol = $currency['swap_currency_symbol']; + } $record->save(); } else { Currency::create($currency); diff --git a/database/seeds/DatabaseSeeder.php b/database/seeds/DatabaseSeeder.php index d7f38d3e1e..1abaa76b64 100644 --- a/database/seeds/DatabaseSeeder.php +++ b/database/seeds/DatabaseSeeder.php @@ -19,10 +19,12 @@ class DatabaseSeeder extends Seeder $this->call('FontsSeeder'); $this->call('BanksSeeder'); $this->call('InvoiceStatusSeeder'); + $this->call('PaymentStatusSeeder'); $this->call('CurrenciesSeeder'); $this->call('DateFormatsSeeder'); $this->call('InvoiceDesignsSeeder'); $this->call('PaymentTermsSeeder'); + $this->call('PaymentTypesSeeder'); $this->call('LanguageSeeder'); } } diff --git a/database/seeds/DateFormatsSeeder.php b/database/seeds/DateFormatsSeeder.php index 40568ca300..c55028b684 100644 --- a/database/seeds/DateFormatsSeeder.php +++ b/database/seeds/DateFormatsSeeder.php @@ -11,22 +11,24 @@ class DateFormatsSeeder extends Seeder // Date formats $formats = [ - ['format' => 'd/M/Y', 'picker_format' => 'dd/M/yyyy', 'label' => '10/Mar/2013'], - ['format' => 'd-M-Y', 'picker_format' => 'dd-M-yyyy', 'label' => '10-Mar-2013'], - ['format' => 'd/F/Y', 'picker_format' => 'dd/MM/yyyy', 'label' => '10/March/2013'], - ['format' => 'd-F-Y', 'picker_format' => 'dd-MM-yyyy', 'label' => '10-March-2013'], - ['format' => 'M j, Y', 'picker_format' => 'M d, yyyy', 'label' => 'Mar 10, 2013'], - ['format' => 'F j, Y', 'picker_format' => 'MM d, yyyy', 'label' => 'March 10, 2013'], - ['format' => 'D M j, Y', 'picker_format' => 'D MM d, yyyy', 'label' => 'Mon March 10, 2013'], - ['format' => 'Y-m-d', 'picker_format' => 'yyyy-mm-dd', 'label' => '2013-03-10'], - ['format' => 'd-m-Y', 'picker_format' => 'dd-mm-yyyy', 'label' => '20-03-2013'], - ['format' => 'm/d/Y', 'picker_format' => 'mm/dd/yyyy', 'label' => '03/20/2013'] + ['format' => 'd/M/Y', 'picker_format' => 'dd/M/yyyy'], + ['format' => 'd-M-Y', 'picker_format' => 'dd-M-yyyy'], + ['format' => 'd/F/Y', 'picker_format' => 'dd/MM/yyyy'], + ['format' => 'd-F-Y', 'picker_format' => 'dd-MM-yyyy'], + ['format' => 'M j, Y', 'picker_format' => 'M d, yyyy'], + ['format' => 'F j, Y', 'picker_format' => 'MM d, yyyy'], + ['format' => 'D M j, Y', 'picker_format' => 'D MM d, yyyy'], + ['format' => 'Y-m-d', 'picker_format' => 'yyyy-mm-dd'], + ['format' => 'd-m-Y', 'picker_format' => 'dd-mm-yyyy'], + ['format' => 'm/d/Y', 'picker_format' => 'mm/dd/yyyy'], + ['format' => 'd.m.Y', 'picker_format' => 'dd.mm.yyyy'], + ['format' => 'j. M. Y', 'picker_format' => 'd. M. yyyy'], + ['format' => 'j. F Y', 'picker_format' => 'd. MM yyyy'] ]; - + foreach ($formats as $format) { - $record = DateFormat::whereLabel($format['label'])->first(); + $record = DateFormat::whereFormat($format['format'])->first(); if ($record) { - $record->format = $format['format']; $record->picker_format = $format['picker_format']; $record->save(); } else { @@ -36,62 +38,24 @@ class DateFormatsSeeder extends Seeder // Date/time formats $formats = [ - [ - 'format' => 'd/M/Y g:i a', - 'format_moment' => 'DD/MMM/YYYY h:mm:ss a', - 'label' => '10/Mar/2013' - ], - [ - 'format' => 'd-M-Y g:i a', - 'format_moment' => 'DD-MMM-YYYY h:mm:ss a', - 'label' => '10-Mar-2013' - ], - [ - 'format' => 'd/F/Y g:i a', - 'format_moment' => 'DD/MMMM/YYYY h:mm:ss a', - 'label' => '10/March/2013' - ], - [ - 'format' => 'd-F-Y g:i a', - 'format_moment' => 'DD-MMMM-YYYY h:mm:ss a', - 'label' => '10-March-2013' - ], - [ - 'format' => 'M j, Y g:i a', - 'format_moment' => 'MMM D, YYYY h:mm:ss a', - 'label' => 'Mar 10, 2013 6:15 pm' - ], - [ - 'format' => 'F j, Y g:i a', - 'format_moment' => 'MMMM D, YYYY h:mm:ss a', - 'label' => 'March 10, 2013 6:15 pm' - ], - [ - 'format' => 'D M jS, Y g:i a', - 'format_moment' => 'ddd MMM Do, YYYY h:mm:ss a', - 'label' => 'Mon March 10th, 2013 6:15 pm' - ], - [ - 'format' => 'Y-m-d g:i a', - 'format_moment' => 'YYYY-MMM-DD h:mm:ss a', - 'label' => '2013-03-10 6:15 pm' - ], - [ - 'format' => 'd-m-Y g:i a', - 'format_moment' => 'DD-MM-YYYY h:mm:ss a', - 'label' => '20-03-2013 6:15 pm' - ], - [ - 'format' => 'm/d/Y g:i a', - 'format_moment' => 'MM/DD/YYYY h:mm:ss a', - 'label' => '03/20/2013 6:15 pm' - ] + ['format' => 'd/M/Y g:i a', 'format_moment' => 'DD/MMM/YYYY h:mm:ss a'], + ['format' => 'd-M-Y g:i a', 'format_moment' => 'DD-MMM-YYYY h:mm:ss a'], + ['format' => 'd/F/Y g:i a', 'format_moment' => 'DD/MMMM/YYYY h:mm:ss a'], + ['format' => 'd-F-Y g:i a', 'format_moment' => 'DD-MMMM-YYYY h:mm:ss a'], + ['format' => 'M j, Y g:i a', 'format_moment' => 'MMM D, YYYY h:mm:ss a'], + ['format' => 'F j, Y g:i a', 'format_moment' => 'MMMM D, YYYY h:mm:ss a'], + ['format' => 'D M jS, Y g:i a', 'format_moment' => 'ddd MMM Do, YYYY h:mm:ss a'], + ['format' => 'Y-m-d g:i a', 'format_moment' => 'YYYY-MMM-DD h:mm:ss a'], + ['format' => 'd-m-Y g:i a', 'format_moment' => 'DD-MM-YYYY h:mm:ss a'], + ['format' => 'm/d/Y g:i a', 'format_moment' => 'MM/DD/YYYY h:mm:ss a'], + ['format' => 'd.m.Y g:i a', 'format_moment' => 'D.MM.YYYY h:mm:ss a'], + ['format' => 'j. M. Y g:i a', 'format_moment' => 'DD. MMM. YYYY h:mm:ss a'], + ['format' => 'j. F Y g:i a', 'format_moment' => 'DD. MMMM YYYY h:mm:ss a'] ]; - + foreach ($formats as $format) { - $record = DatetimeFormat::whereLabel($format['label'])->first(); + $record = DatetimeFormat::whereFormat($format['format'])->first(); if ($record) { - $record->format = $format['format']; $record->format_moment = $format['format_moment']; $record->save(); } else { diff --git a/database/seeds/LanguageSeeder.php b/database/seeds/LanguageSeeder.php index 5fc9569d5c..19fff15c64 100644 --- a/database/seeds/LanguageSeeder.php +++ b/database/seeds/LanguageSeeder.php @@ -22,9 +22,10 @@ class LanguageSeeder extends Seeder ['name' => 'Swedish', 'locale' => 'sv'], ['name' => 'Spanish - Spain', 'locale' => 'es_ES'], ['name' => 'French - Canada', 'locale' => 'fr_CA'], - ['name' => 'Lithuanian', 'locale' => 'lt'], + ['name' => 'Lithuanian', 'locale' => 'lt'], ['name' => 'Polish', 'locale' => 'pl'], ['name' => 'Czech', 'locale' => 'cs'], + ['name' => 'Croatian', 'locale' => 'hr'], ]; foreach ($languages as $language) { diff --git a/database/seeds/PaymentLibrariesSeeder.php b/database/seeds/PaymentLibrariesSeeder.php index 654ad9fe0e..e7884e422d 100644 --- a/database/seeds/PaymentLibrariesSeeder.php +++ b/database/seeds/PaymentLibrariesSeeder.php @@ -15,45 +15,74 @@ class PaymentLibrariesSeeder extends Seeder Eloquent::unguard(); $gateways = [ + ['name' => 'Authorize.Net AIM', 'provider' => 'AuthorizeNet_AIM'], + ['name' => 'Authorize.Net SIM', 'provider' => 'AuthorizeNet_SIM', 'payment_library_id' => 2], + ['name' => 'CardSave', 'provider' => 'CardSave'], + ['name' => 'Eway Rapid', 'provider' => 'Eway_RapidShared', 'is_offsite' => true], + ['name' => 'FirstData Connect', 'provider' => 'FirstData_Connect'], + ['name' => 'GoCardless', 'provider' => 'GoCardless', 'is_offsite' => true], + ['name' => 'Migs ThreeParty', 'provider' => 'Migs_ThreeParty'], + ['name' => 'Migs TwoParty', 'provider' => 'Migs_TwoParty'], + ['name' => 'Mollie', 'provider' => 'Mollie', 'is_offsite' => true], + ['name' => 'MultiSafepay', 'provider' => 'MultiSafepay'], + ['name' => 'Netaxept', 'provider' => 'Netaxept'], + ['name' => 'NetBanx', 'provider' => 'NetBanx'], + ['name' => 'PayFast', 'provider' => 'PayFast', 'is_offsite' => true], + ['name' => 'Payflow Pro', 'provider' => 'Payflow_Pro'], + ['name' => 'PaymentExpress PxPay', 'provider' => 'PaymentExpress_PxPay'], + ['name' => 'PaymentExpress PxPost', 'provider' => 'PaymentExpress_PxPost'], + ['name' => 'PayPal Express', 'provider' => 'PayPal_Express', 'is_offsite' => true], + ['name' => 'PayPal Pro', 'provider' => 'PayPal_Pro'], + ['name' => 'Pin', 'provider' => 'Pin'], + ['name' => 'SagePay Direct', 'provider' => 'SagePay_Direct'], + ['name' => 'SagePay Server', 'provider' => 'SagePay_Server'], + ['name' => 'SecurePay DirectPost', 'provider' => 'SecurePay_DirectPost'], + ['name' => 'Stripe', 'provider' => 'Stripe'], + ['name' => 'TargetPay Direct eBanking', 'provider' => 'TargetPay_Directebanking'], + ['name' => 'TargetPay Ideal', 'provider' => 'TargetPay_Ideal'], + ['name' => 'TargetPay Mr Cash', 'provider' => 'TargetPay_Mrcash'], + ['name' => 'TwoCheckout', 'provider' => 'TwoCheckout', 'is_offsite' => true], + ['name' => 'WorldPay', 'provider' => 'WorldPay'], ['name' => 'BeanStream', 'provider' => 'BeanStream', 'payment_library_id' => 2], ['name' => 'Psigate', 'provider' => 'Psigate', 'payment_library_id' => 2], - ['name' => 'moolah', 'provider' => 'AuthorizeNet_AIM', 'sort_order' => 1, 'recommended' => 1, 'site_url' => 'https://invoiceninja.mymoolah.com/', 'payment_library_id' => 1], - ['name' => 'Alipay', 'provider' => 'Alipay_Express', 'payment_library_id' => 1], - ['name' => 'Buckaroo', 'provider' => 'Buckaroo_CreditCard', 'payment_library_id' => 1], - ['name' => 'Coinbase', 'provider' => 'Coinbase', 'payment_library_id' => 1], - ['name' => 'DataCash', 'provider' => 'DataCash', 'payment_library_id' => 1], + ['name' => 'moolah', 'provider' => 'AuthorizeNet_AIM'], + ['name' => 'Alipay', 'provider' => 'Alipay_Express'], + ['name' => 'Buckaroo', 'provider' => 'Buckaroo_CreditCard'], + ['name' => 'Coinbase', 'provider' => 'Coinbase'], + ['name' => 'DataCash', 'provider' => 'DataCash'], ['name' => 'Neteller', 'provider' => 'Neteller', 'payment_library_id' => 2], - ['name' => 'Pacnet', 'provider' => 'Pacnet', 'payment_library_id' => 1], - ['name' => 'PaymentSense', 'provider' => 'PaymentSense', 'payment_library_id' => 1], - ['name' => 'Realex', 'provider' => 'Realex_Remote', 'payment_library_id' => 1], - ['name' => 'Sisow', 'provider' => 'Sisow', 'payment_library_id' => 1], - ['name' => 'Skrill', 'provider' => 'Skrill', 'payment_library_id' => 1], - ['name' => 'BitPay', 'provider' => 'BitPay', 'payment_library_id' => 1], - ['name' => 'Dwolla', 'provider' => 'Dwolla', 'payment_library_id' => 1], - ['name' => 'Eway Rapid', 'provider' => 'Eway_RapidShared', 'payment_library_id' => 1], - ['name' => 'AGMS', 'provider' => 'Agms', 'payment_library_id' => 1], - ['name' => 'Barclays', 'provider' => 'BarclaysEpdq\Essential', 'payment_library_id' => 1], - ['name' => 'Cardgate', 'provider' => 'Cardgate', 'payment_library_id' => 1], - ['name' => 'Checkout.com', 'provider' => 'CheckoutCom', 'payment_library_id' => 1], - ['name' => 'Creditcall', 'provider' => 'Creditcall', 'payment_library_id' => 1], - ['name' => 'Cybersource', 'provider' => 'Cybersource', 'payment_library_id' => 1], - ['name' => 'ecoPayz', 'provider' => 'Ecopayz', 'payment_library_id' => 1], - ['name' => 'Fasapay', 'provider' => 'Fasapay', 'payment_library_id' => 1], - ['name' => 'Komoju', 'provider' => 'Komoju', 'payment_library_id' => 1], - ['name' => 'Multicards', 'provider' => 'Multicards', 'payment_library_id' => 1], - ['name' => 'Pagar.Me', 'provider' => 'Pagarme', 'payment_library_id' => 1], - ['name' => 'Paysafecard', 'provider' => 'Paysafecard', 'payment_library_id' => 1], - ['name' => 'Paytrace', 'provider' => 'Paytrace_CreditCard', 'payment_library_id' => 1], - ['name' => 'Secure Trading', 'provider' => 'SecureTrading', 'payment_library_id' => 1], - ['name' => 'SecPay', 'provider' => 'SecPay', 'payment_library_id' => 1], - ['name' => 'WeChat Express', 'provider' => 'WeChat_Express', 'payment_library_id' => 1], - ['name' => 'WePay', 'provider' => 'WePay', 'payment_library_id' => 1], + ['name' => 'Pacnet', 'provider' => 'Pacnet'], + ['name' => 'PaymentSense', 'provider' => 'PaymentSense'], + ['name' => 'Realex', 'provider' => 'Realex_Remote'], + ['name' => 'Sisow', 'provider' => 'Sisow'], + ['name' => 'Skrill', 'provider' => 'Skrill'], + ['name' => 'BitPay', 'provider' => 'BitPay', 'is_offsite' => true], + ['name' => 'Dwolla', 'provider' => 'Dwolla', 'is_offsite' => true], + ['name' => 'AGMS', 'provider' => 'Agms'], + ['name' => 'Barclays', 'provider' => 'BarclaysEpdq\Essential'], + ['name' => 'Cardgate', 'provider' => 'Cardgate'], + ['name' => 'Checkout.com', 'provider' => 'CheckoutCom'], + ['name' => 'Creditcall', 'provider' => 'Creditcall'], + ['name' => 'Cybersource', 'provider' => 'Cybersource'], + ['name' => 'ecoPayz', 'provider' => 'Ecopayz'], + ['name' => 'Fasapay', 'provider' => 'Fasapay'], + ['name' => 'Komoju', 'provider' => 'Komoju'], + ['name' => 'Multicards', 'provider' => 'Multicards'], + ['name' => 'Pagar.Me', 'provider' => 'Pagarme'], + ['name' => 'Paysafecard', 'provider' => 'Paysafecard'], + ['name' => 'Paytrace', 'provider' => 'Paytrace_CreditCard'], + ['name' => 'Secure Trading', 'provider' => 'SecureTrading'], + ['name' => 'SecPay', 'provider' => 'SecPay'], + ['name' => 'WeChat Express', 'provider' => 'WeChat_Express'], + ['name' => 'WePay', 'provider' => 'WePay', 'is_offsite' => false], + ['name' => 'Braintree', 'provider' => 'Braintree'], ]; foreach ($gateways as $gateway) { $record = Gateway::where('name', '=', $gateway['name'])->first(); if ($record) { $record->provider = $gateway['provider']; + $record->is_offsite = isset($gateway['is_offsite']) ? boolval($gateway['is_offsite']) : false; $record->save(); } else { Gateway::create($gateway); diff --git a/database/seeds/PaymentStatusSeeder.php b/database/seeds/PaymentStatusSeeder.php new file mode 100644 index 0000000000..4b3da3d085 --- /dev/null +++ b/database/seeds/PaymentStatusSeeder.php @@ -0,0 +1,37 @@ +createPaymentStatuses(); + + Eloquent::reguard(); + } + + private function createPaymentStatuses() + { + $statuses = [ + ['id' => '1', 'name' => 'Pending'], + ['id' => '2', 'name' => 'Voided'], + ['id' => '3', 'name' => 'Failed'], + ['id' => '4', 'name' => 'Completed'], + ['id' => '5', 'name' => 'Partially Refunded'], + ['id' => '6', 'name' => 'Refunded'], + ]; + + foreach ($statuses as $status) { + $record = PaymentStatus::find($status['id']); + if ($record) { + $record->name = $status['name']; + $record->save(); + } else { + PaymentStatus::create($status); + } + } + } +} diff --git a/database/seeds/PaymentTypesSeeder.php b/database/seeds/PaymentTypesSeeder.php new file mode 100644 index 0000000000..6ded622845 --- /dev/null +++ b/database/seeds/PaymentTypesSeeder.php @@ -0,0 +1,44 @@ + 'Apply Credit'), + array('name' => 'Bank Transfer'), + array('name' => 'Cash'), + array('name' => 'Debit'), + array('name' => 'ACH'), + array('name' => 'Visa Card'), + array('name' => 'MasterCard'), + array('name' => 'American Express'), + array('name' => 'Discover Card'), + array('name' => 'Diners Card'), + array('name' => 'EuroCard'), + array('name' => 'Nova'), + array('name' => 'Credit Card Other'), + array('name' => 'PayPal'), + array('name' => 'Google Wallet'), + array('name' => 'Check'), + array('name' => 'Carte Blanche'), + array('name' => 'UnionPay'), + array('name' => 'JCB'), + array('name' => 'Laser'), + array('name' => 'Maestro'), + array('name' => 'Solo'), + array('name' => 'Switch'), + ]; + + foreach ($paymentTypes as $paymentType) { + if (!DB::table('payment_types')->where('name', '=', $paymentType['name'])->get()) { + PaymentType::create($paymentType); + } + } + } + +} \ No newline at end of file diff --git a/database/seeds/UpdateSeeder.php b/database/seeds/UpdateSeeder.php index d445811de5..b407a7ba2e 100644 --- a/database/seeds/UpdateSeeder.php +++ b/database/seeds/UpdateSeeder.php @@ -15,10 +15,12 @@ class UpdateSeeder extends Seeder $this->call('FontsSeeder'); $this->call('BanksSeeder'); $this->call('InvoiceStatusSeeder'); + $this->call('PaymentStatusSeeder'); $this->call('CurrenciesSeeder'); $this->call('DateFormatsSeeder'); $this->call('InvoiceDesignsSeeder'); $this->call('PaymentTermsSeeder'); + $this->call('PaymentTypesSeeder'); $this->call('LanguageSeeder'); } } diff --git a/database/seeds/UserTableSeeder.php b/database/seeds/UserTableSeeder.php index e86bbe4e14..ec4f0ae8f4 100644 --- a/database/seeds/UserTableSeeder.php +++ b/database/seeds/UserTableSeeder.php @@ -7,6 +7,9 @@ use App\Models\Company; use App\Models\Affiliate; use App\Models\Country; use App\Models\InvoiceDesign; +use App\Models\Client; +use App\Models\Contact; +use App\Models\Product; use Faker\Factory; class UserTableSeeder extends Seeder @@ -33,7 +36,7 @@ class UserTableSeeder extends Seeder 'invoice_terms' => $faker->text($faker->numberBetween(50, 300)), 'work_phone' => $faker->phoneNumber, 'work_email' => $faker->safeEmail, - 'invoice_design_id' => min(InvoiceDesign::all()->random()->id, 10), + 'invoice_design_id' => InvoiceDesign::where('id', '<', CUSTOM_DESIGN)->get()->random()->id, 'header_font_id' => min(Font::all()->random()->id, 17), 'body_font_id' => min(Font::all()->random()->id, 17), 'primary_color' => $faker->hexcolor, @@ -41,7 +44,9 @@ class UserTableSeeder extends Seeder 'company_id' => $company->id, ]); - User::create([ + $user = User::create([ + 'first_name' => $faker->firstName, + 'last_name' => $faker->lastName, 'email' => TEST_USERNAME, 'username' => TEST_USERNAME, 'account_id' => $account->id, @@ -50,7 +55,39 @@ class UserTableSeeder extends Seeder 'confirmed' => true, 'notify_sent' => false, 'notify_paid' => false, - 'is_admin' => 1, + 'is_admin' => 1, + ]); + + $client = Client::create([ + 'user_id' => $user->id, + 'account_id' => $account->id, + 'public_id' => 1, + 'name' => $faker->name, + 'address1' => $faker->streetAddress, + 'address2' => $faker->secondaryAddress, + 'city' => $faker->city, + 'state' => $faker->state, + 'postal_code' => $faker->postcode, + 'country_id' => DEFAULT_COUNTRY, + 'currency_id' => DEFAULT_CURRENCY, + ]); + + Contact::create([ + 'user_id' => $user->id, + 'account_id' => $account->id, + 'client_id' => $client->id, + 'public_id' => 1, + 'email' => env('TEST_EMAIL', TEST_USERNAME), + 'is_primary' => true, + ]); + + Product::create([ + 'user_id' => $user->id, + 'account_id' => $account->id, + 'public_id' => 1, + 'product_key' => 'ITEM', + 'notes' => 'Something nice...', + 'cost' => 10, ]); Affiliate::create([ diff --git a/invoiceninja.komodoproject b/invoiceninja.komodoproject deleted file mode 100644 index 16111c8ee8..0000000000 --- a/invoiceninja.komodoproject +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - PHP - - - - application/x-www-form-urlencoded - GET - 1 - 0 - 0 - - - - - PHP - %25d/%25m/%25Y %25H:%25M:%25S - 1 - - default - default - PHP - Project - None - None - None - c:\wamp\bin\php\php5.6.15\php.exe - vendor;C:/webdev/invoiceninja/app - 1 - None - None - - diff --git a/public/browserconfig.xml b/public/browserconfig.xml new file mode 100644 index 0000000000..774ed327e5 --- /dev/null +++ b/public/browserconfig.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/public/built.js b/public/built.js index 8cd3a1e70e..6e96fb8e24 100644 --- a/public/built.js +++ b/public/built.js @@ -30319,6 +30319,34 @@ if (window.ko) { trigger: "hover" } }; + + ko.bindingHandlers.typeahead = { + init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { + var $element = $(element); + var allBindings = allBindingsAccessor(); + + $element.typeahead({ + highlight: true, + minLength: 0, + }, + { + name: 'data', + display: allBindings.key, + limit: 50, + source: searchData(allBindings.items, allBindings.key) + }).on('typeahead:change', function(element, datum, name) { + var value = valueAccessor(); + value(datum); + }); + }, + + update: function (element, valueAccessor) { + var value = ko.utils.unwrapObservable(valueAccessor()); + if (value) { + $(element).typeahead('val', value); + } + } + }; } function getContactDisplayName(contact) @@ -30450,7 +30478,7 @@ function formatAddress(city, state, zip, swap) { str += zip ? zip + ' ' : ''; str += city ? city : ''; str += (city && state) ? ', ' : (city ? ' ' : ''); - str += state; + str += state; } else { str += city ? city : ''; str += (city && state) ? ', ' : (state ? ' ' : ''); @@ -30484,7 +30512,7 @@ function calculateAmounts(invoice) { var hasTaxes = false; var taxes = {}; invoice.has_product_key = false; - + // Bold designs currently breaks w/o the product column if (invoice.invoice_design_id == 2) { invoice.has_product_key = true; @@ -30532,7 +30560,7 @@ function calculateAmounts(invoice) { lineTotal -= roundToTwo(lineTotal * (invoice.discount/100)); } } - + var taxAmount1 = roundToTwo(lineTotal * taxRate1 / 100); if (taxAmount1) { var key = taxName1 + taxRate1; @@ -30609,7 +30637,7 @@ function calculateAmounts(invoice) { invoice.tax_amount1 = taxAmount1; invoice.tax_amount2 = taxAmount2; invoice.item_taxes = taxes; - + if (NINJA.parseFloat(invoice.partial)) { invoice.balance_amount = roundToTwo(invoice.partial); } else { @@ -30934,9 +30962,9 @@ function truncate(string, length){ } }; -// Show/hide the 'Select' option in the datalists +// Show/hide the 'Select' option in the datalists function actionListHandler() { - $('tbody tr').mouseover(function() { + $('tbody tr .tr-action').closest('tr').mouseover(function() { $(this).closest('tr').find('.tr-action').show(); $(this).closest('tr').find('.tr-status').hide(); }).mouseout(function() { @@ -31000,11 +31028,12 @@ function searchData(data, key, fuzzy) { } cb(matches); } -}; +}; function escapeRegExp(str) { return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); } + var NINJA = NINJA || {}; NINJA.TEMPLATES = { @@ -31020,7 +31049,7 @@ NINJA.TEMPLATES = { PHOTO:"10" }; -function GetPdfMake(invoice, javascript, callback) { +function GetPdfMake(invoice, javascript, callback) { javascript = NINJA.decodeJavascript(invoice, javascript); @@ -31085,7 +31114,7 @@ function GetPdfMake(invoice, javascript, callback) { val = NINJA.parseMarkdownText(val, false); } */ - + return val; } @@ -31094,18 +31123,25 @@ function GetPdfMake(invoice, javascript, callback) { var dd = JSON.parse(javascript, jsonCallBack); var designId = invoice.invoice_design_id; if (!invoice.features.remove_created_by) { - if (designId == NINJA.TEMPLATES.CLEAN || designId == NINJA.TEMPLATES.NORMAL) { - dd.footer.columns.push({image: logoImages.imageLogo1, alignment: 'right', width: 130, margin: [0, 0, 0, 0]}) - } else if (designId == NINJA.TEMPLATES.BOLD) { - dd.footer[1].columns.push({image: logoImages.imageLogo2, alignment: 'right', width: 130, margin: [0, -20, 20, 0]}) - } else if (designId == NINJA.TEMPLATES.MODERN) { - dd.footer[1].columns[0].stack.push({image: logoImages.imageLogo3, alignment: 'left', width: 130, margin: [40, 6, 0, 0]}); + var footer = (typeof dd.footer === 'function') ? dd.footer() : dd.footer; + if (footer) { + if (designId == NINJA.TEMPLATES.ELEGANT) { + footer[0].columns.push({image: logoImages.imageLogo1, alignment: 'right', width: 130, margin: [0, -20, 20, 0]}) + } else if (designId == NINJA.TEMPLATES.PLAYFUL) { + footer.push({image: logoImages.imageLogo1, alignment: 'right', width: 130, margin: [0, 0, 10, 10]}) + } else if (designId == NINJA.TEMPLATES.BOLD) { + footer[1].columns.push({image: logoImages.imageLogo2, alignment: 'right', width: 130, margin: [0, -20, 20, 0]}) + } else if (designId == NINJA.TEMPLATES.MODERN) { + footer[1].columns[0].stack.push({image: logoImages.imageLogo3, alignment: 'left', width: 130, margin: [40, 6, 0, 0]}); + } else { + footer.columns.push({image: logoImages.imageLogo1, alignment: 'right', width: 130, margin: [0, 0, 0, 0]}) + } } } - + // set page size dd.pageSize = invoice.account.page_size; - + pdfMake.fonts = {} fonts = window.invoiceFonts || invoice.invoice_fonts; @@ -31126,15 +31162,15 @@ function GetPdfMake(invoice, javascript, callback) { } } } - + if(!dd.defaultStyle)dd.defaultStyle = {font:NINJA.bodyFont}; else if(!dd.defaultStyle.font)dd.defaultStyle.font = NINJA.bodyFont; - + doc = pdfMake.createPdf(dd); doc.save = function(fileName) { this.download(fileName); }; - + return doc; } @@ -31147,7 +31183,7 @@ NINJA.decodeJavascript = function(invoice, javascript) var json = { 'accountName': account.name || ' ', 'accountLogo': window.accountLogo || blankImage, - 'accountDetails': NINJA.accountDetails(invoice), + 'accountDetails': NINJA.accountDetails(invoice), 'accountAddress': NINJA.accountAddress(invoice), 'invoiceDetails': NINJA.invoiceDetails(invoice), 'invoiceDetailsHeight': (NINJA.invoiceDetails(invoice).length * 16) + 16, @@ -31160,7 +31196,7 @@ NINJA.decodeJavascript = function(invoice, javascript) 'notesAndTerms': NINJA.notesAndTerms(invoice), 'subtotals': NINJA.subtotals(invoice), 'subtotalsHeight': (NINJA.subtotals(invoice).length * 16) + 16, - 'subtotalsWithoutBalance': NINJA.subtotals(invoice, true), + 'subtotalsWithoutBalance': NINJA.subtotals(invoice, true), 'subtotalsBalance': NINJA.subtotalsBalance(invoice), 'balanceDue': formatMoneyInvoice(invoice.balance_amount, invoice), 'invoiceFooter': NINJA.invoiceFooter(invoice), @@ -31188,10 +31224,10 @@ NINJA.decodeJavascript = function(invoice, javascript) javascript = javascript.replace(regExp, val); } - // search/replace labels + // search/replace labels var regExp = new RegExp('"\\$\\\w*?Label(UC)?(:)?(\\\?)?"', 'g'); - var matches = javascript.match(regExp); - + var matches = javascript.match(regExp); + if (matches) { for (var i=0; i lastIndex) { parts.push(line.substring(lastIndex, match.index)); @@ -31817,4 +31855,4 @@ NINJA.parseRegExpLine = function(line, regExp, formatter, groupText) } return line; -} \ No newline at end of file +} diff --git a/public/css/built.css b/public/css/built.css index 3c7c53828f..8d994b027e 100644 --- a/public/css/built.css +++ b/public/css/built.css @@ -2230,7 +2230,7 @@ border-bottom: 1px solid #dfe0e1; table.dataTable.no-footer { border-bottom: none; } -.table-striped>tbody>tr:nth-child(odd)>tr, +.table-striped>tbody>tr:nth-child(odd)>tr, .table-striped>tbody>tr:nth-child(odd)>th { background-color: #FDFDFD; } @@ -2321,7 +2321,7 @@ opacity: 1; filter: alpha(opacity=100); } /*buttons*/ -.btn { font-weight: bold; +.btn { font-weight: bold; border-radius: 3px; padding: 9px 12px; } @@ -2387,8 +2387,8 @@ border-color: #0b4d78; } .form-actions .btn, -.form-actions div.btn-group { - margin-left: 10px; +.form-actions div.btn-group { + margin-left: 10px; } .form-actions .btn.btn-success:first-child { @@ -2506,7 +2506,7 @@ border: none; border-radius: 0; color: #fff; background-color: #9b9b9b; - + } .nav-tabs.nav-justified>li:first-child>a { border-radius: 3px 0 0 3px; @@ -2535,7 +2535,7 @@ font-weight: bold; ul.dropdown-menu, .twitter-typeahead .tt-menu { x-moz-box-shadow: 0 0 10px 2px rgba(0,0,0,.05); - x-webkit-box-shadow: 0 0 10px 2px rgba(0,0,0,.05); + x-webkit-box-shadow: 0 0 10px 2px rgba(0,0,0,.05); box-shadow: 0 0 10px 2px rgba(0,0,0,.05); } @@ -2595,7 +2595,7 @@ background-clip: padding-box; /*********************************************** - Dashboard + Dashboard ************************************************/ .in-bold { @@ -2757,14 +2757,14 @@ div.discount-group span { .navbar-default .navbar-nav > li > a:focus { color: #ffffff; } -.navbar-default .navbar-nav > .active > a, -.navbar-default .navbar-nav > .active > a:hover, +.navbar-default .navbar-nav > .active > a, +.navbar-default .navbar-nav > .active > a:hover, .navbar-default .navbar-nav > .active > a:focus { color: #ffffff; background-color: #3276b1; } -.navbar-default .navbar-nav > .open > a, -.navbar-default .navbar-nav > .open > a:hover, +.navbar-default .navbar-nav > .open > a, +.navbar-default .navbar-nav > .open > a:hover, .navbar-default .navbar-nav > .open > a:focus { color: #ffffff; background-color: #3276b1; @@ -2778,8 +2778,8 @@ div.discount-group span { border-top-color: #ffffff; border-bottom-color: #ffffff; } -.navbar-default .navbar-nav > .open > a .caret, -.navbar-default .navbar-nav > .open > a:hover .caret, +.navbar-default .navbar-nav > .open > a .caret, +.navbar-default .navbar-nav > .open > a:hover .caret, .navbar-default .navbar-nav > .open > a:focus .caret { border-top-color: #ffffff; border-bottom-color: #ffffff; @@ -2818,7 +2818,7 @@ div.fb_iframe_widget { display: inline; } div.fb_iframe_widget > span { - vertical-align: top !important; + vertical-align: top !important; } .pro-label { font-size:9px; @@ -2857,12 +2857,12 @@ box-shadow: 0px 0px 15px 0px rgba(0, 5, 5, 0.2); .plans-table .glyphicon-remove {background-color: #da4830;} .plans-table .glyphicon-ok {background-color: #35c156;} .plans-table .glyphicon-star {border-radius: 0; background-color: #2e2b2b; - display: block; - width: 60px; - height: 30px; - position: absolute; - top: -5px; - right: -20px; + display: block; + width: 60px; + height: 30px; + position: absolute; + top: -5px; + right: -20px; -webkit-transform: rotate(45deg); -moz-transform: rotate(45deg); -o-transform: rotate(45deg); @@ -2892,11 +2892,11 @@ box-shadow: 0px 0px 15px 0px rgba(0, 5, 5, 0.2); .ellipsis { overflow: hidden; white-space: nowrap; - text-overflow: ellipsis; + text-overflow: ellipsis; } .entityArchived { - color: #888 !important; + color: #888 !important; } .entityDeleted { @@ -2904,12 +2904,12 @@ box-shadow: 0px 0px 15px 0px rgba(0, 5, 5, 0.2); } -/* Custom, iPhone Retina */ +/* Custom, iPhone Retina */ @media only screen and (min-width : 320px) { - + } -/* Extra Small Devices, Phones */ +/* Extra Small Devices, Phones */ @media only screen and (min-width : 480px) { } @@ -2957,7 +2957,7 @@ box-shadow: 0px 0px 15px 0px rgba(0, 5, 5, 0.2); @media (max-width: 992px) { .hide-phone { display: none !important; - } + } } @media (max-width: 767px) { @@ -2975,8 +2975,8 @@ box-shadow: 0px 0px 15px 0px rgba(0, 5, 5, 0.2); .plans-table .free .cell { padding-right: 0; } .plans-table .free .cell:first-child {margin-right: 0;} .plans-table .cell div:first-child {margin-bottom: 5px;} - .plans-table .cell .cta {margin-bottom: 0 !important;} - .plans-table .pro {margin-top: 40px;} + .plans-table .cell .cta {margin-bottom: 0 !important;} + .plans-table .pro {margin-top: 40px;} } label[for=recommendedGateway_id2].radio{ @@ -3105,14 +3105,14 @@ button .glyphicon { .pro-plan-modal a.button { font-family: 'roboto_slabregular', Georgia, Times, serif; - background: #f38c4f; - background: -moz-linear-gradient(top, #f38c4f 0%, #db7134 100%); - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f38c4f), color-stop(100%,#db7134)); - background: -webkit-linear-gradient(top, #f38c4f 0%,#db7134 100%); - background: -o-linear-gradient(top, #f38c4f 0%,#db7134 100%); - background: -ms-linear-gradient(top, #f38c4f 0%,#db7134 100%); - background: linear-gradient(to bottom, #f38c4f 0%,#db7134 100%); - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f38c4f', endColorstr='#db7134',GradientType=0 ); + background: #f38c4f; + background: -moz-linear-gradient(top, #f38c4f 0%, #db7134 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f38c4f), color-stop(100%,#db7134)); + background: -webkit-linear-gradient(top, #f38c4f 0%,#db7134 100%); + background: -o-linear-gradient(top, #f38c4f 0%,#db7134 100%); + background: -ms-linear-gradient(top, #f38c4f 0%,#db7134 100%); + background: linear-gradient(to bottom, #f38c4f 0%,#db7134 100%); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f38c4f', endColorstr='#db7134',GradientType=0 ); text-shadow: 1px 1px 1px rgba(0, 0, 0, .25); width: 68%; margin-top: 20px; @@ -3175,7 +3175,7 @@ ul.user-accounts a:hover div.remove { .invoice-contact .tooltip-inner { text-align:left; - width: 350px; + width: 350px; } .smaller { @@ -3232,10 +3232,3 @@ div.panel-body div.panel-body { width: 100%; height: 100%; } - -.dropzone .fallback-doc{ - display:none; -} -.dropzone.dz-browser-not-supported .fallback-doc{ - display:block; -} \ No newline at end of file diff --git a/public/css/built.public.css b/public/css/built.public.css index 2a02c2db94..58d0203377 100644 --- a/public/css/built.public.css +++ b/public/css/built.public.css @@ -793,7 +793,7 @@ html { .navbar-header { padding-top: 4px; - padding-bottom: 4px; + padding-bottom: 4px; } .navbar li a { padding-top: 18px; @@ -806,7 +806,7 @@ html { .navbar { x-moz-box-shadow: 0 0 10px 2px rgba(0,0,0,.05); - x-webkit-box-shadow: 0 0 10px 2px rgba(0,0,0,.05); + x-webkit-box-shadow: 0 0 10px 2px rgba(0,0,0,.05); box-shadow: 0 0 10px 2px rgba(0,0,0,.05); } @@ -894,7 +894,7 @@ table.table thead .sorting_desc_disabled:after { content: '' !important } font-weight: 500; } -@media screen and (min-width: 700px) { +@media screen and (min-width: 700px) { #footer .top { padding: 27px 0; } @@ -935,7 +935,7 @@ th {border-left: 1px solid #FFFFFF; } table.dataTable.no-footer { border-bottom: none; } -.table-striped>tbody>tr:nth-child(odd)>td, +.table-striped>tbody>tr:nth-child(odd)>td, .table-striped>tbody>tr:nth-child(odd)>th { background-color: #FDFDFD; } @@ -969,4 +969,4 @@ table td { } /* hide table sorting indicators */ -table.data-table thead .sorting { background: url('') no-repeat center right; } \ No newline at end of file +table.data-table thead .sorting { background: url('') no-repeat center right; } diff --git a/public/css/public.style.css b/public/css/public.style.css index b1f91c2573..a5cdbcc821 100644 --- a/public/css/public.style.css +++ b/public/css/public.style.css @@ -10,7 +10,7 @@ html { .navbar-header { padding-top: 4px; - padding-bottom: 4px; + padding-bottom: 4px; } .navbar li a { padding-top: 18px; @@ -23,7 +23,7 @@ html { .navbar { x-moz-box-shadow: 0 0 10px 2px rgba(0,0,0,.05); - x-webkit-box-shadow: 0 0 10px 2px rgba(0,0,0,.05); + x-webkit-box-shadow: 0 0 10px 2px rgba(0,0,0,.05); box-shadow: 0 0 10px 2px rgba(0,0,0,.05); } @@ -111,7 +111,7 @@ table.table thead .sorting_desc_disabled:after { content: '' !important } font-weight: 500; } -@media screen and (min-width: 700px) { +@media screen and (min-width: 700px) { #footer .top { padding: 27px 0; } @@ -152,7 +152,7 @@ th {border-left: 1px solid #FFFFFF; } table.dataTable.no-footer { border-bottom: none; } -.table-striped>tbody>tr:nth-child(odd)>td, +.table-striped>tbody>tr:nth-child(odd)>td, .table-striped>tbody>tr:nth-child(odd)>th { background-color: #FDFDFD; } @@ -186,4 +186,4 @@ table td { } /* hide table sorting indicators */ -table.data-table thead .sorting { background: url('') no-repeat center right; } \ No newline at end of file +table.data-table thead .sorting { background: url('') no-repeat center right; } diff --git a/public/css/style.css b/public/css/style.css index 801141c03c..47a0d28c2b 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -101,7 +101,7 @@ border-bottom: 1px solid #dfe0e1; table.dataTable.no-footer { border-bottom: none; } -.table-striped>tbody>tr:nth-child(odd)>tr, +.table-striped>tbody>tr:nth-child(odd)>tr, .table-striped>tbody>tr:nth-child(odd)>th { background-color: #FDFDFD; } @@ -192,7 +192,7 @@ opacity: 1; filter: alpha(opacity=100); } /*buttons*/ -.btn { font-weight: bold; +.btn { font-weight: bold; border-radius: 3px; padding: 9px 12px; } @@ -258,8 +258,8 @@ border-color: #0b4d78; } .form-actions .btn, -.form-actions div.btn-group { - margin-left: 10px; +.form-actions div.btn-group { + margin-left: 10px; } .form-actions .btn.btn-success:first-child { @@ -377,7 +377,7 @@ border: none; border-radius: 0; color: #fff; background-color: #9b9b9b; - + } .nav-tabs.nav-justified>li:first-child>a { border-radius: 3px 0 0 3px; @@ -406,7 +406,7 @@ font-weight: bold; ul.dropdown-menu, .twitter-typeahead .tt-menu { x-moz-box-shadow: 0 0 10px 2px rgba(0,0,0,.05); - x-webkit-box-shadow: 0 0 10px 2px rgba(0,0,0,.05); + x-webkit-box-shadow: 0 0 10px 2px rgba(0,0,0,.05); box-shadow: 0 0 10px 2px rgba(0,0,0,.05); } @@ -466,7 +466,7 @@ background-clip: padding-box; /*********************************************** - Dashboard + Dashboard ************************************************/ .in-bold { @@ -628,14 +628,14 @@ div.discount-group span { .navbar-default .navbar-nav > li > a:focus { color: #ffffff; } -.navbar-default .navbar-nav > .active > a, -.navbar-default .navbar-nav > .active > a:hover, +.navbar-default .navbar-nav > .active > a, +.navbar-default .navbar-nav > .active > a:hover, .navbar-default .navbar-nav > .active > a:focus { color: #ffffff; background-color: #3276b1; } -.navbar-default .navbar-nav > .open > a, -.navbar-default .navbar-nav > .open > a:hover, +.navbar-default .navbar-nav > .open > a, +.navbar-default .navbar-nav > .open > a:hover, .navbar-default .navbar-nav > .open > a:focus { color: #ffffff; background-color: #3276b1; @@ -649,8 +649,8 @@ div.discount-group span { border-top-color: #ffffff; border-bottom-color: #ffffff; } -.navbar-default .navbar-nav > .open > a .caret, -.navbar-default .navbar-nav > .open > a:hover .caret, +.navbar-default .navbar-nav > .open > a .caret, +.navbar-default .navbar-nav > .open > a:hover .caret, .navbar-default .navbar-nav > .open > a:focus .caret { border-top-color: #ffffff; border-bottom-color: #ffffff; @@ -689,7 +689,7 @@ div.fb_iframe_widget { display: inline; } div.fb_iframe_widget > span { - vertical-align: top !important; + vertical-align: top !important; } .pro-label { font-size:9px; @@ -728,12 +728,12 @@ box-shadow: 0px 0px 15px 0px rgba(0, 5, 5, 0.2); .plans-table .glyphicon-remove {background-color: #da4830;} .plans-table .glyphicon-ok {background-color: #35c156;} .plans-table .glyphicon-star {border-radius: 0; background-color: #2e2b2b; - display: block; - width: 60px; - height: 30px; - position: absolute; - top: -5px; - right: -20px; + display: block; + width: 60px; + height: 30px; + position: absolute; + top: -5px; + right: -20px; -webkit-transform: rotate(45deg); -moz-transform: rotate(45deg); -o-transform: rotate(45deg); @@ -763,11 +763,11 @@ box-shadow: 0px 0px 15px 0px rgba(0, 5, 5, 0.2); .ellipsis { overflow: hidden; white-space: nowrap; - text-overflow: ellipsis; + text-overflow: ellipsis; } .entityArchived { - color: #888 !important; + color: #888 !important; } .entityDeleted { @@ -775,12 +775,12 @@ box-shadow: 0px 0px 15px 0px rgba(0, 5, 5, 0.2); } -/* Custom, iPhone Retina */ +/* Custom, iPhone Retina */ @media only screen and (min-width : 320px) { - + } -/* Extra Small Devices, Phones */ +/* Extra Small Devices, Phones */ @media only screen and (min-width : 480px) { } @@ -828,7 +828,7 @@ box-shadow: 0px 0px 15px 0px rgba(0, 5, 5, 0.2); @media (max-width: 992px) { .hide-phone { display: none !important; - } + } } @media (max-width: 767px) { @@ -846,8 +846,8 @@ box-shadow: 0px 0px 15px 0px rgba(0, 5, 5, 0.2); .plans-table .free .cell { padding-right: 0; } .plans-table .free .cell:first-child {margin-right: 0;} .plans-table .cell div:first-child {margin-bottom: 5px;} - .plans-table .cell .cta {margin-bottom: 0 !important;} - .plans-table .pro {margin-top: 40px;} + .plans-table .cell .cta {margin-bottom: 0 !important;} + .plans-table .pro {margin-top: 40px;} } label[for=recommendedGateway_id2].radio{ @@ -976,14 +976,14 @@ button .glyphicon { .pro-plan-modal a.button { font-family: 'roboto_slabregular', Georgia, Times, serif; - background: #f38c4f; - background: -moz-linear-gradient(top, #f38c4f 0%, #db7134 100%); - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f38c4f), color-stop(100%,#db7134)); - background: -webkit-linear-gradient(top, #f38c4f 0%,#db7134 100%); - background: -o-linear-gradient(top, #f38c4f 0%,#db7134 100%); - background: -ms-linear-gradient(top, #f38c4f 0%,#db7134 100%); - background: linear-gradient(to bottom, #f38c4f 0%,#db7134 100%); - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f38c4f', endColorstr='#db7134',GradientType=0 ); + background: #f38c4f; + background: -moz-linear-gradient(top, #f38c4f 0%, #db7134 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f38c4f), color-stop(100%,#db7134)); + background: -webkit-linear-gradient(top, #f38c4f 0%,#db7134 100%); + background: -o-linear-gradient(top, #f38c4f 0%,#db7134 100%); + background: -ms-linear-gradient(top, #f38c4f 0%,#db7134 100%); + background: linear-gradient(to bottom, #f38c4f 0%,#db7134 100%); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f38c4f', endColorstr='#db7134',GradientType=0 ); text-shadow: 1px 1px 1px rgba(0, 0, 0, .25); width: 68%; margin-top: 20px; @@ -1046,7 +1046,7 @@ ul.user-accounts a:hover div.remove { .invoice-contact .tooltip-inner { text-align:left; - width: 350px; + width: 350px; } .smaller { @@ -1103,10 +1103,3 @@ div.panel-body div.panel-body { width: 100%; height: 100%; } - -.dropzone .fallback-doc{ - display:none; -} -.dropzone.dz-browser-not-supported .fallback-doc{ - display:block; -} \ No newline at end of file diff --git a/public/images/credit_cards/ach.png b/public/images/credit_cards/ach.png new file mode 100644 index 0000000000..16cf86bdb3 Binary files /dev/null and b/public/images/credit_cards/ach.png differ diff --git a/public/images/credit_cards/americanexpress.png b/public/images/credit_cards/americanexpress.png new file mode 100644 index 0000000000..492d40aff6 Binary files /dev/null and b/public/images/credit_cards/americanexpress.png differ diff --git a/public/images/credit_cards/carteblanche.png b/public/images/credit_cards/carteblanche.png new file mode 100644 index 0000000000..0b8f49aa7e Binary files /dev/null and b/public/images/credit_cards/carteblanche.png differ diff --git a/public/images/credit_cards/creditcardother.png b/public/images/credit_cards/creditcardother.png new file mode 100644 index 0000000000..0b8f49aa7e Binary files /dev/null and b/public/images/credit_cards/creditcardother.png differ diff --git a/public/images/credit_cards/dinerscard.png b/public/images/credit_cards/dinerscard.png new file mode 100644 index 0000000000..72e1808fb1 Binary files /dev/null and b/public/images/credit_cards/dinerscard.png differ diff --git a/public/images/credit_cards/discovercard.png b/public/images/credit_cards/discovercard.png new file mode 100644 index 0000000000..7e36dd7150 Binary files /dev/null and b/public/images/credit_cards/discovercard.png differ diff --git a/public/images/credit_cards/jcb.png b/public/images/credit_cards/jcb.png new file mode 100644 index 0000000000..9bb0cbafdc Binary files /dev/null and b/public/images/credit_cards/jcb.png differ diff --git a/public/images/credit_cards/laser.png b/public/images/credit_cards/laser.png new file mode 100644 index 0000000000..2f2417942b Binary files /dev/null and b/public/images/credit_cards/laser.png differ diff --git a/public/images/credit_cards/maestro.png b/public/images/credit_cards/maestro.png new file mode 100644 index 0000000000..38fdb4b7de Binary files /dev/null and b/public/images/credit_cards/maestro.png differ diff --git a/public/images/credit_cards/mastercard.png b/public/images/credit_cards/mastercard.png new file mode 100644 index 0000000000..af9b1d701c Binary files /dev/null and b/public/images/credit_cards/mastercard.png differ diff --git a/public/images/credit_cards/paypal.png b/public/images/credit_cards/paypal.png new file mode 100644 index 0000000000..4fad9d864c Binary files /dev/null and b/public/images/credit_cards/paypal.png differ diff --git a/public/images/credit_cards/solo.png b/public/images/credit_cards/solo.png new file mode 100644 index 0000000000..c236ecc0f7 Binary files /dev/null and b/public/images/credit_cards/solo.png differ diff --git a/public/images/credit_cards/switch.png b/public/images/credit_cards/switch.png new file mode 100644 index 0000000000..6ff522c6c1 Binary files /dev/null and b/public/images/credit_cards/switch.png differ diff --git a/public/images/credit_cards/unionpay.png b/public/images/credit_cards/unionpay.png new file mode 100644 index 0000000000..0aa7031c20 Binary files /dev/null and b/public/images/credit_cards/unionpay.png differ diff --git a/public/images/credit_cards/visacard.png b/public/images/credit_cards/visacard.png new file mode 100644 index 0000000000..ffd17c5a28 Binary files /dev/null and b/public/images/credit_cards/visacard.png differ diff --git a/public/images/plaid-logo.svg b/public/images/plaid-logo.svg new file mode 100644 index 0000000000..f18a73dfe1 --- /dev/null +++ b/public/images/plaid-logo.svg @@ -0,0 +1,12 @@ + + + + + + diff --git a/public/images/plaid-logowhite.svg b/public/images/plaid-logowhite.svg new file mode 100644 index 0000000000..d30d97299b --- /dev/null +++ b/public/images/plaid-logowhite.svg @@ -0,0 +1,12 @@ + + + + + + diff --git a/public/images/pro_plan/white_label_after.png b/public/images/pro_plan/white_label_after.png index e5201dffca..eb9a34decf 100644 Binary files a/public/images/pro_plan/white_label_after.png and b/public/images/pro_plan/white_label_after.png differ diff --git a/public/images/pro_plan/white_label_before.png b/public/images/pro_plan/white_label_before.png index 66a3ebde71..85700774c5 100644 Binary files a/public/images/pro_plan/white_label_before.png and b/public/images/pro_plan/white_label_before.png differ diff --git a/public/images/report_logo3.png b/public/images/report_logo3.png new file mode 100644 index 0000000000..6d56fca184 Binary files /dev/null and b/public/images/report_logo3.png differ diff --git a/public/index.php b/public/index.php index 37f19c23ab..928f8818c1 100755 --- a/public/index.php +++ b/public/index.php @@ -17,7 +17,6 @@ | loading any of our classes later on. It feels nice to relax. | */ - require __DIR__.'/../bootstrap/autoload.php'; /* diff --git a/public/js/pdf.pdfmake.js b/public/js/pdf.pdfmake.js index 8adf2e6424..a9624c5f3b 100644 --- a/public/js/pdf.pdfmake.js +++ b/public/js/pdf.pdfmake.js @@ -13,7 +13,7 @@ NINJA.TEMPLATES = { PHOTO:"10" }; -function GetPdfMake(invoice, javascript, callback) { +function GetPdfMake(invoice, javascript, callback) { javascript = NINJA.decodeJavascript(invoice, javascript); @@ -78,7 +78,7 @@ function GetPdfMake(invoice, javascript, callback) { val = NINJA.parseMarkdownText(val, false); } */ - + return val; } @@ -87,18 +87,25 @@ function GetPdfMake(invoice, javascript, callback) { var dd = JSON.parse(javascript, jsonCallBack); var designId = invoice.invoice_design_id; if (!invoice.features.remove_created_by) { - if (designId == NINJA.TEMPLATES.CLEAN || designId == NINJA.TEMPLATES.NORMAL) { - dd.footer.columns.push({image: logoImages.imageLogo1, alignment: 'right', width: 130, margin: [0, 0, 0, 0]}) - } else if (designId == NINJA.TEMPLATES.BOLD) { - dd.footer[1].columns.push({image: logoImages.imageLogo2, alignment: 'right', width: 130, margin: [0, -20, 20, 0]}) - } else if (designId == NINJA.TEMPLATES.MODERN) { - dd.footer[1].columns[0].stack.push({image: logoImages.imageLogo3, alignment: 'left', width: 130, margin: [40, 6, 0, 0]}); + var footer = (typeof dd.footer === 'function') ? dd.footer() : dd.footer; + if (footer) { + if (designId == NINJA.TEMPLATES.ELEGANT) { + footer[0].columns.push({image: logoImages.imageLogo1, alignment: 'right', width: 130, margin: [0, -20, 20, 0]}) + } else if (designId == NINJA.TEMPLATES.PLAYFUL) { + footer.push({image: logoImages.imageLogo1, alignment: 'right', width: 130, margin: [0, 0, 10, 10]}) + } else if (designId == NINJA.TEMPLATES.BOLD) { + footer[1].columns.push({image: logoImages.imageLogo2, alignment: 'right', width: 130, margin: [0, -20, 20, 0]}) + } else if (designId == NINJA.TEMPLATES.MODERN) { + footer[1].columns[0].stack.push({image: logoImages.imageLogo3, alignment: 'left', width: 130, margin: [40, 6, 0, 0]}); + } else { + footer.columns.push({image: logoImages.imageLogo1, alignment: 'right', width: 130, margin: [0, 0, 0, 0]}) + } } } - + // set page size dd.pageSize = invoice.account.page_size; - + pdfMake.fonts = {} fonts = window.invoiceFonts || invoice.invoice_fonts; @@ -119,15 +126,15 @@ function GetPdfMake(invoice, javascript, callback) { } } } - + if(!dd.defaultStyle)dd.defaultStyle = {font:NINJA.bodyFont}; else if(!dd.defaultStyle.font)dd.defaultStyle.font = NINJA.bodyFont; - + doc = pdfMake.createPdf(dd); doc.save = function(fileName) { this.download(fileName); }; - + return doc; } @@ -140,7 +147,7 @@ NINJA.decodeJavascript = function(invoice, javascript) var json = { 'accountName': account.name || ' ', 'accountLogo': window.accountLogo || blankImage, - 'accountDetails': NINJA.accountDetails(invoice), + 'accountDetails': NINJA.accountDetails(invoice), 'accountAddress': NINJA.accountAddress(invoice), 'invoiceDetails': NINJA.invoiceDetails(invoice), 'invoiceDetailsHeight': (NINJA.invoiceDetails(invoice).length * 16) + 16, @@ -153,7 +160,7 @@ NINJA.decodeJavascript = function(invoice, javascript) 'notesAndTerms': NINJA.notesAndTerms(invoice), 'subtotals': NINJA.subtotals(invoice), 'subtotalsHeight': (NINJA.subtotals(invoice).length * 16) + 16, - 'subtotalsWithoutBalance': NINJA.subtotals(invoice, true), + 'subtotalsWithoutBalance': NINJA.subtotals(invoice, true), 'subtotalsBalance': NINJA.subtotalsBalance(invoice), 'balanceDue': formatMoneyInvoice(invoice.balance_amount, invoice), 'invoiceFooter': NINJA.invoiceFooter(invoice), @@ -181,10 +188,10 @@ NINJA.decodeJavascript = function(invoice, javascript) javascript = javascript.replace(regExp, val); } - // search/replace labels + // search/replace labels var regExp = new RegExp('"\\$\\\w*?Label(UC)?(:)?(\\\?)?"', 'g'); - var matches = javascript.match(regExp); - + var matches = javascript.match(regExp); + if (matches) { for (var i=0; i lastIndex) { parts.push(line.substring(lastIndex, match.index)); @@ -810,4 +819,4 @@ NINJA.parseRegExpLine = function(line, regExp, formatter, groupText) } return line; -} \ No newline at end of file +} diff --git a/public/js/script.js b/public/js/script.js index a76e6d37cd..b5a4092e26 100644 --- a/public/js/script.js +++ b/public/js/script.js @@ -425,6 +425,34 @@ if (window.ko) { trigger: "hover" } }; + + ko.bindingHandlers.typeahead = { + init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { + var $element = $(element); + var allBindings = allBindingsAccessor(); + + $element.typeahead({ + highlight: true, + minLength: 0, + }, + { + name: 'data', + display: allBindings.key, + limit: 50, + source: searchData(allBindings.items, allBindings.key) + }).on('typeahead:change', function(element, datum, name) { + var value = valueAccessor(); + value(datum); + }); + }, + + update: function (element, valueAccessor) { + var value = ko.utils.unwrapObservable(valueAccessor()); + if (value) { + $(element).typeahead('val', value); + } + } + }; } function getContactDisplayName(contact) @@ -556,7 +584,7 @@ function formatAddress(city, state, zip, swap) { str += zip ? zip + ' ' : ''; str += city ? city : ''; str += (city && state) ? ', ' : (city ? ' ' : ''); - str += state; + str += state; } else { str += city ? city : ''; str += (city && state) ? ', ' : (state ? ' ' : ''); @@ -590,7 +618,7 @@ function calculateAmounts(invoice) { var hasTaxes = false; var taxes = {}; invoice.has_product_key = false; - + // Bold designs currently breaks w/o the product column if (invoice.invoice_design_id == 2) { invoice.has_product_key = true; @@ -638,7 +666,7 @@ function calculateAmounts(invoice) { lineTotal -= roundToTwo(lineTotal * (invoice.discount/100)); } } - + var taxAmount1 = roundToTwo(lineTotal * taxRate1 / 100); if (taxAmount1) { var key = taxName1 + taxRate1; @@ -715,7 +743,7 @@ function calculateAmounts(invoice) { invoice.tax_amount1 = taxAmount1; invoice.tax_amount2 = taxAmount2; invoice.item_taxes = taxes; - + if (NINJA.parseFloat(invoice.partial)) { invoice.balance_amount = roundToTwo(invoice.partial); } else { @@ -1040,9 +1068,9 @@ function truncate(string, length){ } }; -// Show/hide the 'Select' option in the datalists +// Show/hide the 'Select' option in the datalists function actionListHandler() { - $('tbody tr').mouseover(function() { + $('tbody tr .tr-action').closest('tr').mouseover(function() { $(this).closest('tr').find('.tr-action').show(); $(this).closest('tr').find('.tr-status').hide(); }).mouseout(function() { @@ -1106,8 +1134,8 @@ function searchData(data, key, fuzzy) { } cb(matches); } -}; +}; function escapeRegExp(str) { return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); -} \ No newline at end of file +} diff --git a/resources/lang/ca/auth.php b/resources/lang/ca/auth.php new file mode 100644 index 0000000000..ee38289136 --- /dev/null +++ b/resources/lang/ca/auth.php @@ -0,0 +1,19 @@ + 'Aquestes credencials no concorden amb els nostres registres.', + 'throttle' => "Heu superat el nombre màxim d'intents d'accés. Per favor, torna a intentar-ho en :seconds segons.", + +]; diff --git a/resources/lang/ca/pagination.php b/resources/lang/ca/pagination.php new file mode 100644 index 0000000000..df9bf4a288 --- /dev/null +++ b/resources/lang/ca/pagination.php @@ -0,0 +1,19 @@ + '« Anterior', + 'next' => 'Següent »', + +]; diff --git a/resources/lang/ca/passwords.php b/resources/lang/ca/passwords.php new file mode 100644 index 0000000000..6d5bcd77b3 --- /dev/null +++ b/resources/lang/ca/passwords.php @@ -0,0 +1,22 @@ + 'Les contrasenyes han de contenir almenys 6 caràcters i coincidir.', + 'reset' => "La contrasenya s'ha restablert!", + 'sent' => 'Recordatori de contrasenya enviat!', + 'token' => 'Aquest token de recuperació de contrasenya és invàlid.', + 'user' => 'No podem trobar a un usuari amb aquest correu electrònic.', + +]; diff --git a/resources/lang/ca/texts.php b/resources/lang/ca/texts.php new file mode 100644 index 0000000000..ff3ea396cb --- /dev/null +++ b/resources/lang/ca/texts.php @@ -0,0 +1,1369 @@ + 'Organization', + 'name' => 'Name', + 'website' => 'Website', + 'work_phone' => 'Phone', + 'address' => 'Address', + 'address1' => 'Street', + 'address2' => 'Apt/Suite', + 'city' => 'City', + 'state' => 'State/Province', + 'postal_code' => 'Postal Code', + 'country_id' => 'Country', + 'contacts' => 'Contacts', + 'first_name' => 'First Name', + 'last_name' => 'Last Name', + 'phone' => 'Phone', + 'email' => 'Email', + 'additional_info' => 'Additional Info', + 'payment_terms' => 'Payment Terms', + 'currency_id' => 'Currency', + 'size_id' => 'Company Size', + 'industry_id' => 'Industry', + 'private_notes' => 'Private Notes', + 'invoice' => 'Invoice', + 'client' => 'Client', + 'invoice_date' => 'Invoice Date', + 'due_date' => 'Due Date', + 'invoice_number' => 'Invoice Number', + 'invoice_number_short' => 'Invoice #', + 'po_number' => 'PO Number', + 'po_number_short' => 'PO #', + 'frequency_id' => 'How Often', + 'discount' => 'Discount', + 'taxes' => 'Taxes', + 'tax' => 'Tax', + 'item' => 'Item', + 'description' => 'Description', + 'unit_cost' => 'Unit Cost', + 'quantity' => 'Quantity', + 'line_total' => 'Line Total', + 'subtotal' => 'Subtotal', + 'paid_to_date' => 'Paid to Date', + 'balance_due' => 'Balance Due', + 'invoice_design_id' => 'Design', + 'terms' => 'Terms', + 'your_invoice' => 'Your Invoice', + 'remove_contact' => 'Remove contact', + 'add_contact' => 'Add contact', + 'create_new_client' => 'Create new client', + 'edit_client_details' => 'Edit client details', + 'enable' => 'Enable', + 'learn_more' => 'Learn more', + 'manage_rates' => 'Manage rates', + 'note_to_client' => 'Note to Client', + 'invoice_terms' => 'Invoice Terms', + 'save_as_default_terms' => 'Save as default terms', + 'download_pdf' => 'Download PDF', + 'pay_now' => 'Pay Now', + 'save_invoice' => 'Save Invoice', + 'clone_invoice' => 'Clone Invoice', + 'archive_invoice' => 'Archive Invoice', + 'delete_invoice' => 'Delete Invoice', + 'email_invoice' => 'Email Invoice', + 'enter_payment' => 'Enter Payment', + 'tax_rates' => 'Tax Rates', + 'rate' => 'Rate', + 'settings' => 'Settings', + 'enable_invoice_tax' => 'Enable specifying an invoice tax', + 'enable_line_item_tax' => 'Enable specifying line item taxes', + 'dashboard' => 'Dashboard', + 'clients' => 'Clients', + 'invoices' => 'Invoices', + 'payments' => 'Payments', + 'credits' => 'Credits', + 'history' => 'History', + 'search' => 'Search', + 'sign_up' => 'Sign Up', + 'guest' => 'Guest', + 'company_details' => 'Company Details', + 'online_payments' => 'Online Payments', + 'notifications' => 'Email Notifications', + 'import_export' => 'Import | Export', + 'done' => 'Done', + 'save' => 'Save', + 'create' => 'Create', + 'upload' => 'Upload', + 'import' => 'Import', + 'download' => 'Download', + 'cancel' => 'Cancel', + 'close' => 'Close', + 'provide_email' => 'Please provide a valid email address', + 'powered_by' => 'Powered by', + 'no_items' => 'No items', + 'recurring_invoices' => 'Recurring Invoices', + 'recurring_help' => '

    Automatically send clients the same invoices weekly, bi-monthly, monthly, quarterly or annually.

    +

    Use :MONTH, :QUARTER or :YEAR for dynamic dates. Basic math works as well, for example :MONTH-1.

    +

    Examples of dynamic invoice variables:

    +
      +
    • "Gym membership for the month of :MONTH" => "Gym membership for the month of July"
    • +
    • ":YEAR+1 yearly subscription" => "2015 Yearly Subscription"
    • +
    • "Retainer payment for :QUARTER+1" => "Retainer payment for Q2"
    • +
    ', + 'in_total_revenue' => 'in total revenue', + 'billed_client' => 'billed client', + 'billed_clients' => 'billed clients', + 'active_client' => 'active client', + 'active_clients' => 'active clients', + 'invoices_past_due' => 'Invoices Past Due', + 'upcoming_invoices' => 'Upcoming Invoices', + 'average_invoice' => 'Average Invoice', + 'archive' => 'Archive', + 'delete' => 'Delete', + 'archive_client' => 'Archive Client', + 'delete_client' => 'Delete Client', + 'archive_payment' => 'Archive Payment', + 'delete_payment' => 'Delete Payment', + 'archive_credit' => 'Archive Credit', + 'delete_credit' => 'Delete Credit', + 'show_archived_deleted' => 'Show archived/deleted', + 'filter' => 'Filter', + 'new_client' => 'New Client', + 'new_invoice' => 'New Invoice', + 'new_payment' => 'New Payment', + 'new_credit' => 'New Credit', + 'contact' => 'Contact', + 'date_created' => 'Date Created', + 'last_login' => 'Last Login', + 'balance' => 'Balance', + 'action' => 'Action', + 'status' => 'Status', + 'invoice_total' => 'Invoice Total', + 'frequency' => 'Frequency', + 'start_date' => 'Start Date', + 'end_date' => 'End Date', + 'transaction_reference' => 'Transaction Reference', + 'method' => 'Method', + 'payment_amount' => 'Payment Amount', + 'payment_date' => 'Payment Date', + 'credit_amount' => 'Credit Amount', + 'credit_balance' => 'Credit Balance', + 'credit_date' => 'Credit Date', + 'empty_table' => 'No data available in table', + 'select' => 'Select', + 'edit_client' => 'Edit Client', + 'edit_invoice' => 'Edit Invoice', + 'create_invoice' => 'Create Invoice', + 'enter_credit' => 'Enter Credit', + 'last_logged_in' => 'Last logged in', + 'details' => 'Details', + 'standing' => 'Standing', + 'credit' => 'Credit', + 'activity' => 'Activity', + 'date' => 'Date', + 'message' => 'Message', + 'adjustment' => 'Adjustment', + 'are_you_sure' => 'Are you sure?', + 'payment_type_id' => 'Payment Type', + 'amount' => 'Amount', + 'work_email' => 'Email', + 'language_id' => 'Language', + 'timezone_id' => 'Timezone', + 'date_format_id' => 'Date Format', + 'datetime_format_id' => 'Date/Time Format', + 'users' => 'Users', + 'localization' => 'Localization', + 'remove_logo' => 'Remove logo', + 'logo_help' => 'Supported: JPEG, GIF and PNG', + 'payment_gateway' => 'Payment Gateway', + 'gateway_id' => 'Gateway', + 'email_notifications' => 'Email Notifications', + 'email_sent' => 'Email me when an invoice is sent', + 'email_viewed' => 'Email me when an invoice is viewed', + 'email_paid' => 'Email me when an invoice is paid', + 'site_updates' => 'Site Updates', + 'custom_messages' => 'Custom Messages', + 'default_email_footer' => 'Set default email signature', + 'select_file' => 'Please select a file', + 'first_row_headers' => 'Use first row as headers', + 'column' => 'Column', + 'sample' => 'Sample', + 'import_to' => 'Import to', + 'client_will_create' => 'client will be created', + 'clients_will_create' => 'clients will be created', + 'email_settings' => 'Email Settings', + 'client_view_styling' => 'Client View Styling', + 'pdf_email_attachment' => 'Attach PDFs', + 'custom_css' => 'Custom CSS', + 'import_clients' => 'Import Client Data', + 'csv_file' => 'CSV file', + 'export_clients' => 'Export Client Data', + 'created_client' => 'Successfully created client', + 'created_clients' => 'Successfully created :count client(s)', + 'updated_settings' => 'Successfully updated settings', + 'removed_logo' => 'Successfully removed logo', + 'sent_message' => 'Successfully sent message', + 'invoice_error' => 'Please make sure to select a client and correct any errors', + 'limit_clients' => 'Sorry, this will exceed the limit of :count clients', + 'payment_error' => 'There was an error processing your payment. Please try again later.', + 'registration_required' => 'Please sign up to email an invoice', + 'confirmation_required' => 'Please confirm your email address', + 'updated_client' => 'Successfully updated client', + 'created_client' => 'Successfully created client', + 'archived_client' => 'Successfully archived client', + 'archived_clients' => 'Successfully archived :count clients', + 'deleted_client' => 'Successfully deleted client', + 'deleted_clients' => 'Successfully deleted :count clients', + 'updated_invoice' => 'Successfully updated invoice', + 'created_invoice' => 'Successfully created invoice', + 'cloned_invoice' => 'Successfully cloned invoice', + 'emailed_invoice' => 'Successfully emailed invoice', + 'and_created_client' => 'and created client', + 'archived_invoice' => 'Successfully archived invoice', + 'archived_invoices' => 'Successfully archived :count invoices', + 'deleted_invoice' => 'Successfully deleted invoice', + 'deleted_invoices' => 'Successfully deleted :count invoices', + 'created_payment' => 'Successfully created payment', + 'created_payments' => 'Successfully created :count payment(s)', + 'archived_payment' => 'Successfully archived payment', + 'archived_payments' => 'Successfully archived :count payments', + 'deleted_payment' => 'Successfully deleted payment', + 'deleted_payments' => 'Successfully deleted :count payments', + 'applied_payment' => 'Successfully applied payment', + 'created_credit' => 'Successfully created credit', + 'archived_credit' => 'Successfully archived credit', + 'archived_credits' => 'Successfully archived :count credits', + 'deleted_credit' => 'Successfully deleted credit', + 'deleted_credits' => 'Successfully deleted :count credits', + 'imported_file' => 'Successfully imported file', + 'updated_vendor' => 'Successfully updated vendor', + 'created_vendor' => 'Successfully created vendor', + 'archived_vendor' => 'Successfully archived vendor', + 'archived_vendors' => 'Successfully archived :count vendors', + 'deleted_vendor' => 'Successfully deleted vendor', + 'deleted_vendors' => 'Successfully deleted :count vendors', + 'confirmation_subject' => 'Invoice Ninja Account Confirmation', + 'confirmation_header' => 'Account Confirmation', + 'confirmation_message' => 'Please access the link below to confirm your account.', + 'invoice_subject' => 'New invoice :invoice from :account', + 'invoice_message' => 'To view your invoice for :amount, click the link below.', + 'payment_subject' => 'Payment Received', + 'payment_message' => 'Thank you for your payment of :amount.', + 'email_salutation' => 'Dear :name,', + 'email_signature' => 'Regards,', + 'email_from' => 'The Invoice Ninja Team', + 'invoice_link_message' => 'To view the invoice click the link below:', + 'notification_invoice_paid_subject' => 'Invoice :invoice was paid by :client', + 'notification_invoice_sent_subject' => 'Invoice :invoice was sent to :client', + 'notification_invoice_viewed_subject' => 'Invoice :invoice was viewed by :client', + 'notification_invoice_paid' => 'A payment of :amount was made by client :client towards Invoice :invoice.', + '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.', + 'reset_password' => 'You can reset your account password by clicking the following button:', + 'secure_payment' => 'Secure Payment', + 'card_number' => 'Card Number', + 'expiration_month' => 'Expiration Month', + 'expiration_year' => 'Expiration Year', + 'cvv' => 'CVV', + 'logout' => 'Log Out', + 'sign_up_to_save' => 'Sign up to save your work', + 'agree_to_terms' => 'I agree to the Invoice Ninja :terms', + 'terms_of_service' => 'Terms of Service', + 'email_taken' => 'The email address is already registered', + 'working' => 'Working', + 'success' => 'Success', + '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.', + 'password' => 'Password', + 'pro_plan_product' => 'Pro Plan', + 'pro_plan_success' => 'Thanks for choosing Invoice Ninja\'s Pro plan!

     
    + Next Steps

    A payable invoice has been sent to the email + address associated with your account. To unlock all of the awesome + Pro features, please follow the instructions on the invoice to pay + for a year of Pro-level invoicing.

    + Can\'t find the invoice? Need further assistance? We\'re happy to help + -- email us at contact@invoiceninja.com', + 'unsaved_changes' => 'You have unsaved changes', + 'custom_fields' => 'Custom Fields', + 'company_fields' => 'Company Fields', + 'client_fields' => 'Client Fields', + 'field_label' => 'Field Label', + 'field_value' => 'Field Value', + 'edit' => 'Edit', + 'set_name' => 'Set your company name', + 'view_as_recipient' => 'View as recipient', + 'product_library' => 'Product Library', + 'product' => 'Product', + 'products' => 'Product Library', + 'fill_products' => 'Auto-fill products', + 'fill_products_help' => 'Selecting a product will automatically fill in the description and cost', + 'update_products' => 'Auto-update products', + 'update_products_help' => 'Updating an invoice will automatically update the product library', + 'create_product' => 'Add Product', + 'edit_product' => 'Edit Product', + 'archive_product' => 'Archive Product', + 'updated_product' => 'Successfully updated product', + 'created_product' => 'Successfully created product', + 'archived_product' => 'Successfully archived product', + 'pro_plan_custom_fields' => ':link to enable custom fields by joining the Pro Plan', + 'advanced_settings' => 'Advanced Settings', + 'pro_plan_advanced_settings' => ':link to enable the advanced settings by joining the Pro Plan', + 'invoice_design' => 'Invoice Design', + 'specify_colors' => 'Specify colors', + 'specify_colors_label' => 'Select the colors used in the invoice', + 'chart_builder' => 'Chart Builder', + 'ninja_email_footer' => 'Use :site to invoice your clients and get paid online for free!', + 'go_pro' => 'Go Pro', + 'quote' => 'Quote', + 'quotes' => 'Quotes', + 'quote_number' => 'Quote Number', + 'quote_number_short' => 'Quote #', + 'quote_date' => 'Quote Date', + 'quote_total' => 'Quote Total', + 'your_quote' => 'Your Quote', + 'total' => 'Total', + 'clone' => 'Clone', + 'new_quote' => 'New Quote', + 'create_quote' => 'Create Quote', + 'edit_quote' => 'Edit Quote', + 'archive_quote' => 'Archive Quote', + 'delete_quote' => 'Delete Quote', + 'save_quote' => 'Save Quote', + 'email_quote' => 'Email Quote', + 'clone_quote' => 'Clone Quote', + 'convert_to_invoice' => 'Convert to Invoice', + 'view_invoice' => 'View Invoice', + 'view_client' => 'View Client', + 'view_quote' => 'View Quote', + 'updated_quote' => 'Successfully updated quote', + 'created_quote' => 'Successfully created quote', + 'cloned_quote' => 'Successfully cloned quote', + 'emailed_quote' => 'Successfully emailed quote', + 'archived_quote' => 'Successfully archived quote', + 'archived_quotes' => 'Successfully archived :count quotes', + 'deleted_quote' => 'Successfully deleted quote', + 'deleted_quotes' => 'Successfully deleted :count quotes', + 'converted_to_invoice' => 'Successfully converted quote to invoice', + 'quote_subject' => 'New quote $quote from :account', + 'quote_message' => 'To view your quote for :amount, click the link below.', + 'quote_link_message' => 'To view your client quote click the link below:', + 'notification_quote_sent_subject' => 'Quote :invoice was sent to :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_viewed' => 'The following client :client viewed Quote :invoice for :amount.', + 'session_expired' => 'Your session has expired.', + 'invoice_fields' => 'Invoice Fields', + 'invoice_options' => 'Invoice Options', + '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_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.', + 'charge_taxes' => 'Charge taxes', + 'user_management' => 'User Management', + 'add_user' => 'Add User', + 'send_invite' => 'Send invitation', + 'sent_invite' => 'Successfully sent invitation', + 'updated_user' => 'Successfully updated user', + 'invitation_message' => 'You\'ve been invited by :invitor. ', + 'register_to_add_user' => 'Please sign up to add a user', + 'user_state' => 'State', + 'edit_user' => 'Edit User', + 'delete_user' => 'Delete User', + 'active' => 'Active', + 'pending' => 'Pending', + 'deleted_user' => 'Successfully deleted user', + '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_recurring_email_invoice' => 'Are you sure you want this invoice emailed?', + 'cancel_account' => 'Delete Account', + 'cancel_account_message' => 'Warning: This will permanently erase all of your data, there is no undo.', + 'go_back' => 'Go Back', + 'data_visualizations' => 'Data Visualizations', + 'sample_data' => 'Sample data shown', + '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', + 'invoice_settings' => 'Invoice Settings', + 'invoice_number_prefix' => 'Invoice Number Prefix', + 'invoice_number_counter' => 'Invoice Number Counter', + 'quote_number_prefix' => 'Quote Number Prefix', + 'quote_number_counter' => 'Quote Number Counter', + 'share_invoice_counter' => 'Share invoice counter', + 'invoice_issued_to' => 'Invoice issued to', + 'invalid_counter' => 'To prevent a possible conflict please set either an invoice or quote number prefix', + 'mark_sent' => 'Mark Sent', + 'gateway_help_1' => ':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_27' => ':link to sign up for TwoCheckout.', + 'more_designs' => 'More designs', + 'more_designs_title' => 'Additional Invoice Designs', + 'more_designs_cloud_header' => 'Go Pro for more invoice designs', + 'more_designs_cloud_text' => '', + 'more_designs_self_host_text' => '', + 'buy' => 'Buy', + 'bought_designs' => 'Successfully added additional invoice designs', + 'sent' => 'sent', + 'vat_number' => 'VAT Number', + 'timesheets' => 'Timesheets', + '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_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.', + 'id_number' => 'ID Number', + 'white_label_link' => 'White label', + 'white_label_header' => 'White Label', + 'bought_white_label' => 'Successfully enabled white label license', + 'white_labeled' => 'White labeled', + 'restore' => 'Restore', + 'restore_invoice' => 'Restore Invoice', + 'restore_quote' => 'Restore Quote', + 'restore_client' => 'Restore Client', + 'restore_credit' => 'Restore Credit', + 'restore_payment' => 'Restore Payment', + 'restored_invoice' => 'Successfully restored invoice', + 'restored_quote' => 'Successfully restored quote', + 'restored_client' => 'Successfully restored client', + 'restored_payment' => 'Successfully restored payment', + 'restored_credit' => 'Successfully restored credit', + 'reason_for_canceling' => 'Help us improve our site by telling us why you\'re leaving.', + 'discount_percent' => 'Percent', + 'discount_amount' => 'Amount', + 'invoice_history' => 'Invoice History', + 'quote_history' => 'Quote History', + 'current_version' => 'Current version', + 'select_version' => 'Select version', + 'view_history' => 'View History', + 'edit_payment' => 'Edit Payment', + 'updated_payment' => 'Successfully updated payment', + 'deleted' => 'Deleted', + 'restore_user' => 'Restore User', + 'restored_user' => 'Successfully restored user', + 'show_deleted_users' => 'Show deleted users', + 'email_templates' => 'Email Templates', + 'invoice_email' => 'Invoice Email', + 'payment_email' => 'Payment Email', + 'quote_email' => 'Quote Email', + 'reset_all' => 'Reset All', + 'approve' => 'Approve', + '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_1' => 'Disabled', + 'token_billing_2' => 'Opt-in - checkbox is shown but not selected', + 'token_billing_3' => 'Opt-out - checkbox is shown and selected', + 'token_billing_4' => 'Always', + 'token_billing_checkbox' => 'Store credit card details', + 'view_in_gateway' => 'View in :gateway', + 'use_card_on_file' => 'Use Card on File', + 'edit_payment_details' => 'Edit payment details', + 'token_billing' => 'Save card details', + 'token_billing_secure' => 'The data is stored securely by :link', + 'support' => 'Support', + 'contact_information' => 'Contact Information', + '256_encryption' => '256-Bit Encryption', + 'amount_due' => 'Amount due', + 'billing_address' => 'Billing Address', + 'billing_method' => 'Billing Method', + 'order_overview' => 'Order overview', + '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.', + 'invoice_footer' => 'Invoice Footer', + 'save_as_default_footer' => 'Save as default footer', + 'token_management' => 'Token Management', + 'tokens' => 'Tokens', + 'add_token' => 'Add Token', + 'show_deleted_tokens' => 'Show deleted tokens', + 'deleted_token' => 'Successfully deleted token', + 'created_token' => 'Successfully created token', + 'updated_token' => 'Successfully updated token', + 'edit_token' => 'Edit Token', + 'delete_token' => 'Delete Token', + 'token' => 'Token', + 'add_gateway' => 'Add Gateway', + 'delete_gateway' => 'Delete Gateway', + 'edit_gateway' => 'Edit Gateway', + 'updated_gateway' => 'Successfully updated gateway', + 'created_gateway' => 'Successfully created gateway', + 'deleted_gateway' => 'Successfully deleted gateway', + 'pay_with_paypal' => 'PayPal', + 'pay_with_card' => 'Credit Card', + 'change_password' => 'Change password', + 'current_password' => 'Current password', + 'new_password' => 'New password', + 'confirm_password' => 'Confirm password', + 'password_error_incorrect' => 'The current password is incorrect.', + 'password_error_invalid' => 'The new password is invalid.', + 'updated_password' => 'Successfully updated password', + 'api_tokens' => 'API Tokens', + 'users_and_tokens' => 'Users & Tokens', + 'account_login' => 'Account Login', + 'recover_password' => 'Recover your password', + 'forgot_password' => 'Forgot your password?', + 'email_address' => 'Email address', + 'lets_go' => 'Let\'s go', + 'password_recovery' => 'Password Recovery', + 'send_email' => 'Send email', + 'set_password' => 'Set Password', + 'converted' => 'Converted', + 'email_approved' => 'Email me when a quote is approved', + 'notification_quote_approved_subject' => 'Quote :invoice was approved by :client', + 'notification_quote_approved' => 'The following client :client approved Quote :invoice for :amount.', + 'resend_confirmation' => 'Resend confirmation email', + 'confirmation_resent' => 'The confirmation email was resent', + 'gateway_help_42' => ':link to sign up for BitPay.
    Note: use a Legacy API Key, not an API token.', + 'payment_type_credit_card' => 'Credit Card', + 'payment_type_paypal' => 'PayPal', + 'payment_type_bitcoin' => 'Bitcoin', + 'knowledge_base' => 'Knowledge Base', + 'partial' => 'Partial', + 'partial_remaining' => ':partial of :balance', + 'more_fields' => 'More Fields', + 'less_fields' => 'Less Fields', + 'client_name' => 'Client Name', + 'pdf_settings' => 'PDF Settings', + 'product_settings' => 'Product Settings', + 'auto_wrap' => 'Auto Line Wrap', + 'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.', + 'view_documentation' => 'View Documentation', + '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.', + 'rows' => 'rows', + 'www' => 'www', + 'logo' => 'Logo', + 'subdomain' => 'Subdomain', + 'provide_name_or_email' => 'Please provide a contact name or email', + 'charts_and_reports' => 'Charts & Reports', + 'chart' => 'Chart', + 'report' => 'Report', + 'group_by' => 'Group by', + 'paid' => 'Paid', + 'enable_report' => 'Report', + 'enable_chart' => 'Chart', + 'totals' => 'Totals', + 'run' => 'Run', + 'export' => 'Export', + 'documentation' => 'Documentation', + 'zapier' => 'Zapier', + 'recurring' => 'Recurring', + 'last_invoice_sent' => 'Last invoice sent :date', + 'processed_updates' => 'Successfully completed update', + 'tasks' => 'Tasks', + 'new_task' => 'New Task', + 'start_time' => 'Start Time', + 'created_task' => 'Successfully created task', + 'updated_task' => 'Successfully updated task', + 'edit_task' => 'Edit Task', + 'archive_task' => 'Archive Task', + 'restore_task' => 'Restore Task', + 'delete_task' => 'Delete Task', + 'stop_task' => 'Stop Task', + 'time' => 'Time', + 'start' => 'Start', + 'stop' => 'Stop', + 'now' => 'Now', + 'timer' => 'Timer', + 'manual' => 'Manual', + 'date_and_time' => 'Date & Time', + 'second' => 'second', + 'seconds' => 'seconds', + 'minute' => 'minute', + 'minutes' => 'minutes', + 'hour' => 'hour', + 'hours' => 'hours', + 'task_details' => 'Task Details', + 'duration' => 'Duration', + 'end_time' => 'End Time', + 'end' => 'End', + 'invoiced' => 'Invoiced', + 'logged' => 'Logged', + 'running' => 'Running', + 'task_error_multiple_clients' => 'The tasks can\'t belong to different clients', + 'task_error_running' => 'Please stop running tasks first', + 'task_error_invoiced' => 'Tasks have already been invoiced', + 'restored_task' => 'Successfully restored task', + 'archived_task' => 'Successfully archived task', + 'archived_tasks' => 'Successfully archived :count tasks', + 'deleted_task' => 'Successfully deleted task', + 'deleted_tasks' => 'Successfully deleted :count tasks', + 'create_task' => 'Create Task', + 'stopped_task' => 'Successfully stopped task', + 'invoice_task' => 'Invoice Task', + 'invoice_labels' => 'Invoice Labels', + 'prefix' => 'Prefix', + 'counter' => 'Counter', + 'payment_type_dwolla' => 'Dwolla', + 'gateway_help_43' => ':link to sign up for Dwolla', + 'partial_value' => 'Must be greater than zero and less than the total', + 'more_actions' => 'More Actions', + 'pro_plan_title' => 'NINJA PRO', + 'pro_plan_call_to_action' => 'Upgrade Now!', + 'pro_plan_feature1' => 'Create Unlimited Clients', + 'pro_plan_feature2' => 'Access to 10 Beautiful Invoice Designs', + 'pro_plan_feature3' => 'Custom URLs - "YourBrand.InvoiceNinja.com"', + 'pro_plan_feature4' => 'Remove "Created by Invoice Ninja"', + 'pro_plan_feature5' => 'Multi-user Access & Activity Tracking', + 'pro_plan_feature6' => 'Create Quotes & Pro-forma Invoices', + 'pro_plan_feature7' => 'Customize Invoice Field Titles & Numbering', + 'pro_plan_feature8' => 'Option to Attach PDFs to Client Emails', + 'resume' => 'Resume', + 'break_duration' => 'Break', + 'edit_details' => 'Edit Details', + 'work' => 'Work', + 'timezone_unset' => 'Please :link to set your timezone', + 'click_here' => 'click here', + 'email_receipt' => 'Email payment receipt to the client', + 'created_payment_emailed_client' => 'Successfully created payment and emailed client', + 'add_company' => 'Add Company', + 'untitled' => 'Untitled', + 'new_company' => 'New Company', + 'associated_accounts' => 'Successfully linked accounts', + 'unlinked_account' => 'Successfully unlinked accounts', + 'login' => 'Login', + 'or' => 'or', + 'email_error' => 'There was a problem sending the email', + 'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.', + 'payment_terms_help' => 'Sets the default invoice due date', + 'unlink_account' => 'Unlink Account', + 'unlink' => 'Unlink', + 'show_address' => 'Show Address', + 'show_address_help' => 'Require client to provide their billing address', + 'update_address' => 'Update Address', + 'update_address_help' => 'Update client\'s address with provided details', + 'times' => 'Times', + 'set_now' => 'Set to now', + 'dark_mode' => 'Dark Mode', + 'dark_mode_help' => 'Show white text on black background', + 'add_to_invoice' => 'Add to invoice :invoice', + 'create_new_invoice' => 'Create new invoice', + 'task_errors' => 'Please correct any overlapping times', + 'from' => 'From', + 'to' => 'To', + 'font_size' => 'Font Size', + 'primary_color' => 'Primary Color', + 'secondary_color' => 'Secondary Color', + 'customize_design' => 'Customize Design', + 'content' => 'Content', + 'styles' => 'Styles', + 'defaults' => 'Defaults', + 'margins' => 'Margins', + 'header' => 'Header', + 'footer' => 'Footer', + 'custom' => 'Custom', + 'invoice_to' => 'Invoice to', + 'invoice_no' => 'Invoice No.', + 'recent_payments' => 'Recent Payments', + 'outstanding' => 'Outstanding', + 'manage_companies' => 'Manage Companies', + 'total_revenue' => 'Total Revenue', + 'current_user' => 'Current User', + 'new_recurring_invoice' => 'New Recurring Invoice', + 'recurring_invoice' => 'Recurring Invoice', + 'recurring_too_soon' => 'It\'s too soon to create the next recurring invoice, it\'s scheduled for :date', + 'created_by_invoice' => 'Created by :invoice', + 'primary_user' => 'Primary User', + 'help' => 'Help', + 'customize_help' => '

    We use pdfmake to define the invoice designs declaratively. The pdfmake playground provide\'s a great way to see the library in action.

    +

    You can access a child property using dot notation. For example to show the client name you could use $client.name.

    +

    If you need help figuring something out post a question to our support forum with the design you\'re using.

    ', + 'invoice_due_date' => 'Due Date', + 'quote_due_date' => 'Valid Until', + 'valid_until' => 'Valid Until', + 'reset_terms' => 'Reset terms', + 'reset_footer' => 'Reset footer', + 'invoices_sent' => ':count invoice sent|:count invoices sent', + 'status_draft' => 'Draft', + 'status_sent' => 'Sent', + 'status_viewed' => 'Viewed', + 'status_partial' => 'Partial', + 'status_paid' => 'Paid', + 'show_line_item_tax' => 'Display line item taxes inline', + 'iframe_url' => 'Website', + '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.', + 'auto_bill' => 'Auto Bill', + 'military_time' => '24 Hour Time', + 'last_sent' => 'Last Sent', + 'reminder_emails' => 'Reminder Emails', + 'templates_and_reminders' => 'Templates & Reminders', + 'subject' => 'Subject', + 'body' => 'Body', + 'first_reminder' => 'First Reminder', + 'second_reminder' => 'Second Reminder', + 'third_reminder' => 'Third Reminder', + 'num_days_reminder' => 'Days after due date', + 'reminder_subject' => 'Reminder: Invoice :invoice from :account', + 'reset' => 'Reset', + 'invoice_not_found' => 'The requested invoice is not available', + 'referral_program' => 'Referral Program', + 'referral_code' => 'Referral URL', + 'last_sent_on' => 'Sent Last: :date', + 'page_expire' => 'This page will expire soon, :click_here to keep working', + 'upcoming_quotes' => 'Upcoming Quotes', + 'expired_quotes' => 'Expired Quotes', + 'sign_up_using' => 'Sign up using', + 'invalid_credentials' => 'These credentials do not match our records', + 'show_all_options' => 'Show all options', + 'user_details' => 'User Details', + 'oneclick_login' => 'One-Click Login', + 'disable' => 'Disable', + 'invoice_quote_number' => 'Invoice and Quote Numbers', + 'invoice_charges' => 'Invoice Charges', + 'notification_invoice_bounced' => 'We were unable to deliver Invoice :invoice to :contact.', + 'notification_invoice_bounced_subject' => 'Unable to deliver Invoice :invoice', + 'notification_quote_bounced' => 'We were unable to deliver Quote :invoice to :contact.', + 'notification_quote_bounced_subject' => 'Unable to deliver Quote :invoice', + 'custom_invoice_link' => 'Custom Invoice Link', + 'total_invoiced' => 'Total Invoiced', + 'open_balance' => 'Open Balance', + 'verify_email' => 'Please visit the link in the account confirmation email to verify your email address.', + 'basic_settings' => 'Basic Settings', + 'pro' => 'Pro', + 'gateways' => 'Payment Gateways', + 'next_send_on' => 'Send Next: :date', + 'no_longer_running' => 'This invoice is not scheduled to run', + 'general_settings' => 'General Settings', + 'customize' => 'Customize', + 'oneclick_login_help' => 'Connect an account to login without a password', + 'referral_code_help' => 'Earn money by sharing our app online', + 'enable_with_stripe' => 'Enable | Requires Stripe', + 'tax_settings' => 'Tax Settings', + 'create_tax_rate' => 'Add Tax Rate', + 'updated_tax_rate' => 'Successfully updated tax rate', + 'created_tax_rate' => 'Successfully created tax rate', + 'edit_tax_rate' => 'Edit tax rate', + 'archive_tax_rate' => 'Archive Tax Rate', + 'archived_tax_rate' => 'Successfully archived the tax rate', + 'default_tax_rate_id' => 'Default Tax Rate', + 'tax_rate' => 'Tax Rate', + 'recurring_hour' => 'Recurring Hour', + 'pattern' => 'Pattern', + 'pattern_help_title' => 'Pattern Help', + 'pattern_help_1' => 'Create custom invoice and quote numbers by specifying a pattern', + 'pattern_help_2' => 'Available variables:', + 'pattern_help_3' => 'For example, :example would be converted to :value', + 'see_options' => 'See options', + 'invoice_counter' => 'Invoice Counter', + 'quote_counter' => 'Quote Counter', + 'type' => 'Type', + 'activity_1' => ':user created client :client', + 'activity_2' => ':user archived client :client', + 'activity_3' => ':user deleted client :client', + 'activity_4' => ':user created invoice :invoice', + 'activity_5' => ':user updated invoice :invoice', + 'activity_6' => ':user emailed invoice :invoice to :contact', + 'activity_7' => ':contact viewed invoice :invoice', + 'activity_8' => ':user archived invoice :invoice', + 'activity_9' => ':user deleted invoice :invoice', + 'activity_10' => ':contact entered payment :payment for :invoice', + 'activity_11' => ':user updated payment :payment', + 'activity_12' => ':user archived payment :payment', + 'activity_13' => ':user deleted payment :payment', + 'activity_14' => ':user entered :credit credit', + 'activity_15' => ':user updated :credit credit', + 'activity_16' => ':user archived :credit credit', + 'activity_17' => ':user deleted :credit credit', + 'activity_18' => ':user created quote :quote', + 'activity_19' => ':user updated quote :quote', + 'activity_20' => ':user emailed quote :quote to :contact', + 'activity_21' => ':contact viewed quote :quote', + 'activity_22' => ':user archived quote :quote', + 'activity_23' => ':user deleted quote :quote', + 'activity_24' => ':user restored quote :quote', + 'activity_25' => ':user restored invoice :invoice', + 'activity_26' => ':user restored client :client', + 'activity_27' => ':user restored payment :payment', + 'activity_28' => ':user restored :credit credit', + 'activity_29' => ':contact approved quote :quote', + 'activity_30' => ':user created :vendor', + 'activity_31' => ':user created :vendor', + 'activity_32' => ':user created :vendor', + 'activity_33' => ':user created :vendor', + 'activity_34' => ':user created expense :expense', + 'activity_35' => ':user created :vendor', + 'activity_36' => ':user created :vendor', + 'activity_37' => ':user created :vendor', + 'payment' => 'Payment', + 'system' => 'System', + 'signature' => 'Email Signature', + 'default_messages' => 'Default Messages', + 'quote_terms' => 'Quote Terms', + 'default_quote_terms' => 'Default Quote Terms', + 'default_invoice_terms' => 'Default Invoice Terms', + 'default_invoice_footer' => 'Default Invoice Footer', + 'quote_footer' => 'Quote Footer', + 'free' => 'Free', + 'quote_is_approved' => 'This quote is approved', + 'apply_credit' => 'Apply Credit', + 'system_settings' => 'System Settings', + 'archive_token' => 'Archive Token', + 'archived_token' => 'Successfully archived token', + 'archive_user' => 'Archive User', + 'archived_user' => 'Successfully archived user', + 'archive_account_gateway' => 'Archive Gateway', + 'archived_account_gateway' => 'Successfully archived gateway', + 'archive_recurring_invoice' => 'Archive Recurring Invoice', + 'archived_recurring_invoice' => 'Successfully archived recurring invoice', + 'delete_recurring_invoice' => 'Delete Recurring Invoice', + 'deleted_recurring_invoice' => 'Successfully deleted recurring invoice', + 'restore_recurring_invoice' => 'Restore Recurring Invoice', + 'restored_recurring_invoice' => 'Successfully restored recurring invoice', + 'archived' => 'Archived', + 'untitled_account' => 'Untitled Company', + 'before' => 'Before', + 'after' => 'After', + 'reset_terms_help' => 'Reset to the default account terms', + 'reset_footer_help' => 'Reset to the default account footer', + 'export_data' => 'Export Data', + 'user' => 'User', + 'country' => 'Country', + 'include' => 'Include', + '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_data' => 'Import Data', + 'source' => 'Source', + 'csv' => 'CSV', + 'client_file' => 'Client File', + 'invoice_file' => 'Invoice File', + 'task_file' => 'Task File', + 'no_mapper' => 'No valid mapping for file', + 'invalid_csv_header' => 'Invalid CSV Header', + 'client_portal' => 'Client Portal', + 'admin' => 'Admin', + 'disabled' => 'Disabled', + 'show_archived_users' => 'Show archived users', + 'notes' => 'Notes', + 'invoice_will_create' => 'client will be created', + 'invoices_will_create' => 'invoices will be created', + 'failed_to_import' => 'The following records failed to import, they either already exist or are missing required fields.', + 'publishable_key' => 'Publishable Key', + 'secret_key' => 'Secret Key', + 'missing_publishable_key' => 'Set your Stripe publishable key for an improved checkout process', + 'email_design' => 'Email Design', + 'due_by' => 'Due by :date', + 'enable_email_markup' => 'Enable Markup', + 'enable_email_markup_help' => 'Make it easier for your clients to pay you by adding schema.org markup to your emails.', + 'template_help_title' => 'Templates Help', + 'template_help_1' => 'Available variables:', + 'email_design_id' => 'Email Style', + 'email_design_help' => 'Make your emails look more professional with HTML layouts', + 'plain' => 'Plain', + 'light' => 'Light', + 'dark' => 'Dark', + '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.', + 'invoice_number_help' => 'Specify a prefix or use a custom pattern to dynamically set the invoice number.', + 'quote_number_help' => 'Specify a prefix or use a custom pattern to dynamically set the quote number.', + 'custom_client_fields_helps' => 'Add a field when creating a client and display the label and value on 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 field when creating an invoice and display the label and value on the PDF.', + 'custom_invoice_charges_helps' => 'Add a field when creating an invoice and include the charge in the invoice subtotals.', + 'token_expired' => 'Validation token was expired. Please try again.', + 'invoice_link' => 'Invoice Link', + 'button_confirmation_message' => 'Click to confirm your email address.', + 'confirm' => 'Confirm', + 'email_preferences' => 'Email Preferences', + 'created_invoices' => 'Successfully created :count invoice(s)', + 'next_invoice_number' => 'The next invoice number is :number.', + 'next_quote_number' => 'The next quote number is :number.', + 'days_before' => 'days before', + 'days_after' => 'days after', + 'field_due_date' => 'due date', + 'field_invoice_date' => 'invoice date', + 'schedule' => 'Schedule', + 'email_designs' => 'Email Designs', + 'assigned_when_sent' => 'Assigned when sent', + 'white_label_purchase_link' => 'Purchase a white label license', + 'expense' => 'Expense', + 'expenses' => 'Expenses', + 'new_expense' => 'New Expense', + 'enter_expense' => 'Enter Expense', + 'vendors' => 'Vendors', + 'new_vendor' => 'New Vendor', + 'payment_terms_net' => 'Net', + 'vendor' => 'Vendor', + 'edit_vendor' => 'Edit Vendor', + 'archive_vendor' => 'Archive Vendor', + 'delete_vendor' => 'Delete Vendor', + 'view_vendor' => 'View Vendor', + 'deleted_expense' => 'Successfully deleted expense', + 'archived_expense' => 'Successfully archived expense', + 'deleted_expenses' => 'Successfully deleted expenses', + 'archived_expenses' => 'Successfully archived expenses', + 'expense_amount' => 'Expense Amount', + 'expense_balance' => 'Expense Balance', + 'expense_date' => 'Expense Date', + 'expense_should_be_invoiced' => 'Should this expense be invoiced?', + 'public_notes' => 'Public Notes', + 'invoice_amount' => 'Invoice Amount', + 'exchange_rate' => 'Exchange Rate', + 'yes' => 'Yes', + 'no' => 'No', + 'should_be_invoiced' => 'Should be invoiced', + 'view_expense' => 'View expense # :expense', + 'edit_expense' => 'Edit Expense', + 'archive_expense' => 'Archive Expense', + 'delete_expense' => 'Delete Expense', + 'view_expense_num' => 'Expense # :expense', + 'updated_expense' => 'Successfully updated expense', + 'created_expense' => 'Successfully created expense', + 'enter_expense' => 'Enter Expense', + 'view' => 'View', + 'restore_expense' => 'Restore Expense', + 'invoice_expense' => 'Invoice Expense', + 'expense_error_multiple_clients' => 'The expenses can\'t belong to different clients', + 'expense_error_invoiced' => 'Expense has already been invoiced', + 'convert_currency' => 'Convert currency', + 'num_days' => 'Number of days', + 'create_payment_term' => 'Create Payment Term', + 'edit_payment_terms' => 'Edit Payment Term', + 'edit_payment_term' => 'Edit Payment Term', + 'archive_payment_term' => 'Archive Payment Term', + 'recurring_due_dates' => 'Recurring Invoice Due Dates', + 'recurring_due_date_help' => '

    Automatically sets a due date for the invoice.

    +

    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.

    +

    Invoices on a weekly cycle set to be due on the day of the week they are created will be due the next week.

    +

    For example:

    +
      +
    • Today is the 15th, due date is 1st of the month. The due date should likely be the 1st of the next month.
    • +
    • Today is the 15th, due date is the last day of the month. The due date will be the last day of the this month. +
    • +
    • Today is the 15th, due date is the 15th day of the month. The due date will be the 15th day of next month. +
    • +
    • Today is the Friday, due date is the 1st Friday after. The due date will be next Friday, not today. +
    • +
    ', + 'due' => 'Due', + 'next_due_on' => 'Due Next: :date', + 'use_client_terms' => 'Use client terms', + 'day_of_month' => ':ordinal day of month', + 'last_day_of_month' => 'Last day of month', + 'day_of_week_after' => ':ordinal :day after', + 'sunday' => 'Sunday', + 'monday' => 'Monday', + 'tuesday' => 'Tuesday', + 'wednesday' => 'Wednesday', + 'thursday' => 'Thursday', + 'friday' => 'Friday', + 'saturday' => 'Saturday', + 'header_font_id' => 'Header 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.', + 'live_preview' => 'Live Preview', + '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.', + 'quote_message_button' => 'To view your quote for :amount, click the button below.', + 'payment_message_button' => 'Thank you for your payment of :amount.', + 'payment_type_direct_debit' => 'Direct Debit', + 'bank_accounts' => 'Credit Cards & Banks', + 'add_bank_account' => 'Add Bank Account', + 'setup_account' => 'Setup Account', + 'import_expenses' => 'Import Expenses', + 'bank_id' => 'Bank', + 'integration_type' => 'Integration Type', + 'updated_bank_account' => 'Successfully updated bank account', + 'edit_bank_account' => 'Edit Bank Account', + 'archive_bank_account' => 'Archive Bank Account', + 'archived_bank_account' => 'Successfully archived bank account', + 'created_bank_account' => 'Successfully created bank account', + 'validate_bank_account' => 'Validate Bank Account', + '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.', + 'username' => 'Username', + 'account_number' => 'Account Number', + 'account_name' => 'Account Name', + 'bank_account_error' => 'Failed to retreive account details, please check your credentials.', + 'status_approved' => 'Approved', + 'quote_settings' => 'Quote Settings', + 'auto_convert_quote' => 'Auto convert quote', + 'auto_convert_quote_help' => 'Automatically convert a quote to an invoice when approved by a client.', + 'validate' => 'Validate', + 'info' => 'Info', + '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.', + '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.', + 'trello_roadmap' => 'Trello Roadmap', + 'header_footer' => 'Header/Footer', + 'first_page' => 'First page', + 'all_pages' => 'All pages', + 'last_page' => 'Last page', + 'all_pages_header' => 'Show Header on', + 'all_pages_footer' => 'Show Footer on', + 'invoice_currency' => 'Invoice Currency', + 'enable_https' => 'We strongly recommend using HTTPS to accept credit card details online.', + 'quote_issued_to' => 'Quote issued to', + 'show_currency_code' => 'Currency Code', + 'trial_message' => 'Your account will receive a free two week trial of our pro plan.', + 'trial_footer' => 'Your free trial lasts :count more days, :link to upgrade now.', + 'trial_footer_last_day' => 'This is the last day of your free trial, :link to upgrade now.', + 'trial_call_to_action' => 'Start Free Trial', + 'trial_success' => 'Successfully enabled two week free pro plan trial', + 'overdue' => 'Overdue', + + + 'white_label_text' => 'Purchase a ONE YEAR white label license for $: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 :link', + 'reset_password_footer' => 'If you did not request this password reset please email our support: :email', + 'limit_users' => 'Sorry, this will exceed the limit of :limit users', + 'more_designs_self_host_header' => 'Get 6 more invoice designs for just $:price', + 'old_browser' => 'Please use a newer browser', + 'white_label_custom_css' => ':link for $: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 400+ US banks.', + + 'pro_plan_remove_logo' => ':link to remove the Invoice Ninja logo by joining the Pro Plan', + 'pro_plan_remove_logo_link' => 'Click here', + 'invitation_status_sent' => 'Email Sent', + 'invitation_status_opened' => 'Email Openend', + 'invitation_status_viewed' => 'Invoice Viewed', + 'email_error_inactive_client' => 'Emails can not be sent to inactive clients', + 'email_error_inactive_contact' => 'Emails can not be sent to inactive contacts', + 'email_error_inactive_invoice' => 'Emails can not be sent to inactive invoices', + 'email_error_user_unregistered' => 'Please register your account to send emails', + 'email_error_user_unconfirmed' => 'Please confirm your account to send emails', + 'email_error_invalid_contact_email' => 'Invalid contact email', + + 'navigation' => 'Navigation', + 'list_invoices' => 'List Invoices', + 'list_clients' => 'List Clients', + 'list_quotes' => 'List Quotes', + 'list_tasks' => 'List Tasks', + 'list_expenses' => 'List Expenses', + 'list_recurring_invoices' => 'List Recurring Invoices', + 'list_payments' => 'List Payments', + 'list_credits' => 'List Credits', + 'tax_name' => 'Tax Name', + 'report_settings' => 'Report Settings', + 'search_hotkey' => 'shortcut is /', + + 'new_user' => 'New User', + 'new_product' => 'New Product', + 'new_tax_rate' => 'New Tax Rate', + 'invoiced_amount' => 'Invoiced Amount', + 'invoice_item_fields' => 'Invoice Item Fields', + 'custom_invoice_item_fields_help' => 'Add a field when creating an invoice item and display the label and value on the PDF.', + 'recurring_invoice_number' => 'Recurring Invoice Number', + 'recurring_invoice_number_prefix_help' => 'Speciy a prefix to be added to the invoice number for recurring invoices. The default value is \'R\'.', + + // Client Passwords + 'enable_portal_password'=>'Password protect invoices', + 'enable_portal_password_help'=>'Allows you to set a password for each contact. If a password is set, the contact will be required to enter a password before viewing invoices.', + 'send_portal_password'=>'Generate password automatically', + 'send_portal_password_help'=>'If no password is set, one will be generated and sent with the first invoice.', + + 'expired' => 'Expired', + 'invalid_card_number' => 'The credit card number is not valid.', + 'invalid_expiry' => 'The expiration date is not valid.', + 'invalid_cvv' => 'The CVV is not valid.', + 'cost' => 'Cost', + 'create_invoice_for_sample' => 'Note: create your first invoice to see a preview here.', + + // User Permissions + 'owner' => 'Owner', + 'administrator' => 'Administrator', + 'administrator_help' => 'Allow user to manage users, change settings and modify all records', + 'user_create_all' => 'Create clients, invoices, etc.', + 'user_view_all' => 'View all clients, invoices, etc.', + 'user_edit_all' => 'Edit all clients, invoices, etc.', + 'gateway_help_20' => ':link to sign up for Sage Pay.', + 'gateway_help_21' => ':link to sign up for Sage Pay.', + 'partial_due' => 'Partial Due', + 'restore_vendor' => 'Restore Vendor', + 'restored_vendor' => 'Successfully restored vendor', + 'restored_expense' => 'Successfully restored expense', + 'permissions' => 'Permissions', + 'create_all_help' => 'Allow user to create and modify records', + 'view_all_help' => 'Allow user to view records they didn\'t create', + 'edit_all_help' => 'Allow user to modify records they didn\'t create', + 'view_payment' => 'View Payment', + + 'january' => 'January', + 'february' => 'February', + 'march' => 'March', + 'april' => 'April', + 'may' => 'May', + 'june' => 'June', + 'july' => 'July', + 'august' => 'August', + 'september' => 'September', + 'october' => 'October', + 'november' => 'November', + 'december' => 'December', + + // Documents + 'documents_header' => 'Documents:', + 'email_documents_header' => 'Documents:', + 'email_documents_example_1' => 'Widgets Receipt.pdf', + 'email_documents_example_2' => 'Final Deliverable.zip', + 'invoice_documents' => 'Documents', + 'expense_documents' => 'Attached Documents', + 'invoice_embed_documents' => 'Embed Documents', + 'invoice_embed_documents_help' => 'Include attached images in the invoice.', + 'document_email_attachment' => 'Attach Documents', + 'download_documents' => 'Download Documents (:size)', + 'documents_from_expenses' => 'From Expenses:', + 'dropzone_default_message' => 'Drop files or click to upload', + 'dropzone_fallback_message' => 'Your browser does not support drag\'n\'drop file uploads.', + 'dropzone_fallback_text' => 'Please use the fallback form below to upload your files like in the olden days.', + 'dropzone_file_too_big' => 'File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.', + 'dropzone_invalid_file_type' => 'You can\'t upload files of this type.', + 'dropzone_response_error' => 'Server responded with {{statusCode}} code.', + 'dropzone_cancel_upload' => 'Cancel upload', + 'dropzone_cancel_upload_confirmation' => 'Are you sure you want to cancel this upload?', + 'dropzone_remove_file' => 'Remove file', + 'documents' => 'Documents', + 'document_date' => 'Document Date', + 'document_size' => 'Size', + + 'enable_client_portal' => 'Client Portal', + 'enable_client_portal_help' => 'Show/hide the client portal.', + 'enable_client_portal_dashboard' => 'Dashboard', + 'enable_client_portal_dashboard_help' => 'Show/hide the dashboard page in the client portal.', + + // Plans + 'account_management' => 'Account Management', + 'plan_status' => 'Plan Status', + + 'plan_upgrade' => 'Upgrade', + 'plan_change' => 'Change Plan', + 'pending_change_to' => 'Changes To', + 'plan_changes_to' => ':plan on :date', + 'plan_term_changes_to' => ':plan (:term) on :date', + 'cancel_plan_change' => 'Cancel Change', + 'plan' => 'Plan', + 'expires' => 'Expires', + 'renews' => 'Renews', + 'plan_expired' => ':plan Plan Expired', + 'trial_expired' => ':plan Plan Trial Ended', + 'never' => 'Never', + 'plan_free' => 'Free', + 'plan_pro' => 'Pro', + 'plan_enterprise' => 'Enterprise', + 'plan_white_label' => 'Self Hosted (White labeled)', + 'plan_free_self_hosted' => 'Self Hosted (Free)', + 'plan_trial' => 'Trial', + 'plan_term' => 'Term', + 'plan_term_monthly' => 'Monthly', + 'plan_term_yearly' => 'Yearly', + 'plan_term_month' => 'Month', + 'plan_term_year' => 'Year', + 'plan_price_monthly' => '$:price/Month', + 'plan_price_yearly' => '$:price/Year', + 'updated_plan' => 'Updated plan settings', + 'plan_paid' => 'Term Started', + 'plan_started' => 'Plan Started', + 'plan_expires' => 'Plan Expires', + + 'white_label_button' => 'White Label', + + 'pro_plan_year_description' => 'One year enrollment in the Invoice Ninja Pro Plan.', + 'pro_plan_month_description' => 'One month enrollment in the Invoice Ninja Pro Plan.', + 'enterprise_plan_product' => 'Enterprise Plan', + 'enterprise_plan_year_description' => 'One year enrollment in the Invoice Ninja Enterprise Plan.', + 'enterprise_plan_month_description' => 'One month enrollment in the Invoice Ninja Enterprise Plan.', + 'plan_credit_product' => 'Credit', + 'plan_credit_description' => 'Credit for unused time', + 'plan_pending_monthly' => 'Will switch to monthly on :date', + 'plan_refunded' => 'A refund has been issued.', + + 'live_preview' => 'Live Preview', + 'page_size' => 'Page Size', + 'live_preview_disabled' => 'Live preview has been disabled to support selected font', + 'invoice_number_padding' => 'Padding', + 'preview' => 'Preview', + 'list_vendors' => 'List Vendors', + 'add_users_not_supported' => 'Upgrade to the Enterprise plan to add additional users to your account.', + 'enterprise_plan_features' => 'The Enterprise plan adds support for multiple users and file attachments, :link to see the full list of features.', + 'return_to_app' => 'Return to app', + + + // Payment updates + 'refund_payment' => 'Refund Payment', + 'refund_max' => 'Max:', + 'refund' => 'Refund', + 'are_you_sure_refund' => 'Refund selected payments?', + 'status_pending' => 'Pending', + 'status_completed' => 'Completed', + 'status_failed' => 'Failed', + 'status_partially_refunded' => 'Partially Refunded', + 'status_partially_refunded_amount' => ':amount Refunded', + 'status_refunded' => 'Refunded', + 'status_voided' => 'Cancelled', + 'refunded_payment' => 'Refunded Payment', + 'activity_39' => ':user cancelled a :payment_amount payment (:payment)', + 'activity_40' => ':user refunded :adjustment of a :payment_amount payment (:payment)', + 'card_expiration' => 'Exp: :expires', + + 'card_creditcardother' => 'Unknown', + 'card_americanexpress' => 'American Express', + 'card_carteblanche' => 'Carte Blanche', + 'card_unionpay' => 'UnionPay', + 'card_diners' => 'Diners Club', + 'card_discover' => 'Discover', + 'card_jcb' => 'JCB', + 'card_laser' => 'Laser', + 'card_maestro' => 'Maestro', + 'card_mastercard' => 'MasterCard', + 'card_solo' => 'Solo', + 'card_switch' => 'Switch', + 'card_visacard' => 'Visa', + 'card_ach' => 'ACH', + + 'payment_type_stripe' => 'Stripe', + 'ach' => 'ACH', + 'enable_ach' => 'Enable ACH', + 'stripe_ach_help' => 'ACH support must also be enabled at Stripe.', + 'ach_disabled' => 'Another gateway is already configured for direct debit.', + + 'plaid' => 'Plaid', + 'client_id' => 'Client Id', + 'secret' => 'Secret', + 'public_key' => 'Public Key', + 'plaid_optional' => '(optional)', + 'plaid_environment_help' => 'When a Stripe test key is given, Plaid\'s development environement (tartan) will be used.', + 'other_providers' => 'Other Providers', + 'country_not_supported' => 'That country is not supported.', + 'invalid_routing_number' => 'The routing number is not valid.', + 'invalid_account_number' => 'The account number is not valid.', + 'account_number_mismatch' => 'The account numbers do not match.', + 'missing_account_holder_type' => 'Please select an individual or company account.', + 'missing_account_holder_name' => 'Please enter the account holder\'s name.', + 'routing_number' => 'Routing Number', + 'confirm_account_number' => 'Confirm Account Number', + 'individual_account' => 'Individual Account', + 'company_account' => 'Company Account', + 'account_holder_name' => 'Account Holder Name', + 'add_account' => 'Add Account', + 'payment_methods' => 'Payment Methods', + 'complete_verification' => 'Complete Verification', + 'verification_amount1' => 'Amount 1', + 'verification_amount2' => 'Amount 2', + 'payment_method_verified' => 'Verification completed successfully', + 'verification_failed' => 'Verification Failed', + 'remove_payment_method' => 'Remove Payment Method', + 'confirm_remove_payment_method' => 'Are you sure you want to remove this payment method?', + 'remove' => 'Remove', + 'payment_method_removed' => 'Removed payment method.', + 'bank_account_verification_help' => 'We have made two deposits into your account with the description "VERIFICATION". These deposits will take 1-2 business days to appear on your statement. Please enter the amounts below.', + 'bank_account_verification_next_steps' => 'We have made two deposits into your account with the description "VERIFICATION". These deposits will take 1-2 business days to appear on your statement. + Once you have the amounts, come back to this payment methods page and click "Complete Verification" next to the account.', + 'unknown_bank' => 'Unknown Bank', + 'ach_verification_delay_help' => 'You will be able to use the account after completing verification. Verification usually takes 1-2 business days.', + 'add_credit_card' => 'Add Credit Card', + 'payment_method_added' => 'Added payment method.', + 'use_for_auto_bill' => 'Use For Autobill', + 'used_for_auto_bill' => 'Autobill Payment Method', + 'payment_method_set_as_default' => 'Set Autobill payment method.', + 'activity_41' => ':payment_amount payment (:payment) failed', + 'webhook_url' => 'Webhook URL', + 'stripe_webhook_help' => 'You must :link.', + 'stripe_webhook_help_link_text' => 'add this URL as an endpoint at Stripe', + 'payment_method_error' => 'There was an error adding your payment methd. Please try again later.', + 'notification_invoice_payment_failed_subject' => 'Payment failed for Invoice :invoice', + 'notification_invoice_payment_failed' => 'A payment made by client :client towards Invoice :invoice failed. The payment has been marked as failed and :amount has been added to the client\'s balance.', + 'link_with_plaid' => 'Link Account Instantly with Plaid', + 'link_manually' => 'Link Manually', + 'secured_by_plaid' => 'Secured by Plaid', + 'plaid_linked_status' => 'Your bank account at :bank', + 'add_payment_method' => 'Add Payment Method', + 'account_holder_type' => 'Account Holder Type', + 'ach_authorization' => 'I authorize :company to use my bank account for future payments and, if necessary, electronically credit my account to correct erroneous debits. I understand that I may cancel this authorization at any time by removing the payment method or by contacting :email.', + 'ach_authorization_required' => 'You must consent to ACH transactions.', + 'off' => 'Off', + 'opt_in' => 'Opt-in', + 'opt_out' => 'Opt-out', + 'always' => 'Always', + 'opted_out' => 'Opted out', + 'opted_in' => 'Opted in', + 'manage_auto_bill' => 'Manage Auto-bill', + 'enabled' => 'Enabled', + 'paypal' => 'PayPal', + 'braintree_enable_paypal' => 'Enable PayPal payments through BrainTree', + 'braintree_paypal_disabled_help' => 'The PayPal gateway is processing PayPal payments', + 'braintree_paypal_help' => 'You must also :link.', + 'braintree_paypal_help_link_text' => 'link PayPal to your BrainTree account', + 'token_billing_braintree_paypal' => 'Save payment details', + 'add_paypal_account' => 'Add PayPal Account', + + + 'no_payment_method_specified' => 'No payment method specified', + 'chart_type' => 'Chart Type', + 'format' => 'Format', + 'import_ofx' => 'Import OFX', + 'ofx_file' => 'OFX File', + 'ofx_parse_failed' => 'Failed to parse OFX file', + + // WePay + 'wepay' => 'WePay', + 'sign_up_with_wepay' => 'Sign up with WePay', + 'use_another_provider' => 'Use another provider', + 'company_name' => 'Company Name', + 'wepay_company_name_help' => 'This will appear on client\'s credit card statements.', + 'wepay_description_help' => 'The purpose of this account.', + 'wepay_tos_agree' => 'I agree to the :link.', + 'wepay_tos_link_text' => 'WePay Terms of Service', + 'resend_confirmation_email' => 'Resend Confirmation Email', + 'manage_wepay_account' => 'Manage WePay Account', + 'action_required' => 'Action Required', + 'finish_setup' => 'Finish Setup', + 'created_wepay_confirmation_required' => 'Please check your email and confirm your email address with WePay.', + 'switch_to_wepay' => 'Switch to WePay', + 'switch' => 'Switch', + 'restore_account_gateway' => 'Restore Gateway', + 'restored_account_gateway' => 'Successfully restored gateway', + 'united_states' => 'United States', + 'canada' => 'Canada', + 'accept_debit_cards' => 'Accept Debit Cards', + 'debit_cards' => 'Debit Cards', + + 'warn_start_date_changed' => 'The next invoice will be sent on the new start date.', + 'original_start_date' => 'Original start date', + 'new_start_date' => 'New start date', + 'security' => 'Security', + 'see_whats_new' => 'See what\'s new in v:version', + 'wait_for_upload' => 'Please wait for the document upload to complete.', + 'upgrade_for_permissions' => 'Upgrade to our Enterprise plan to enable permissions.', + 'enable_second_tax_rate' => 'Enable specifying a second tax rate', + 'payment_file' => 'Payment File', + 'expense_file' => 'Expense File', + 'product_file' => 'Product File', + 'import_products' => 'Import Products', + 'products_will_create' => 'products will be created.', + 'product_key' => 'Product', + 'created_products' => 'Successfully created :count product(s)', + 'export_help' => 'Use JSON if you plan to import the data into Invoice Ninja.', + 'JSON_file' => 'JSON File', + + 'view_dashboard' => 'View Dashboard', + 'client_session_expired' => 'Session Expired', + 'client_session_expired_message' => 'Your session has expired. Please click the link in your email again.', + + 'auto_bill_notification' => 'This invoice will automatically be billed to your :payment_method on file on :due_date.', + 'auto_bill_payment_method_bank_transfer' => 'bank account', + 'auto_bill_payment_method_credit_card' => 'credit card', + 'auto_bill_payment_method_paypal' => 'PayPal account', + 'auto_bill_notification_placeholder' => 'This invoice will automatically be billed to your credit card on file on the due date.', + 'payment_settings' => 'Payment Settings', + + 'on_send_date' => 'On send date', + 'on_due_date' => 'On due date', + 'auto_bill_ach_date_help' => 'ACH auto bill will always happen on the due date', + 'warn_change_auto_bill' => 'Due to NACHA rules, changes to this invoice may prevent ACH auto bill.', + + 'bank_account' => 'Bank Account', + 'payment_processed_through_wepay' => 'ACH payments will be processed using WePay.', + 'wepay_payment_tos_agree' => 'I agree to the WePay :terms and :privacy_policy.', + 'privacy_policy' => 'Privacy Policy', + 'wepay_payment_tos_agree_required' => 'You must agree to the WePay Terms of Service and Privacy Policy.', + 'payment_settings_supported_gateways' => 'These options are supported by the WePay, Stripe, and Braintree gateways.', + 'ach_email_prompt' => 'Please enter your email address:', + 'verification_pending' => 'Verification Pending', + + 'update_font_cache' => 'Please force refresh the page to update the font cache.', + 'more_options' => 'More options', + 'credit_card' => 'Credit Card', + 'bank_transfer' => 'Bank Transfer', + 'no_transaction_reference' => 'We did not recieve a payment transaction reference from the gateway.', + 'use_bank_on_file' => 'Use Bank on File', + 'auto_bill_email_message' => 'This invoice will automatically be billed to the payment method on file on the due date.', + 'bitcoin' => 'Bitcoin', + 'added_on' => 'Added :date', + 'failed_remove_payment_method' => 'Failed to remove the payment method', + 'gateway_exists' => 'This gateway already exists', + 'manual_entry' => 'Manual entry', + +); + +return $LANG; + +?> diff --git a/resources/lang/ca/validation.php b/resources/lang/ca/validation.php new file mode 100644 index 0000000000..e08e8bd152 --- /dev/null +++ b/resources/lang/ca/validation.php @@ -0,0 +1,116 @@ + ':attribute ha de ser acceptat.', + 'active_url' => ':attribute no és un URL vàlid.', + 'after' => ':attribute ha de ser una data posterior a :date.', + 'alpha' => ':attribute només pot contenir lletres.', + 'alpha_dash' => ':attribute només por contenir lletres, números i guions.', + 'alpha_num' => ':attribute només pot contenir lletres i números.', + 'array' => ':attribute ha de ser un conjunt.', + 'before' => ':attribute ha de ser una data anterior a :date.', + 'between' => [ + 'numeric' => ":attribute ha d'estar entre :min - :max.", + 'file' => ':attribute ha de pesar entre :min - :max kilobytes.', + 'string' => ':attribute ha de tenir entre :min - :max caràcters.', + 'array' => ':attribute ha de tenir entre :min - :max ítems.', + ], + 'boolean' => 'El camp :attribute ha de ser veritat o fals', + 'confirmed' => 'La confirmació de :attribute no coincideix.', + 'date' => ':attribute no és una data vàlida.', + 'date_format' => ':attribute no correspon al format :format.', + 'different' => ':attribute i :other han de ser diferents.', + 'digits' => ':attribute ha de tenir :digits digits.', + 'digits_between' => ':attribute ha de tenir entre :min i :max digits.', + 'dimensions' => 'The :attribute has invalid image dimensions.', + 'distinct' => 'The :attribute field has a duplicate value.', + 'email' => ':attribute no és un e-mail vàlid', + 'exists' => ':attribute és invàlid.', + 'filled' => 'El camp :attribute és obligatori.', + 'image' => ':attribute ha de ser una imatge.', + 'in' => ':attribute és invàlid', + 'in_array' => 'The :attribute field does not exist in :other.', + 'integer' => ':attribute ha de ser un nombre enter.', + 'ip' => ':attribute ha de ser una adreça IP vàlida.', + 'json' => 'El camp :attribute ha de contenir una cadena JSON vàlida.', + 'max' => [ + 'numeric' => ':attribute no ha de ser major a :max.', + 'file' => ':attribute no ha de ser més gran que :max kilobytes.', + 'string' => ':attribute no ha de ser més gran que :max characters.', + 'array' => ':attribute no ha de tenir més de :max ítems.', + ], + 'mimes' => ':attribute ha de ser un arxiu amb format: :values.', + 'min' => [ + 'numeric' => "El tamany de :attribute ha de ser d'almenys :min.", + 'file' => "El tamany de :attribute ha de ser d'almenys :min kilobytes.", + 'string' => ':attribute ha de contenir almenys :min caràcters.', + 'array' => ':attribute ha de tenir almenys :min ítems.', + ], + 'not_in' => ':attribute és invàlid.', + 'numeric' => ':attribute ha de ser numèric.', + 'present' => 'The :attribute field must be present.', + 'regex' => 'El format de :attribute és invàlid.', + 'required' => 'El camp :attribute és obligatori.', + 'required_if' => 'El camp :attribute és obligatori quan :other és :value.', + 'required_unless' => 'The :attribute field is required unless :other is in :values.', + 'required_with' => 'El camp :attribute és obligatori quan :values és present.', + 'required_with_all' => 'El camp :attribute és obligatori quan :values és present.', + 'required_without' => 'El camp :attribute és obligatori quan :values no és present.', + 'required_without_all' => 'El camp :attribute és obligatori quan cap dels :values estan presents.', + 'same' => ':attribute i :other han de coincidir.', + 'size' => [ + 'numeric' => 'El tamany de :attribute ha de ser :size.', + 'file' => 'El tamany de :attribute ha de ser :size kilobytes.', + 'string' => ':attribute ha de contenir :size caràcters.', + 'array' => ':attribute ha de contenir :size ítems.', + ], + 'string' => 'El camp :attribute ha de ser una cadena de caràcters.', + 'timezone' => 'El camp :attribute ha de ser una zona vàlida.', + 'unique' => ':attribute ja ha estat registrat.', + 'url' => 'El format :attribute és invàlid.', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'custom-message', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [ + // + ], + +]; diff --git a/resources/lang/cs/texts.php b/resources/lang/cs/texts.php index 97771446b4..262fc40f97 100644 --- a/resources/lang/cs/texts.php +++ b/resources/lang/cs/texts.php @@ -268,7 +268,6 @@ $LANG = array( 'erase_data' => 'Toto kompletně vymaže navždy Vaše data.', 'password' => 'Heslo', 'pro_plan_product' => 'Profi plán', - 'pro_plan_description' => 'Roční využití Invoice Ninja Profi plánu.', 'pro_plan_success' => 'Děkujeme za použití Invoice Ninja\'s Profi plánu!

     
    Další kroky

    Faktura k úhradě Vám byla zaslána na email spojený s tímto účtem. Pro povolení všech skvělých profi vlastností si prosím přečtěte instrukce pro provedení platby na zaslané faktuře @@ -423,7 +422,7 @@ $LANG = array( 'invoice_history' => 'Historie faktur', 'quote_history' => 'Historie nabídek', 'current_version' => 'Současná verze', - 'select_versiony' => 'Zvolte verzi', + 'select_version' => 'Select version', 'view_history' => 'Zobrazit historii', 'edit_payment' => 'Editovat platbu', 'updated_payment' => 'Platba úspěšně změněna', @@ -444,8 +443,8 @@ $LANG = array( 'token_billing_3' => 'Opt-out - je zobrazen zaškrtnutý', 'token_billing_4' => 'Vždy', 'token_billing_checkbox' => 'Ukládat detaily platební karty', - 'view_in_stripe' => 'Zobrazit ve Stripe', - 'use_card_on_file' => 'Použít uloženou kartu', + 'view_in_gateway' => 'View in :gateway', + 'use_card_on_file' => 'Use Card on File', 'edit_payment_details' => 'Editovat platební údaje', 'token_billing' => 'Ukládat platební údaje', 'token_billing_secure' => 'Data jsou bezpečně uložena u :stripe_link', @@ -517,8 +516,8 @@ $LANG = array( 'duplicate_post' => 'Varování: předchozí stránka byla odeslána dvakrát. Druhé odeslání bylo ignorováno.', 'view_documentation' => 'Zobrazit dokumentaci', 'app_title' => 'Open source online fakrurace', - 'app_description' => 'Invoice Ninja je bezplatné open-source řešení pro fakturaci a účtování zákazníkům. - S Invoice Ninja, můžete jednoduše vytvářet a posílat hezké faktury z jakéhokoli zařízení, které má přístup na web. Vaši klienti si mohou faktury + 'app_description' => 'Invoice Ninja je bezplatné open-source řešení pro fakturaci a účtování zákazníkům. + S Invoice Ninja, můžete jednoduše vytvářet a posílat hezké faktury z jakéhokoli zařízení, které má přístup na web. Vaši klienti si mohou faktury vytisknout, stáhnout jako PDF nebo Vám rovnou online zaplatit.', 'rows' => 'řádky', 'www' => 'www', @@ -655,9 +654,9 @@ $LANG = array( 'created_by_invoice' => 'Vytvořeno :invoice', 'primary_user' => 'Primární uživatel', 'help' => 'Pomoc', - 'customize_help' => '

    Používáme pdfmake pro definování vzhledu faktur. Pdfmake zkušebna poskytuje skvělou cestu jak knihovnu vidět v akci

    -

    Pro přístup k podřízené položce se používá tečkové konvence. Například zobrazit pro zobrazení jména klienta použijte $client.name.

    -

    Pokud potřebujete s něčím pomoci - pošlete dotaz na náš fórum podpory.

    ', + 'customize_help' => '

    We use pdfmake to define the invoice designs declaratively. The pdfmake playground provide\'s a great way to see the library in action.

    +

    You can access a child property using dot notation. For example to show the client name you could use $client.name.

    +

    If you need help figuring something out post a question to our support forum with the design you\'re using.

    ', 'invoice_due_date' => 'Datum splatnosti', 'quote_due_date' => 'Platí do', 'valid_until' => 'Platí do', @@ -899,7 +898,7 @@ $LANG = array( 'view_expense_num' => 'Náklad # :expense', 'updated_expense' => 'Náklad úspěšně změněn', 'created_expense' => 'Náklad úspěšně vytvořen', - 'enter_expense' => 'Zadat náklady', + 'enter_expense' => 'Zadat náklad', 'view' => 'Zobrazit', 'restore_expense' => 'Obnovit náklady', 'invoice_expense' => 'Fakturovat náklady', @@ -913,7 +912,7 @@ $LANG = array( 'archive_payment_term' => 'Archivovat platební podmínky', 'recurring_due_dates' => 'Datumy splatnosti pravidelných faktur', 'recurring_due_date_help' => '

    Automaticky nastavit datum splatnosti na fakturách

    -

    U faktury s měsíčním nebo ročním cyklem bude nastavena měsíční splatnost v dalším měsíci. 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. +

    U faktury s měsíčním nebo ročním cyklem bude nastavena měsíční splatnost v dalším měsíci. 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. Faktury se splatností k 29. nebo 30 v měsících, které tyto dny nemají se splatnost nastaví k poslednímu dni v měsíci.

    Faktury s týdenním cyklem mají jako výchozí týdenní splatnost.

    Například:

    @@ -995,40 +994,26 @@ $LANG = array( 'overdue' => 'Po termínu', - 'white_label_text' => 'Objednejte si white label licenci na JEDEN ROK $'.WHITE_LABEL_PRICE.' pro odstranění značky Invoice Ninja z klientského portálu a stránek podpory.', - 'user_email_footer' => 'Pro úpravu emailových notifikací prosím navštivte '.SITE_URL.'/settings/notifications', - 'reset_password_footer' => 'Pokud jste nepožádali o resetování hesla, prosím kontaktujte naši podporu na: '.CONTACT_EMAIL, - 'limit_users' => 'Omlouváme se, to už přesáhlo limit '.MAX_NUM_USERS.' uživatelů', - 'more_designs_self_host_header' => 'Získejte 6 dalších vzhledů faktur jen za $'.INVOICE_DESIGNS_PRICE, - 'old_browser' => 'Prosím použijte novější prohlížeč', - 'white_label_custom_css' => ':link za $'.WHITE_LABEL_PRICE.' získáte volitelné úpravy a pomůžete podpoře našeho projektu.', - 'bank_accounts_help' => 'Připojte si bankovní účet pro automatický import nákladů a tvorbu dodavatelů. K dispozici pro American Express přes 400 amerických bank.', - 'security' => [ - 'too_many_attempts' => 'Mnoho přístupů. Zkuste to prosím za několik minut.', - 'wrong_credentials' => 'Neplatný email nebo heslo.', - 'confirmation' => 'Váš účet byl potvrzen!', - 'wrong_confirmation' => 'Chybný potvrzovací kód.', - 'password_forgot' => 'Informace týkající se resetování hesla byla odeslána na Váš email.', - 'password_reset' => 'Heslo bylo změněno úspěšně.', - 'wrong_password_reset' => 'Neplatné heslo. Zkuste znovu', - ], - 'pro_plan' => [ - 'remove_logo' => ':link pro odstranění loga Invoice Ninja připojením se k profi plánu', - 'remove_logo_link' => 'Klikněte zde', - ], - 'invitation_status' => [ - 'sent' => 'Email odeslán', - 'opened' => 'Email otevřen', - 'viewed' => 'Faktura zobrazena', - ], - 'email_errors' => [ - 'inactive_client' => 'Emaily nemohou být odeslány neaktivním klientům', - 'inactive_contact' => 'Emaily nemohou být odeslány neaktivním kontaktům', - 'inactive_invoice' => 'Emaily nemohou být odeslány k neaktivním fakturám', - 'user_unregistered' => 'Pro odesílání emailů si prosím zaregistrujte účet', - 'user_unconfirmed' => 'Pro posílání emailů potvrďte prosím Váš účet.', - 'invalid_contact_email' => 'Neplatný kontaktní email', - ], + 'white_label_text' => 'Objednejte si white label licenci na JEDEN ROK $:price pro odstranění značky Invoice Ninja z klientského portálu a stránek podpory.', + 'user_email_footer' => 'Pro úpravu emailových notifikací prosím navštivte :link', + 'reset_password_footer' => 'Pokud jste nepožádali o resetování hesla, prosím kontaktujte naši podporu na: :email', + 'limit_users' => 'Omlouváme se, to už přesáhlo limit :limit uživatelů', + 'more_designs_self_host_header' => 'Získejte 6 dalších vzhledů faktur jen za $:price', + 'old_browser' => 'Prosím použijte novější prohlížeč', + 'white_label_custom_css' => ':link za $:price získáte volitelné úpravy a pomůžete podpoře našeho projektu.', + 'bank_accounts_help' => 'Připojte si bankovní účet pro automatický import nákladů a tvorbu dodavatelů. K dispozici pro American Express přes 400 amerických bank.', + + 'pro_plan_remove_logo' => ':link pro odstranění loga Invoice Ninja připojením se k profi plánu', + 'pro_plan_remove_logo_link' => 'Klikněte zde', + 'invitation_status_sent' => 'Email odeslán', + 'invitation_status_opened' => 'Email otevřen', + 'invitation_status_viewed' => 'Faktura zobrazena', + 'email_error_inactive_client' => 'Emaily nemohou být odeslány neaktivním klientům', + 'email_error_inactive_contact' => 'Emaily nemohou být odeslány neaktivním kontaktům', + 'email_error_inactive_invoice' => 'Emaily nemohou být odeslány k neaktivním fakturám', + 'email_error_user_unregistered' => 'Pro odesílání emailů si prosím zaregistrujte účet', + 'email_error_user_unconfirmed' => 'Pro posílání emailů potvrďte prosím Váš účet.', + 'email_error_invalid_contact_email' => 'Neplatný kontaktní email', 'navigation' => 'Navigace', 'list_invoices' => 'Seznam faktur', @@ -1051,22 +1036,20 @@ $LANG = array( 'custom_invoice_item_fields_help' => 'Během vytváření faktury si přidejte pole a zobrazte si jeho popis a hodnotu v PDF.', 'recurring_invoice_number' => 'Číslo pravidelné faktury', 'recurring_invoice_number_prefix_help' => 'Určete prefix, který se přidá k číslu pravidelných faktur. Výchozí hodnota je \'R\'.', - 'enable_client_portal' => 'Dashboard', - 'enable_client_portal_help' => 'Skrýt/zobrazit dashboard v klientském portálu.', // Client Passwords 'enable_portal_password'=>'Faktury chráněné heslem', 'enable_portal_password_help'=>'Umožní Vám nastavit heslo pro každý kontakt. Pokud heslo nastavíte, tak kontakt ho bude pro zobrazení faktury vždy použít.', 'send_portal_password'=>'Generovat heslo automaticky', 'send_portal_password_help'=>'Pokud heslo není nastaveno, bude vygenerováno a zasláno spolu s první fakturou.', - + 'expired' => 'Expirované', 'invalid_card_number' => 'Číslo platební karty není platné.', 'invalid_expiry' => 'Datum expirace není platné.', 'invalid_cvv' => 'CVV není platné.', 'cost' => 'Cena', 'create_invoice_for_sample' => 'Poznámka: vytvořte si první fakturu a zde si ji prohlédněte.', - + // User Permissions 'owner' => 'Vlastník', 'administrator' => 'Administrátor', @@ -1084,8 +1067,8 @@ $LANG = array( 'create_all_help' => 'Povolit uživatelům měnit záznamy', 'view_all_help' => 'Povolit uživatelům zobrazit záznamy, které nevytvořili', 'edit_all_help' => 'Povolit uživatelům měnit záznamy, které nevytvořili', - 'view_payment' => 'Zobrazit platbu', - + 'view_payment' => 'Zobrazit platbu', + 'january' => 'Leden', 'february' => 'Únor', 'march' => 'Březen', @@ -1098,7 +1081,7 @@ $LANG = array( 'october' => 'Říjen', 'november' => 'Listopad', 'december' => 'Prosinec', - + // Documents 'documents_header' => 'Documents:', 'email_documents_header' => 'Documents:', @@ -1111,30 +1094,28 @@ $LANG = array( 'document_email_attachment' => 'Attach Documents', 'download_documents' => 'Download Documents (:size)', 'documents_from_expenses' => 'From Expenses:', - 'dropzone' => array(// See http://www.dropzonejs.com/#config-dictDefaultMessage - 'DefaultMessage' => 'Drop files or click to upload', - 'FallbackMessage' => 'Your browser does not support drag\'n\'drop file uploads.', - 'FallbackText' => 'Please use the fallback form below to upload your files like in the olden days.', - 'FileTooBig' => 'File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.', - 'InvalidFileType' => 'You can\'t upload files of this type.', - 'ResponseError' => 'Server responded with {{statusCode}} code.', - 'CancelUpload' => 'Cancel upload', - 'CancelUploadConfirmation' => 'Are you sure you want to cancel this upload?', - 'RemoveFile' => 'Remove file', - ), + 'dropzone_default_message' => 'Drop files or click to upload', + 'dropzone_fallback_message' => 'Your browser does not support drag\'n\'drop file uploads.', + 'dropzone_fallback_text' => 'Please use the fallback form below to upload your files like in the olden days.', + 'dropzone_file_too_big' => 'File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.', + 'dropzone_invalid_file_type' => 'You can\'t upload files of this type.', + 'dropzone_response_error' => 'Server responded with {{statusCode}} code.', + 'dropzone_cancel_upload' => 'Cancel upload', + 'dropzone_cancel_upload_confirmation' => 'Are you sure you want to cancel this upload?', + 'dropzone_remove_file' => 'Remove file', 'documents' => 'Documents', 'document_date' => 'Document Date', 'document_size' => 'Size', - 'enable_client_portal' => 'Client Portal', - 'enable_client_portal_help' => 'Show/hide the client portal.', + 'enable_client_portal' => 'Dashboard', + 'enable_client_portal_help' => 'Skrýt/zobrazit dashboard v klientském portálu.', 'enable_client_portal_dashboard' => 'Dashboard', 'enable_client_portal_dashboard_help' => 'Show/hide the dashboard page in the client portal.', - + // Plans 'account_management' => 'Account Management', 'plan_status' => 'Plan Status', - + 'plan_upgrade' => 'Upgrade', 'plan_change' => 'Change Plan', 'pending_change_to' => 'Changes To', @@ -1164,9 +1145,9 @@ $LANG = array( 'plan_paid' => 'Term Started', 'plan_started' => 'Plan Started', 'plan_expires' => 'Plan Expires', - + 'white_label_button' => 'White Label', - + 'pro_plan_year_description' => 'One year enrollment in the Invoice Ninja Pro Plan.', 'pro_plan_month_description' => 'One month enrollment in the Invoice Ninja Pro Plan.', 'enterprise_plan_product' => 'Enterprise Plan', @@ -1177,18 +1158,214 @@ $LANG = array( 'plan_pending_monthly' => 'Will switch to monthly on :date', 'plan_refunded' => 'A refund has been issued.', - 'live_preview' => 'Live Preview', + 'live_preview' => 'Náhled', 'page_size' => 'Page Size', 'live_preview_disabled' => 'Live preview has been disabled to support selected font', 'invoice_number_padding' => 'Padding', 'preview' => 'Preview', 'list_vendors' => 'List Vendors', 'add_users_not_supported' => 'Upgrade to the Enterprise plan to add additional users to your account.', - 'enterprise_plan_features' => 'The Enterprise plan adds support for multiple users and file attachments.', + 'enterprise_plan_features' => 'The Enterprise plan adds support for multiple users and file attachments, :link to see the full list of features.', 'return_to_app' => 'Return to app', - + + + // Payment updates + 'refund_payment' => 'Refund Payment', + 'refund_max' => 'Max:', + 'refund' => 'Refund', + 'are_you_sure_refund' => 'Refund selected payments?', + 'status_pending' => 'Pending', + 'status_completed' => 'Completed', + 'status_failed' => 'Failed', + 'status_partially_refunded' => 'Partially Refunded', + 'status_partially_refunded_amount' => ':amount Refunded', + 'status_refunded' => 'Refunded', + 'status_voided' => 'Cancelled', + 'refunded_payment' => 'Refunded Payment', + 'activity_39' => ':user cancelled a :payment_amount payment (:payment)', + 'activity_40' => ':user refunded :adjustment of a :payment_amount payment (:payment)', + 'card_expiration' => 'Exp: :expires', + + 'card_creditcardother' => 'Unknown', + 'card_americanexpress' => 'American Express', + 'card_carteblanche' => 'Carte Blanche', + 'card_unionpay' => 'UnionPay', + 'card_diners' => 'Diners Club', + 'card_discover' => 'Discover', + 'card_jcb' => 'JCB', + 'card_laser' => 'Laser', + 'card_maestro' => 'Maestro', + 'card_mastercard' => 'MasterCard', + 'card_solo' => 'Solo', + 'card_switch' => 'Switch', + 'card_visacard' => 'Visa', + 'card_ach' => 'ACH', + + 'payment_type_stripe' => 'Stripe', + 'ach' => 'ACH', + 'enable_ach' => 'Enable ACH', + 'stripe_ach_help' => 'ACH support must also be enabled at Stripe.', + 'ach_disabled' => 'Another gateway is already configured for direct debit.', + + 'plaid' => 'Plaid', + 'client_id' => 'Client Id', + 'secret' => 'Secret', + 'public_key' => 'Public Key', + 'plaid_optional' => '(optional)', + 'plaid_environment_help' => 'When a Stripe test key is given, Plaid\'s development environement (tartan) will be used.', + 'other_providers' => 'Other Providers', + 'country_not_supported' => 'That country is not supported.', + 'invalid_routing_number' => 'The routing number is not valid.', + 'invalid_account_number' => 'The account number is not valid.', + 'account_number_mismatch' => 'The account numbers do not match.', + 'missing_account_holder_type' => 'Please select an individual or company account.', + 'missing_account_holder_name' => 'Please enter the account holder\'s name.', + 'routing_number' => 'Routing Number', + 'confirm_account_number' => 'Confirm Account Number', + 'individual_account' => 'Individual Account', + 'company_account' => 'Company Account', + 'account_holder_name' => 'Account Holder Name', + 'add_account' => 'Add Account', + 'payment_methods' => 'Payment Methods', + 'complete_verification' => 'Complete Verification', + 'verification_amount1' => 'Amount 1', + 'verification_amount2' => 'Amount 2', + 'payment_method_verified' => 'Verification completed successfully', + 'verification_failed' => 'Verification Failed', + 'remove_payment_method' => 'Remove Payment Method', + 'confirm_remove_payment_method' => 'Are you sure you want to remove this payment method?', + 'remove' => 'Remove', + 'payment_method_removed' => 'Removed payment method.', + 'bank_account_verification_help' => 'We have made two deposits into your account with the description "VERIFICATION". These deposits will take 1-2 business days to appear on your statement. Please enter the amounts below.', + 'bank_account_verification_next_steps' => 'We have made two deposits into your account with the description "VERIFICATION". These deposits will take 1-2 business days to appear on your statement. + Once you have the amounts, come back to this payment methods page and click "Complete Verification" next to the account.', + 'unknown_bank' => 'Unknown Bank', + 'ach_verification_delay_help' => 'You will be able to use the account after completing verification. Verification usually takes 1-2 business days.', + 'add_credit_card' => 'Add Credit Card', + 'payment_method_added' => 'Added payment method.', + 'use_for_auto_bill' => 'Use For Autobill', + 'used_for_auto_bill' => 'Autobill Payment Method', + 'payment_method_set_as_default' => 'Set Autobill payment method.', + 'activity_41' => ':payment_amount payment (:payment) failed', + 'webhook_url' => 'Webhook URL', + 'stripe_webhook_help' => 'You must :link.', + 'stripe_webhook_help_link_text' => 'add this URL as an endpoint at Stripe', + 'payment_method_error' => 'There was an error adding your payment methd. Please try again later.', + 'notification_invoice_payment_failed_subject' => 'Payment failed for Invoice :invoice', + 'notification_invoice_payment_failed' => 'A payment made by client :client towards Invoice :invoice failed. The payment has been marked as failed and :amount has been added to the client\'s balance.', + 'link_with_plaid' => 'Link Account Instantly with Plaid', + 'link_manually' => 'Link Manually', + 'secured_by_plaid' => 'Secured by Plaid', + 'plaid_linked_status' => 'Your bank account at :bank', + 'add_payment_method' => 'Add Payment Method', + 'account_holder_type' => 'Account Holder Type', + 'ach_authorization' => 'I authorize :company to use my bank account for future payments and, if necessary, electronically credit my account to correct erroneous debits. I understand that I may cancel this authorization at any time by removing the payment method or by contacting :email.', + 'ach_authorization_required' => 'You must consent to ACH transactions.', + 'off' => 'Off', + 'opt_in' => 'Opt-in', + 'opt_out' => 'Opt-out', + 'always' => 'Always', + 'opted_out' => 'Opted out', + 'opted_in' => 'Opted in', + 'manage_auto_bill' => 'Manage Auto-bill', + 'enabled' => 'Enabled', + 'paypal' => 'PayPal', + 'braintree_enable_paypal' => 'Enable PayPal payments through BrainTree', + 'braintree_paypal_disabled_help' => 'The PayPal gateway is processing PayPal payments', + 'braintree_paypal_help' => 'You must also :link.', + 'braintree_paypal_help_link_text' => 'link PayPal to your BrainTree account', + 'token_billing_braintree_paypal' => 'Save payment details', + 'add_paypal_account' => 'Add PayPal Account', + + + 'no_payment_method_specified' => 'No payment method specified', + 'chart_type' => 'Chart Type', + 'format' => 'Format', + 'import_ofx' => 'Import OFX', + 'ofx_file' => 'OFX File', + 'ofx_parse_failed' => 'Failed to parse OFX file', + + // WePay + 'wepay' => 'WePay', + 'sign_up_with_wepay' => 'Sign up with WePay', + 'use_another_provider' => 'Use another provider', + 'company_name' => 'Company Name', + 'wepay_company_name_help' => 'This will appear on client\'s credit card statements.', + 'wepay_description_help' => 'The purpose of this account.', + 'wepay_tos_agree' => 'I agree to the :link.', + 'wepay_tos_link_text' => 'WePay Terms of Service', + 'resend_confirmation_email' => 'Resend Confirmation Email', + 'manage_wepay_account' => 'Manage WePay Account', + 'action_required' => 'Action Required', + 'finish_setup' => 'Finish Setup', + 'created_wepay_confirmation_required' => 'Please check your email and confirm your email address with WePay.', + 'switch_to_wepay' => 'Switch to WePay', + 'switch' => 'Switch', + 'restore_account_gateway' => 'Restore Gateway', + 'restored_account_gateway' => 'Successfully restored gateway', + 'united_states' => 'United States', + 'canada' => 'Canada', + 'accept_debit_cards' => 'Accept Debit Cards', + 'debit_cards' => 'Debit Cards', + + 'warn_start_date_changed' => 'The next invoice will be sent on the new start date.', + 'original_start_date' => 'Original start date', + 'new_start_date' => 'New start date', + 'security' => 'Security', + 'see_whats_new' => 'See what\'s new in v:version', + 'wait_for_upload' => 'Please wait for the document upload to complete.', + 'upgrade_for_permissions' => 'Upgrade to our Enterprise plan to enable permissions.', + 'enable_second_tax_rate' => 'Enable specifying a second tax rate', + 'payment_file' => 'Payment File', + 'expense_file' => 'Expense File', + 'product_file' => 'Product File', + 'import_products' => 'Import Products', + 'products_will_create' => 'products will be created.', + 'product_key' => 'Product', + 'created_products' => 'Successfully created :count product(s)', + 'export_help' => 'Use JSON if you plan to import the data into Invoice Ninja.', + 'JSON_file' => 'JSON File', + + 'view_dashboard' => 'View Dashboard', + 'client_session_expired' => 'Session Expired', + 'client_session_expired_message' => 'Your session has expired. Please click the link in your email again.', + + 'auto_bill_notification' => 'This invoice will automatically be billed to your :payment_method on file on :due_date.', + 'auto_bill_payment_method_bank_transfer' => 'bank account', + 'auto_bill_payment_method_credit_card' => 'credit card', + 'auto_bill_payment_method_paypal' => 'PayPal account', + 'auto_bill_notification_placeholder' => 'This invoice will automatically be billed to your credit card on file on the due date.', + 'payment_settings' => 'Payment Settings', + + 'on_send_date' => 'On send date', + 'on_due_date' => 'On due date', + 'auto_bill_ach_date_help' => 'ACH auto bill will always happen on the due date', + 'warn_change_auto_bill' => 'Due to NACHA rules, changes to this invoice may prevent ACH auto bill.', + + 'bank_account' => 'Bank Account', + 'payment_processed_through_wepay' => 'ACH payments will be processed using WePay.', + 'wepay_payment_tos_agree' => 'I agree to the WePay :terms and :privacy_policy.', + 'privacy_policy' => 'Privacy Policy', + 'wepay_payment_tos_agree_required' => 'You must agree to the WePay Terms of Service and Privacy Policy.', + 'payment_settings_supported_gateways' => 'These options are supported by the WePay, Stripe, and Braintree gateways.', + 'ach_email_prompt' => 'Please enter your email address:', + 'verification_pending' => 'Verification Pending', + + 'update_font_cache' => 'Please force refresh the page to update the font cache.', + 'more_options' => 'More options', + 'credit_card' => 'Credit Card', + 'bank_transfer' => 'Bank Transfer', + 'no_transaction_reference' => 'We did not recieve a payment transaction reference from the gateway.', + 'use_bank_on_file' => 'Use Bank on File', + 'auto_bill_email_message' => 'This invoice will automatically be billed to the payment method on file on the due date.', + 'bitcoin' => 'Bitcoin', + 'added_on' => 'Added :date', + 'failed_remove_payment_method' => 'Failed to remove the payment method', + 'gateway_exists' => 'This gateway already exists', + 'manual_entry' => 'Manual entry', + ); return $LANG; -?>. +?> diff --git a/resources/lang/da/texts.php b/resources/lang/da/texts.php index af939b8f7a..60405977e5 100644 --- a/resources/lang/da/texts.php +++ b/resources/lang/da/texts.php @@ -1,8 +1,6 @@ 'Organisation', 'name' => 'Navn', 'website' => 'Webside', @@ -25,8 +23,6 @@ return array( 'size_id' => 'Størrelse', 'industry_id' => 'Sektor', 'private_notes' => 'Private notater', - - // invoice 'invoice' => 'Faktura', 'client' => 'Klient', 'invoice_date' => 'Faktureringsdato', @@ -50,7 +46,6 @@ return array( 'invoice_design_id' => 'Design', 'terms' => 'Vilkår', 'your_invoice' => 'Din faktura', - 'remove_contact' => 'Fjern kontakt', 'add_contact' => 'Tilføj kontakt', 'create_new_client' => 'Opret ny klient', @@ -74,8 +69,6 @@ return array( 'settings' => 'Indstillinger', 'enable_invoice_tax' => 'Aktiver for at specificere en faktura skat', 'enable_line_item_tax' => 'Aktiver for at specificere per linjefaktura skat', - - // navigation 'dashboard' => 'Oversigt', 'clients' => 'Klienter', 'invoices' => 'Fakturaer', @@ -100,8 +93,6 @@ return array( 'provide_email' => 'Opgiv venligst en gyldig e-mail', 'powered_by' => 'Drevet af', 'no_items' => 'Ingen elementer', - - // recurring invoices 'recurring_invoices' => 'Gentagende fakturaer', 'recurring_help' => '

    Send automatisk klienter de samme fakturaer ugentligt, bi-månedligt, månedligt, kvartalsvis eller årligt.

    Brug :MONTH, :QUARTER eller :YEAR for dynamiske datoer. Grundliggende matematik fungerer også, for eksempel :MONTH-1.

    @@ -111,8 +102,6 @@ return array(
  • ":YEAR+1 årligt abonnement" => "2015 årligt abonnement"
  • "Forudbetaling for :QUARTER+1" => "Forudbetaling for Q2"
  • ', - - // dashboard 'in_total_revenue' => 'totale indtægter', 'billed_client' => 'faktureret klient', 'billed_clients' => 'fakturerede klienter', @@ -121,8 +110,6 @@ return array( 'invoices_past_due' => 'Forfaldne fakturaer', 'upcoming_invoices' => 'Kommende fakturaer', 'average_invoice' => 'Gennemsnitlig fakturaer', - - // list pages 'archive' => 'Arkiv', 'delete' => 'Slet', 'archive_client' => 'Arkiver klient', @@ -158,8 +145,6 @@ return array( 'select' => 'Vælg', 'edit_client' => 'Rediger klient', 'edit_invoice' => 'Rediger faktura', - - // client view page 'create_invoice' => 'Opret faktura', 'enter_credit' => 'Tilføj kredit', 'last_logged_in' => 'Sidste log ind', @@ -171,12 +156,8 @@ return array( 'message' => 'Besked', 'adjustment' => 'Justering', 'are_you_sure' => 'Er du sikker?', - - // payment pages 'payment_type_id' => 'Betalingsmetode', 'amount' => 'Beløb', - - // account/company pages 'work_email' => 'E-mail', 'language_id' => 'Sprog', 'timezone_id' => 'Tidszone', @@ -194,11 +175,7 @@ return array( 'email_paid' => 'Notifikation når en faktura er betalt', 'site_updates' => 'Webside opdateringer', 'custom_messages' => 'Tilpassede meldinger', - 'default_invoice_terms' => 'Sæt standard fakturavilkår', 'default_email_footer' => 'Sæt standard e-mailsignatur', - 'import_clients' => 'Importer klientdata', - 'csv_file' => 'Vælg CSV-fil', - 'export_clients' => 'Eksporter klientdata', 'select_file' => 'Venligst vælg en fil', 'first_row_headers' => 'Brug første række som overskrifter', 'column' => 'Kolonne', @@ -207,9 +184,12 @@ return array( 'client_will_create' => 'Klient vil blive oprettet', 'clients_will_create' => 'Klienter vil blive oprettet', 'email_settings' => 'E-mail Indstillinger', + 'client_view_styling' => 'Client View Styling', 'pdf_email_attachment' => 'Vedhæft PDF til e-mails', - - // application messages + 'custom_css' => 'Custom CSS', + 'import_clients' => 'Importer klientdata', + 'csv_file' => 'Vælg CSV-fil', + 'export_clients' => 'Eksporter klientdata', 'created_client' => 'Klient oprettet succesfuldt', 'created_clients' => 'Klienter oprettet succesfuldt', 'updated_settings' => 'Indstillinger opdateret', @@ -220,14 +200,12 @@ return array( 'payment_error' => 'Det opstod en fejl under din betaling. Venligst prøv igen senere.', 'registration_required' => 'Venligst registrer dig for at sende e-mail faktura', 'confirmation_required' => 'Venligst bekræft din e-mail adresse', - 'updated_client' => 'Klient opdateret', - 'created_client' => 'Klient oprettet', + 'created_client' => 'Klient oprettet succesfuldt', 'archived_client' => 'Klient arkiveret', 'archived_clients' => 'Arkiverede :count klienter', 'deleted_client' => 'Klient slettet', 'deleted_clients' => 'Slettede :count klienter', - 'updated_invoice' => 'Faktura opdateret', 'created_invoice' => 'Faktura oprettet', 'cloned_invoice' => 'Faktura kopieret', @@ -237,21 +215,25 @@ return array( 'archived_invoices' => 'Arkiverede :count fakturaer', 'deleted_invoice' => 'Faktura slettet', 'deleted_invoices' => 'Slettede :count fakturaer', - 'created_payment' => 'Betaling oprettet', + 'created_payments' => 'Successfully created :count payment(s)', 'archived_payment' => 'Betaling arkiveret', 'archived_payments' => 'Arkiverede :count betalinger', 'deleted_payment' => 'Betaling slettet', 'deleted_payments' => 'Slettede :count betalinger', 'applied_payment' => 'Betaling ajourført', - 'created_credit' => 'Kredit oprettet', 'archived_credit' => 'Kredit arkiveret', 'archived_credits' => 'Arkiverede :count kreditter', 'deleted_credit' => 'Kredit slettet', 'deleted_credits' => 'Slettede :count kreditter', - - // Emails + 'imported_file' => 'Successfully imported file', + 'updated_vendor' => 'Successfully updated vendor', + 'created_vendor' => 'Successfully created vendor', + 'archived_vendor' => 'Successfully archived vendor', + 'archived_vendors' => 'Successfully archived :count vendors', + 'deleted_vendor' => 'Successfully deleted vendor', + 'deleted_vendors' => 'Successfully deleted :count vendors', 'confirmation_subject' => 'Invoice Ninja konto bekræftelse', 'confirmation_header' => 'Konto bekræftelse', 'confirmation_message' => 'Venligst klik på linket nedenfor for at bekræfte din konto.', @@ -262,7 +244,6 @@ return array( 'email_salutation' => 'Kære :name,', 'email_signature' => 'Med venlig hilsen,', 'email_from' => 'Invoice Ninja Teamet', - 'user_email_footer' => 'For at justere varslings indstillingene besøg venligst'.SITE_URL.'/settings/notifications', 'invoice_link_message' => 'Hvis du vil se din klient faktura klik på linket under:', 'notification_invoice_paid_subject' => 'Faktura :invoice betalt af :client', 'notification_invoice_sent_subject' => 'Faktura :invoice sendt til :client', @@ -271,32 +252,11 @@ return array( 'notification_invoice_sent' => 'En e-mail er blevet sendt til :client med faktura :invoice pålydende :amount.', 'notification_invoice_viewed' => ':client har set faktura :invoice pålydende :amount.', 'reset_password' => 'Du kan nulstille din adgangskode ved at besøge følgende link:', - 'reset_password_footer' => 'Hvis du ikke bad om at få nulstillet din adgangskode kontakt venligst kundeservice: '.CONTACT_EMAIL, - - // Payment page 'secure_payment' => 'Sikker betaling', 'card_number' => 'Kortnummer', 'expiration_month' => 'Udløbsdato', 'expiration_year' => 'Udløbsår', 'cvv' => 'Kontrolcifre', - - // Security alerts - 'security' => [ - 'too_many_attempts' => 'For mange forsøg. Prøv igen om nogen få minutter.', - 'wrong_credentials' => 'Forkert e-mail eller adgangskode.', - 'confirmation' => 'Din konto har blevet bekræftet!', - 'wrong_confirmation' => 'Forkert bekræftelseskode.', - 'password_forgot' => 'Informationen om nulstilling af din adgangskode er blevet sendt til din e-mail.', - 'password_reset' => 'Adgangskode ændret', - 'wrong_password_reset' => 'Ugyldig adgangskode. Prøv på ny', - ], - - // Pro Plan - 'pro_plan' => [ - 'remove_logo' => ':link for at fjerne Invoice Ninja-logoet, opgrader til en Pro Plan', - 'remove_logo_link' => 'Klik her', - ], - 'logout' => 'Log ud', 'sign_up_to_save' => 'Registrer dig for at gemme dit arbejde', 'agree_to_terms' => 'Jeg accepterer Invoice Ninja :terms', @@ -307,9 +267,7 @@ return array( 'success_message' => 'Du er blevet registreret. Klik på linket som du har modtaget i e-mail bekræftelsen for at bekræfte din e-mail adresse.', 'erase_data' => 'Dette vil permanent slette dine oplysninger.', 'password' => 'Adgangskode', - 'pro_plan_product' => 'Pro Plan', - 'pro_plan_description' => 'Et års indmelding i Invoice Ninja Pro Plan.', 'pro_plan_success' => 'Tak fordi du valgte Invoice Ninja\'s Pro plan!

     
    De næste skridt

    En betalbar faktura er sendt til den e-email adresse som er tilknyttet din konto. For at låse op for alle de utrolige @@ -317,7 +275,6 @@ return array( betale for et år med Pro-niveau funktionerer.

    Kan du ikke finde fakturaen? Har behov for mere hjælp? Vi hjælper dig gerne hvis der skulle være noget galt -- kontakt os på contact@invoiceninja.com', - 'unsaved_changes' => 'Du har ikke gemte ændringer', 'custom_fields' => 'Egendefineret felt', 'company_fields' => 'Selskabets felt', @@ -327,8 +284,6 @@ return array( 'edit' => 'Rediger', 'set_name' => 'Sæt dit firmanavn', 'view_as_recipient' => 'Vis som modtager', - - // product management 'product_library' => 'Produkt bibliotek', 'product' => 'Produkt', 'products' => 'Produkter', @@ -343,18 +298,14 @@ return array( 'created_product' => 'Produkt oprettet', 'archived_product' => 'Produkt arkiveret', 'pro_plan_custom_fields' => ':link for at aktivere egendefinerede felter skal du have en Pro Plan', - 'advanced_settings' => 'Aavancerede indstillinger', 'pro_plan_advanced_settings' => ':link for at aktivere avancerede indstillinger skal du være have en Pro Plan', 'invoice_design' => 'Fakturadesign', 'specify_colors' => 'Egendefineret farve', 'specify_colors_label' => 'Vælg de farver som skal bruges i fakturaen', - 'chart_builder' => 'Diagram bygger', 'ninja_email_footer' => 'Brug :sitet til at fakturere dine kunder og bliv betalt på nettet - gratis!', 'go_pro' => 'Vælg Pro', - - // Quotes 'quote' => 'Pristilbud', 'quotes' => 'Pristilbud', 'quote_number' => 'Tilbuds nummer', @@ -364,7 +315,6 @@ return array( 'your_quote' => 'Dit tilbud', 'total' => 'Total', 'clone' => 'Kopier', - 'new_quote' => 'Nyt tilbud', 'create_quote' => 'Opret tilbud', 'edit_quote' => 'Rediger tilbud', @@ -377,7 +327,6 @@ return array( 'view_invoice' => 'Se faktura', 'view_client' => 'Vis klient', 'view_quote' => 'Se tilbud', - 'updated_quote' => 'Tilbud opdateret', 'created_quote' => 'Tilbud oprettet', 'cloned_quote' => 'Tilbud kopieret', @@ -387,7 +336,6 @@ return array( 'deleted_quote' => 'Tilbud slettet', 'deleted_quotes' => 'Slettede :count tilbud', 'converted_to_invoice' => 'Tilbud konverteret til faktura', - 'quote_subject' => 'Nyt tilbud fra :account', 'quote_message' => 'For at se dit tilbud pålydende :amount, klik på linket nedenfor.', 'quote_link_message' => 'Hvis du vil se din klients tilbud, klik på linket under:', @@ -395,16 +343,13 @@ return array( 'notification_quote_viewed_subject' => 'Tilbudet :invoice er set af :client', 'notification_quote_sent' => 'Følgende klient :client blev sendt tilbudsfaktura :invoice pålydende :amount.', 'notification_quote_viewed' => 'Følgende klient :client har set tilbudsfakturaen :invoice pålydende :amount.', - 'session_expired' => 'Session er udløbet.', - 'invoice_fields' => 'Faktura felt', 'invoice_options' => 'Faktura indstillinger', 'hide_quantity' => 'Skjul antal', 'hide_quantity_help' => 'Hvis du altid kun har 1 som antal på dine fakturalinjer på fakturaen, kan du vælge ikke at vise antal på fakturaen.', 'hide_paid_to_date' => 'Skjul delbetalinger', 'hide_paid_to_date_help' => 'Vis kun delbetalinger hvis der er forekommet en delbetaling.', - 'charge_taxes' => 'Inkluder skat', 'user_management' => 'Brugerhåndtering', 'add_user' => 'Tilføj bruger', @@ -419,21 +364,16 @@ return array( 'active' => 'Aktiv', 'pending' => 'Afventer', 'deleted_user' => 'Bruger slettet', - 'limit_users' => 'Desværre, dette vil overstige grænsen på '.MAX_NUM_USERS.' brugere', - 'confirm_email_invoice' => 'Er du sikker på at du vil sende en e-mail med denne faktura?', 'confirm_email_quote' => 'Er du sikker på du ville sende en e-mail med dette tilbud?', 'confirm_recurring_email_invoice' => 'Gentagende er slået til, er du sikker på du sende en e-mail med denne faktura?', - 'cancel_account' => 'Annuller konto', 'cancel_account_message' => 'Advarsel: Dette ville slette alle dine data og kan ikke fortrydes', 'go_back' => 'Gå tilbage', - 'data_visualizations' => 'Data visualisering', 'sample_data' => 'Eksempel data vist', 'hide' => 'Skjul', 'new_version_available' => 'En ny version af :releases_link er tilgængelig. Din nuværende version er v:user_version, den nyeste version er v:latest_version', - 'invoice_settings' => 'Faktura indstillinger', 'invoice_number_prefix' => 'Faktura nummer præfiks', 'invoice_number_counter' => 'Faktura nummer tæller', @@ -443,59 +383,48 @@ return array( 'invoice_issued_to' => 'Faktura udstedt til', 'invalid_counter' => 'For at undgå mulige overlap, sæt et faktura eller tilbuds nummer præfiks', 'mark_sent' => 'Markér som sendt', - 'gateway_help_1' => ':link til at registrere dig hos Authorize.net.', 'gateway_help_2' => ':link til at registrere dig hos Authorize.net.', 'gateway_help_17' => ':link til at hente din PayPal API signatur.', 'gateway_help_27' => ':link til at registrere dig hos TwoCheckout.', - 'more_designs' => 'Flere designs', 'more_designs_title' => 'Yderligere faktura designs', 'more_designs_cloud_header' => 'Skift til Pro for flere faktura designs', 'more_designs_cloud_text' => '', - 'more_designs_self_host_header' => 'Få 6 flere faktura designs for kun $'.INVOICE_DESIGNS_PRICE, 'more_designs_self_host_text' => '', 'buy' => 'Køb', 'bought_designs' => 'Yderligere faktura designs tilføjet', 'sent' => 'sendt', - 'vat_number' => 'SE/CVR nummer', 'timesheets' => 'Timesedler', - 'payment_title' => 'Indtast din faktura adresse og kreditkort information', 'payment_cvv' => '*Dette er det 3-4 cifrede nummer på bagsiden af dit kort', 'payment_footer1' => '*Faktura adressen skal matche den der er tilknyttet kortet.', 'payment_footer2' => '*Klik kun på "Betal Nu" én gang - transaktionen kan tage helt op til 1 minut inden den er færdig.', - 'id_number' => 'SE/CVR nummer', 'white_label_link' => 'Hvid Label', 'white_label_header' => 'Hvid Label', 'bought_white_label' => 'Hvid Label licens accepteret', 'white_labeled' => 'Hvid Label', - 'restore' => 'Genskab', 'restore_invoice' => 'Genskab faktura', 'restore_quote' => 'Genskab tilbud', 'restore_client' => 'Genskab Klient', 'restore_credit' => 'Genskab Kredit', 'restore_payment' => 'Genskab Betaling', - 'restored_invoice' => 'Faktura genskabt', 'restored_quote' => 'Tilbud genskabt', 'restored_client' => 'Klient genskabt', 'restored_payment' => 'Betaling genskabt', 'restored_credit' => 'Kredit genskabt', - 'reason_for_canceling' => 'Hjælp os med at blive bedre ved at fortælle os hvorfor du forlader os.', 'discount_percent' => 'Procent', 'discount_amount' => 'Beløb', - 'invoice_history' => 'Faktura historik', 'quote_history' => 'Tilbuds historik', 'current_version' => 'Nuværende version', 'select_version' => 'Vælg version', 'view_history' => 'Vis historik', - 'edit_payment' => 'Redigér betaling', 'updated_payment' => 'Betaling opdateret', 'deleted' => 'Slettet', @@ -508,7 +437,6 @@ return array( 'quote_email' => 'Tilbuds e-mail', 'reset_all' => 'Nulstil alle', 'approve' => 'Godkend', - 'token_billing_type_id' => 'Tokensk Fakturering', 'token_billing_help' => 'Tillader dig at gemme kredit kort oplysninger, for at kunne fakturere dem senere.', 'token_billing_1' => 'Slukket', @@ -516,12 +444,11 @@ return array( 'token_billing_3' => 'Fravalg - checkboks er vist og valgt', 'token_billing_4' => 'Altid', 'token_billing_checkbox' => 'Opbevar kreditkort oplysninger', - 'view_in_stripe' => 'Vis i Stripe ', - 'use_card_on_file' => 'Brug allerede gemt kort', + 'view_in_gateway' => 'Vis i :gateway', + 'use_card_on_file' => 'Use Card on File', 'edit_payment_details' => 'Redigér betalings detaljer', 'token_billing' => 'Gem kort detaljer', - 'token_billing_secure' => 'Kort data er opbevaret sikkert hos :stripe_link', - + 'token_billing_secure' => 'Kort data er opbevaret sikkert hos :link', 'support' => 'Kundeservice', 'contact_information' => 'Kontakt information', '256_encryption' => '256-Bit Kryptering', @@ -531,11 +458,8 @@ return array( 'order_overview' => 'Ordre oversigt', 'match_address' => '*Adressen skal matche det tilknyttede kredit kort.', 'click_once' => '**Klik kun på "Betal Nu" én gang - transaktionen kan tage helt op til 1 minut inden den er færdig.', - - 'default_invoice_footer' => 'Sæt standard faktura fodnoter', 'invoice_footer' => 'Faktura fodnoter', 'save_as_default_footer' => 'Gem som standard fodnoter', - 'token_management' => 'Token Administration', 'tokens' => 'Token\'s', 'add_token' => 'Tilføj token', @@ -546,7 +470,6 @@ return array( 'edit_token' => 'Redigér token', 'delete_token' => 'Slet token', 'token' => 'Token', - 'add_gateway' => 'Tilføj betalings portal', 'delete_gateway' => 'Slet betalings portal', 'edit_gateway' => 'Redigér betalings portal', @@ -555,7 +478,6 @@ return array( 'deleted_gateway' => 'Betalings portal slettet', 'pay_with_paypal' => 'PayPal', 'pay_with_card' => 'Kredit kort', - 'change_password' => 'Skift adgangskode', 'current_password' => 'Nuværende adgangskode', 'new_password' => 'Ny adgangskode', @@ -563,7 +485,6 @@ return array( 'password_error_incorrect' => 'Den nuværende adgangskode er forkert.', 'password_error_invalid' => 'Den nye adgangskode er ugyldig.', 'updated_password' => 'Adgangskode opdateret', - 'api_tokens' => 'API Token\'s', 'users_and_tokens' => 'Brugere & Token\'s', 'account_login' => 'Konto Log ind', @@ -575,13 +496,11 @@ return array( 'send_email' => 'Send e-mail', 'set_password' => 'Sæt adgangskode', 'converted' => 'Konverteret', - 'email_approved' => 'E-mail mig når et tilbud er accepteret', 'notification_quote_approved_subject' => 'Tilbudet :invoice blev accepteret af :client', 'notification_quote_approved' => 'Den følgende klient :client accepterede tilbud :invoice lydende på :amount.', 'resend_confirmation' => 'Send bekræftelses e-mail igen', 'confirmation_resent' => 'Bekræftelses e-mail er afsendt', - 'gateway_help_42' => ':link til registrering hos BitPay.
    Bemærk: brug en use a Legacy API nøgle, og ikke en API token.', 'payment_type_credit_card' => 'Kredit kort', 'payment_type_paypal' => 'PayPal', @@ -589,19 +508,16 @@ return array( 'knowledge_base' => 'Vidensbase', 'partial' => 'Delvis', 'partial_remaining' => ':partial af :balance', - 'more_fields' => 'Flere felter', 'less_fields' => 'Mindre felter', 'client_name' => 'Klient navn', 'pdf_settings' => 'PDF Indstillinger', - 'utf8_invoices' => 'Ny PDF driver Beta', 'product_settings' => 'Produkt Indstillinger', 'auto_wrap' => 'Automatisk linie ombrydning', 'duplicate_post' => 'Advarsel: den foregående side blev sendt to gange. Den anden afsendelse er blevet ignoreret.', 'view_documentation' => 'Vis dokumentation', 'app_title' => 'Gratis Open-Source Online fakturering', 'app_description' => 'Invoice Ninja er en gratis, open-source løsning til at håndtere fakturering og betaling af dine kunder. Med Invoice Ninja, kan du let generere og sende smukke fakturaer fra et hvilket som helst udstyr der har adgang til internettet. Dine klienter kan udskrive dine fakturarer, hente dem som PDF filer, og endda betale dem on-line inde fra Invoice Ninja.', - 'rows' => 'rækker', 'www' => 'www', 'logo' => 'Logo', @@ -621,7 +537,6 @@ return array( 'zapier' => 'Zapier', 'recurring' => 'Gentagne', 'last_invoice_sent' => 'Sidste faktura sendt :date', - 'processed_updates' => 'Opdatering gennemført', 'tasks' => 'Opogaver', 'new_task' => 'Ny opgave', @@ -667,12 +582,10 @@ return array( 'invoice_labels' => 'Faktura labels', 'prefix' => 'Præfix', 'counter' => 'Tæller', - 'payment_type_dwolla' => 'Dwolla', 'gateway_help_43' => ':link til at registrere dig hos Dwolla.', 'partial_value' => 'Skal være større end nul og mindre end totalen', 'more_actions' => 'Flere handlinger', - 'pro_plan_title' => 'NINJA PRO', 'pro_plan_call_to_action' => 'Opgradér Nu!', 'pro_plan_feature1' => 'Opret ubegrænset antal klienter', @@ -683,28 +596,23 @@ return array( 'pro_plan_feature6' => 'Opret tilbud og proforma fakturaer', 'pro_plan_feature7' => 'Brugerdefinerede faktura felt titler og nummerering', 'pro_plan_feature8' => 'Mulighed for at vedhæfte PDF filer til klient e-mails', - 'resume' => 'Genoptag', 'break_duration' => 'Pause', 'edit_details' => 'Rediger detaljer', 'work' => 'Arbejde', 'timezone_unset' => 'Indstil :link din tidszone', 'click_here' => 'Klik her', - 'email_receipt' => 'Send e-mail kvittering til klienten', 'created_payment_emailed_client' => 'Betaling modtaget og e-mail kvittering sendt til klienten', - 'add_account' => 'Tilføj konto', + 'add_company' => 'Add Company', 'untitled' => 'Ingen titel', - 'new_account' => 'Ny konto', + 'new_company' => 'New Company', 'associated_accounts' => 'Konti sammenkædet', 'unlinked_account' => 'Sammenkædning af konti ophævet', 'login' => 'Log ind', 'or' => 'eller', - 'email_error' => 'Der opstod et problem ved afsendelse af e-mailen', - 'created_by_recurring' => 'Oprettet af gentaget faktura nr.: :invoice', 'confirm_recurring_timing' => 'Bemærk: e-mail bliver sendt i starten af timen.', - 'old_browser' => 'Din browser er registreret som værende af ældre dato og den vil ikke kunne bruges, skift til en nyere version browser', 'payment_terms_help' => 'Sætter standard fakturaens forfalds dato', 'unlink_account' => 'Fjern sammenkædning af konti', 'unlink' => 'Fjern sammenkædning', @@ -725,7 +633,6 @@ return array( 'primary_color' => 'Primær Farve', 'secondary_color' => 'Sekundær Farve', 'customize_design' => 'Tilpas Design', - 'content' => 'Indhold', 'styles' => 'Stilarter', 'defaults' => 'Standarder', @@ -739,17 +646,16 @@ return array( 'outstanding' => 'Forfaldne', 'manage_companies' => 'Manage Companies', 'total_revenue' => 'Total Revenue', - 'current_user' => 'Nuværende bruger', 'new_recurring_invoice' => 'Ny gentaget fakture', 'recurring_invoice' => 'Gentaget faktura', + 'recurring_too_soon' => 'Det er for tidligt at generere den næste faktura, it\'s scheduled for :date', 'created_by_invoice' => 'Oprettet fra :invoice', 'primary_user' => 'Primær bruger', 'help' => 'Hjælp', - 'customize_help' => '

    Vi bruger pdfmake til at definere faktura design felter. pdfmake legeplads giver en god mulighed for at se biblioteket i aktion.

    -

    For at tilgå under indstillingerne ved hjælp af dot notation. For eksempel kan man for at vise klient navnet bruge $client.name.

    -

    Hvis du mangler svar på nogen spørgsmål så post et spørgsmål i vores support forum.

    ', - + 'customize_help' => '

    We use pdfmake to define the invoice designs declaratively. The pdfmake playground provide\'s a great way to see the library in action.

    +

    You can access a child property using dot notation. For example to show the client name you could use $client.name.

    +

    If you need help figuring something out post a question to our support forum with the design you\'re using.

    ', 'invoice_due_date' => 'Due Date', 'quote_due_date' => 'Valid Until', 'valid_until' => 'Valid Until', @@ -762,15 +668,12 @@ return array( 'status_partial' => 'Partial', 'status_paid' => 'Paid', 'show_line_item_tax' => 'Display line item taxes inline', - 'iframe_url' => 'Website', '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.', - 'auto_bill' => 'Auto Bill', 'military_time' => '24 Hour Time', 'last_sent' => 'Last Sent', - 'reminder_emails' => 'Reminder Emails', 'templates_and_reminders' => 'Templates & Reminders', 'subject' => 'Subject', @@ -782,15 +685,12 @@ return array( 'reminder_subject' => 'Reminder: Invoice :invoice from :account', 'reset' => 'Reset', 'invoice_not_found' => 'The requested invoice is not available', - 'referral_program' => 'Referral Program', 'referral_code' => 'Referral Code', 'last_sent_on' => 'Last sent on :date', - 'page_expire' => 'This page will expire soon, :click_here to keep working', 'upcoming_quotes' => 'Upcoming Quotes', 'expired_quotes' => 'Expired Quotes', - 'sign_up_using' => 'Sign up using', 'invalid_credentials' => 'These credentials do not match our records', 'show_all_options' => 'Show all options', @@ -799,17 +699,10 @@ return array( 'disable' => 'Disable', 'invoice_quote_number' => 'Invoice and Quote Numbers', '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_subject' => 'Unable to deliver Invoice :invoice', 'notification_quote_bounced' => 'We were unable to deliver Quote :invoice to :contact.', 'notification_quote_bounced_subject' => 'Unable to deliver Quote :invoice', - 'custom_invoice_link' => 'Custom Invoice Link', 'total_invoiced' => 'Total Invoiced', 'open_balance' => 'Open Balance', @@ -817,15 +710,12 @@ return array( 'basic_settings' => 'Basic Settings', 'pro' => 'Pro', 'gateways' => 'Payment Gateways', - 'recurring_too_soon' => 'Det er for tidligt at generere den næste faktura, it\'s scheduled for :date', - 'next_send_on' => 'Send Next: :date', 'no_longer_running' => 'This invoice is not scheduled to run', 'general_settings' => 'General Settings', 'customize' => 'Customize', 'oneclick_login_help' => 'Connect an account to login without a password', 'referral_code_help' => 'Earn money by sharing our app online', - 'enable_with_stripe' => 'Enable | Requires Stripe', 'tax_settings' => 'Tax Settings', 'create_tax_rate' => 'Add Tax Rate', @@ -846,7 +736,6 @@ return array( 'invoice_counter' => 'Invoice Counter', 'quote_counter' => 'Quote Counter', 'type' => 'Type', - 'activity_1' => ':user created client :client', 'activity_2' => ':user archived client :client', 'activity_3' => ':user deleted client :client', @@ -876,18 +765,24 @@ return array( 'activity_27' => ':user restored payment :payment', 'activity_28' => ':user restored :credit credit', 'activity_29' => ':contact approved quote :quote', - + 'activity_30' => ':user created :vendor', + 'activity_31' => ':user created :vendor', + 'activity_32' => ':user created :vendor', + 'activity_33' => ':user created :vendor', + 'activity_34' => ':user created expense :expense', + 'activity_35' => ':user created :vendor', + 'activity_36' => ':user created :vendor', + 'activity_37' => ':user created :vendor', 'payment' => 'Payment', 'system' => 'System', 'signature' => 'Email Signature', 'default_messages' => 'Default Messages', 'quote_terms' => 'Quote Terms', 'default_quote_terms' => 'Default Quote Terms', - 'default_invoice_terms' => 'Default Invoice Terms', - 'default_invoice_footer' => 'Default Invoice Footer', + 'default_invoice_terms' => 'Sæt standard fakturavilkår', + 'default_invoice_footer' => 'Sæt standard faktura fodnoter', 'quote_footer' => 'Quote Footer', 'free' => 'Free', - 'quote_is_approved' => 'This quote is approved', 'apply_credit' => 'Apply Credit', 'system_settings' => 'System Settings', @@ -905,7 +800,6 @@ return array( 'restored_recurring_invoice' => 'Successfully restored recurring invoice', 'archived' => 'Archived', 'untitled_account' => 'Untitled Company', - 'before' => 'Before', 'after' => 'After', 'reset_terms_help' => 'Reset to the default account terms', @@ -914,7 +808,6 @@ return array( 'user' => 'User', 'country' => 'Country', 'include' => 'Include', - '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_data' => 'Import Data', @@ -925,16 +818,6 @@ return array( 'task_file' => 'Task File', 'no_mapper' => 'No valid mapping for file', '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', 'admin' => 'Admin', 'disabled' => 'Disabled', @@ -943,11 +826,9 @@ return array( 'invoice_will_create' => 'client will be created', 'invoices_will_create' => 'invoices will be created', 'failed_to_import' => 'The following records failed to import, they either already exist or are missing required fields.', - 'publishable_key' => 'Publishable Key', 'secret_key' => 'Secret Key', 'missing_publishable_key' => 'Set your Stripe publishable key for an improved checkout process', - 'email_design' => 'Email Design', 'due_by' => 'Due by :date', 'enable_email_markup' => 'Enable Markup', @@ -959,7 +840,6 @@ return array( 'plain' => 'Plain', 'light' => 'Light', 'dark' => 'Dark', - '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.', 'invoice_number_help' => 'Specify a prefix or use a custom pattern to dynamically set the invoice number.', @@ -968,8 +848,6 @@ return array( '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_charges_helps' => 'Add a text input to the invoice create/edit page and include the charge in the invoice subtotals.', - 'color_help' => 'Note: the primary color is also used in the client portal and custom email designs.', - 'token_expired' => 'Validation token was expired. Please try again.', 'invoice_link' => 'Invoice Link', 'button_confirmation_message' => 'Click to confirm your email address.', @@ -978,7 +856,6 @@ return array( 'created_invoices' => 'Successfully created :count invoice(s)', 'next_invoice_number' => 'The next invoice number is :number.', 'next_quote_number' => 'The next quote number is :number.', - 'days_before' => 'days before', 'days_after' => 'days after', 'field_due_date' => 'due date', @@ -986,11 +863,7 @@ return array( 'schedule' => 'Schedule', 'email_designs' => 'Email Designs', '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', - - // Expense / vendor 'expense' => 'Expense', 'expenses' => 'Expenses', 'new_expense' => 'Enter Expense', @@ -1007,8 +880,6 @@ return array( 'archived_expense' => 'Successfully archived expense', 'deleted_expenses' => 'Successfully deleted expenses', 'archived_expenses' => 'Successfully archived expenses', - - // Expenses 'expense_amount' => 'Expense Amount', 'expense_balance' => 'Expense Balance', 'expense_date' => 'Expense Date', @@ -1030,18 +901,14 @@ return array( 'view' => 'View', 'restore_expense' => 'Restore Expense', 'invoice_expense' => 'Invoice Expense', - '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', 'convert_currency' => 'Convert currency', - - // Payment terms 'num_days' => 'Number of days', 'create_payment_term' => 'Create Payment Term', 'edit_payment_terms' => 'Edit Payment Term', 'edit_payment_term' => 'Edit Payment Term', 'archive_payment_term' => 'Archive Payment Term', - - // recurring due dates 'recurring_due_dates' => 'Recurring Invoice Due Dates', 'recurring_due_date_help' => '

    Automatically sets a due date for the invoice.

    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.

    @@ -1069,15 +936,11 @@ return array( 'thursday' => 'Thursday', 'friday' => 'Friday', 'saturday' => 'Saturday', - - // Fonts 'header_font_id' => 'Header 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.', - 'live_preview' => 'Live Preview', '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.', 'quote_message_button' => 'To view your quote for :amount, click the button below.', 'payment_message_button' => 'Thank you for your payment of :amount.', @@ -1094,7 +957,6 @@ return array( 'archived_bank_account' => 'Successfully archived bank account', 'created_bank_account' => 'Successfully created 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 400+ US banks.', '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.', 'username' => 'Username', @@ -1108,7 +970,6 @@ return array( 'validate' => 'Validate', 'info' => 'Info', '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.', '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.', @@ -1129,7 +990,28 @@ return array( 'trial_call_to_action' => 'Start Free Trial', '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.', + + + 'white_label_text' => 'Purchase a ONE YEAR white label license for $:price to remove the Invoice Ninja branding from the client portal and help support our project.', + 'user_email_footer' => 'For at justere varslings indstillingene besøg venligst :link', + 'reset_password_footer' => 'Hvis du ikke bad om at få nulstillet din adgangskode kontakt venligst kundeservice: :email', + 'limit_users' => 'Desværre, dette vil overstige grænsen på :limit brugere', + 'more_designs_self_host_header' => 'Få 6 flere faktura designs for kun $:price', + 'old_browser' => 'Din browser er registreret som værende af ældre dato og den vil ikke kunne bruges, skift til en nyere version browser', + 'white_label_custom_css' => ':link for $: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 400+ US banks.', + + 'pro_plan_remove_logo' => ':link for at fjerne Invoice Ninja-logoet, opgrader til en Pro Plan', + 'pro_plan_remove_logo_link' => 'Klik her', + 'invitation_status_sent' => 'Email Sent', + 'invitation_status_opened' => 'Email Openend', + 'invitation_status_viewed' => 'Invoice Viewed', + 'email_error_inactive_client' => 'Emails can not be sent to inactive clients', + 'email_error_inactive_contact' => 'Emails can not be sent to inactive contacts', + 'email_error_inactive_invoice' => 'Emails can not be sent to inactive invoices', + 'email_error_user_unregistered' => 'Please register your account to send emails', + 'email_error_user_unconfirmed' => 'Please confirm your account to send emails', + 'email_error_invalid_contact_email' => 'Invalid contact email', 'navigation' => 'Navigation', 'list_invoices' => 'List Invoices', @@ -1152,22 +1034,20 @@ return array( 'custom_invoice_item_fields_help' => 'Add a field when creating an invoice item and display the label and value on the PDF.', 'recurring_invoice_number' => 'Recurring Invoice Number', 'recurring_invoice_number_prefix_help' => 'Speciy a prefix to be added to the invoice number for recurring invoices. The default value is \'R\'.', - 'enable_client_portal' => 'Dashboard', - 'enable_client_portal_help' => 'Show/hide the dashboard page in the client portal.', // Client Passwords 'enable_portal_password'=>'Password protect invoices', 'enable_portal_password_help'=>'Allows you to set a password for each contact. If a password is set, the contact will be required to enter a password before viewing invoices.', 'send_portal_password'=>'Generate password automatically', 'send_portal_password_help'=>'If no password is set, one will be generated and sent with the first invoice.', - + 'expired' => 'Expired', 'invalid_card_number' => 'The credit card number is not valid.', 'invalid_expiry' => 'The expiration date is not valid.', 'invalid_cvv' => 'The CVV is not valid.', 'cost' => 'Cost', 'create_invoice_for_sample' => 'Note: create your first invoice to see a preview here.', - + // User Permissions 'owner' => 'Owner', 'administrator' => 'Administrator', @@ -1185,8 +1065,8 @@ return array( 'create_all_help' => 'Allow user to create and modify records', 'view_all_help' => 'Allow user to view records they didn\'t create', 'edit_all_help' => 'Allow user to modify records they didn\'t create', - 'view_payment' => 'View Payment', - + 'view_payment' => 'View Payment', + 'january' => 'January', 'february' => 'February', 'march' => 'March', @@ -1212,30 +1092,28 @@ return array( 'document_email_attachment' => 'Attach Documents', 'download_documents' => 'Download Documents (:size)', 'documents_from_expenses' => 'From Expenses:', - 'dropzone' => array(// See http://www.dropzonejs.com/#config-dictDefaultMessage - 'DefaultMessage' => 'Drop files or click to upload', - 'FallbackMessage' => 'Your browser does not support drag\'n\'drop file uploads.', - 'FallbackText' => 'Please use the fallback form below to upload your files like in the olden days.', - 'FileTooBig' => 'File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.', - 'InvalidFileType' => 'You can\'t upload files of this type.', - 'ResponseError' => 'Server responded with {{statusCode}} code.', - 'CancelUpload' => 'Cancel upload', - 'CancelUploadConfirmation' => 'Are you sure you want to cancel this upload?', - 'RemoveFile' => 'Remove file', - ), + 'dropzone_default_message' => 'Drop files or click to upload', + 'dropzone_fallback_message' => 'Your browser does not support drag\'n\'drop file uploads.', + 'dropzone_fallback_text' => 'Please use the fallback form below to upload your files like in the olden days.', + 'dropzone_file_too_big' => 'File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.', + 'dropzone_invalid_file_type' => 'You can\'t upload files of this type.', + 'dropzone_response_error' => 'Server responded with {{statusCode}} code.', + 'dropzone_cancel_upload' => 'Cancel upload', + 'dropzone_cancel_upload_confirmation' => 'Are you sure you want to cancel this upload?', + 'dropzone_remove_file' => 'Remove file', 'documents' => 'Documents', 'document_date' => 'Document Date', 'document_size' => 'Size', - 'enable_client_portal' => 'Client Portal', - 'enable_client_portal_help' => 'Show/hide the client portal.', + 'enable_client_portal' => 'Dashboard', + 'enable_client_portal_help' => 'Show/hide the dashboard page in the client portal.', 'enable_client_portal_dashboard' => 'Dashboard', 'enable_client_portal_dashboard_help' => 'Show/hide the dashboard page in the client portal.', - + // Plans 'account_management' => 'Account Management', 'plan_status' => 'Plan Status', - + 'plan_upgrade' => 'Upgrade', 'plan_change' => 'Change Plan', 'pending_change_to' => 'Changes To', @@ -1265,9 +1143,9 @@ return array( 'plan_paid' => 'Term Started', 'plan_started' => 'Plan Started', 'plan_expires' => 'Plan Expires', - + 'white_label_button' => 'White Label', - + 'pro_plan_year_description' => 'One year enrollment in the Invoice Ninja Pro Plan.', 'pro_plan_month_description' => 'One month enrollment in the Invoice Ninja Pro Plan.', 'enterprise_plan_product' => 'Enterprise Plan', @@ -1285,7 +1163,207 @@ return array( 'preview' => 'Preview', 'list_vendors' => 'List Vendors', 'add_users_not_supported' => 'Upgrade to the Enterprise plan to add additional users to your account.', - 'enterprise_plan_features' => 'The Enterprise plan adds support for multiple users and file attachments.', + 'enterprise_plan_features' => 'The Enterprise plan adds support for multiple users and file attachments, :link to see the full list of features.', 'return_to_app' => 'Return to app', - -); \ No newline at end of file + + + // Payment updates + 'refund_payment' => 'Refund Payment', + 'refund_max' => 'Max:', + 'refund' => 'Refund', + 'are_you_sure_refund' => 'Refund selected payments?', + 'status_pending' => 'Pending', + 'status_completed' => 'Completed', + 'status_failed' => 'Failed', + 'status_partially_refunded' => 'Partially Refunded', + 'status_partially_refunded_amount' => ':amount Refunded', + 'status_refunded' => 'Refunded', + 'status_voided' => 'Cancelled', + 'refunded_payment' => 'Refunded Payment', + 'activity_39' => ':user cancelled a :payment_amount payment (:payment)', + 'activity_40' => ':user refunded :adjustment of a :payment_amount payment (:payment)', + 'card_expiration' => 'Exp: :expires', + + 'card_creditcardother' => 'Unknown', + 'card_americanexpress' => 'American Express', + 'card_carteblanche' => 'Carte Blanche', + 'card_unionpay' => 'UnionPay', + 'card_diners' => 'Diners Club', + 'card_discover' => 'Discover', + 'card_jcb' => 'JCB', + 'card_laser' => 'Laser', + 'card_maestro' => 'Maestro', + 'card_mastercard' => 'MasterCard', + 'card_solo' => 'Solo', + 'card_switch' => 'Switch', + 'card_visacard' => 'Visa', + 'card_ach' => 'ACH', + + 'payment_type_stripe' => 'Stripe', + 'ach' => 'ACH', + 'enable_ach' => 'Enable ACH', + 'stripe_ach_help' => 'ACH support must also be enabled at Stripe.', + 'ach_disabled' => 'Another gateway is already configured for direct debit.', + + 'plaid' => 'Plaid', + 'client_id' => 'Client Id', + 'secret' => 'Secret', + 'public_key' => 'Public Key', + 'plaid_optional' => '(optional)', + 'plaid_environment_help' => 'When a Stripe test key is given, Plaid\'s development environement (tartan) will be used.', + 'other_providers' => 'Other Providers', + 'country_not_supported' => 'That country is not supported.', + 'invalid_routing_number' => 'The routing number is not valid.', + 'invalid_account_number' => 'The account number is not valid.', + 'account_number_mismatch' => 'The account numbers do not match.', + 'missing_account_holder_type' => 'Please select an individual or company account.', + 'missing_account_holder_name' => 'Please enter the account holder\'s name.', + 'routing_number' => 'Routing Number', + 'confirm_account_number' => 'Confirm Account Number', + 'individual_account' => 'Individual Account', + 'company_account' => 'Company Account', + 'account_holder_name' => 'Account Holder Name', + 'add_account' => 'Tilføj konto', + 'payment_methods' => 'Payment Methods', + 'complete_verification' => 'Complete Verification', + 'verification_amount1' => 'Amount 1', + 'verification_amount2' => 'Amount 2', + 'payment_method_verified' => 'Verification completed successfully', + 'verification_failed' => 'Verification Failed', + 'remove_payment_method' => 'Remove Payment Method', + 'confirm_remove_payment_method' => 'Are you sure you want to remove this payment method?', + 'remove' => 'Remove', + 'payment_method_removed' => 'Removed payment method.', + 'bank_account_verification_help' => 'We have made two deposits into your account with the description "VERIFICATION". These deposits will take 1-2 business days to appear on your statement. Please enter the amounts below.', + 'bank_account_verification_next_steps' => 'We have made two deposits into your account with the description "VERIFICATION". These deposits will take 1-2 business days to appear on your statement. + Once you have the amounts, come back to this payment methods page and click "Complete Verification" next to the account.', + 'unknown_bank' => 'Unknown Bank', + 'ach_verification_delay_help' => 'You will be able to use the account after completing verification. Verification usually takes 1-2 business days.', + 'add_credit_card' => 'Add Credit Card', + 'payment_method_added' => 'Added payment method.', + 'use_for_auto_bill' => 'Use For Autobill', + 'used_for_auto_bill' => 'Autobill Payment Method', + 'payment_method_set_as_default' => 'Set Autobill payment method.', + 'activity_41' => ':payment_amount payment (:payment) failed', + 'webhook_url' => 'Webhook URL', + 'stripe_webhook_help' => 'You must :link.', + 'stripe_webhook_help_link_text' => 'add this URL as an endpoint at Stripe', + 'payment_method_error' => 'There was an error adding your payment methd. Please try again later.', + 'notification_invoice_payment_failed_subject' => 'Payment failed for Invoice :invoice', + 'notification_invoice_payment_failed' => 'A payment made by client :client towards Invoice :invoice failed. The payment has been marked as failed and :amount has been added to the client\'s balance.', + 'link_with_plaid' => 'Link Account Instantly with Plaid', + 'link_manually' => 'Link Manually', + 'secured_by_plaid' => 'Secured by Plaid', + 'plaid_linked_status' => 'Your bank account at :bank', + 'add_payment_method' => 'Add Payment Method', + 'account_holder_type' => 'Account Holder Type', + 'ach_authorization' => 'I authorize :company to use my bank account for future payments and, if necessary, electronically credit my account to correct erroneous debits. I understand that I may cancel this authorization at any time by removing the payment method or by contacting :email.', + 'ach_authorization_required' => 'You must consent to ACH transactions.', + 'off' => 'Off', + 'opt_in' => 'Opt-in', + 'opt_out' => 'Opt-out', + 'always' => 'Always', + 'opted_out' => 'Opted out', + 'opted_in' => 'Opted in', + 'manage_auto_bill' => 'Manage Auto-bill', + 'enabled' => 'Enabled', + 'paypal' => 'PayPal', + 'braintree_enable_paypal' => 'Enable PayPal payments through BrainTree', + 'braintree_paypal_disabled_help' => 'The PayPal gateway is processing PayPal payments', + 'braintree_paypal_help' => 'You must also :link.', + 'braintree_paypal_help_link_text' => 'link PayPal to your BrainTree account', + 'token_billing_braintree_paypal' => 'Save payment details', + 'add_paypal_account' => 'Add PayPal Account', + + + 'no_payment_method_specified' => 'No payment method specified', + 'chart_type' => 'Chart Type', + 'format' => 'Format', + 'import_ofx' => 'Import OFX', + 'ofx_file' => 'OFX File', + 'ofx_parse_failed' => 'Failed to parse OFX file', + + // WePay + 'wepay' => 'WePay', + 'sign_up_with_wepay' => 'Sign up with WePay', + 'use_another_provider' => 'Use another provider', + 'company_name' => 'Company Name', + 'wepay_company_name_help' => 'This will appear on client\'s credit card statements.', + 'wepay_description_help' => 'The purpose of this account.', + 'wepay_tos_agree' => 'I agree to the :link.', + 'wepay_tos_link_text' => 'WePay Terms of Service', + 'resend_confirmation_email' => 'Resend Confirmation Email', + 'manage_wepay_account' => 'Manage WePay Account', + 'action_required' => 'Action Required', + 'finish_setup' => 'Finish Setup', + 'created_wepay_confirmation_required' => 'Please check your email and confirm your email address with WePay.', + 'switch_to_wepay' => 'Switch to WePay', + 'switch' => 'Switch', + 'restore_account_gateway' => 'Restore Gateway', + 'restored_account_gateway' => 'Successfully restored gateway', + 'united_states' => 'United States', + 'canada' => 'Canada', + 'accept_debit_cards' => 'Accept Debit Cards', + 'debit_cards' => 'Debit Cards', + + 'warn_start_date_changed' => 'The next invoice will be sent on the new start date.', + 'original_start_date' => 'Original start date', + 'new_start_date' => 'New start date', + 'security' => 'Security', + 'see_whats_new' => 'See what\'s new in v:version', + 'wait_for_upload' => 'Please wait for the document upload to complete.', + 'upgrade_for_permissions' => 'Upgrade to our Enterprise plan to enable permissions.', + 'enable_second_tax_rate' => 'Enable specifying a second tax rate', + 'payment_file' => 'Payment File', + 'expense_file' => 'Expense File', + 'product_file' => 'Product File', + 'import_products' => 'Import Products', + 'products_will_create' => 'products will be created.', + 'product_key' => 'Product', + 'created_products' => 'Successfully created :count product(s)', + 'export_help' => 'Use JSON if you plan to import the data into Invoice Ninja.', + 'JSON_file' => 'JSON File', + + 'view_dashboard' => 'View Dashboard', + 'client_session_expired' => 'Session Expired', + 'client_session_expired_message' => 'Your session has expired. Please click the link in your email again.', + + 'auto_bill_notification' => 'This invoice will automatically be billed to your :payment_method on file on :due_date.', + 'auto_bill_payment_method_bank_transfer' => 'bank account', + 'auto_bill_payment_method_credit_card' => 'credit card', + 'auto_bill_payment_method_paypal' => 'PayPal account', + 'auto_bill_notification_placeholder' => 'This invoice will automatically be billed to your credit card on file on the due date.', + 'payment_settings' => 'Payment Settings', + + 'on_send_date' => 'On send date', + 'on_due_date' => 'On due date', + 'auto_bill_ach_date_help' => 'ACH auto bill will always happen on the due date', + 'warn_change_auto_bill' => 'Due to NACHA rules, changes to this invoice may prevent ACH auto bill.', + + 'bank_account' => 'Bank Account', + 'payment_processed_through_wepay' => 'ACH payments will be processed using WePay.', + 'wepay_payment_tos_agree' => 'I agree to the WePay :terms and :privacy_policy.', + 'privacy_policy' => 'Privacy Policy', + 'wepay_payment_tos_agree_required' => 'You must agree to the WePay Terms of Service and Privacy Policy.', + 'payment_settings_supported_gateways' => 'These options are supported by the WePay, Stripe, and Braintree gateways.', + 'ach_email_prompt' => 'Please enter your email address:', + 'verification_pending' => 'Verification Pending', + + 'update_font_cache' => 'Please force refresh the page to update the font cache.', + 'more_options' => 'More options', + 'credit_card' => 'Credit Card', + 'bank_transfer' => 'Bank Transfer', + 'no_transaction_reference' => 'We did not recieve a payment transaction reference from the gateway.', + 'use_bank_on_file' => 'Use Bank on File', + 'auto_bill_email_message' => 'This invoice will automatically be billed to the payment method on file on the due date.', + 'bitcoin' => 'Bitcoin', + 'added_on' => 'Added :date', + 'failed_remove_payment_method' => 'Failed to remove the payment method', + 'gateway_exists' => 'This gateway already exists', + 'manual_entry' => 'Manual entry', + +); + +return $LANG; + +?> diff --git a/resources/lang/de/texts.php b/resources/lang/de/texts.php index 64c2222bab..d585ebe7ae 100644 --- a/resources/lang/de/texts.php +++ b/resources/lang/de/texts.php @@ -1,6 +1,6 @@ 'Organisation', @@ -25,8 +25,6 @@ return array( 'size_id' => 'Firmengröße', 'industry_id' => 'Kategorie', 'private_notes' => 'Notizen', - - // invoice 'invoice' => 'Rechnung', 'client' => 'Kunde', 'invoice_date' => 'Rechnungsdatum', @@ -50,7 +48,6 @@ return array( 'invoice_design_id' => 'Design', 'terms' => 'Bedingungen', 'your_invoice' => 'Ihre Rechnung', - 'remove_contact' => 'Kontakt löschen', 'add_contact' => 'Kontakt hinzufügen', 'create_new_client' => 'Einen neuen Kunden erstellen', @@ -74,8 +71,6 @@ return array( 'settings' => 'Einstellungen', 'enable_invoice_tax' => 'Ermögliche das Bestimmen einer Rechnungssteuer', 'enable_line_item_tax' => 'Ermögliche das Bestimmen von Steuern für Belegpositionen', - - // navigation 'dashboard' => 'Dashboard', 'clients' => 'Kunden', 'invoices' => 'Rechnungen', @@ -100,8 +95,6 @@ return array( 'provide_email' => 'Bitte gib eine gültige E-Mail-Adresse an', 'powered_by' => 'Powered by', 'no_items' => 'Keine Objekte', - - // recurring invoices 'recurring_invoices' => 'Wiederkehrende Rechnungen', 'recurring_help' => '

    Sende deinem Kunden wöchentlich, zwei mal im Monat, monatlich, vierteljährlich oder jährlich automatisch die gleiche Rechnung.

    Benutze :MONTH, :QUARTER oder :YEAR für ein dynamisches Datum. Grundlegende Mathematik funktioniert genauso gut, zum Beispiel :MONTH-1.

    @@ -111,8 +104,6 @@ return array(
  • ":YEAR+1 Jahresbeitrag" => "2015 Jahresbeitrag"
  • "Vorschusszahlung für :QUARTER+1" => "Vorschusszahlung für Q2"
  • ', - - // dashboard 'in_total_revenue' => 'Gesamtumsatz', 'billed_client' => 'abgerechneter Kunde', 'billed_clients' => 'abgerechnete Kunden', @@ -121,8 +112,6 @@ return array( 'invoices_past_due' => 'Fällige Rechnungen', 'upcoming_invoices' => 'Kommende Rechnungen', 'average_invoice' => 'Durchschnittlicher Rechnungsbetrag', - - // list pages 'archive' => 'archivieren', 'delete' => 'löschen', 'archive_client' => 'Kunde archivieren', @@ -158,8 +147,6 @@ return array( 'select' => 'Wählen', 'edit_client' => 'Kunde bearbeiten', 'edit_invoice' => 'Rechnung bearbeiten', - - // client view page 'create_invoice' => 'Rechnung erstellen', 'enter_credit' => 'Guthaben eingeben', 'last_logged_in' => 'Zuletzt eingeloggt', @@ -171,12 +158,8 @@ return array( 'message' => 'Nachricht', 'adjustment' => 'Anpassung', 'are_you_sure' => 'Bist du dir sicher?', - - // payment pages 'payment_type_id' => 'Zahlungsart', 'amount' => 'Betrag', - - // account/company pages 'work_email' => 'E-Mail', 'language_id' => 'Sprache', 'timezone_id' => 'Zeitzone', @@ -194,11 +177,7 @@ return array( 'email_paid' => 'Benachrichtigen, wenn eine Rechnung bezahlt wurde', 'site_updates' => 'Seiten Updates', 'custom_messages' => 'Benutzerdefinierte Nachrichten', - 'default_invoice_terms' => 'Standard-Rechnungsbedingungen', 'default_email_footer' => 'Standard-E-Mail Signatur', - 'import_clients' => 'Importiere Kundendaten', - 'csv_file' => 'Wähle CSV Datei', - 'export_clients' => 'Exportiere Kundendaten', 'select_file' => 'Bitte wähle eine Datei', 'first_row_headers' => 'Benutze erste Zeile als Kopfzeile', 'column' => 'Spalte', @@ -207,9 +186,12 @@ return array( 'client_will_create' => 'Kunde wird erstellt', 'clients_will_create' => 'Kunden werden erstellt', 'email_settings' => 'E-Mail-Einstellungen', + 'client_view_styling' => 'Client View Styling', 'pdf_email_attachment' => 'PDF an E-Mails anhängen', - - // application messages + 'custom_css' => 'Benutzerdefiniertes CSS', + 'import_clients' => 'Importiere Kundendaten', + 'csv_file' => 'Wähle CSV Datei', + 'export_clients' => 'Exportiere Kundendaten', 'created_client' => 'Kunde erfolgreich angelegt', 'created_clients' => ':count Kunden erfolgreich angelegt', 'updated_settings' => 'Einstellungen erfolgreich aktualisiert', @@ -220,14 +202,12 @@ return array( 'payment_error' => 'Es ist ein Fehler während der Zahlung aufgetreten. Bitte versuche es später noch einmal.', 'registration_required' => 'Bitte melde dich an um eine Rechnung zu versenden', 'confirmation_required' => 'Bitte bestätige deine E-Mail-Adresse', - 'updated_client' => 'Kunde erfolgreich aktualisiert', - 'created_client' => 'Kunde erfolgreich erstellt', + 'created_client' => 'Kunde erfolgreich angelegt', 'archived_client' => 'Kunde erfolgreich archiviert', 'archived_clients' => ':count Kunden erfolgreich archiviert', 'deleted_client' => 'Kunde erfolgreich gelöscht', 'deleted_clients' => ':count Kunden erfolgreich gelöscht', - 'updated_invoice' => 'Rechnung erfolgreich aktualisiert', 'created_invoice' => 'Rechnung erfolgreich erstellt', 'cloned_invoice' => 'Rechnung erfolgreich dupliziert', @@ -237,21 +217,25 @@ return array( 'archived_invoices' => ':count Rechnungen erfolgreich archiviert', 'deleted_invoice' => 'Rechnung erfolgreich gelöscht', 'deleted_invoices' => ':count Rechnungen erfolgreich gelöscht', - 'created_payment' => 'Zahlung erfolgreich erstellt', + 'created_payments' => ':count Zahlung(en) erfolgreich erstellt', 'archived_payment' => 'Zahlung erfolgreich archiviert', 'archived_payments' => ':count Zahlungen erfolgreich archiviert', 'deleted_payment' => 'Zahlung erfolgreich gelöscht', 'deleted_payments' => ':count Zahlungen erfolgreich gelöscht', 'applied_payment' => 'Zahlung erfolgreich angewandt', - 'created_credit' => 'Guthaben erfolgreich erstellt', 'archived_credit' => 'Guthaben erfolgreich archiviert', 'archived_credits' => ':count Guthaben erfolgreich archiviert', 'deleted_credit' => 'Guthaben erfolgreich gelöscht', 'deleted_credits' => ':count Guthaben erfolgreich gelöscht', - - // Emails + 'imported_file' => 'Datei erfolgreich importiert', + 'updated_vendor' => 'Successfully updated vendor', + 'created_vendor' => 'Successfully created vendor', + 'archived_vendor' => 'Successfully archived vendor', + 'archived_vendors' => 'Successfully archived :count vendors', + 'deleted_vendor' => 'Successfully deleted vendor', + 'deleted_vendors' => 'Successfully deleted :count vendors', 'confirmation_subject' => 'InvoiceNinja Kontobestätigung', 'confirmation_header' => 'Kontobestätigung', 'confirmation_message' => 'Bitte klicke auf den folgenden Link um dein Konto zu bestätigen.', @@ -262,7 +246,6 @@ return array( 'email_salutation' => 'Sehr geehrte/r :name,', 'email_signature' => 'Mit freundlichen Grüßen,', 'email_from' => 'Das InvoiceNinja Team', - 'user_email_footer' => 'Um deine E-Mail-Benachrichtigungen anzupassen besuche bitte '.SITE_URL.'/settings/notifications', 'invoice_link_message' => 'Um deine Kundenrechnung anzuschauen, klicke auf den folgenden Link:', 'notification_invoice_paid_subject' => 'Die Rechnung :invoice wurde von :client bezahlt.', 'notification_invoice_sent_subject' => 'Die Rechnung :invoice wurde an :client versendet.', @@ -271,32 +254,11 @@ return array( 'notification_invoice_sent' => 'Dem Kunden :client wurde die Rechnung :invoice über :amount versendet.', 'notification_invoice_viewed' => 'Der Kunde :client hat sich die Rechnung :invoice über :amount angesehen.', 'reset_password' => 'Du kannst dein Passwort zurücksetzen, indem du auf den folgenden Link klickst:', - 'reset_password_footer' => 'Wenn du das Zurücksetzen des Passworts nicht beantragt hast, benachrichtige bitte unseren Support: '.CONTACT_EMAIL, - - // Payment page 'secure_payment' => 'Sichere Zahlung', 'card_number' => 'Kartennummer', 'expiration_month' => 'Ablaufmonat', 'expiration_year' => 'Ablaufjahr', 'cvv' => 'Kartenprüfziffer', - - // Security alerts - 'security' => array( - 'too_many_attempts' => 'Zu viele Versuche. Bitte probiere es in ein paar Minuten erneut.', - 'wrong_credentials' => 'Falsche E-Mail-Adresse oder falsches Passwort.', - 'confirmation' => 'Dein Konto wurde bestätigt!', - 'wrong_confirmation' => 'Falscher Bestätigungscode.', - 'password_forgot' => 'Weitere Informationen um das Passwort zurückzusetzen wurden dir per E-Mail zugeschickt.', - 'password_reset' => 'Dein Passwort wurde erfolgreich geändert.', - 'wrong_password_reset' => 'Ungültiges Passwort. Versuche es erneut', - ), - - // Pro Plan - 'pro_plan' => [ - 'remove_logo' => ':link, um das InvoiceNinja-Logo zu entfernen, indem du dem Pro Plan beitrittst', - 'remove_logo_link' => 'Klicke hier', - ], - 'logout' => 'Ausloggen', 'sign_up_to_save' => 'Melde dich an, um deine Arbeit zu speichern', 'agree_to_terms' => 'Ich akzeptiere die InvoiceNinja :terms', @@ -307,9 +269,7 @@ return array( 'success_message' => 'Du hast dich erfolgreich registriert. Bitte besuche den Link in deiner Bestätigungsmail um deine E-Mail-Adresse zu verifizieren.', 'erase_data' => 'Diese Aktion wird deine Daten dauerhaft löschen.', 'password' => 'Passwort', - 'pro_plan_product' => 'Pro Plan', - 'pro_plan_description' => 'Jahresmitgliedschaft beim Invoice Ninja Pro Plan.', 'pro_plan_success' => 'Danke, dass Sie Invoice Ninja\'s Pro gewählt haben!

     
    Nächste SchritteEine bezahlbare Rechnung wurde an die Mailadresse, welche mit Ihrem Account verbunden ist, geschickt. Um alle der umfangreichen @@ -317,7 +277,6 @@ return array( die Pro Funktionen zu nutzen. Sie finden die Rechnung nicht? Sie benötigen weitere Hilfe? Wir helfen gerne -- schicken Sie uns doch eine Email an contact@invoice-ninja.com', - 'unsaved_changes' => 'Es liegen ungespeicherte Änderungen vor', 'custom_fields' => 'Benutzerdefinierte Felder', 'company_fields' => 'Firmenfelder', @@ -327,8 +286,7 @@ return array( 'edit' => 'Bearbeiten', 'set_name' => 'Den Firmennamen setzen', 'view_as_recipient' => 'Als Empfänger betrachten', - - // product management + 'product_library' => 'Produktbibliothek', 'product' => 'Produkt', 'products' => 'Produkte', 'fill_products' => 'Produkte automatisch ausfüllen', @@ -341,20 +299,15 @@ return array( 'updated_product' => 'Produkt erfolgreich aktualisiert', 'created_product' => 'Produkt erfolgreich erstellt', 'archived_product' => 'Produkt erfolgreich archiviert', - 'product_library' => 'Produktbibliothek', 'pro_plan_custom_fields' => ':link um durch eine Pro-Mitgliedschaft erweiterte Felder zu aktivieren', - 'advanced_settings' => 'Erweiterte Einstellungen', 'pro_plan_advanced_settings' => ':link um durch eine Pro-Mitgliedschaft erweiterte Einstellungen zu aktivieren', 'invoice_design' => 'Rechnungsdesign', 'specify_colors' => 'Farben wählen', 'specify_colors_label' => 'Wähle die in der Rechnung verwendeten Farben', - 'chart_builder' => 'Diagrammersteller', 'ninja_email_footer' => 'Nutze :site um Kunden Rechnungen zu stellen und online bezahlt zu werden, kostenlos!', 'go_pro' => 'Go Pro', - - // Quotes 'quote' => 'Angebot', 'quotes' => 'Angebote', 'quote_number' => 'Angebotsnummer', @@ -364,7 +317,6 @@ return array( 'your_quote' => 'Ihr Angebot', 'total' => 'Gesamt', 'clone' => 'Duplizieren', - 'new_quote' => 'Neues Angebot', 'create_quote' => 'Angebot erstellen', 'edit_quote' => 'Angebot bearbeiten', @@ -375,9 +327,8 @@ return array( 'clone_quote' => 'Angebot duplizieren', 'convert_to_invoice' => 'In Rechnung umwandeln', 'view_invoice' => 'Rechnung anschauen', - 'view_quote' => 'Angebot anschauen', 'view_client' => 'Kunde anschauen', - + 'view_quote' => 'Angebot anschauen', 'updated_quote' => 'Angebot erfolgreich aktualisiert', 'created_quote' => 'Angebot erfolgreich erstellt', 'cloned_quote' => 'Angebot erfolgreich dupliziert', @@ -387,7 +338,6 @@ return array( 'deleted_quote' => 'Angebot erfolgreich gelöscht', 'deleted_quotes' => ':count Angebote erfolgreich gelöscht', 'converted_to_invoice' => 'Angebot erfolgreich in Rechnung umgewandelt', - 'quote_subject' => 'Neues Angebot von :account', 'quote_message' => 'Klicken Sie auf den folgenden Link um das Angebot über :amount anzuschauen.', 'quote_link_message' => 'Klicke auf den folgenden Link um das Angebot deines Kunden anzuschauen:', @@ -395,16 +345,13 @@ return array( 'notification_quote_viewed_subject' => 'Angebot :invoice wurde von :client angeschaut', 'notification_quote_sent' => 'Der folgende Kunde :client erhielt das Angebot :invoice über :amount.', 'notification_quote_viewed' => 'Der folgende Kunde :client hat sich das Angebot :client über :amount angesehen.', - 'session_expired' => 'Deine Sitzung ist abgelaufen.', - 'invoice_fields' => 'Rechnungsfelder', 'invoice_options' => 'Rechnungsoptionen', 'hide_quantity' => 'Menge verbergen', 'hide_quantity_help' => 'Wenn deine Menge immer 1 beträgt, kannst du deine Rechnung einfach halten, indem du dieses Feld entfernst.', 'hide_paid_to_date' => '"Bereits gezahlt" ausblenden', 'hide_paid_to_date_help' => '"Bereits gezahlt" nur anzeigen, wenn eine Zahlung eingegangen ist.', - 'charge_taxes' => 'Steuern erheben', 'user_management' => 'Benutzerverwaltung', 'add_user' => 'Benutzer hinzufügen', @@ -419,21 +366,16 @@ return array( 'active' => 'Aktiv', 'pending' => 'Ausstehend', 'deleted_user' => 'Benutzer erfolgreich gelöscht', - 'limit_users' => 'Entschuldige, das würde das Limit von '.MAX_NUM_USERS.' Benutzern überschreiten', - 'confirm_email_invoice' => 'Bist du sicher, dass du diese Rechnung per E-Mail versenden möchtest?', 'confirm_email_quote' => 'Bist du sicher, dass du dieses Angebot per E-Mail versenden möchtest', 'confirm_recurring_email_invoice' => 'Wiederkehrende Rechnung ist aktiv. Bis du sicher, dass du diese Rechnung weiterhin als E-Mail verschicken möchtest?', - 'cancel_account' => 'Konto Kündigen', 'cancel_account_message' => 'Warnung: Alle Daten werden unwiderruflich und vollständig gelöscht, es gibt kein zurück.', 'go_back' => 'Zurück', - 'data_visualizations' => 'Datenvisualisierungen', 'sample_data' => 'Beispieldaten werden angezeigt', 'hide' => 'Verbergen', 'new_version_available' => 'Eine neue Version von :releases_link ist verfügbar. Du benutzt v:user_version, die aktuelle ist v:latest_version', - 'invoice_settings' => 'Rechnungseinstellungen', 'invoice_number_prefix' => 'Präfix für Rechnungsnummer', 'invoice_number_counter' => 'Zähler für Rechnungsnummer', @@ -443,59 +385,48 @@ return array( 'invoice_issued_to' => 'Rechnung ausgestellt für', 'invalid_counter' => 'Bitte setze, um Probleme zu vermeiden, entweder ein Rechnungs- oder Angebotspräfix.', 'mark_sent' => 'Als versendet markieren', - 'gateway_help_1' => ':link um sich bei Authorize.net anzumelden.', 'gateway_help_2' => ':link um sich bei Authorize.net anzumelden.', 'gateway_help_17' => ':link um deine PayPal API-Signatur zu erhalten.', 'gateway_help_27' => ':link um sich bei TwoCheckout anzumelden.', - 'more_designs' => 'Weitere Designs', 'more_designs_title' => 'Zusätzliche Rechnungsdesigns', 'more_designs_cloud_header' => 'Werde Pro-Mitglied für zusätzliche Rechnungsdesigns', 'more_designs_cloud_text' => '', - 'more_designs_self_host_header' => 'Erhalte 6 zusätzliche Rechnungsdesigns für nur $'.INVOICE_DESIGNS_PRICE, 'more_designs_self_host_text' => '', 'buy' => 'Kaufen', 'bought_designs' => 'Die zusätzliche Rechnungsdesigns wurden erfolgreich hinzugefügt', 'sent' => 'versendet', - 'vat_number' => 'USt-IdNr.', 'timesheets' => 'Zeittabellen', - 'payment_title' => 'Geben Sie Ihre Rechnungsadresse und Ihre Kreditkarteninformationen ein', 'payment_cvv' => '*Dies ist die 3-4-stellige Nummer auf der Rückseite Ihrer Kreditkarte', 'payment_footer1' => '*Die Rechnungsadresse muss mit der Adresse der Kreditkarte übereinstimmen.', 'payment_footer2' => '*Bitte drücken Sie nur einmal auf "Jetzt bezahlen" - die Verarbeitung der Transaktion kann bis zu einer Minute dauern.', - 'id_number' => 'ID-Nummer', 'white_label_link' => 'Branding entfernen', 'white_label_header' => 'Branding entfernen', 'bought_white_label' => 'Branding-freie Lizenz erfolgreich aktiviert', 'white_labeled' => 'Branding entfernt', - 'restore' => 'Wiederherstellen', 'restore_invoice' => 'Rechnung wiederherstellen', 'restore_quote' => 'Angebot wiederherstellen', 'restore_client' => 'Kunde wiederherstellen', 'restore_credit' => 'Guthaben wiederherstellen', 'restore_payment' => 'Zahlung wiederherstellen', - 'restored_invoice' => 'Rechnung erfolgreich wiederhergestellt', 'restored_quote' => 'Angebot erfolgreich wiederhergestellt', 'restored_client' => 'Kunde erfolgreich wiederhergestellt', 'restored_payment' => 'Zahlung erfolgreich wiederhergestellt', 'restored_credit' => 'Guthaben erfolgreich wiederhergestellt', - 'reason_for_canceling' => 'Hilf uns, unser Angebot zu verbessern, indem du uns mitteilst, weswegen du dich dazu entschieden hast, unseren Service nicht länger zu nutzen.', 'discount_percent' => 'Prozent', 'discount_amount' => 'Wert', - 'invoice_history' => 'Rechnungshistorie', 'quote_history' => 'Angebotshistorie', 'current_version' => 'Aktuelle Version', - 'select_versiony' => 'Version auswählen', + 'select_version' => 'Version auswählen', 'view_history' => 'Historie anzeigen', - 'edit_payment' => 'Zahlung bearbeiten', 'updated_payment' => 'Zahlung erfolgreich aktualisiert', 'deleted' => 'Gelöscht', @@ -508,7 +439,6 @@ return array( 'quote_email' => 'Angebotsmail', 'reset_all' => 'Alle zurücksetzen', 'approve' => 'Zustimmen', - 'token_billing_type_id' => 'Token Billing', 'token_billing_help' => 'Ermöglicht Ihnen, Kreditkarten mit Ihrem Gateway zu speichern und diese zu einem späteren Zeitpunkt zu belasten.', 'token_billing_1' => 'Deaktiviert', @@ -516,12 +446,11 @@ return array( 'token_billing_3' => 'Opt-out - Kontrollkästchen wird angezeigt und ist ausgewählt', 'token_billing_4' => 'Immer', 'token_billing_checkbox' => 'Kreditkarteninformationen speichern', - 'view_in_stripe' => 'Auf Stripe anzeigen', - 'use_card_on_file' => 'Verwende gespeicherte Kreditkarte', + 'view_in_gateway' => 'Auf :gateway anzeigen', + 'use_card_on_file' => 'Use Card on File', 'edit_payment_details' => 'Zahlungsdetails bearbeiten', 'token_billing' => 'Kreditkarte merken', - 'token_billing_secure' => 'Die Daten werden sicher von :stripe_link gespeichert.', - + 'token_billing_secure' => 'Die Daten werden sicher von :link gespeichert.', 'support' => 'Support', 'contact_information' => 'Kontakt-Informationen', '256_encryption' => '256-Bit-Verschlüsselung', @@ -531,11 +460,8 @@ return array( 'order_overview' => 'Bestellübersicht', 'match_address' => '*Die Rechnungsadresse muss mit der Adresse der Kreditkarte übereinstimmen.', 'click_once' => '*Bitte drücken Sie nur einmal auf "Jetzt bezahlen" - die Verarbeitung der Transaktion kann bis zu einer Minute dauern.', - - 'default_invoice_footer' => 'Standard-Fußzeile festlegen', 'invoice_footer' => 'Fußzeile', 'save_as_default_footer' => 'Als Standard-Fußzeile speichern', - 'token_management' => 'Token Verwaltung', 'tokens' => 'Token', 'add_token' => 'Token hinzufügen', @@ -546,7 +472,6 @@ return array( 'edit_token' => 'Token bearbeiten', 'delete_token' => 'Token löschen', 'token' => 'Token', - 'add_gateway' => 'Zahlungsanbieter hinzufügen', 'delete_gateway' => 'Zahlungsanbieter löschen', 'edit_gateway' => 'Zahlungsanbieter bearbeiten', @@ -555,7 +480,6 @@ return array( 'deleted_gateway' => 'Zahlungsanbieter erfolgreich gelöscht', 'pay_with_paypal' => 'PayPal', 'pay_with_card' => 'Kreditkarte', - 'change_password' => 'Passwort ändern', 'current_password' => 'Aktuelles Passwort', 'new_password' => 'Neues Passwort', @@ -563,7 +487,6 @@ return array( 'password_error_incorrect' => 'Das aktuelle Passwort ist nicht korrekt.', 'password_error_invalid' => 'Das neue Passwort ist ungültig.', 'updated_password' => 'Passwort erfolgreich aktualisiert', - 'api_tokens' => 'API Token', 'users_and_tokens' => 'Benutzer & Token', 'account_login' => 'Konto Login', @@ -571,18 +494,15 @@ return array( 'forgot_password' => 'Passwort vergessen?', 'email_address' => 'E-Mail-Adresse', 'lets_go' => 'Auf geht\'s', - //'lets_go' => 'Login', 'password_recovery' => 'Passwort-Wiederherstellung', 'send_email' => 'E-Mail verschicken', 'set_password' => 'Passwort festlegen', 'converted' => 'Umgewandelt', - 'email_approved' => 'Per E-Mail benachrichtigen, wenn ein Angebot angenommen wurde', 'notification_quote_approved_subject' => 'Angebot :invoice wurde von :client angenommen.', 'notification_quote_approved' => 'Der folgende Kunde :client nahm das Angebot :invoice über :amount an.', 'resend_confirmation' => 'Bestätigungsmail erneut senden', 'confirmation_resent' => 'Bestätigungsemail wurde erneut versendet', - 'gateway_help_42' => ':link zum Registrieren auf BitPay.
    Hinweis: benutze einen Legacy API Key, keinen API token.', 'payment_type_credit_card' => 'Kreditkarte', 'payment_type_paypal' => 'PayPal', @@ -590,7 +510,6 @@ return array( 'knowledge_base' => 'FAQ', 'partial' => 'Partiell', 'partial_remaining' => ':partial von :balance', - 'more_fields' => 'Weitere Felder', 'less_fields' => 'Weniger Felder', 'client_name' => 'Kundenname', @@ -601,7 +520,6 @@ return array( 'view_documentation' => 'Dokumentation anzeigen', 'app_title' => 'Kostenlose Online Open-Source Rechnungsausstellung', 'app_description' => 'InvoiceNinja ist eine kostenlose, quelloffene Lösung für die Rechnungsstellung und Abrechnung von Kunden. Mit Invoice Ninja kannst du einfach schöne Rechnungen erstellen und verschicken, von jedem Gerät mit Internetzugang. Deine Kunden können die Rechnungen drucken, als PDF Datei herunterladen und sogar online im System bezahlen.', - 'rows' => 'Zeilen', 'www' => 'www', 'logo' => 'Logo', @@ -621,7 +539,6 @@ return array( 'zapier' => 'Zapier', 'recurring' => 'Wiederkehrend', 'last_invoice_sent' => 'Letzte Rechnung verschickt am :date', - 'processed_updates' => 'Update erfolgreich abgeschlossen', 'tasks' => 'Zeiterfassung', 'new_task' => 'Neue Aufgabe', @@ -667,12 +584,10 @@ return array( 'invoice_labels' => 'Rechnung Spaltenüberschriften', 'prefix' => 'Präfix', 'counter' => 'Zähler', - 'payment_type_dwolla' => 'Dwolla', 'gateway_help_43' => ':link zum Registrieren auf Dwolla.', 'partial_value' => 'Muss größer als Null und kleiner als der Gesamtbetrag sein', 'more_actions' => 'Weitere Aktionen', - 'pro_plan_title' => 'NINJA PRO', 'pro_plan_call_to_action' => 'Jetzt Upgraden!', 'pro_plan_feature1' => 'Unlimitierte Anzahl Kunden erstellen', @@ -683,14 +598,12 @@ return array( 'pro_plan_feature6' => 'Angebote & pro-forma Rechnungen erstellen', 'pro_plan_feature7' => 'Rechungstitelfelder und Nummerierung anpassen', 'pro_plan_feature8' => 'PDFs an E-Mails zu Kunden anhängen', - 'resume' => 'Fortfahren', 'break_duration' => 'Pause', 'edit_details' => 'Details bearbeiten', 'work' => 'Arbeiten', 'timezone_unset' => 'Bitte :link um deine Zeitzone zu setzen', 'click_here' => 'hier klicken', - 'email_receipt' => 'Zahlungsbestätigung an Kunden per E-Mail senden', 'created_payment_emailed_client' => 'Zahlung erfolgreich erstellt und Kunde per E-Mail benachrichtigt', 'add_company' => 'Konto hinzufügen', @@ -700,10 +613,8 @@ return array( 'unlinked_account' => 'Konten erfolgreich getrennt', 'login' => 'Login', 'or' => 'oder', - 'email_error' => 'Es gab ein Problem beim Senden dieses E-Mails.', 'confirm_recurring_timing' => 'Beachten Sie: E-Mails werden zu Beginn der Stunde versendet.', - 'old_browser' => 'Bitte verwenden Sie einen neueren Browser', 'payment_terms_help' => 'Setzt das Standardfälligkeitsdatum', 'unlink_account' => 'Konten trennen', 'unlink' => 'Trennen', @@ -724,7 +635,6 @@ return array( 'primary_color' => 'Primäre Farbe', 'secondary_color' => 'Sekundäre Farbe', 'customize_design' => 'Design Anpassen', - 'content' => 'Inhalt', 'styles' => 'Stile', 'defaults' => 'Standards', @@ -738,7 +648,6 @@ return array( 'outstanding' => 'Ausstehend', 'manage_companies' => 'Unternehmen verwalten', 'total_revenue' => 'Gesamteinnahmen', - 'current_user' => 'Aktueller Benutzer', 'new_recurring_invoice' => 'Neue wiederkehrende Rechnung', 'recurring_invoice' => 'Wiederkehrende Rechnung', @@ -746,10 +655,9 @@ return array( 'created_by_invoice' => 'Erstellt durch :invoice', 'primary_user' => 'Primärer Benutzer', 'help' => 'Hilfe', - 'customize_help' => '

    Wir benutzen zur deklarativen Definition der Rechnungsdesigns pdfmake. Der pdfmake playground bietet Gelegenheit die Bibliothek in Aktion zu sehen.

    -

    Mit der dot notation kann auf Kind-Eigenschaften zugegriffen werden. Für den Kundennamen kann man zum Beispiel $client.name benutzen.

    -

    Wenn du Hilfe brauchst schreibe uns gern im Support Forum (Englisch).

    ', - + 'customize_help' => '

    We use pdfmake to define the invoice designs declaratively. The pdfmake playground provide\'s a great way to see the library in action.

    +

    You can access a child property using dot notation. For example to show the client name you could use $client.name.

    +

    If you need help figuring something out post a question to our support forum with the design you\'re using.

    ', 'invoice_due_date' => 'Fällig am', 'quote_due_date' => 'Gültig bis', 'valid_until' => 'Gültig bis', @@ -762,15 +670,12 @@ return array( 'status_partial' => 'Teilweise', 'status_paid' => 'Bezahlt', 'show_line_item_tax' => 'Steuern für Belegpositionen in der jeweiligen Zeile anzeigen', - 'iframe_url' => 'Webseite', 'iframe_url_help1' => 'Kopiere den folgenden Code in eine Seite auf deiner Website.', 'iframe_url_help2' => 'Du kannst diese Funktion testen, in dem du für eine Rechnung \'Als Empfänger betrachten\'. anklickst.', - 'auto_bill' => 'Auto-Rechnung', 'military_time' => '24-Stunden-Zeit', 'last_sent' => 'Zuletzt versendet', - 'reminder_emails' => 'Erinnerungs-Emails', 'templates_and_reminders' => 'Vorlagen & Erinnerungen', 'subject' => 'Betreff', @@ -782,15 +687,12 @@ return array( 'reminder_subject' => 'Erinnerung: Rechnung :invoice von :account', 'reset' => 'Zurücksetzen', 'invoice_not_found' => 'Die gewünschte Rechnung ist nicht verfügbar', - 'referral_program' => 'Referral Program', 'referral_code' => 'Referral Code', 'last_sent_on' => 'Zuletzt versendet am :date', - 'page_expire' => 'Diese Seite wird bald ablaufen, :click_here um weiter zu arbeiten', 'upcoming_quotes' => 'Kommende Angebote', 'expired_quotes' => 'Abgelaufene Angebote', - 'sign_up_using' => 'Anmelden mit', 'invalid_credentials' => 'Diese Zugangsdaten können wir nicht finden.', 'show_all_options' => 'Zeige alle Optionen', @@ -799,17 +701,10 @@ return array( 'disable' => 'Deaktivieren', 'invoice_quote_number' => 'Rechnungs- und Angebotsnummern', 'invoice_charges' => 'Rechnungsgebühren', - - 'invitation_status' => [ - 'sent' => 'E-Mail versendet', - 'opened' => 'E-Mail geöffnet', - 'viewed' => 'Rechnung angesehen', - ], 'notification_invoice_bounced' => 'Die Rechnung :invoice an :contact konnte nicht zugestellt werden.', 'notification_invoice_bounced_subject' => 'Rechnung :invoice nicht zugestellt.', 'notification_quote_bounced' => 'Das Angebot :invoice an :contact konnte nicht zugestellt werden.', 'notification_quote_bounced_subject' => 'Angebot :invoice wurde nicht zugestellt.', - 'custom_invoice_link' => 'Manueller Rechnungs-Link', 'total_invoiced' => 'Rechnungs-Betrag', 'open_balance' => 'Offener Betrag', @@ -817,15 +712,12 @@ return array( 'basic_settings' => 'Allgemeine Einstellungen', 'pro' => 'Pro', 'gateways' => 'Zahlungs-Gateways', - 'next_send_on' => 'Nächster Versand: :date', 'no_longer_running' => 'Diese Rechnung wird momentan nicht automatisch erstellt.', 'general_settings' => 'Allgemeine Einstellungen', 'customize' => 'Anpassen', - 'oneclick_login_help' => 'Verbinde ein Benutzerkonto, um dich ohne Passwort anzumelden', 'referral_code_help' => 'Verdiene Geld, wenn du unsere App online teilst', - 'enable_with_stripe' => 'Enable | Requires Stripe', 'tax_settings' => 'Steuer-Einstellungen', 'create_tax_rate' => 'Neuer Steuersatz', @@ -836,7 +728,6 @@ return array( 'archived_tax_rate' => 'Steuersatz archiviert', 'default_tax_rate_id' => 'Standard-Steuersatz', 'tax_rate' => 'Steuersatz', - 'recurring_hour' => 'Wiederholende Stunde', 'pattern' => 'Schema', 'pattern_help_title' => 'Schema-Hilfe', @@ -847,7 +738,6 @@ return array( 'invoice_counter' => 'Rechnungszähler', 'quote_counter' => 'Angebotszähler', 'type' => 'Typ', - 'activity_1' => ':user erstellte Kunde :client', 'activity_2' => ':user archivierte Kunde :client', 'activity_3' => ':user löschte Kunde :client', @@ -877,7 +767,16 @@ return array( 'activity_27' => ':user stellte Zahlung :payment wieder her', 'activity_28' => ':user stellte Guthaben :credit wieder her', 'activity_29' => ':contact akzeptierte Angebot :quote', - + 'activity_30' => ':user created :vendor', + 'activity_31' => ':user created :vendor', + 'activity_32' => ':user created :vendor', + 'activity_33' => ':user created :vendor', + 'activity_34' => ':user created expense :expense', + 'activity_35' => ':user created :vendor', + 'activity_36' => ':user created :vendor', + 'activity_37' => ':user created :vendor', + 'activity_42' => ':user erstellte Aufgabe ":task"', + 'activity_43' => ':user aktualisierte Aufgabe ":task"', 'payment' => 'Zahlung', 'system' => 'System', 'signature' => 'Email-Signatur', @@ -885,10 +784,9 @@ return array( 'quote_terms' => 'Angebotsbedingungen', 'default_quote_terms' => 'Standard-Angebotsbedingungen', 'default_invoice_terms' => 'Standard-Rechnungsbedingungen', - 'default_invoice_footer' => 'Standard-Rechnungsfußzeile', + 'default_invoice_footer' => 'Standard-Fußzeile festlegen', 'quote_footer' => 'Angebots-Fußzeile', 'free' => 'Free', - 'quote_is_approved' => 'Dieses Angebot ist angenommen', 'apply_credit' => 'Guthaben anwenden', 'system_settings' => 'Systemeinstellungen', @@ -906,7 +804,6 @@ return array( 'restored_recurring_invoice' => 'Wiederkehrende Rechnung erfolgreich wiederhergestellt', 'archived' => 'Archiviert', 'untitled_account' => 'Unbenannte Firma', - 'before' => 'Vor', 'after' => 'Nach', 'reset_terms_help' => 'Auf die Standardzahlungsbedingungen des Kontos zurücksetzen', @@ -915,7 +812,6 @@ return array( 'user' => 'Benutzer', 'country' => 'Land', 'include' => 'Hinzufügen', - 'logo_too_large' => 'Ihr Logo ist nur :size. Um eine bessere Darstellung im PDF Dokument zu erhalten, empfehlen wir ein Bild größer als 200KB', 'import_freshbooks' => 'Importiere von FreshBooks', 'import_data' => 'Importiere Daten', @@ -926,16 +822,6 @@ return array( 'task_file' => 'Task File', 'no_mapper' => 'Kein gültiges Mapping für die Datei', 'invalid_csv_header' => 'Ungültiger CSV Header', - - 'email_errors' => [ - 'inactive_client' => 'Emails können nicht zu inaktiven Kunden gesendet werden', - 'inactive_contact' => 'Emails können nicht zu inaktiven Kontakten gesendet werden', - 'inactive_invoice' => 'Emails können nicht zu inaktiven Rechnungen gesendet werden', - 'user_unregistered' => 'Bitte registrieren Sie sich um Emails zu versenden', - 'user_unconfirmed' => 'Bitte bestätigen Sie Ihr Konto um Emails zu senden', - 'invalid_contact_email' => 'Ungültige Kontakt Email Adresse', - ], - 'client_portal' => 'Kunden-Portal', 'admin' => 'Admin', 'disabled' => 'Disabled', @@ -944,11 +830,9 @@ return array( 'invoice_will_create' => 'Kunde wird erstellt', 'invoices_will_create' => 'Rechnung wird erstellt', 'failed_to_import' => 'Die folgenden Daten konnten nicht importiert werden. Entweder sind diese bereits vorhanden oder es fehlen benötigte Felder.', - 'publishable_key' => 'Öffentlicher Schlüssel', 'secret_key' => 'Geheimer Schlüssel', 'missing_publishable_key' => 'Set your Stripe publishable key for an improved checkout process', - 'email_design' => 'Email Design', 'due_by' => 'Fällig am :date', 'enable_email_markup' => 'Enable Markup', @@ -960,7 +844,6 @@ return array( 'plain' => 'Einfach', 'light' => 'Hell', 'dark' => 'Dunkel', - '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.', 'invoice_number_help' => 'Specify a prefix or use a custom pattern to dynamically set the invoice number.', @@ -969,8 +852,6 @@ return array( '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_charges_helps' => 'Add a text input to the invoice create/edit page and include the charge in the invoice subtotals.', - 'color_help' => 'Note: the primary color is also used in the client portal and custom email designs.', - 'token_expired' => 'Validation token was expired. Please try again.', 'invoice_link' => 'Link zur Rechnung', 'button_confirmation_message' => 'Bitte klicken um Ihre Email-Adresse zu bestätigen.', @@ -979,7 +860,6 @@ return array( 'created_invoices' => ':count Rechnung(en) erfolgreich erstellt', 'next_invoice_number' => 'Die nächste Rechnungsnummer ist :number.', 'next_quote_number' => 'Die nächste Angebotsnummer ist :number.', - 'days_before' => 'Tage vorher', 'days_after' => 'Tage danach', 'field_due_date' => 'Fälligkeitsdatum', @@ -987,11 +867,7 @@ return array( 'schedule' => 'Zeitgesteuert', 'email_designs' => 'Email Designs', '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', - - // Expense / vendor 'expense' => 'Ausgabe', 'expenses' => 'Ausgaben', 'new_expense' => 'Neue Ausgabe', @@ -1008,10 +884,8 @@ return array( 'archived_expense' => 'Ausgabe erfolgreich archiviert', 'deleted_expenses' => ' Ausgaben erfolgreich gelöscht', 'archived_expenses' => 'Ausgaben erfolgreich archiviert', - - // Expenses 'expense_amount' => 'Ausgabensumme', - 'expense_balance' => 'Ausgabendifferenz', // don't know if this is a good translation. + 'expense_balance' => 'Ausgabendifferenz', 'expense_date' => 'Ausgabendatum', 'expense_should_be_invoiced' => 'Soll diese Ausgabe in Rechnung gestellt werden?', 'public_notes' => 'Öffentliche Notizen', @@ -1019,7 +893,7 @@ return array( 'exchange_rate' => 'Wechselkurs', 'yes' => 'Ja', 'no' => 'Nein', - 'should_be_invoiced' => 'Should be invoiced', //??? + 'should_be_invoiced' => 'Should be invoiced', 'view_expense' => 'Ausgabe # :expense ansehen', 'edit_expense' => 'Ausgabe Bearbeiten', 'archive_expense' => 'Ausgabe Archivieren', @@ -1027,22 +901,18 @@ return array( 'view_expense_num' => 'Ausgabe # :expense', 'updated_expense' => 'Ausgabe erfolgreich aktualisiert', 'created_expense' => 'Ausgabe erfolgreich erstellt', - 'enter_expense' => 'Ausgabe Eingeben', + 'enter_expense' => 'Ausgabe eingeben', 'view' => 'View', 'restore_expense' => 'Ausgabe Wiederherstellen', 'invoice_expense' => 'Ausgabe in Rechnung stellen', 'expense_error_multiple_clients' => 'Die Ausgaben können nicht zu unterschiedlichen Kunden gehören', 'expense_error_invoiced' => 'Ausgabe wurde bereits in Rechnung gestellt', 'convert_currency' => 'Währung umrechnen', - - // Payment terms 'num_days' => 'Anzahl Tage', 'create_payment_term' => 'Create Payment Term', 'edit_payment_terms' => 'Edit Payment Term', 'edit_payment_term' => 'Edit Payment Term', 'archive_payment_term' => 'Archive Payment Term', - - // recurring due dates 'recurring_due_dates' => 'Recurring Invoice Due Dates', 'recurring_due_date_help' => '

    Automatically sets a due date for the invoice.

    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.

    @@ -1070,22 +940,18 @@ return array( 'thursday' => 'Donnerstag', 'friday' => 'Freitag', 'saturday' => 'Samstag', - - // Fonts 'header_font_id' => 'Header-Schriftart', 'body_font_id' => 'Body-Schriftart', 'color_font_help' => 'Info: Die primäre Farbe und Schriftarten werden auch im Kundenportal und im individuellen Mail-Design verwendet.', - 'live_preview' => 'Live-Voransicht', 'invalid_mail_config' => 'Unable to send email, please check that the mail settings are correct.', - 'invoice_message_button' => 'Um Ihre Rechnung über :amount zu sehen, klicken Sie die Schaltfläche unten.', 'quote_message_button' => 'Um Ihr Angebot über :amount zu sehen, klicken Sie die Schaltfläche unten.', 'payment_message_button' => 'Vielen Dank für Ihre Zahlung von :amount.', 'payment_type_direct_debit' => 'Einzugsermächtigung', 'bank_accounts' => 'Bankverbindungen', 'add_bank_account' => 'Bankverbindung hinzufügen', - 'setup_account' => 'Account einrichten', // I hope here is not meant "bank account". I translated "Account". + 'setup_account' => 'Account einrichten', 'import_expenses' => 'Ausgaben importieren', 'bank_id' => 'bank', 'integration_type' => 'Integrations-Typ', @@ -1095,12 +961,11 @@ return array( 'archived_bank_account' => 'Bankverbindung erfolgreich archiviert', 'created_bank_account' => 'Bankverbindung erfolgreich erstellt', 'validate_bank_account' => 'Bankverbindung bestätigen', - 'bank_accounts_help' => 'Fügen Sie eine Bankverbindung hinzu, um Ausgaben automatisch zu importieren und Lieferanten zu erstellen. Unterstützt American Express und 400+ US-Banken.', 'bank_password_help' => 'Info: Ihr Passwort wird sicher übertragen und zu keiner Zeit auf unseren Servern gespeichert.', 'bank_password_warning' => 'Warnung: Ihr Passwort könnte in Klartext übertragen werden, wir empfehlen Ihnen HTTPS zu verwenden.', 'username' => 'Benutzername', - 'account_number' => 'Account Number', // bank account?? - 'account_name' => 'Account Name', // bank account?? + 'account_number' => 'Account Number', + 'account_name' => 'Account Name', 'bank_account_error' => 'Failed to retreive account details, please check your credentials.', 'status_approved' => 'Approved', 'quote_settings' => 'Quote Settings', @@ -1109,7 +974,6 @@ return array( 'validate' => 'Validate', 'info' => 'Info', '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.', '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.', @@ -1130,7 +994,28 @@ return array( 'trial_call_to_action' => 'Kostenlose Probezeit starten', 'trial_success' => 'Erfolgreich eine 2-Wochen Testversion aktiviert', 'overdue' => 'Überfällig', - 'white_label_text' => 'Kaufen Sie eine 1 Jahres Whitelabel Lizenz zum Preis von $'.WHITE_LABEL_PRICE.' um das Invoice Ninja Branding vom Kundenportal zu entfernen und unser Projekt zu unterstützen.', + + + 'white_label_text' => 'Kaufen Sie eine 1 Jahres Whitelabel Lizenz zum Preis von $:price um das Invoice Ninja Branding vom Kundenportal zu entfernen und unser Projekt zu unterstützen.', + 'user_email_footer' => 'Um deine E-Mail-Benachrichtigungen anzupassen besuche bitte :link', + 'reset_password_footer' => 'Wenn du das Zurücksetzen des Passworts nicht beantragt hast, benachrichtige bitte unseren Support: :email', + 'limit_users' => 'Entschuldige, das würde das Limit von :limit Benutzern überschreiten', + 'more_designs_self_host_header' => 'Erhalte 6 zusätzliche Rechnungsdesigns für nur $:price', + 'old_browser' => 'Bitte verwenden Sie einen neueren Browser', + 'white_label_custom_css' => ':link for $:price to enable custom styling and help support our project.', + 'bank_accounts_help' => 'Fügen Sie eine Bankverbindung hinzu, um Ausgaben automatisch zu importieren und Lieferanten zu erstellen. Unterstützt American Express und 400+ US-Banken.', + + 'pro_plan_remove_logo' => ':link, um das InvoiceNinja-Logo zu entfernen, indem du dem Pro Plan beitrittst', + 'pro_plan_remove_logo_link' => 'Klicke hier', + 'invitation_status_sent' => 'E-Mail versendet', + 'invitation_status_opened' => 'E-Mail geöffnet', + 'invitation_status_viewed' => 'Rechnung angesehen', + 'email_error_inactive_client' => 'Emails können nicht zu inaktiven Kunden gesendet werden', + 'email_error_inactive_contact' => 'Emails können nicht zu inaktiven Kontakten gesendet werden', + 'email_error_inactive_invoice' => 'Emails können nicht zu inaktiven Rechnungen gesendet werden', + 'email_error_user_unregistered' => 'Bitte registrieren Sie sich um Emails zu versenden', + 'email_error_user_unconfirmed' => 'Bitte bestätigen Sie Ihr Konto um Emails zu senden', + 'email_error_invalid_contact_email' => 'Ungültige Kontakt Email Adresse', 'navigation' => 'Navigation', 'list_invoices' => 'Liste Rechnungen', @@ -1149,26 +1034,24 @@ return array( 'new_product' => 'Neues Produkt', 'new_tax_rate' => 'Neuer Steuersatz', 'invoiced_amount' => 'Rechnungsbetrag', - 'invoice_item_fields' => 'Rechnungspositions Feld', + 'invoice_item_fields' => 'Rechnungspositionsfeld', 'custom_invoice_item_fields_help' => 'Add a field when creating an invoice item and display the label and value on the PDF.', 'recurring_invoice_number' => 'Wiederkehrende Rechnungsnummer', 'recurring_invoice_number_prefix_help' => 'Geben Sie einen Präfix für wiederkehrende Rechnungen an. Standard ist \'R\'.', - 'enable_client_portal' => 'Dashboard', - 'enable_client_portal_help' => 'Zeige das Dashboard im Kundenportal.', // Client Passwords 'enable_portal_password'=>'Passwortgeschützte Rechnungen', 'enable_portal_password_help'=>'Erlaubt Ihnen ein Passwort für jeden Kontakt zu erstellen. Wenn ein Passwort erstellt wurde, muss der Kunde dieses eingeben, bevor er eine Rechnung ansehen darf.', 'send_portal_password'=>'Erstelle das Passwort automatisch', 'send_portal_password_help'=>'Wenn kein Passwort gesetzt wurde, wird eins generiert und mit der ersten Rechnung verschickt.', - + 'expired' => 'Abgelaufen', 'invalid_card_number' => 'Die Kreditkartennummer ist nicht gültig.', 'invalid_expiry' => 'Das Ablaufdatum ist nicht gültig.', 'invalid_cvv' => 'Der CVV Code ist nicht gültig.', 'cost' => 'Kosten', 'create_invoice_for_sample' => 'Hinweis: Erstellen Sie Ihre erste Rechnung um hier eine Vorschau zu sehen.', - + // User Permissions 'owner' => 'Eigentümer', 'administrator' => 'Administrator', @@ -1186,8 +1069,8 @@ return array( 'create_all_help' => 'Allow user to create and modify records', 'view_all_help' => 'Allow user to view records they didn\'t create', 'edit_all_help' => 'Allow user to modify records they didn\'t create', - 'view_payment' => 'Zahlung zeigen', - + 'view_payment' => 'Zahlung zeigen', + 'january' => 'Januar', 'february' => 'Februar', 'march' => 'März', @@ -1202,41 +1085,39 @@ return array( 'december' => 'Dezember', // Documents - 'documents_header' => 'Documents:', - 'email_documents_header' => 'Documents:', + 'documents_header' => 'Dokumente:', + 'email_documents_header' => 'Dokumente:', 'email_documents_example_1' => 'Widgets Receipt.pdf', 'email_documents_example_2' => 'Final Deliverable.zip', - 'invoice_documents' => 'Documents', - 'expense_documents' => 'Attached Documents', - 'invoice_embed_documents' => 'Embed Documents', + 'invoice_documents' => 'Dokumente', + 'expense_documents' => 'Angehängte Dokumente', + 'invoice_embed_documents' => 'Dokumente einbetten', 'invoice_embed_documents_help' => 'Include attached images in the invoice.', - 'document_email_attachment' => 'Attach Documents', - 'download_documents' => 'Download Documents (:size)', + 'document_email_attachment' => 'Dokumente anhängen', + 'download_documents' => 'Dokumente herunterladen (:size)', 'documents_from_expenses' => 'From Expenses:', - 'dropzone' => array(// See http://www.dropzonejs.com/#config-dictDefaultMessage - 'DefaultMessage' => 'Drop files or click to upload', - 'FallbackMessage' => 'Your browser does not support drag\'n\'drop file uploads.', - 'FallbackText' => 'Please use the fallback form below to upload your files like in the olden days.', - 'FileTooBig' => 'File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.', - 'InvalidFileType' => 'You can\'t upload files of this type.', - 'ResponseError' => 'Server responded with {{statusCode}} code.', - 'CancelUpload' => 'Cancel upload', - 'CancelUploadConfirmation' => 'Are you sure you want to cancel this upload?', - 'RemoveFile' => 'Remove file', - ), - 'documents' => 'Documents', + 'dropzone_default_message' => 'Drop files or click to upload', + 'dropzone_fallback_message' => 'Your browser does not support drag\'n\'drop file uploads.', + 'dropzone_fallback_text' => 'Please use the fallback form below to upload your files like in the olden days.', + 'dropzone_file_too_big' => 'File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.', + 'dropzone_invalid_file_type' => 'You can\'t upload files of this type.', + 'dropzone_response_error' => 'Server responded with {{statusCode}} code.', + 'dropzone_cancel_upload' => 'Cancel upload', + 'dropzone_cancel_upload_confirmation' => 'Are you sure you want to cancel this upload?', + 'dropzone_remove_file' => 'Remove file', + 'documents' => 'Dokumente', 'document_date' => 'Document Date', 'document_size' => 'Size', - 'enable_client_portal' => 'Client Portal', - 'enable_client_portal_help' => 'Show/hide the client portal.', + 'enable_client_portal' => 'Dashboard', + 'enable_client_portal_help' => 'Zeige das Dashboard im Kundenportal.', 'enable_client_portal_dashboard' => 'Dashboard', 'enable_client_portal_dashboard_help' => 'Show/hide the dashboard page in the client portal.', - + // Plans 'account_management' => 'Account Management', 'plan_status' => 'Plan Status', - + 'plan_upgrade' => 'Upgrade', 'plan_change' => 'Change Plan', 'pending_change_to' => 'Changes To', @@ -1266,9 +1147,9 @@ return array( 'plan_paid' => 'Term Started', 'plan_started' => 'Plan Started', 'plan_expires' => 'Plan Expires', - + 'white_label_button' => 'White Label', - + 'pro_plan_year_description' => 'One year enrollment in the Invoice Ninja Pro Plan.', 'pro_plan_month_description' => 'One month enrollment in the Invoice Ninja Pro Plan.', 'enterprise_plan_product' => 'Enterprise Plan', @@ -1279,14 +1160,543 @@ return array( 'plan_pending_monthly' => 'Will switch to monthly on :date', 'plan_refunded' => 'A refund has been issued.', - 'live_preview' => 'Live Preview', + 'live_preview' => 'Live-Voransicht', 'page_size' => 'Page Size', 'live_preview_disabled' => 'Live preview has been disabled to support selected font', 'invoice_number_padding' => 'Padding', 'preview' => 'Preview', 'list_vendors' => 'List Vendors', 'add_users_not_supported' => 'Upgrade to the Enterprise plan to add additional users to your account.', - 'enterprise_plan_features' => 'The Enterprise plan adds support for multiple users and file attachments.', + 'enterprise_plan_features' => 'The Enterprise plan adds support for multiple users and file attachments, :link to see the full list of features.', 'return_to_app' => 'Return to app', - + + // Payment updates + 'refund_payment' => 'Zahlung erstatten', + 'refund_max' => 'Max:', + 'refund' => 'Erstattung', + 'are_you_sure_refund' => 'Ausgewählte Zahlungen erstatten?', + 'status_pending' => 'Ausstehend', + 'status_completed' => 'Abgeschlossen', + 'status_failed' => 'Fehlgeschlagen', + 'status_partially_refunded' => 'Teilweise erstattet', + 'status_partially_refunded_amount' => ':amount erstattet', + 'status_refunded' => 'Erstattet', + 'status_voided' => 'Abgebrochen', + 'refunded_payment' => 'Zahlung erstattet', + 'activity_39' => ':user cancelled a :payment_amount payment (:payment)', + 'activity_40' => ':user refunded :adjustment of a :payment_amount payment (:payment)', + 'card_expiration' => 'Exp: :expires', + + 'card_creditcardother' => 'Unbekannt', + 'card_americanexpress' => 'American Express', + 'card_carteblanche' => 'Carte Blanche', + 'card_unionpay' => 'UnionPay', + 'card_diners' => 'Diners Club', + 'card_discover' => 'Discover', + 'card_jcb' => 'JCB', + 'card_laser' => 'Laser', + 'card_maestro' => 'Maestro', + 'card_mastercard' => 'MasterCard', + 'card_solo' => 'Solo', + 'card_switch' => 'Switch', + 'card_visacard' => 'Visa', + 'card_ach' => 'ACH', + + 'payment_type_stripe' => 'Stripe', + 'ach' => 'ACH', + 'enable_ach' => 'Enable ACH', + 'stripe_ach_help' => 'ACH support must also be enabled at Stripe.', + 'ach_disabled' => 'Another gateway is already configured for direct debit.', + + 'plaid' => 'Plaid', + 'client_id' => 'Kundennummer', + 'secret' => 'Passwort', + 'public_key' => 'Öffentlicher Schlüssel', + 'plaid_optional' => '(optional)', + 'plaid_environment_help' => 'When a Stripe test key is given, Plaid\'s development environement (tartan) will be used.', + 'other_providers' => 'Andere Anbieter', + 'country_not_supported' => 'Dieses Land wird nicht unterstützt.', + 'invalid_routing_number' => 'Die Bankleitzahl ist nicht gültig.', + 'invalid_account_number' => 'Die Kontonummer ist nicht gültig.', + 'account_number_mismatch' => 'Die Kontonummern stimmen nicht überein.', + 'missing_account_holder_type' => 'Bitte wählen Sie ein Einzel- oder Firmenkonto aus.', + 'missing_account_holder_name' => 'Bitten geben Sie den Namen des Kontoinhabers ein.', + 'routing_number' => 'Bankleitzahl', + 'confirm_account_number' => 'Kontonummer bestätigen', + 'individual_account' => 'Einzelkonto', + 'company_account' => 'Firmenkonto', + 'account_holder_name' => 'Name des Kontoinhabers', + 'add_account' => 'Konto hinzufügen', + 'payment_methods' => 'Zahlungsarten', + 'complete_verification' => 'Überprüfung abschließen', + 'verification_amount1' => 'Betrag 1', + 'verification_amount2' => 'Betrag 2', + 'payment_method_verified' => 'Überprüfung erfolgreich abgeschlossen', + 'verification_failed' => 'Überprüfung fehlgeschlagen', + 'remove_payment_method' => 'Zahlungsart entfernen', + 'confirm_remove_payment_method' => 'Wollen Sie diese Zahlungart wirklich entfernen?', + 'remove' => 'Entfernen', + 'payment_method_removed' => 'Zahlungsart entfernt.', + 'bank_account_verification_help' => 'We have made two deposits into your account with the description "VERIFICATION". These deposits will take 1-2 business days to appear on your statement. Please enter the amounts below.', + 'bank_account_verification_next_steps' => 'We have made two deposits into your account with the description "VERIFICATION". These deposits will take 1-2 business days to appear on your statement. + Once you have the amounts, come back to this payment methods page and click "Complete Verification" next to the account.', + 'unknown_bank' => 'Bank unbekannt', + 'ach_verification_delay_help' => 'Nach der Überprüfung können Sie das Konto sofort benutzen. Die Überprüfung dauert in der Regel 1-2 Arbeitstage.', + 'add_credit_card' => 'Kreditkarte hinzufügen', + 'payment_method_added' => 'Zahlungsart hinzugefügt.', + 'use_for_auto_bill' => 'Use For Autobill', + 'used_for_auto_bill' => 'Autobill Payment Method', + 'payment_method_set_as_default' => 'Set Autobill payment method.', + 'activity_41' => ':payment_amount payment (:payment) failed', + 'webhook_url' => 'Webhook URL', + 'stripe_webhook_help' => 'Sie müssen :link', + 'stripe_webhook_help_link_text' => 'add this URL as an endpoint at Stripe', + 'payment_method_error' => 'There was an error adding your payment methd. Please try again later.', + 'notification_invoice_payment_failed_subject' => 'Zahlung für Rechnung :invoice fehlgeschlagen', + 'notification_invoice_payment_failed' => 'A payment made by client :client towards Invoice :invoice failed. The payment has been marked as failed and :amount has been added to the client\'s balance.', + 'link_with_plaid' => 'Konto sofort mit Plaid verknüpfen', + 'link_manually' => 'Manuel verbinden', + 'secured_by_plaid' => 'Secured by Plaid', + 'plaid_linked_status' => 'Ihr Konto bei :bank', + 'add_payment_method' => 'Zahlungsart hinzufügen', + 'account_holder_type' => 'Art des Kontoinhabers', + 'ach_authorization' => 'I authorize :company to use my bank account for future payments and, if necessary, electronically credit my account to correct erroneous debits. I understand that I may cancel this authorization at any time by removing the payment method or by contacting :email.', + 'ach_authorization_required' => 'You must consent to ACH transactions.', + 'off' => 'Aus', + 'opt_in' => 'Anmelden', + 'opt_out' => 'Abmelden', + 'always' => 'Immer', + 'opted_out' => 'Abgemeldet', + 'opted_in' => 'Angemeldet', + 'manage_auto_bill' => 'Manage Auto-bill', + 'enabled' => 'Aktiviert', + 'paypal' => 'PayPal', + 'braintree_enable_paypal' => 'PayPal Zahlungen mittels BrainTree aktivieren', + 'braintree_paypal_disabled_help' => 'The PayPal gateway is processing PayPal payments', + 'braintree_paypal_help' => 'Sie müssen auch :link', + 'braintree_paypal_help_link_text' => 'PayPal Konto mit BrainTree verknüpfen', + 'token_billing_braintree_paypal' => 'Zahlungsdetails speichern', + 'add_paypal_account' => 'PayPal Konto hinzufügen', + + + 'no_payment_method_specified' => 'Keine Zahlungsart angegeben', + 'chart_type' => 'Diagrammtyp', + 'format' => 'Format', + 'import_ofx' => 'OFX importieren', + 'ofx_file' => 'OFX Datei', + 'ofx_parse_failed' => 'Einlesen der OFX Datei fehlgeschlagen', + + // WePay + 'wepay' => 'WePay', + 'sign_up_with_wepay' => 'Mit WePay anmelden', + 'use_another_provider' => 'Anderen Anbieter verwenden', + 'company_name' => 'Firmenname', + 'wepay_company_name_help' => 'Das erscheint auf den Kontoauszügen des Kunden.', + 'wepay_description_help' => 'Zweck des Kontos.', + 'wepay_tos_agree' => 'I agree to the :link.', + 'wepay_tos_link_text' => 'WePay Servicebedingungen', + 'resend_confirmation_email' => 'Bestätigungsemail nochmal senden', + 'manage_wepay_account' => 'WePay Konto verwalten', + 'action_required' => 'Handeln erforderlich', + 'finish_setup' => 'Setup abschließen', + 'created_wepay_confirmation_required' => 'Bitte prüfen Sie Ihr E-Mail Konto und bestätigen Sie Ihre E-Mail Adresse bei WePay.', + 'switch_to_wepay' => 'Wechsel zu WePay', + 'switch' => 'Switch', + 'restore_account_gateway' => 'Restore Gateway', + 'restored_account_gateway' => 'Successfully restored gateway', + 'united_states' => 'Vereinigte Staaten von Amerika', + 'canada' => 'Kanada', + 'accept_debit_cards' => 'Debitkarten aktzeptieren', + 'debit_cards' => 'Debitkarten', + + 'warn_start_date_changed' => 'The next invoice will be sent on the new start date.', + 'original_start_date' => 'Original start date', + 'new_start_date' => 'New start date', + 'security' => 'Security', + 'see_whats_new' => 'See what\'s new in v:version', + 'wait_for_upload' => 'Please wait for the document upload to complete.', + 'upgrade_for_permissions' => 'Upgrade to our Enterprise plan to enable permissions.', + 'enable_second_tax_rate' => 'Enable specifying a second tax rate', + 'payment_file' => 'Payment File', + 'expense_file' => 'Expense File', + 'product_file' => 'Product File', + 'import_products' => 'Import Products', + 'products_will_create' => 'products will be created.', + 'product_key' => 'Product', + 'created_products' => 'Successfully created :count product(s)', + 'export_help' => 'Use JSON if you plan to import the data into Invoice Ninja.', + 'JSON_file' => 'JSON File', + + 'view_dashboard' => 'View Dashboard', + 'client_session_expired' => 'Session Expired', + 'client_session_expired_message' => 'Your session has expired. Please click the link in your email again.', + + 'auto_bill_notification' => 'This invoice will automatically be billed to your :payment_method on file on :due_date.', + 'auto_bill_payment_method_bank_transfer' => 'bank account', + 'auto_bill_payment_method_credit_card' => 'credit card', + 'auto_bill_payment_method_paypal' => 'PayPal account', + 'auto_bill_notification_placeholder' => 'This invoice will automatically be billed to your credit card on file on the due date.', + 'payment_settings' => 'Payment Settings', + + 'on_send_date' => 'On send date', + 'on_due_date' => 'On due date', + 'auto_bill_ach_date_help' => 'ACH auto bill will always happen on the due date', + 'warn_change_auto_bill' => 'Due to NACHA rules, changes to this invoice may prevent ACH auto bill.', + + 'bank_account' => 'Bank Account', + 'payment_processed_through_wepay' => 'ACH payments will be processed using WePay.', + 'wepay_payment_tos_agree' => 'I agree to the WePay :terms and :privacy_policy.', + 'privacy_policy' => 'Privacy Policy', + 'wepay_payment_tos_agree_required' => 'You must agree to the WePay Terms of Service and Privacy Policy.', + 'payment_settings_supported_gateways' => 'These options are supported by the WePay, Stripe, and Braintree gateways.', + 'ach_email_prompt' => 'Please enter your email address:', + 'verification_pending' => 'Verification Pending', + + 'update_font_cache' => 'Please force refresh the page to update the font cache.', + 'more_options' => 'More options', + 'credit_card' => 'Credit Card', + 'bank_transfer' => 'Bank Transfer', + 'no_transaction_reference' => 'We did not recieve a payment transaction reference from the gateway.', + 'use_bank_on_file' => 'Use Bank on File', + 'auto_bill_email_message' => 'This invoice will automatically be billed to the payment method on file on the due date.', + 'bitcoin' => 'Bitcoin', + 'added_on' => 'Added :date', + 'failed_remove_payment_method' => 'Failed to remove the payment method', + 'gateway_exists' => 'This gateway already exists', + 'manual_entry' => 'Manual entry', + 'start_of_week' => 'Erster Tag der Woche', + + // Frequencies + 'freq_weekly' => 'wöchentlich', + 'freq_two_weeks' => 'zweiwöchentlich', + 'freq_four_weeks' => 'vierwöchentlich', + 'freq_monthly' => 'monatlich', + 'freq_three_months' => 'dreimonatlich', + 'freq_six_months' => 'halbjährlich', + 'freq_annually' => 'jährlich', + + // Payment types + 'payment_type_Apply Credit' => 'Kredit', + 'payment_type_Bank Transfer' => 'Überweisung', + 'payment_type_Cash' => 'Bar', + 'payment_type_Debit' => 'Guthaben', + 'payment_type_ACH' => 'ACH', + 'payment_type_Visa Card' => 'VISA', + 'payment_type_MasterCard' => 'MasterCard', + 'payment_type_American Express' => 'American Express', + 'payment_type_Discover Card' => 'Discover Card', + 'payment_type_Diners Card' => 'Diners Card', + 'payment_type_EuroCard' => 'EuroCard', + 'payment_type_Nova' => 'Nova', + 'payment_type_Credit Card Other' => 'Andere Kreditkarte', + 'payment_type_PayPal' => 'PayPal', + 'payment_type_Google Wallet' => 'Google Wallet', + 'payment_type_Check' => 'Scheck', + + // Industries + 'industry_Accounting & Legal' => 'Buchhaltung & Rechnungswesen', + 'industry_Advertising' => 'Werbung', + 'industry_Aerospace' => 'Luft- und Raumfahrt', + 'industry_Agriculture' => 'Landwirtschaft', + 'industry_Automotive' => 'Automobilbau', + 'industry_Banking & Finance' => 'Bank- und Finanzwesen', + 'industry_Biotechnology' => 'Biotechnologie', + 'industry_Broadcasting' => 'Rundfunk', + 'industry_Business Services' => 'Dienstleistungen', + 'industry_Commodities & Chemicals' => 'Handelsgüter und Chemikalien', + 'industry_Communications' => 'Kommunikation', + 'industry_Computers & Hightech' => 'Computer und Hochtechnologie', + 'industry_Defense' => 'Verteidigungsbereich', + 'industry_Energy' => 'Energie', + 'industry_Entertainment' => 'Unterhaltung', + 'industry_Government' => 'Regierungsbereich', + 'industry_Healthcare & Life Sciences' => 'Gesundheitswesen und Biowissenschaften', + 'industry_Insurance' => 'Versicherung', + 'industry_Manufacturing' => 'Herstellung', + 'industry_Marketing' => 'Marketing', + 'industry_Media' => 'Medien', + 'industry_Nonprofit & Higher Ed' => 'Nonprofit-Bereich', + 'industry_Pharmaceuticals' => 'Pharmazeutika', + 'industry_Professional Services & Consulting' => 'Unternehmensberatung', + 'industry_Real Estate' => 'Immobilien', + 'industry_Retail & Wholesale' => 'Einzel- und Großhandel', + 'industry_Sports' => 'Sport', + 'industry_Transportation' => 'Transport', + 'industry_Travel & Luxury' => 'Reisen und Luxus', + 'industry_Other' => 'Andere', + 'industry_Photography' => 'Fotografie', + + // Countries + 'country_Afghanistan' => '', + 'country_Albania' => 'Albanien', + 'country_Antarctica' => '', + 'country_Algeria' => 'Algerien', + 'country_American Samoa' => '', + 'country_Andorra' => '', + 'country_Angola' => '', + 'country_Antigua and Barbuda' => '', + 'country_Azerbaijan' => '', + 'country_Argentina' => 'Argentinien', + 'country_Australia' => '', + 'country_Austria' => '', + 'country_Bahamas' => '', + 'country_Bahrain' => '', + 'country_Bangladesh' => '', + 'country_Armenia' => '', + 'country_Barbados' => '', + 'country_Belgium' => '', + 'country_Bermuda' => '', + 'country_Bhutan' => '', + 'country_Bolivia, Plurinational State of' => '', + 'country_Bosnia and Herzegovina' => '', + 'country_Botswana' => '', + 'country_Bouvet Island' => '', + 'country_Brazil' => '', + 'country_Belize' => '', + 'country_British Indian Ocean Territory' => '', + 'country_Solomon Islands' => '', + 'country_Virgin Islands, British' => '', + 'country_Brunei Darussalam' => '', + 'country_Bulgaria' => '', + 'country_Myanmar' => '', + 'country_Burundi' => '', + 'country_Belarus' => '', + 'country_Cambodia' => '', + 'country_Cameroon' => '', + 'country_Canada' => '', + 'country_Cape Verde' => '', + 'country_Cayman Islands' => '', + 'country_Central African Republic' => '', + 'country_Sri Lanka' => '', + 'country_Chad' => '', + 'country_Chile' => '', + 'country_China' => '', + 'country_Taiwan, Province of China' => '', + 'country_Christmas Island' => '', + 'country_Cocos (Keeling) Islands' => '', + 'country_Colombia' => '', + 'country_Comoros' => '', + 'country_Mayotte' => '', + 'country_Congo' => '', + 'country_Congo, the Democratic Republic of the' => '', + 'country_Cook Islands' => '', + 'country_Costa Rica' => '', + 'country_Croatia' => '', + 'country_Cuba' => '', + 'country_Cyprus' => '', + 'country_Czech Republic' => '', + 'country_Benin' => '', + 'country_Denmark' => '', + 'country_Dominica' => '', + 'country_Dominican Republic' => '', + 'country_Ecuador' => '', + 'country_El Salvador' => '', + 'country_Equatorial Guinea' => '', + 'country_Ethiopia' => '', + 'country_Eritrea' => '', + 'country_Estonia' => '', + 'country_Faroe Islands' => '', + 'country_Falkland Islands (Malvinas)' => '', + 'country_South Georgia and the South Sandwich Islands' => '', + 'country_Fiji' => '', + 'country_Finland' => '', + 'country_Åland Islands' => '', + 'country_France' => 'Frankreich', + 'country_French Guiana' => '', + 'country_French Polynesia' => '', + 'country_French Southern Territories' => '', + 'country_Djibouti' => '', + 'country_Gabon' => '', + 'country_Georgia' => '', + 'country_Gambia' => '', + 'country_Palestinian Territory, Occupied' => '', + 'country_Germany' => 'Deutschland', + 'country_Ghana' => '', + 'country_Gibraltar' => '', + 'country_Kiribati' => '', + 'country_Greece' => '', + 'country_Greenland' => '', + 'country_Grenada' => '', + 'country_Guadeloupe' => '', + 'country_Guam' => '', + 'country_Guatemala' => '', + 'country_Guinea' => '', + 'country_Guyana' => '', + 'country_Haiti' => '', + 'country_Heard Island and McDonald Islands' => '', + 'country_Holy See (Vatican City State)' => '', + 'country_Honduras' => '', + 'country_Hong Kong' => '', + 'country_Hungary' => '', + 'country_Iceland' => '', + 'country_India' => '', + 'country_Indonesia' => '', + 'country_Iran, Islamic Republic of' => '', + 'country_Iraq' => '', + 'country_Ireland' => '', + 'country_Israel' => '', + 'country_Italy' => '', + 'country_Côte d\'Ivoire' => '', + 'country_Jamaica' => '', + 'country_Japan' => '', + 'country_Kazakhstan' => '', + 'country_Jordan' => '', + 'country_Kenya' => '', + 'country_Korea, Democratic People\'s Republic of' => '', + 'country_Korea, Republic of' => '', + 'country_Kuwait' => '', + 'country_Kyrgyzstan' => '', + 'country_Lao People\'s Democratic Republic' => '', + 'country_Lebanon' => '', + 'country_Lesotho' => '', + 'country_Latvia' => '', + 'country_Liberia' => '', + 'country_Libya' => '', + 'country_Liechtenstein' => '', + 'country_Lithuania' => '', + 'country_Luxembourg' => '', + 'country_Macao' => '', + 'country_Madagascar' => '', + 'country_Malawi' => '', + 'country_Malaysia' => '', + 'country_Maldives' => '', + 'country_Mali' => '', + 'country_Malta' => '', + 'country_Martinique' => '', + 'country_Mauritania' => '', + 'country_Mauritius' => '', + 'country_Mexico' => '', + 'country_Monaco' => '', + 'country_Mongolia' => '', + 'country_Moldova, Republic of' => '', + 'country_Montenegro' => '', + 'country_Montserrat' => '', + 'country_Morocco' => '', + 'country_Mozambique' => '', + 'country_Oman' => '', + 'country_Namibia' => '', + 'country_Nauru' => '', + 'country_Nepal' => '', + 'country_Netherlands' => '', + 'country_Curaçao' => '', + 'country_Aruba' => '', + 'country_Sint Maarten (Dutch part)' => '', + 'country_Bonaire, Sint Eustatius and Saba' => '', + 'country_New Caledonia' => '', + 'country_Vanuatu' => '', + 'country_New Zealand' => '', + 'country_Nicaragua' => '', + 'country_Niger' => '', + 'country_Nigeria' => '', + 'country_Niue' => '', + 'country_Norfolk Island' => '', + 'country_Norway' => '', + 'country_Northern Mariana Islands' => '', + 'country_United States Minor Outlying Islands' => '', + 'country_Micronesia, Federated States of' => '', + 'country_Marshall Islands' => '', + 'country_Palau' => '', + 'country_Pakistan' => '', + 'country_Panama' => '', + 'country_Papua New Guinea' => '', + 'country_Paraguay' => '', + 'country_Peru' => '', + 'country_Philippines' => '', + 'country_Pitcairn' => '', + 'country_Poland' => '', + 'country_Portugal' => '', + 'country_Guinea-Bissau' => '', + 'country_Timor-Leste' => '', + 'country_Puerto Rico' => '', + 'country_Qatar' => '', + 'country_Réunion' => '', + 'country_Romania' => '', + 'country_Russian Federation' => '', + 'country_Rwanda' => '', + 'country_Saint Barthélemy' => '', + 'country_Saint Helena, Ascension and Tristan da Cunha' => '', + 'country_Saint Kitts and Nevis' => '', + 'country_Anguilla' => '', + 'country_Saint Lucia' => '', + 'country_Saint Martin (French part)' => '', + 'country_Saint Pierre and Miquelon' => '', + 'country_Saint Vincent and the Grenadines' => '', + 'country_San Marino' => '', + 'country_Sao Tome and Principe' => '', + 'country_Saudi Arabia' => '', + 'country_Senegal' => '', + 'country_Serbia' => '', + 'country_Seychelles' => '', + 'country_Sierra Leone' => '', + 'country_Singapore' => '', + 'country_Slovakia' => '', + 'country_Viet Nam' => '', + 'country_Slovenia' => '', + 'country_Somalia' => '', + 'country_South Africa' => '', + 'country_Zimbabwe' => '', + 'country_Spain' => '', + 'country_South Sudan' => '', + 'country_Sudan' => '', + 'country_Western Sahara' => '', + 'country_Suriname' => '', + 'country_Svalbard and Jan Mayen' => '', + 'country_Swaziland' => '', + 'country_Sweden' => '', + 'country_Switzerland' => '', + 'country_Syrian Arab Republic' => '', + 'country_Tajikistan' => '', + 'country_Thailand' => '', + 'country_Togo' => '', + 'country_Tokelau' => '', + 'country_Tonga' => '', + 'country_Trinidad and Tobago' => '', + 'country_United Arab Emirates' => '', + 'country_Tunisia' => '', + 'country_Turkey' => '', + 'country_Turkmenistan' => '', + 'country_Turks and Caicos Islands' => '', + 'country_Tuvalu' => '', + 'country_Uganda' => '', + 'country_Ukraine' => '', + 'country_Macedonia, the former Yugoslav Republic of' => '', + 'country_Egypt' => '', + 'country_United Kingdom' => '', + 'country_Guernsey' => '', + 'country_Jersey' => '', + 'country_Isle of Man' => '', + 'country_Tanzania, United Republic of' => '', + 'country_United States' => '', + 'country_Virgin Islands, U.S.' => '', + 'country_Burkina Faso' => '', + 'country_Uruguay' => '', + 'country_Uzbekistan' => '', + 'country_Venezuela, Bolivarian Republic of' => '', + 'country_Wallis and Futuna' => '', + 'country_Samoa' => '', + 'country_Yemen' => '', + 'country_Zambi' => '', + + // Languages + 'lang_Brazilian Portuguese' => 'Brazilian Portuguese', + 'lang_Croatian' => 'Kroatisch', + 'lang_Czech' => 'Tschechisch', + 'lang_Danish' => 'Dänisch', + 'lang_Dutch' => 'Niederländisch', + 'lang_English' => 'Englisch', + 'lang_French' => 'Französisch', + 'lang_French - Canada' => 'French - Canada', + 'lang_German' => 'Deutsch', + 'lang_Italian' => 'Italian', + 'lang_Japanese' => 'Japanese', + 'lang_Lithuanian' => 'Lithuanian', + 'lang_Norwegian' => 'Norwegian', + 'lang_Polish' => 'Polish', + 'lang_Spanish' => 'Spanish', + 'lang_Spanish - Spain' => 'Spanish - Spain', + 'lang_Swedish' => 'Swedish', ); + +return $LANG; + +?> \ No newline at end of file diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index a6532a6eb9..4038ee96a2 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -1,6 +1,7 @@ 'Organization', 'name' => 'Name', 'website' => 'Website', @@ -386,7 +387,7 @@ $LANG = array( 'gateway_help_1' => ':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_27' => ':link to sign up for TwoCheckout.', + 'gateway_help_27' => ':link to sign up for 2Checkout.com. To ensure payments are tracked set :complete_link as the redirect URL under Account > Site Management in the 2Checkout portal.', 'more_designs' => 'More designs', 'more_designs_title' => 'Additional Invoice Designs', 'more_designs_cloud_header' => 'Go Pro for more invoice designs', @@ -444,11 +445,11 @@ $LANG = array( 'token_billing_3' => 'Opt-out - checkbox is shown and selected', 'token_billing_4' => 'Always', 'token_billing_checkbox' => 'Store credit card details', - 'view_in_stripe' => 'View in Stripe', - 'use_card_on_file' => 'Use card on file', + 'view_in_gateway' => 'View in :gateway', + 'use_card_on_file' => 'Use Card on File', 'edit_payment_details' => 'Edit payment 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 :link', 'support' => 'Support', 'contact_information' => 'Contact Information', '256_encryption' => '256-Bit Encryption', @@ -654,8 +655,8 @@ $LANG = array( 'primary_user' => 'Primary User', 'help' => 'Help', 'customize_help' => '

    We use pdfmake to define the invoice designs declaratively. The pdfmake playground provide\'s a great way to see the library in action.

    -

    To access a child property using dot notation. For example to show the client name you could use $client.name.

    -

    If you need help figuring something out post a question to our support forum.

    ', +

    You can access a child property using dot notation. For example to show the client name you could use $client.name.

    +

    If you need help figuring something out post a question to our support forum with the design you\'re using.

    ', 'invoice_due_date' => 'Due Date', 'quote_due_date' => 'Valid Until', 'valid_until' => 'Valid Until', @@ -773,6 +774,8 @@ $LANG = array( 'activity_35' => ':user created :vendor', 'activity_36' => ':user created :vendor', 'activity_37' => ':user created :vendor', + 'activity_42' => ':user created task ":task"', + 'activity_43' => ':user updated task ":task"', 'payment' => 'Payment', 'system' => 'System', 'signature' => 'Email Signature', @@ -978,8 +981,8 @@ $LANG = array( 'first_page' => 'First page', 'all_pages' => 'All pages', 'last_page' => 'Last page', - 'all_pages_header' => 'Show header on', - 'all_pages_footer' => 'Show footer on', + 'all_pages_header' => 'Show Header on', + 'all_pages_footer' => 'Show Footer on', 'invoice_currency' => 'Invoice Currency', 'enable_https' => 'We strongly recommend using HTTPS to accept credit card details online.', 'quote_issued_to' => 'Quote issued to', @@ -992,40 +995,26 @@ $LANG = array( '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.', - '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 newer browser', - '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 400+ US banks.', - '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', - ], + 'white_label_text' => 'Purchase a ONE YEAR white label license for $:price to remove the Invoice Ninja branding and help support our project.', + 'user_email_footer' => 'To adjust your email notification settings please visit :link', + 'reset_password_footer' => 'If you did not request this password reset please email our support: :email', + 'limit_users' => 'Sorry, this will exceed the limit of :limit users', + 'more_designs_self_host_header' => 'Get 6 more invoice designs for just $:price', + 'old_browser' => 'Please use a newer browser', + 'white_label_custom_css' => ':link for $: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 400+ US banks.', + + 'pro_plan_remove_logo' => ':link to remove the Invoice Ninja logo by joining the Pro Plan', + 'pro_plan_remove_logo_link' => 'Click here', + 'invitation_status_sent' => 'Email Sent', + 'invitation_status_opened' => 'Email Openend', + 'invitation_status_viewed' => 'Invoice Viewed', + 'email_error_inactive_client' => 'Emails can not be sent to inactive clients', + 'email_error_inactive_contact' => 'Emails can not be sent to inactive contacts', + 'email_error_inactive_invoice' => 'Emails can not be sent to inactive invoices', + 'email_error_user_unregistered' => 'Please register your account to send emails', + 'email_error_user_unconfirmed' => 'Please confirm your account to send emails', + 'email_error_invalid_contact_email' => 'Invalid contact email', 'navigation' => 'Navigation', 'list_invoices' => 'List Invoices', @@ -1106,17 +1095,15 @@ $LANG = array( 'document_email_attachment' => 'Attach Documents', 'download_documents' => 'Download Documents (:size)', 'documents_from_expenses' => 'From Expenses:', - 'dropzone' => array(// See http://www.dropzonejs.com/#config-dictDefaultMessage - 'DefaultMessage' => 'Drop files or click to upload', - 'FallbackMessage' => 'Your browser does not support drag\'n\'drop file uploads.', - 'FallbackText' => 'Please use the fallback form below to upload your files like in the olden days.', - 'FileTooBig' => 'File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.', - 'InvalidFileType' => 'You can\'t upload files of this type.', - 'ResponseError' => 'Server responded with {{statusCode}} code.', - 'CancelUpload' => 'Cancel upload', - 'CancelUploadConfirmation' => 'Are you sure you want to cancel this upload?', - 'RemoveFile' => 'Remove file', - ), + 'dropzone_default_message' => 'Drop files or click to upload', + 'dropzone_fallback_message' => 'Your browser does not support drag\'n\'drop file uploads.', + 'dropzone_fallback_text' => 'Please use the fallback form below to upload your files like in the olden days.', + 'dropzone_file_too_big' => 'File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.', + 'dropzone_invalid_file_type' => 'You can\'t upload files of this type.', + 'dropzone_response_error' => 'Server responded with {{statusCode}} code.', + 'dropzone_cancel_upload' => 'Cancel upload', + 'dropzone_cancel_upload_confirmation' => 'Are you sure you want to cancel this upload?', + 'dropzone_remove_file' => 'Remove file', 'documents' => 'Documents', 'document_date' => 'Document Date', 'document_size' => 'Size', @@ -1182,10 +1169,868 @@ $LANG = array( 'enterprise_plan_features' => 'The Enterprise plan adds support for multiple users and file attachments, :link to see the full list of features.', 'return_to_app' => 'Return to app', + + // Payment updates + 'refund_payment' => 'Refund Payment', + 'refund_max' => 'Max:', + 'refund' => 'Refund', + 'are_you_sure_refund' => 'Refund selected payments?', + 'status_pending' => 'Pending', + 'status_completed' => 'Completed', + 'status_failed' => 'Failed', + 'status_partially_refunded' => 'Partially Refunded', + 'status_partially_refunded_amount' => ':amount Refunded', + 'status_refunded' => 'Refunded', + 'status_voided' => 'Cancelled', + 'refunded_payment' => 'Refunded Payment', + 'activity_39' => ':user cancelled a :payment_amount payment (:payment)', + 'activity_40' => ':user refunded :adjustment of a :payment_amount payment (:payment)', + 'card_expiration' => 'Exp: :expires', + + 'card_creditcardother' => 'Unknown', + 'card_americanexpress' => 'American Express', + 'card_carteblanche' => 'Carte Blanche', + 'card_unionpay' => 'UnionPay', + 'card_diners' => 'Diners Club', + 'card_discover' => 'Discover', + 'card_jcb' => 'JCB', + 'card_laser' => 'Laser', + 'card_maestro' => 'Maestro', + 'card_mastercard' => 'MasterCard', + 'card_solo' => 'Solo', + 'card_switch' => 'Switch', + 'card_visacard' => 'Visa', + 'card_ach' => 'ACH', + + 'payment_type_stripe' => 'Stripe', + 'ach' => 'ACH', + 'enable_ach' => 'Enable ACH', + 'stripe_ach_help' => 'ACH support must also be enabled at Stripe.', + 'ach_disabled' => 'Another gateway is already configured for direct debit.', + + 'plaid' => 'Plaid', + 'client_id' => 'Client Id', + 'secret' => 'Secret', + 'public_key' => 'Public Key', + 'plaid_optional' => '(optional)', + 'plaid_environment_help' => 'When a Stripe test key is given, Plaid\'s development environement (tartan) will be used.', + 'other_providers' => 'Other Providers', + 'country_not_supported' => 'That country is not supported.', + 'invalid_routing_number' => 'The routing number is not valid.', + 'invalid_account_number' => 'The account number is not valid.', + 'account_number_mismatch' => 'The account numbers do not match.', + 'missing_account_holder_type' => 'Please select an individual or company account.', + 'missing_account_holder_name' => 'Please enter the account holder\'s name.', + 'routing_number' => 'Routing Number', + 'confirm_account_number' => 'Confirm Account Number', + 'individual_account' => 'Individual Account', + 'company_account' => 'Company Account', + 'account_holder_name' => 'Account Holder Name', + 'add_account' => 'Add Account', + 'payment_methods' => 'Payment Methods', + 'complete_verification' => 'Complete Verification', + 'verification_amount1' => 'Amount 1', + 'verification_amount2' => 'Amount 2', + 'payment_method_verified' => 'Verification completed successfully', + 'verification_failed' => 'Verification Failed', + 'remove_payment_method' => 'Remove Payment Method', + 'confirm_remove_payment_method' => 'Are you sure you want to remove this payment method?', + 'remove' => 'Remove', + 'payment_method_removed' => 'Removed payment method.', + 'bank_account_verification_help' => 'We have made two deposits into your account with the description "VERIFICATION". These deposits will take 1-2 business days to appear on your statement. Please enter the amounts below.', + 'bank_account_verification_next_steps' => 'We have made two deposits into your account with the description "VERIFICATION". These deposits will take 1-2 business days to appear on your statement. + Once you have the amounts, come back to this payment methods page and click "Complete Verification" next to the account.', + 'unknown_bank' => 'Unknown Bank', + 'ach_verification_delay_help' => 'You will be able to use the account after completing verification. Verification usually takes 1-2 business days.', + 'add_credit_card' => 'Add Credit Card', + 'payment_method_added' => 'Added payment method.', + 'use_for_auto_bill' => 'Use For Autobill', + 'used_for_auto_bill' => 'Autobill Payment Method', + 'payment_method_set_as_default' => 'Set Autobill payment method.', + 'activity_41' => ':payment_amount payment (:payment) failed', + 'webhook_url' => 'Webhook URL', + 'stripe_webhook_help' => 'You must :link.', + 'stripe_webhook_help_link_text' => 'add this URL as an endpoint at Stripe', + 'payment_method_error' => 'There was an error adding your payment methd. Please try again later.', + 'notification_invoice_payment_failed_subject' => 'Payment failed for Invoice :invoice', + 'notification_invoice_payment_failed' => 'A payment made by client :client towards Invoice :invoice failed. The payment has been marked as failed and :amount has been added to the client\'s balance.', + 'link_with_plaid' => 'Link Account Instantly with Plaid', + 'link_manually' => 'Link Manually', + 'secured_by_plaid' => 'Secured by Plaid', + 'plaid_linked_status' => 'Your bank account at :bank', + 'add_payment_method' => 'Add Payment Method', + 'account_holder_type' => 'Account Holder Type', + 'ach_authorization' => 'I authorize :company to use my bank account for future payments and, if necessary, electronically credit my account to correct erroneous debits. I understand that I may cancel this authorization at any time by removing the payment method or by contacting :email.', + 'ach_authorization_required' => 'You must consent to ACH transactions.', + 'off' => 'Off', + 'opt_in' => 'Opt-in', + 'opt_out' => 'Opt-out', + 'always' => 'Always', + 'opted_out' => 'Opted out', + 'opted_in' => 'Opted in', + 'manage_auto_bill' => 'Manage Auto-bill', + 'enabled' => 'Enabled', + 'paypal' => 'PayPal', + 'braintree_enable_paypal' => 'Enable PayPal payments through BrainTree', + 'braintree_paypal_disabled_help' => 'The PayPal gateway is processing PayPal payments', + 'braintree_paypal_help' => 'You must also :link.', + 'braintree_paypal_help_link_text' => 'link PayPal to your BrainTree account', + 'token_billing_braintree_paypal' => 'Save payment details', + 'add_paypal_account' => 'Add PayPal Account', + + + 'no_payment_method_specified' => 'No payment method specified', + 'chart_type' => 'Chart Type', + 'format' => 'Format', + 'import_ofx' => 'Import OFX', + 'ofx_file' => 'OFX File', + 'ofx_parse_failed' => 'Failed to parse OFX file', + + // WePay + 'wepay' => 'WePay', + 'sign_up_with_wepay' => 'Sign up with WePay', + 'use_another_provider' => 'Use another provider', + 'company_name' => 'Company Name', + 'wepay_company_name_help' => 'This will appear on client\'s credit card statements.', + 'wepay_description_help' => 'The purpose of this account.', + 'wepay_tos_agree' => 'I agree to the :link.', + 'wepay_tos_link_text' => 'WePay Terms of Service', + 'resend_confirmation_email' => 'Resend Confirmation Email', + 'manage_wepay_account' => 'Manage WePay Account', + 'action_required' => 'Action Required', + 'finish_setup' => 'Finish Setup', + 'created_wepay_confirmation_required' => 'Please check your email and confirm your email address with WePay.', + 'switch_to_wepay' => 'Switch to WePay', + 'switch' => 'Switch', + 'restore_account_gateway' => 'Restore Gateway', + 'restored_account_gateway' => 'Successfully restored gateway', + 'united_states' => 'United States', + 'canada' => 'Canada', + 'accept_debit_cards' => 'Accept Debit Cards', + 'debit_cards' => 'Debit Cards', + + 'warn_start_date_changed' => 'The next invoice will be sent on the new start date.', + 'original_start_date' => 'Original start date', + 'new_start_date' => 'New start date', + 'security' => 'Security', + 'see_whats_new' => 'See what\'s new in v:version', + 'wait_for_upload' => 'Please wait for the document upload to complete.', + 'upgrade_for_permissions' => 'Upgrade to our Enterprise plan to enable permissions.', + 'enable_second_tax_rate' => 'Enable specifying a second tax rate', + 'payment_file' => 'Payment File', + 'expense_file' => 'Expense File', + 'product_file' => 'Product File', + 'import_products' => 'Import Products', + 'products_will_create' => 'products will be created.', + 'product_key' => 'Product', + 'created_products' => 'Successfully created :count product(s)', + 'export_help' => 'Use JSON if you plan to import the data into Invoice Ninja.', + 'JSON_file' => 'JSON File', + + 'view_dashboard' => 'View Dashboard', + 'client_session_expired' => 'Session Expired', + 'client_session_expired_message' => 'Your session has expired. Please click the link in your email again.', + + 'auto_bill_notification' => 'This invoice will automatically be billed to your :payment_method on file on :due_date.', + 'auto_bill_payment_method_bank_transfer' => 'bank account', + 'auto_bill_payment_method_credit_card' => 'credit card', + 'auto_bill_payment_method_paypal' => 'PayPal account', + 'auto_bill_notification_placeholder' => 'This invoice will automatically be billed to your credit card on file on the due date.', + 'payment_settings' => 'Payment Settings', + + 'on_send_date' => 'On send date', + 'on_due_date' => 'On due date', + 'auto_bill_ach_date_help' => 'ACH auto bill will always happen on the due date', + 'warn_change_auto_bill' => 'Due to NACHA rules, changes to this invoice may prevent ACH auto bill.', + + 'bank_account' => 'Bank Account', + 'payment_processed_through_wepay' => 'ACH payments will be processed using WePay.', + 'wepay_payment_tos_agree' => 'I agree to the WePay :terms and :privacy_policy.', + 'privacy_policy' => 'Privacy Policy', + 'wepay_payment_tos_agree_required' => 'You must agree to the WePay Terms of Service and Privacy Policy.', + 'payment_settings_supported_gateways' => 'These options are supported by the WePay, Stripe, and Braintree gateways.', + 'ach_email_prompt' => 'Please enter your email address:', + 'verification_pending' => 'Verification Pending', + 'update_font_cache' => 'Please force refresh the page to update the font cache.', + 'more_options' => 'More options', + 'credit_card' => 'Credit Card', + 'bank_transfer' => 'Bank Transfer', + 'no_transaction_reference' => 'We did not recieve a payment transaction reference from the gateway.', + 'use_bank_on_file' => 'Use Bank on File', + 'auto_bill_email_message' => 'This invoice will automatically be billed to the payment method on file on the due date.', + 'bitcoin' => 'Bitcoin', + 'added_on' => 'Added :date', + 'failed_remove_payment_method' => 'Failed to remove the payment method', + 'gateway_exists' => 'This gateway already exists', + 'manual_entry' => 'Manual entry', + 'start_of_week' => 'First day of the week', + + // Frequencies + 'freq_weekly' => 'Weekly', + 'freq_two_weeks' => 'Two weeks', + 'freq_four_weeks' => 'Four weeks', + 'freq_monthly' => 'Monthly', + 'freq_three_months' => 'Three months', + 'freq_six_months' => 'Six months', + 'freq_annually' => 'Annually', + + // Payment types + 'payment_type_Apply Credit' => 'Apply Credit', + 'payment_type_Bank Transfer' => 'Bank Transfer', + 'payment_type_Cash' => 'Cash', + 'payment_type_Debit' => 'Debit', + 'payment_type_ACH' => 'ACH', + 'payment_type_Visa Card' => 'Visa Card', + 'payment_type_MasterCard' => 'MasterCard', + 'payment_type_American Express' => 'American Express', + 'payment_type_Discover Card' => 'Discover Card', + 'payment_type_Diners Card' => 'Diners Card', + 'payment_type_EuroCard' => 'EuroCard', + 'payment_type_Nova' => 'Nova', + 'payment_type_Credit Card Other' => 'Credit Card Other', + 'payment_type_PayPal' => 'PayPal', + 'payment_type_Google Wallet' => 'Google Wallet', + 'payment_type_Check' => 'Check', + + // Industries + 'industry_Accounting & Legal' => 'Accounting & Legal', + 'industry_Advertising' => 'Advertising', + 'industry_Aerospace' => 'Aerospace', + 'industry_Agriculture' => 'Agriculture', + 'industry_Automotive' => 'Automotive', + 'industry_Banking & Finance' => 'Banking & Finance', + 'industry_Biotechnology' => 'Biotechnology', + 'industry_Broadcasting' => 'Broadcasting', + 'industry_Business Services' => 'Business Services', + 'industry_Commodities & Chemicals' => 'Commodities & Chemicals', + 'industry_Communications' => 'Communications', + 'industry_Computers & Hightech' => 'Computers & Hightech', + 'industry_Defense' => 'Defense', + 'industry_Energy' => 'Energy', + 'industry_Entertainment' => 'Entertainment', + 'industry_Government' => 'Government', + 'industry_Healthcare & Life Sciences' => 'Healthcare & Life Sciences', + 'industry_Insurance' => 'Insurance', + 'industry_Manufacturing' => 'Manufacturing', + 'industry_Marketing' => 'Marketing', + 'industry_Media' => 'Media', + 'industry_Nonprofit & Higher Ed' => 'Nonprofit & Higher Ed', + 'industry_Pharmaceuticals' => 'Pharmaceuticals', + 'industry_Professional Services & Consulting' => 'Professional Services & Consulting', + 'industry_Real Estate' => 'Real Estate', + 'industry_Retail & Wholesale' => 'Retail & Wholesale', + 'industry_Sports' => 'Sports', + 'industry_Transportation' => 'Transportation', + 'industry_Travel & Luxury' => 'Travel & Luxury', + 'industry_Other' => 'Other', + 'industry_Photography' =>'Photography', + + // Countries + 'country_Afghanistan' => 'Afghanistan', + 'country_Albania' => 'Albania', + 'country_Antarctica' => 'Antarctica', + 'country_Algeria' => 'Algeria', + 'country_American Samoa' => 'American Samoa', + 'country_Andorra' => 'Andorra', + 'country_Angola' => 'Angola', + 'country_Antigua and Barbuda' => 'Antigua and Barbuda', + 'country_Azerbaijan' => 'Azerbaijan', + 'country_Argentina' => 'Argentina', + 'country_Australia' => 'Australia', + 'country_Austria' => 'Austria', + 'country_Bahamas' => 'Bahamas', + 'country_Bahrain' => 'Bahrain', + 'country_Bangladesh' => 'Bangladesh', + 'country_Armenia' => 'Armenia', + 'country_Barbados' => 'Barbados', + 'country_Belgium' => 'Belgium', + 'country_Bermuda' => 'Bermuda', + 'country_Bhutan' => 'Bhutan', + 'country_Bolivia, Plurinational State of' => 'Bolivia, Plurinational State of', + 'country_Bosnia and Herzegovina' => 'Bosnia and Herzegovina', + 'country_Botswana' => 'Botswana', + 'country_Bouvet Island' => 'Bouvet Island', + 'country_Brazil' => 'Brazil', + 'country_Belize' => 'Belize', + 'country_British Indian Ocean Territory' => 'British Indian Ocean Territory', + 'country_Solomon Islands' => 'Solomon Islands', + 'country_Virgin Islands, British' => 'Virgin Islands, British', + 'country_Brunei Darussalam' => 'Brunei Darussalam', + 'country_Bulgaria' => 'Bulgaria', + 'country_Myanmar' => 'Myanmar', + 'country_Burundi' => 'Burundi', + 'country_Belarus' => 'Belarus', + 'country_Cambodia' => 'Cambodia', + 'country_Cameroon' => 'Cameroon', + 'country_Canada' => 'Canada', + 'country_Cape Verde' => 'Cape Verde', + 'country_Cayman Islands' => 'Cayman Islands', + 'country_Central African Republic' => 'Central African Republic', + 'country_Sri Lanka' => 'Sri Lanka', + 'country_Chad' => 'Chad', + 'country_Chile' => 'Chile', + 'country_China' => 'China', + 'country_Taiwan, Province of China' => 'Taiwan, Province of China', + 'country_Christmas Island' => 'Christmas Island', + 'country_Cocos (Keeling) Islands' => 'Cocos (Keeling) Islands', + 'country_Colombia' => 'Colombia', + 'country_Comoros' => 'Comoros', + 'country_Mayotte' => 'Mayotte', + 'country_Congo' => 'Congo', + 'country_Congo, the Democratic Republic of the' => 'Congo, the Democratic Republic of the', + 'country_Cook Islands' => 'Cook Islands', + 'country_Costa Rica' => 'Costa Rica', + 'country_Croatia' => 'Croatia', + 'country_Cuba' => 'Cuba', + 'country_Cyprus' => 'Cyprus', + 'country_Czech Republic' => 'Czech Republic', + 'country_Benin' => 'Benin', + 'country_Denmark' => 'Denmark', + 'country_Dominica' => 'Dominica', + 'country_Dominican Republic' => 'Dominican Republic', + 'country_Ecuador' => 'Ecuador', + 'country_El Salvador' => 'El Salvador', + 'country_Equatorial Guinea' => 'Equatorial Guinea', + 'country_Ethiopia' => 'Ethiopia', + 'country_Eritrea' => 'Eritrea', + 'country_Estonia' => 'Estonia', + 'country_Faroe Islands' => 'Faroe Islands', + 'country_Falkland Islands (Malvinas)' => 'Falkland Islands (Malvinas)', + 'country_South Georgia and the South Sandwich Islands' => 'South Georgia and the South Sandwich Islands', + 'country_Fiji' => 'Fiji', + 'country_Finland' => 'Finland', + 'country_Åland Islands' => 'Åland Islands', + 'country_France' => 'France', + 'country_French Guiana' => 'French Guiana', + 'country_French Polynesia' => 'French Polynesia', + 'country_French Southern Territories' => 'French Southern Territories', + 'country_Djibouti' => 'Djibouti', + 'country_Gabon' => 'Gabon', + 'country_Georgia' => 'Georgia', + 'country_Gambia' => 'Gambia', + 'country_Palestinian Territory, Occupied' => 'Palestinian Territory, Occupied', + 'country_Germany' => 'Germany', + 'country_Ghana' => 'Ghana', + 'country_Gibraltar' => 'Gibraltar', + 'country_Kiribati' => 'Kiribati', + 'country_Greece' => 'Greece', + 'country_Greenland' => 'Greenland', + 'country_Grenada' => 'Grenada', + 'country_Guadeloupe' => 'Guadeloupe', + 'country_Guam' => 'Guam', + 'country_Guatemala' => 'Guatemala', + 'country_Guinea' => 'Guinea', + 'country_Guyana' => 'Guyana', + 'country_Haiti' => 'Haiti', + 'country_Heard Island and McDonald Islands' => 'Heard Island and McDonald Islands', + 'country_Holy See (Vatican City State)' => 'Holy See (Vatican City State)', + 'country_Honduras' => 'Honduras', + 'country_Hong Kong' => 'Hong Kong', + 'country_Hungary' => 'Hungary', + 'country_Iceland' => 'Iceland', + 'country_India' => 'India', + 'country_Indonesia' => 'Indonesia', + 'country_Iran, Islamic Republic of' => 'Iran, Islamic Republic of', + 'country_Iraq' => 'Iraq', + 'country_Ireland' => 'Ireland', + 'country_Israel' => 'Israel', + 'country_Italy' => 'Italy', + 'country_Côte d\'Ivoire' => 'Côte d\'Ivoire', + 'country_Jamaica' => 'Jamaica', + 'country_Japan' => 'Japan', + 'country_Kazakhstan' => 'Kazakhstan', + 'country_Jordan' => 'Jordan', + 'country_Kenya' => 'Kenya', + 'country_Korea, Democratic People\'s Republic of' => 'Korea, Democratic People\'s Republic of', + 'country_Korea, Republic of' => 'Korea, Republic of', + 'country_Kuwait' => 'Kuwait', + 'country_Kyrgyzstan' => 'Kyrgyzstan', + 'country_Lao People\'s Democratic Republic' => 'Lao People\'s Democratic Republic', + 'country_Lebanon' => 'Lebanon', + 'country_Lesotho' => 'Lesotho', + 'country_Latvia' => 'Latvia', + 'country_Liberia' => 'Liberia', + 'country_Libya' => 'Libya', + 'country_Liechtenstein' => 'Liechtenstein', + 'country_Lithuania' => 'Lithuania', + 'country_Luxembourg' => 'Luxembourg', + 'country_Macao' => 'Macao', + 'country_Madagascar' => 'Madagascar', + 'country_Malawi' => 'Malawi', + 'country_Malaysia' => 'Malaysia', + 'country_Maldives' => 'Maldives', + 'country_Mali' => 'Mali', + 'country_Malta' => 'Malta', + 'country_Martinique' => 'Martinique', + 'country_Mauritania' => 'Mauritania', + 'country_Mauritius' => 'Mauritius', + 'country_Mexico' => 'Mexico', + 'country_Monaco' => 'Monaco', + 'country_Mongolia' => 'Mongolia', + 'country_Moldova, Republic of' => 'Moldova, Republic of', + 'country_Montenegro' => 'Montenegro', + 'country_Montserrat' => 'Montserrat', + 'country_Morocco' => 'Morocco', + 'country_Mozambique' => 'Mozambique', + 'country_Oman' => 'Oman', + 'country_Namibia' => 'Namibia', + 'country_Nauru' => 'Nauru', + 'country_Nepal' => 'Nepal', + 'country_Netherlands' => 'Netherlands', + 'country_Curaçao' => 'Curaçao', + 'country_Aruba' => 'Aruba', + 'country_Sint Maarten (Dutch part)' => 'Sint Maarten (Dutch part)', + 'country_Bonaire, Sint Eustatius and Saba' => 'Bonaire, Sint Eustatius and Saba', + 'country_New Caledonia' => 'New Caledonia', + 'country_Vanuatu' => 'Vanuatu', + 'country_New Zealand' => 'New Zealand', + 'country_Nicaragua' => 'Nicaragua', + 'country_Niger' => 'Niger', + 'country_Nigeria' => 'Nigeria', + 'country_Niue' => 'Niue', + 'country_Norfolk Island' => 'Norfolk Island', + 'country_Norway' => 'Norway', + 'country_Northern Mariana Islands' => 'Northern Mariana Islands', + 'country_United States Minor Outlying Islands' => 'United States Minor Outlying Islands', + 'country_Micronesia, Federated States of' => 'Micronesia, Federated States of', + 'country_Marshall Islands' => 'Marshall Islands', + 'country_Palau' => 'Palau', + 'country_Pakistan' => 'Pakistan', + 'country_Panama' => 'Panama', + 'country_Papua New Guinea' => 'Papua New Guinea', + 'country_Paraguay' => 'Paraguay', + 'country_Peru' => 'Peru', + 'country_Philippines' => 'Philippines', + 'country_Pitcairn' => 'Pitcairn', + 'country_Poland' => 'Poland', + 'country_Portugal' => 'Portugal', + 'country_Guinea-Bissau' => 'Guinea-Bissau', + 'country_Timor-Leste' => 'Timor-Leste', + 'country_Puerto Rico' => 'Puerto Rico', + 'country_Qatar' => 'Qatar', + 'country_Réunion' => 'Réunion', + 'country_Romania' => 'Romania', + 'country_Russian Federation' => 'Russian Federation', + 'country_Rwanda' => 'Rwanda', + 'country_Saint Barthélemy' => 'Saint Barthélemy', + 'country_Saint Helena, Ascension and Tristan da Cunha' => 'Saint Helena, Ascension and Tristan da Cunha', + 'country_Saint Kitts and Nevis' => 'Saint Kitts and Nevis', + 'country_Anguilla' => 'Anguilla', + 'country_Saint Lucia' => 'Saint Lucia', + 'country_Saint Martin (French part)' => 'Saint Martin (French part)', + 'country_Saint Pierre and Miquelon' => 'Saint Pierre and Miquelon', + 'country_Saint Vincent and the Grenadines' => 'Saint Vincent and the Grenadines', + 'country_San Marino' => 'San Marino', + 'country_Sao Tome and Principe' => 'Sao Tome and Principe', + 'country_Saudi Arabia' => 'Saudi Arabia', + 'country_Senegal' => 'Senegal', + 'country_Serbia' => 'Serbia', + 'country_Seychelles' => 'Seychelles', + 'country_Sierra Leone' => 'Sierra Leone', + 'country_Singapore' => 'Singapore', + 'country_Slovakia' => 'Slovakia', + 'country_Viet Nam' => 'Viet Nam', + 'country_Slovenia' => 'Slovenia', + 'country_Somalia' => 'Somalia', + 'country_South Africa' => 'South Africa', + 'country_Zimbabwe' => 'Zimbabwe', + 'country_Spain' => 'Spain', + 'country_South Sudan' => 'South Sudan', + 'country_Sudan' => 'Sudan', + 'country_Western Sahara' => 'Western Sahara', + 'country_Suriname' => 'Suriname', + 'country_Svalbard and Jan Mayen' => 'Svalbard and Jan Mayen', + 'country_Swaziland' => 'Swaziland', + 'country_Sweden' => 'Sweden', + 'country_Switzerland' => 'Switzerland', + 'country_Syrian Arab Republic' => 'Syrian Arab Republic', + 'country_Tajikistan' => 'Tajikistan', + 'country_Thailand' => 'Thailand', + 'country_Togo' => 'Togo', + 'country_Tokelau' => 'Tokelau', + 'country_Tonga' => 'Tonga', + 'country_Trinidad and Tobago' => 'Trinidad and Tobago', + 'country_United Arab Emirates' => 'United Arab Emirates', + 'country_Tunisia' => 'Tunisia', + 'country_Turkey' => 'Turkey', + 'country_Turkmenistan' => 'Turkmenistan', + 'country_Turks and Caicos Islands' => 'Turks and Caicos Islands', + 'country_Tuvalu' => 'Tuvalu', + 'country_Uganda' => 'Uganda', + 'country_Ukraine' => 'Ukraine', + 'country_Macedonia, the former Yugoslav Republic of' => 'Macedonia, the former Yugoslav Republic of', + 'country_Egypt' => 'Egypt', + 'country_United Kingdom' => 'United Kingdom', + 'country_Guernsey' => 'Guernsey', + 'country_Jersey' => 'Jersey', + 'country_Isle of Man' => 'Isle of Man', + 'country_Tanzania, United Republic of' => 'Tanzania, United Republic of', + 'country_United States' => 'United States', + 'country_Virgin Islands, U.S.' => 'Virgin Islands, U.S.', + 'country_Burkina Faso' => 'Burkina Faso', + 'country_Uruguay' => 'Uruguay', + 'country_Uzbekistan' => 'Uzbekistan', + 'country_Venezuela, Bolivarian Republic of' => 'Venezuela, Bolivarian Republic of', + 'country_Wallis and Futuna' => 'Wallis and Futuna', + 'country_Samoa' => 'Samoa', + 'country_Yemen' => 'Yemen', + 'country_Zambi' => 'Zambi', + + // Languages + 'lang_Brazilian Portuguese' => 'Brazilian Portuguese', + 'lang_Croatian' => 'Croatian', + 'lang_Czech' => 'Czech', + 'lang_Danish' => 'Danish', + 'lang_Dutch' => 'Dutch', + 'lang_English' => 'English', + 'lang_French' => 'French', + 'lang_French - Canada' => 'French - Canada', + 'lang_German' => 'German', + 'lang_Italian' => 'Italian', + 'lang_Japanese' => 'Japanese', + 'lang_Lithuanian' => 'Lithuanian', + 'lang_Norwegian' => 'Norwegian', + 'lang_Polish' => 'Polish', + 'lang_Spanish' => 'Spanish', + 'lang_Spanish - Spain' => 'Spanish - Spain', + 'lang_Swedish' => 'Swedish', + + // Frequencies + 'freq_weekly' => 'Weekly', + 'freq_two_weeks' => 'Two weeks', + 'freq_four_weeks' => 'Four weeks', + 'freq_monthly' => 'Monthly', + 'freq_three_months' => 'Three months', + 'freq_six_months' => 'Six months', + 'freq_annually' => 'Annually', + + // Payment types + 'payment_type_Apply Credit' => 'Apply Credit', + 'payment_type_Bank Transfer' => 'Bank Transfer', + 'payment_type_Cash' => 'Cash', + 'payment_type_Debit' => 'Debit', + 'payment_type_ACH' => 'ACH', + 'payment_type_Visa Card' => 'Visa Card', + 'payment_type_MasterCard' => 'MasterCard', + 'payment_type_American Express' => 'American Express', + 'payment_type_Discover Card' => 'Discover Card', + 'payment_type_Diners Card' => 'Diners Card', + 'payment_type_EuroCard' => 'EuroCard', + 'payment_type_Nova' => 'Nova', + 'payment_type_Credit Card Other' => 'Credit Card Other', + 'payment_type_PayPal' => 'PayPal', + 'payment_type_Google Wallet' => 'Google Wallet', + 'payment_type_Check' => 'Check', + + // Industries + 'industry_Accounting & Legal' => 'Accounting & Legal', + 'industry_Advertising' => 'Advertising', + 'industry_Aerospace' => 'Aerospace', + 'industry_Agriculture' => 'Agriculture', + 'industry_Automotive' => 'Automotive', + 'industry_Banking & Finance' => 'Banking & Finance', + 'industry_Biotechnology' => 'Biotechnology', + 'industry_Broadcasting' => 'Broadcasting', + 'industry_Business Services' => 'Business Services', + 'industry_Commodities & Chemicals' => 'Commodities & Chemicals', + 'industry_Communications' => 'Communications', + 'industry_Computers & Hightech' => 'Computers & Hightech', + 'industry_Defense' => 'Defense', + 'industry_Energy' => 'Energy', + 'industry_Entertainment' => 'Entertainment', + 'industry_Government' => 'Government', + 'industry_Healthcare & Life Sciences' => 'Healthcare & Life Sciences', + 'industry_Insurance' => 'Insurance', + 'industry_Manufacturing' => 'Manufacturing', + 'industry_Marketing' => 'Marketing', + 'industry_Media' => 'Media', + 'industry_Nonprofit & Higher Ed' => 'Nonprofit & Higher Ed', + 'industry_Pharmaceuticals' => 'Pharmaceuticals', + 'industry_Professional Services & Consulting' => 'Professional Services & Consulting', + 'industry_Real Estate' => 'Real Estate', + 'industry_Retail & Wholesale' => 'Retail & Wholesale', + 'industry_Sports' => 'Sports', + 'industry_Transportation' => 'Transportation', + 'industry_Travel & Luxury' => 'Travel & Luxury', + 'industry_Other' => 'Other', + 'industry_Photography' =>'Photography', + + // Countries + 'country_Afghanistan' => 'Afghanistan', + 'country_Albania' => 'Albania', + 'country_Antarctica' => 'Antarctica', + 'country_Algeria' => 'Algeria', + 'country_American Samoa' => 'American Samoa', + 'country_Andorra' => 'Andorra', + 'country_Angola' => 'Angola', + 'country_Antigua and Barbuda' => 'Antigua and Barbuda', + 'country_Azerbaijan' => 'Azerbaijan', + 'country_Argentina' => 'Argentina', + 'country_Australia' => 'Australia', + 'country_Austria' => 'Austria', + 'country_Bahamas' => 'Bahamas', + 'country_Bahrain' => 'Bahrain', + 'country_Bangladesh' => 'Bangladesh', + 'country_Armenia' => 'Armenia', + 'country_Barbados' => 'Barbados', + 'country_Belgium' => 'Belgium', + 'country_Bermuda' => 'Bermuda', + 'country_Bhutan' => 'Bhutan', + 'country_Bolivia, Plurinational State of' => 'Bolivia, Plurinational State of', + 'country_Bosnia and Herzegovina' => 'Bosnia and Herzegovina', + 'country_Botswana' => 'Botswana', + 'country_Bouvet Island' => 'Bouvet Island', + 'country_Brazil' => 'Brazil', + 'country_Belize' => 'Belize', + 'country_British Indian Ocean Territory' => 'British Indian Ocean Territory', + 'country_Solomon Islands' => 'Solomon Islands', + 'country_Virgin Islands, British' => 'Virgin Islands, British', + 'country_Brunei Darussalam' => 'Brunei Darussalam', + 'country_Bulgaria' => 'Bulgaria', + 'country_Myanmar' => 'Myanmar', + 'country_Burundi' => 'Burundi', + 'country_Belarus' => 'Belarus', + 'country_Cambodia' => 'Cambodia', + 'country_Cameroon' => 'Cameroon', + 'country_Canada' => 'Canada', + 'country_Cape Verde' => 'Cape Verde', + 'country_Cayman Islands' => 'Cayman Islands', + 'country_Central African Republic' => 'Central African Republic', + 'country_Sri Lanka' => 'Sri Lanka', + 'country_Chad' => 'Chad', + 'country_Chile' => 'Chile', + 'country_China' => 'China', + 'country_Taiwan, Province of China' => 'Taiwan, Province of China', + 'country_Christmas Island' => 'Christmas Island', + 'country_Cocos (Keeling) Islands' => 'Cocos (Keeling) Islands', + 'country_Colombia' => 'Colombia', + 'country_Comoros' => 'Comoros', + 'country_Mayotte' => 'Mayotte', + 'country_Congo' => 'Congo', + 'country_Congo, the Democratic Republic of the' => 'Congo, the Democratic Republic of the', + 'country_Cook Islands' => 'Cook Islands', + 'country_Costa Rica' => 'Costa Rica', + 'country_Croatia' => 'Croatia', + 'country_Cuba' => 'Cuba', + 'country_Cyprus' => 'Cyprus', + 'country_Czech Republic' => 'Czech Republic', + 'country_Benin' => 'Benin', + 'country_Denmark' => 'Denmark', + 'country_Dominica' => 'Dominica', + 'country_Dominican Republic' => 'Dominican Republic', + 'country_Ecuador' => 'Ecuador', + 'country_El Salvador' => 'El Salvador', + 'country_Equatorial Guinea' => 'Equatorial Guinea', + 'country_Ethiopia' => 'Ethiopia', + 'country_Eritrea' => 'Eritrea', + 'country_Estonia' => 'Estonia', + 'country_Faroe Islands' => 'Faroe Islands', + 'country_Falkland Islands (Malvinas)' => 'Falkland Islands (Malvinas)', + 'country_South Georgia and the South Sandwich Islands' => 'South Georgia and the South Sandwich Islands', + 'country_Fiji' => 'Fiji', + 'country_Finland' => 'Finland', + 'country_Åland Islands' => 'Åland Islands', + 'country_France' => 'France', + 'country_French Guiana' => 'French Guiana', + 'country_French Polynesia' => 'French Polynesia', + 'country_French Southern Territories' => 'French Southern Territories', + 'country_Djibouti' => 'Djibouti', + 'country_Gabon' => 'Gabon', + 'country_Georgia' => 'Georgia', + 'country_Gambia' => 'Gambia', + 'country_Palestinian Territory, Occupied' => 'Palestinian Territory, Occupied', + 'country_Germany' => 'Germany', + 'country_Ghana' => 'Ghana', + 'country_Gibraltar' => 'Gibraltar', + 'country_Kiribati' => 'Kiribati', + 'country_Greece' => 'Greece', + 'country_Greenland' => 'Greenland', + 'country_Grenada' => 'Grenada', + 'country_Guadeloupe' => 'Guadeloupe', + 'country_Guam' => 'Guam', + 'country_Guatemala' => 'Guatemala', + 'country_Guinea' => 'Guinea', + 'country_Guyana' => 'Guyana', + 'country_Haiti' => 'Haiti', + 'country_Heard Island and McDonald Islands' => 'Heard Island and McDonald Islands', + 'country_Holy See (Vatican City State)' => 'Holy See (Vatican City State)', + 'country_Honduras' => 'Honduras', + 'country_Hong Kong' => 'Hong Kong', + 'country_Hungary' => 'Hungary', + 'country_Iceland' => 'Iceland', + 'country_India' => 'India', + 'country_Indonesia' => 'Indonesia', + 'country_Iran, Islamic Republic of' => 'Iran, Islamic Republic of', + 'country_Iraq' => 'Iraq', + 'country_Ireland' => 'Ireland', + 'country_Israel' => 'Israel', + 'country_Italy' => 'Italy', + 'country_Côte d\'Ivoire' => 'Côte d\'Ivoire', + 'country_Jamaica' => 'Jamaica', + 'country_Japan' => 'Japan', + 'country_Kazakhstan' => 'Kazakhstan', + 'country_Jordan' => 'Jordan', + 'country_Kenya' => 'Kenya', + 'country_Korea, Democratic People\'s Republic of' => 'Korea, Democratic People\'s Republic of', + 'country_Korea, Republic of' => 'Korea, Republic of', + 'country_Kuwait' => 'Kuwait', + 'country_Kyrgyzstan' => 'Kyrgyzstan', + 'country_Lao People\'s Democratic Republic' => 'Lao People\'s Democratic Republic', + 'country_Lebanon' => 'Lebanon', + 'country_Lesotho' => 'Lesotho', + 'country_Latvia' => 'Latvia', + 'country_Liberia' => 'Liberia', + 'country_Libya' => 'Libya', + 'country_Liechtenstein' => 'Liechtenstein', + 'country_Lithuania' => 'Lithuania', + 'country_Luxembourg' => 'Luxembourg', + 'country_Macao' => 'Macao', + 'country_Madagascar' => 'Madagascar', + 'country_Malawi' => 'Malawi', + 'country_Malaysia' => 'Malaysia', + 'country_Maldives' => 'Maldives', + 'country_Mali' => 'Mali', + 'country_Malta' => 'Malta', + 'country_Martinique' => 'Martinique', + 'country_Mauritania' => 'Mauritania', + 'country_Mauritius' => 'Mauritius', + 'country_Mexico' => 'Mexico', + 'country_Monaco' => 'Monaco', + 'country_Mongolia' => 'Mongolia', + 'country_Moldova, Republic of' => 'Moldova, Republic of', + 'country_Montenegro' => 'Montenegro', + 'country_Montserrat' => 'Montserrat', + 'country_Morocco' => 'Morocco', + 'country_Mozambique' => 'Mozambique', + 'country_Oman' => 'Oman', + 'country_Namibia' => 'Namibia', + 'country_Nauru' => 'Nauru', + 'country_Nepal' => 'Nepal', + 'country_Netherlands' => 'Netherlands', + 'country_Curaçao' => 'Curaçao', + 'country_Aruba' => 'Aruba', + 'country_Sint Maarten (Dutch part)' => 'Sint Maarten (Dutch part)', + 'country_Bonaire, Sint Eustatius and Saba' => 'Bonaire, Sint Eustatius and Saba', + 'country_New Caledonia' => 'New Caledonia', + 'country_Vanuatu' => 'Vanuatu', + 'country_New Zealand' => 'New Zealand', + 'country_Nicaragua' => 'Nicaragua', + 'country_Niger' => 'Niger', + 'country_Nigeria' => 'Nigeria', + 'country_Niue' => 'Niue', + 'country_Norfolk Island' => 'Norfolk Island', + 'country_Norway' => 'Norway', + 'country_Northern Mariana Islands' => 'Northern Mariana Islands', + 'country_United States Minor Outlying Islands' => 'United States Minor Outlying Islands', + 'country_Micronesia, Federated States of' => 'Micronesia, Federated States of', + 'country_Marshall Islands' => 'Marshall Islands', + 'country_Palau' => 'Palau', + 'country_Pakistan' => 'Pakistan', + 'country_Panama' => 'Panama', + 'country_Papua New Guinea' => 'Papua New Guinea', + 'country_Paraguay' => 'Paraguay', + 'country_Peru' => 'Peru', + 'country_Philippines' => 'Philippines', + 'country_Pitcairn' => 'Pitcairn', + 'country_Poland' => 'Poland', + 'country_Portugal' => 'Portugal', + 'country_Guinea-Bissau' => 'Guinea-Bissau', + 'country_Timor-Leste' => 'Timor-Leste', + 'country_Puerto Rico' => 'Puerto Rico', + 'country_Qatar' => 'Qatar', + 'country_Réunion' => 'Réunion', + 'country_Romania' => 'Romania', + 'country_Russian Federation' => 'Russian Federation', + 'country_Rwanda' => 'Rwanda', + 'country_Saint Barthélemy' => 'Saint Barthélemy', + 'country_Saint Helena, Ascension and Tristan da Cunha' => 'Saint Helena, Ascension and Tristan da Cunha', + 'country_Saint Kitts and Nevis' => 'Saint Kitts and Nevis', + 'country_Anguilla' => 'Anguilla', + 'country_Saint Lucia' => 'Saint Lucia', + 'country_Saint Martin (French part)' => 'Saint Martin (French part)', + 'country_Saint Pierre and Miquelon' => 'Saint Pierre and Miquelon', + 'country_Saint Vincent and the Grenadines' => 'Saint Vincent and the Grenadines', + 'country_San Marino' => 'San Marino', + 'country_Sao Tome and Principe' => 'Sao Tome and Principe', + 'country_Saudi Arabia' => 'Saudi Arabia', + 'country_Senegal' => 'Senegal', + 'country_Serbia' => 'Serbia', + 'country_Seychelles' => 'Seychelles', + 'country_Sierra Leone' => 'Sierra Leone', + 'country_Singapore' => 'Singapore', + 'country_Slovakia' => 'Slovakia', + 'country_Viet Nam' => 'Viet Nam', + 'country_Slovenia' => 'Slovenia', + 'country_Somalia' => 'Somalia', + 'country_South Africa' => 'South Africa', + 'country_Zimbabwe' => 'Zimbabwe', + 'country_Spain' => 'Spain', + 'country_South Sudan' => 'South Sudan', + 'country_Sudan' => 'Sudan', + 'country_Western Sahara' => 'Western Sahara', + 'country_Suriname' => 'Suriname', + 'country_Svalbard and Jan Mayen' => 'Svalbard and Jan Mayen', + 'country_Swaziland' => 'Swaziland', + 'country_Sweden' => 'Sweden', + 'country_Switzerland' => 'Switzerland', + 'country_Syrian Arab Republic' => 'Syrian Arab Republic', + 'country_Tajikistan' => 'Tajikistan', + 'country_Thailand' => 'Thailand', + 'country_Togo' => 'Togo', + 'country_Tokelau' => 'Tokelau', + 'country_Tonga' => 'Tonga', + 'country_Trinidad and Tobago' => 'Trinidad and Tobago', + 'country_United Arab Emirates' => 'United Arab Emirates', + 'country_Tunisia' => 'Tunisia', + 'country_Turkey' => 'Turkey', + 'country_Turkmenistan' => 'Turkmenistan', + 'country_Turks and Caicos Islands' => 'Turks and Caicos Islands', + 'country_Tuvalu' => 'Tuvalu', + 'country_Uganda' => 'Uganda', + 'country_Ukraine' => 'Ukraine', + 'country_Macedonia, the former Yugoslav Republic of' => 'Macedonia, the former Yugoslav Republic of', + 'country_Egypt' => 'Egypt', + 'country_United Kingdom' => 'United Kingdom', + 'country_Guernsey' => 'Guernsey', + 'country_Jersey' => 'Jersey', + 'country_Isle of Man' => 'Isle of Man', + 'country_Tanzania, United Republic of' => 'Tanzania, United Republic of', + 'country_United States' => 'United States', + 'country_Virgin Islands, U.S.' => 'Virgin Islands, U.S.', + 'country_Burkina Faso' => 'Burkina Faso', + 'country_Uruguay' => 'Uruguay', + 'country_Uzbekistan' => 'Uzbekistan', + 'country_Venezuela, Bolivarian Republic of' => 'Venezuela, Bolivarian Republic of', + 'country_Wallis and Futuna' => 'Wallis and Futuna', + 'country_Samoa' => 'Samoa', + 'country_Yemen' => 'Yemen', + 'country_Zambi' => 'Zambi', + + 'view_client_portal' => 'View client portal', + 'view_portal' => 'View Portal', + 'vendor_contacts' => 'Vendor Contacts', + 'all' => 'All', + 'selected' => 'Selected', + 'category' => 'Category', + 'categories' => 'Categories', + 'new_expense_category' => 'New Expense Category', + 'edit_category' => 'Edit Category', + 'archive_expense_category' => 'Archive Category', + 'expense_categories' => 'Expense Categories', + 'list_expense_categories' => 'List Expense Categories', + 'updated_expense_category' => 'Successfully updated expense category', + 'created_expense_category' => 'Successfully created expense category', + 'archived_expense_category' => 'Successfully archived expense category', + 'archived_expense_categories' => 'Successfully archived :count expense category', + 'restore_expense_category' => 'Restore expense category', + 'restored_expense_category' => 'Successfully restored expense category', + 'apply_taxes' => 'Apply taxes', + 'min_to_max_users' => ':min to :max users', + 'max_users_reached' => 'The maximum number of users has been reached.' ); return $LANG; -?>. +?> diff --git a/resources/lang/es/texts.php b/resources/lang/es/texts.php index eccabaf4a6..9dad0dd9af 100644 --- a/resources/lang/es/texts.php +++ b/resources/lang/es/texts.php @@ -1,17 +1,15 @@ 'Empresa', - 'name' => 'Nombre', //Razon social-Colombia, + 'name' => 'Nombre', 'website' => 'Sitio Web', 'work_phone' => 'Teléfono', 'address' => 'Dirección', 'address1' => 'Calle', 'address2' => 'Bloq/Pta', 'city' => 'Ciudad', - 'state' => 'Región/Provincia', //Departamento-Colombia, Comarca-Panama + 'state' => 'Región/Provincia', 'postal_code' => 'Código Postal', 'country_id' => 'País', 'contacts' => 'Contactos', @@ -20,14 +18,12 @@ return array( 'phone' => 'Teléfono', 'email' => 'Correo Electrónico', 'additional_info' => 'Información adicional', - 'payment_terms' => 'Plazos de pago', // + 'payment_terms' => 'Plazos de pago', 'currency_id' => 'Divisa', 'size_id' => 'Tamaño de la Empresa', 'industry_id' => 'Industria', 'private_notes' => 'Notas Privadas', - - // invoice - 'invoice' => 'Factura de venta', //Factura de Venta-Colombia + 'invoice' => 'Factura de venta', 'client' => 'Cliente', 'invoice_date' => 'Fecha de factura', 'due_date' => 'Fecha de pago', @@ -38,7 +34,7 @@ return array( 'frequency_id' => 'Frecuencia', 'discount' => 'Descuento', 'taxes' => 'Impuestos', - 'tax' => 'Impuesto', //IVA for almost all latinamerica, ISV-Honduras, ITBMS-Panama, IV-Costa Rica, ITBIS- Republica Dominicana, IVU-Puerto Rico + 'tax' => 'Impuesto', 'item' => 'Concepto', 'description' => 'Descripción', 'unit_cost' => 'Coste unitario', @@ -73,8 +69,6 @@ return array( 'settings' => 'Configuración', 'enable_invoice_tax' => 'Activar impuesto para la factura', 'enable_line_item_tax' => 'Activar impuesto por concepto', - - // navigation 'dashboard' => 'Inicio', 'clients' => 'Clientes', 'invoices' => 'Facturas', @@ -99,8 +93,6 @@ return array( 'provide_email' => 'Por favor facilita una dirección de correo electrónico válida.', 'powered_by' => 'Plataforma por ', 'no_items' => 'No hay data', - - // recurring invoices 'recurring_invoices' => 'Facturas recurrentes', 'recurring_help' => '

    Enviar facturas automáticamente a clientes semanalmente, bi-mensualmente, mensualmente, trimestral o anualmente.

    Uso :MONTH, :QUARTER or :YEAR para fechas dinámicas. Matemáticas básicas también funcionan bien. Por ejemplo: :MONTH-1.

    @@ -110,8 +102,6 @@ return array(
  • ":YEAR+1 suscripción anual" => "2015 suscripción anual"
  • "Retainer payment for :QUARTER+1" => "Pago anticipo de pagos para T2"
  • ', - - // dashboard 'in_total_revenue' => 'ingreso total', 'billed_client' => 'cliente facturado', 'billed_clients' => 'clientes facturados', @@ -120,8 +110,6 @@ return array( 'invoices_past_due' => 'Facturas vencidas', 'upcoming_invoices' => 'Próximas facturas', 'average_invoice' => 'Promedio de facturación', - - // list pages 'archive' => 'Archivar', 'delete' => 'Eliminar', 'archive_client' => 'Archivar cliente', @@ -157,25 +145,19 @@ return array( 'select' => 'Seleccionar', 'edit_client' => 'Editar Cliente', 'edit_invoice' => 'Editar Factura', - - // client view page 'create_invoice' => 'Crear Factura', 'enter_credit' => 'Agregar Crédito', 'last_logged_in' => 'Último inicio de sesión', 'details' => 'Detalles', - 'standing' => 'Standing', //What is this for, context of it's use + 'standing' => 'Standing', 'credit' => 'Crédito', 'activity' => 'Actividad', 'date' => 'Fecha', 'message' => 'Mensaje', 'adjustment' => 'Ajustes', 'are_you_sure' => '¿Estás seguro?', - - // payment pages 'payment_type_id' => 'Tipo de pago', 'amount' => 'Cantidad', - - // account/company pages 'work_email' => 'Correo electrónico de la empresa', 'language_id' => 'Idioma', 'timezone_id' => 'Zona horaria', @@ -193,22 +175,21 @@ return array( 'email_paid' => 'Avísame por correo cuando una factura se paga', 'site_updates' => 'Actualizaciones del sitio', 'custom_messages' => 'Mensajes a medida', - 'default_invoice_terms' => 'Configurar términos de factura por defecto', 'default_email_footer' => 'Configurar firma de correo por defecto', - 'import_clients' => 'Importar datos del cliente', - 'csv_file' => 'Seleccionar archivo CSV', - 'export_clients' => 'Exportar datos del cliente', 'select_file' => 'Seleccionar archivo', 'first_row_headers' => 'Usar la primera fila como encabezados', 'column' => 'Columna', 'sample' => 'Ejemplo', 'import_to' => 'Importar a', - 'client_will_create' => 'cliente se creará', //What is this for, context of it's use - 'clients_will_create' => 'clientes se crearan', //What is this for, context of it's use + 'client_will_create' => 'cliente se creará', + 'clients_will_create' => 'clientes se crearan', 'email_settings' => 'Configuración del Correo Electrónico', + 'client_view_styling' => 'Client View Styling', 'pdf_email_attachment' => 'Adjuntar PDF\'s a los Correos', - - // application messages + 'custom_css' => 'Custom CSS', + 'import_clients' => 'Importar datos del cliente', + 'csv_file' => 'Seleccionar archivo CSV', + 'export_clients' => 'Exportar datos del cliente', 'created_client' => 'cliente creado con éxito', 'created_clients' => ':count clientes creados con éxito', 'updated_settings' => 'Configuración actualizada con éxito', @@ -220,7 +201,7 @@ return array( 'registration_required' => 'Inscríbete para enviar una factura', 'confirmation_required' => 'Por favor confirma tu dirección de correo electrónico', 'updated_client' => 'Cliente actualizado con éxito', - 'created_client' => 'Cliente creado con éxito', + 'created_client' => 'cliente creado con éxito', 'archived_client' => 'Cliente archivado con éxito', 'archived_clients' => ':count clientes archivados con éxito', 'deleted_client' => 'Cliente eliminado con éxito', @@ -235,6 +216,7 @@ return array( 'deleted_invoice' => 'Factura eliminada con éxito', 'deleted_invoices' => ':count facturas eliminadas con éxito', 'created_payment' => 'Pago creado con éxito', + 'created_payments' => 'Successfully created :count payment(s)', 'archived_payment' => 'Pago archivado con éxito', 'archived_payments' => ':count pagos archivados con éxito', 'deleted_payment' => 'Pago eliminado con éxito', @@ -245,7 +227,13 @@ return array( 'archived_credits' => ':count creditos archivados con éxito', 'deleted_credit' => 'Créditos eliminados con éxito', 'deleted_credits' => ':count creditos eliminados con éxito', - // Emails + 'imported_file' => 'Successfully imported file', + 'updated_vendor' => 'Successfully updated vendor', + 'created_vendor' => 'Successfully created vendor', + 'archived_vendor' => 'Successfully archived vendor', + 'archived_vendors' => 'Successfully archived :count vendors', + 'deleted_vendor' => 'Successfully deleted vendor', + 'deleted_vendors' => 'Successfully deleted :count vendors', 'confirmation_subject' => 'Corfimación de tu cuenta en Invoice Ninja', 'confirmation_header' => 'Confirmación de Cuenta', 'confirmation_message' => 'Por favor, haz clic en el enlace abajo para confirmar tu cuenta.', @@ -256,7 +244,6 @@ return array( 'email_salutation' => 'Estimado :name,', 'email_signature' => 'Un saludo cordial,', 'email_from' => 'El equipo de Invoice Ninja ', - 'user_email_footer' => 'Para ajustar la configuración de las notificaciones de tu correo, visita '.SITE_URL.'/settings/notifications', 'invoice_link_message' => 'Para visualizar la factura de cliente, haz clic en el enlace abajo:', 'notification_invoice_paid_subject' => 'La factura :invoice ha sido pagada por el cliente :client', 'notification_invoice_sent_subject' => 'La factura :invoice ha sido enviada a el cliente :client', @@ -265,31 +252,11 @@ return array( 'notification_invoice_sent' => 'La factura :invoice por valor de :amount fue enviada al cliente :cliente.', 'notification_invoice_viewed' => 'La factura :invoice por valor de :amount fue visualizada por el cliente :client.', 'reset_password' => 'Puedes reconfigurar la contraseña de tu cuenta haciendo clic en el siguiente enlace:', - 'reset_password_footer' => 'Si no has solicitado un cambio de contraseña, por favor contactate con nosostros: '.CONTACT_EMAIL, - - // Payment page 'secure_payment' => 'Pago seguro', 'card_number' => 'Número de tarjeta', 'expiration_month' => 'Mes de caducidad', 'expiration_year' => 'Año de caducidad', 'cvv' => 'CVV', - - // Security alerts - 'security' => array( - 'too_many_attempts' => 'Demasiados intentos fallidos. Inténtalo de nuevo en un par de minutos.', - 'wrong_credentials' => 'Contraseña o correo incorrecto.', - 'confirmation' => '¡Tu cuenta se ha confirmado!', - 'wrong_confirmation' => 'Código de confirmación incorrecto.', - 'password_forgot' => 'La información sobre el cambio de tu contraseña se ha enviado a tu dirección de correo electrónico.', - 'password_reset' => 'Tu contraseña se ha cambiado con éxito.', - 'wrong_password_reset' => 'Contraseña no válida. Inténtalo de nuevo', - ), - - // Pro Plan - 'pro_plan' => [ - 'remove_logo' => ':link haz click para eliminar el logo de Invoice Ninja', //Maybe incorrect for the context - 'remove_logo_link' => 'Haz clic aquí', - ], 'logout' => 'Cerrar sesión', 'sign_up_to_save' => 'Registrate para guardar tu trabajo', 'agree_to_terms' => 'Estoy de acuerdo con los términos de Invoice Ninja :terms', @@ -300,9 +267,7 @@ return array( 'success_message' => 'Te has registrado con éxito. Por favor, haz clic en el enlace de el correo de confirmación para verificar tu dirección de correo electrónico.', 'erase_data' => 'Esta acción eliminará todos tus datos de forma permanente.', 'password' => 'Contraseña', - 'pro_plan_product' => 'Plan Pro', - 'pro_plan_description' => 'Un año de inscripción en el Plan Pro de Invoice Ninja.', 'pro_plan_success' => '¡Gracias por unirte a Invoice Ninja! Al realizar el pago de tu factura, se iniciara tu PLAN PRO.', 'unsaved_changes' => 'Tienes cambios no guardados', 'custom_fields' => 'Campos a medida', @@ -311,9 +276,8 @@ return array( 'field_label' => 'Etiqueta del campo', 'field_value' => 'Valor del campo', 'edit' => 'Editar', + 'set_name' => 'Set your company name', 'view_as_recipient' => 'Ver como destinitario', - - // product management 'product_library' => 'Inventario de productos', 'product' => 'Producto', 'products' => 'Productos', @@ -336,8 +300,6 @@ return array( 'chart_builder' => 'Constructor de graficos', 'ninja_email_footer' => 'Usa :site para facturar a tus clientes y recibir pagos de forma gratuita!', 'go_pro' => 'Hazte Pro', - - // Quotes 'quote' => 'Cotización', 'quotes' => 'Cotizaciones', 'quote_number' => 'Numero de cotización', @@ -346,7 +308,7 @@ return array( 'quote_total' => 'Total cotizado', 'your_quote' => 'Tu cotización', 'total' => 'Total', - 'clone' => 'Clon', //Whats the context for this one + 'clone' => 'Clon', 'new_quote' => 'Nueva cotización', 'create_quote' => 'Crear Cotización', 'edit_quote' => 'Editar Cotización', @@ -357,8 +319,8 @@ return array( 'clone_quote' => 'Clonar Cotización', 'convert_to_invoice' => 'Convertir a Factura', 'view_invoice' => 'Ver Factura', - 'view_quote' => 'Ver Cotización', 'view_client' => 'Ver Cliente', + 'view_quote' => 'Ver Cotización', 'updated_quote' => 'Cotización actualizada con éxito', 'created_quote' => 'Cotización creada con éxito', 'cloned_quote' => 'Cotización clonada con éxito', @@ -385,7 +347,7 @@ return array( 'charge_taxes' => 'Cargar impuestos', 'user_management' => 'Gestión de usario', 'add_user' => 'Añadir usario', - 'send_invite' => 'Enviar invitación', //Context for its use + 'send_invite' => 'Enviar invitación', 'sent_invite' => 'Invitación enviada con éxito', 'updated_user' => 'Usario actualizado con éxito', 'invitation_message' => ':invitor te ha invitado a unirte a su cuenta en Invoice Ninja.', @@ -396,7 +358,6 @@ return array( 'active' => 'Activar', 'pending' => 'Pendiente', 'deleted_user' => 'Usario eliminado con éxito', - 'limit_users' => 'Lo sentimos, esta acción excederá el límite de '.MAX_NUM_USERS.' usarios', 'confirm_email_invoice' => '¿Estás seguro que quieres enviar esta factura?', 'confirm_email_quote' => '¿Estás seguro que quieres enviar esta cotización?', 'confirm_recurring_email_invoice' => 'Se ha marcado esta factura como recurrente, estás seguro que quieres enviar esta factura?', @@ -416,59 +377,48 @@ return array( 'invoice_issued_to' => 'Factura emitida a', 'invalid_counter' => 'Para evitar posibles conflictos, por favor crea un prefijo de facturación y de cotización.', 'mark_sent' => 'Marcar como enviado', - 'gateway_help_1' => ':link para registrarse con Authorize.net.', 'gateway_help_2' => ':link para registrarse con Authorize.net.', 'gateway_help_17' => ':link para obtener su firma del API de PayPal.', 'gateway_help_27' => ':link para registrarse con TwoCheckout.', - 'more_designs' => 'Más diseños', 'more_designs_title' => 'Diseños Adicionales de Facturas', 'more_designs_cloud_header' => 'Vete Pro para más diseños de facturas', 'more_designs_cloud_text' => '', - 'more_designs_self_host_header' => 'Adquiera 6 diseños adicionales de facturas por solo $'.INVOICE_DESIGNS_PRICE, 'more_designs_self_host_text' => '', 'buy' => 'Comprar', 'bought_designs' => 'Diseños adicionales de facturas agregados con éxito', - 'sent' => 'enviado', + 'vat_number' => 'Número de Impuesto', 'timesheets' => 'Hojas de Tiempo', - 'payment_title' => 'Ingresa la Dirección de Facturación de tu Tareta de Crédito', 'payment_cvv' => '*Este es el número de 3-4 dígitos en la parte posterior de tu tarjeta de crédito', 'payment_footer1' => '*La dirección debe coincidir con la dirección asociada a la tarjeta de crédito.', 'payment_footer2' => '*Por favor haz clic en "PAGAR AHORA" sólo una vez - la transacción puede demorarse hasta un minuto en ser procesada.', - 'vat_number' => 'Número de Impuesto', - 'id_number' => 'ID Number', 'white_label_link' => 'Etiqueta Blanca', 'white_label_header' => 'Etiqueta Blanca', 'bought_white_label' => 'Licencia de etiqueta blanca habilitada con éxito', 'white_labeled' => 'Etiqueta Blanca', - 'restore' => 'Restaurar', 'restore_invoice' => 'Restaurar Invoice', 'restore_quote' => 'Restaurar Quote', 'restore_client' => 'Restaurar Client', 'restore_credit' => 'Restaurar Credit', 'restore_payment' => 'Restaurar Payment', - 'restored_invoice' => 'Factura restaurada con éxito', 'restored_quote' => 'Cotización restaurada con éxito', 'restored_client' => 'Cliente restaurado con éxito', 'restored_payment' => 'Pago restaurado con éxito', 'restored_credit' => 'Crédito restaurado con éxito', - 'reason_for_canceling' => 'Ayúdenos a mejorar contándonos porqué se va.', 'discount_percent' => 'Porcentaje', 'discount_amount' => 'Cantidad', - 'invoice_history' => 'Facturar Historial', 'quote_history' => 'Cotizar Historial', 'current_version' => 'Versión actual', 'select_version' => 'Seleccionar versión', 'view_history' => 'Ver Historial', - 'edit_payment' => 'Editar Pago', 'updated_payment' => 'Pago actualizado con éxito', 'deleted' => 'Eliminado', @@ -481,7 +431,6 @@ return array( 'quote_email' => 'Correo de Cotizacion', 'reset_all' => 'Reiniciar Todos', 'approve' => 'Aprobar', - 'token_billing_type_id' => 'Token de Facturación', 'token_billing_help' => 'Permite almacenar tarjetas de crédito con su gateway de pagos, y facturar en una fecha posterior.', 'token_billing_1' => 'Deshabilitado', @@ -489,12 +438,11 @@ return array( 'token_billing_3' => 'Opt-out - el checkbox es mostrado y seleccionado', 'token_billing_4' => 'Siempre', 'token_billing_checkbox' => 'Almacenar detalles de la tarjeta de crédito', - 'view_in_stripe' => 'Ver en Stripe', - 'use_card_on_file' => 'Usar la tarjeta en el archivo', + 'view_in_gateway' => 'Ver en :gateway', + 'use_card_on_file' => 'Use Card on File', 'edit_payment_details' => 'Editar detalles del pago', 'token_billing' => 'Guardar detalles de la tarjeta', - 'token_billing_secure' => 'La información es almacenada de manera segura por :stripe_link', - + 'token_billing_secure' => 'La información es almacenada de manera segura por :link', 'support' => 'Soporte', 'contact_information' => 'Información de Contacto', '256_encryption' => 'Encripción de 256-Bit', @@ -504,11 +452,8 @@ return array( 'order_overview' => 'Resumen de la orden', 'match_address' => '*La dirección debe coincidir con la dirección asociada a la tarjeta de crédito.', 'click_once' => '*Por favor haz clic en "PAGAR AHORA" sólo una vez - la transacción puede demorarse hasta un minuto en ser procesada.', - - 'default_invoice_footer' => 'Asignar pié de página por defecto para la factura', 'invoice_footer' => 'Pié de págia de la factura', 'save_as_default_footer' => 'Guardar como el pié de página por defecto', - 'token_management' => 'Administración de Tokens', 'tokens' => 'Tokens', 'add_token' => 'Agregar Token', @@ -519,7 +464,6 @@ return array( 'edit_token' => 'Editar Token', 'delete_token' => 'Eliminar Token', 'token' => 'Token', - 'add_gateway' => 'Agregar Gateway', 'delete_gateway' => 'Eliminar Gateway', 'edit_gateway' => 'Editar Gateway', @@ -528,7 +472,6 @@ return array( 'deleted_gateway' => 'Gateway eliminado con éxito', 'pay_with_paypal' => 'PayPal', 'pay_with_card' => 'Tarjeta de Crédito', - 'change_password' => 'Cambiar contraseña', 'current_password' => 'contraseña actual', 'new_password' => 'Nueva contraseña', @@ -536,7 +479,6 @@ return array( 'password_error_incorrect' => 'La contraseña actual es incorrecta.', 'password_error_invalid' => 'La nueva contraseña es inválida.', 'updated_password' => 'Contraseñaactualizada con éxito', - 'api_tokens' => 'API Tokens', 'users_and_tokens' => 'Usuarios y Tokens', 'account_login' => 'Ingreso', @@ -548,13 +490,11 @@ return array( 'send_email' => 'Enviar Correo', 'set_password' => 'Asignar Contraseña', 'converted' => 'Convertido', - 'email_approved' => 'Enviarme un correo cuando una cotización sea aprobada', 'notification_quote_approved_subject' => 'Cotización :invoice fue aprobada por :client', 'notification_quote_approved' => 'El cliente :client ha aprobado la cotización :invoice por el valor :amount.', 'resend_confirmation' => 'Reenviar correo de confirmación', 'confirmation_resent' => 'El correo de confirmación fue reenviado', - 'gateway_help_42' => ':link para registrarse en BitPay.
    Nota: use una llave del API legacy, no un token API.', 'payment_type_credit_card' => 'Tarjeta de Crédito', 'payment_type_paypal' => 'PayPal', @@ -562,7 +502,6 @@ return array( 'knowledge_base' => 'Base de Conocimiento', 'partial' => 'Parcial', 'partial_remaining' => ':partial de :balance', - 'more_fields' => ' Más Campos', 'less_fields' => 'Menos Campos', 'client_name' => 'Nombre del Cliente', @@ -573,7 +512,6 @@ return array( 'view_documentation' => 'Ver Documentación', 'app_title' => 'Facturación Open-Source Gratuita', 'app_description' => 'Invoice Ninja es una solución open-source gratuita para manejar la facturación de tus clientes. Con Invoice Ninja, se pueden crear y enviar hermosas facturas desde cualquier dispositivo que tenga acceso a Internet. Tus clientes pueden imprimir tus facturas, descargarlas en formato PDF o inclusive pagarlas en linea desde esta misma plataforma', - 'rows' => 'filas', 'www' => 'www', 'logo' => 'Logo', @@ -593,7 +531,6 @@ return array( 'zapier' => 'Zapier', 'recurring' => 'Recurrente', 'last_invoice_sent' => 'Ultima factura enviada en :date', - 'processed_updates' => 'Actualización completada con éxito', 'tasks' => 'Tareas', 'new_task' => 'Nueva Tarea', @@ -639,12 +576,10 @@ return array( 'invoice_labels' => 'Etiquetas', 'prefix' => 'Prefijo', 'counter' => 'Contador', - 'payment_type_dwolla' => 'Dwolla', 'gateway_help_43' => ':link para registrarse con Dwolla.', 'partial_value' => 'Debe ser mayor que cero y menor que el total', 'more_actions' => 'Más Acciones', - 'pro_plan_title' => 'NINJA PRO', 'pro_plan_call_to_action' => 'Actualízate Ahora!', 'pro_plan_feature1' => 'Crea Clientes Ilimitados', @@ -655,21 +590,12 @@ return array( 'pro_plan_feature6' => 'Crea Cotizaciones y facturas Pro-forma', 'pro_plan_feature7' => 'Personaliza los Títulos de los Campos y Numeración de las Facturas', 'pro_plan_feature8' => 'Opción para adjuntarle documentos PDF a los correos dirigidos a los clientes', - 'resume' => 'Continuar', 'break_duration' => 'Descanso', 'edit_details' => 'Editar Detalles', 'work' => 'Trabajo', 'timezone_unset' => 'Por favor :link para configurar tu Uso Horario', 'click_here' => 'haz clic aquí', - - 'resume' => 'Continuar', - 'break_duration' => 'Descanso', - 'edit_details' => 'Editar Detalles', - 'work' => 'Tranajo', - 'timezone_unset' => 'Por favor :link para configurar tu Uso Horario', - 'click_here' => 'haga clic aquí', - 'email_receipt' => 'Enviar por correo electrónico el recibo de pago al cliente', 'created_payment_emailed_client' => 'Pago creado y enviado al cliente con éxito', 'add_company' => 'Agregar Compañía', @@ -679,10 +605,8 @@ return array( 'unlinked_account' => 'Cuentas desconectadas con éxito', 'login' => 'Ingresar', 'or' => 'o', - 'email_error' => 'Hubo un problema enviando el correo', 'confirm_recurring_timing' => 'Nota: los correos son enviados al inicio de la hora.', - 'old_browser' => 'Por favor utiliza más reciente', 'payment_terms_help' => 'Asigna la fecha de vencimiento por defecto de la factura', 'unlink_account' => 'Desconectar Cuenta', 'unlink' => 'Desconectar', @@ -703,7 +627,6 @@ return array( 'primary_color' => 'Color Primario', 'secondary_color' => 'Color Secundario', 'customize_design' => 'Personalizar el Diseño', - 'content' => 'Contenido', 'styles' => 'Estílos', 'defaults' => 'Valores por Defecto', @@ -717,17 +640,16 @@ return array( 'outstanding' => 'Sobresaliente', 'manage_companies' => 'Administrar Compañías', 'total_revenue' => 'Ingresos Totales', - 'current_user' => 'Usuario Actual', 'new_recurring_invoice' => 'Nueva Factura Recurrente', 'recurring_invoice' => 'Factura Recurrente', + 'recurring_too_soon' => 'Es my pronto para crear la siguiente factura recurrente, it\'s scheduled for :date', 'created_by_invoice' => 'Creado por :invoice', 'primary_user' => 'Usuario Primario', 'help' => 'Ayuda', - 'customize_help' => '

    Nosotros usamos pdfmake para definir los diseños de las facturas de manera declarativa. El playground de pdfmake es una excelente manera de ver a la librería en acción.

    -

    Para acceder a una propiedad hija usando notación de punto.Por ejemplo, para mostrar el nombre de un cliente se puede usar $client.name.

    -

    Si necesitas ayuda entendiendo algo puede preguntar en nuestro foro de soporte.

    ', - + 'customize_help' => '

    We use pdfmake to define the invoice designs declaratively. The pdfmake playground provide\'s a great way to see the library in action.

    +

    You can access a child property using dot notation. For example to show the client name you could use $client.name.

    +

    If you need help figuring something out post a question to our support forum with the design you\'re using.

    ', 'invoice_due_date' => 'Fecha de Vencimiento', 'quote_due_date' => 'Válida Hasta', 'valid_until' => 'Válida Hasta', @@ -740,15 +662,12 @@ return array( 'status_partial' => 'Parcial', 'status_paid' => 'Pagado', 'show_line_item_tax' => ' Mostrar impuestos por cada ítem en línea.', - 'iframe_url' => 'Sitio Web', 'iframe_url_help1' => 'Copia el siguiente código en una página de tu sitio web.', 'iframe_url_help2' => 'Puedes probar esta funcionalidad haciendo clic en \'Ver como el destinitario\' de una factura.', - 'auto_bill' => 'Cobro Automático', 'military_time' => 'Tiempo 24 Horas', 'last_sent' => 'Último Enviado', - 'reminder_emails' => 'Correos de Recordatorio', 'templates_and_reminders' => 'Plantillas & Recordatorios', 'subject' => 'Asunto', @@ -760,15 +679,12 @@ return array( 'reminder_subject' => 'Recordatorio: Factura :invoice de :account', 'reset' => 'Reiniciar', 'invoice_not_found' => 'La factura solicitada no está disponible', - 'referral_program' => 'Programa de Referidos', 'referral_code' => 'Código de Referidos', 'last_sent_on' => 'ültimo enviado en :date', - 'page_expire' => 'Esta página expirará pronto, :click_here para que siga funcionando', 'upcoming_quotes' => 'Próximas Cotizaciones', 'expired_quotes' => 'Cotizaciones Vencidas', - 'sign_up_using' => 'Ingrese usando', 'invalid_credentials' => 'Estas credenciales no concuerdan con nuestros registros', 'show_all_options' => 'Mostrar todas las opciones', @@ -777,17 +693,10 @@ return array( 'disable' => 'Deshabilitar', 'invoice_quote_number' => 'Números de Cotización y Factura', 'invoice_charges' => 'Cargos de Factura', - - 'invitation_status' => [ - 'sent' => 'Correo enviado', - 'opened' => 'Correo Abierto', - 'viewed' => 'Factura Vista', - ], 'notification_invoice_bounced' => 'No nos fue posible entregar la Factura :invoice a :contact.', 'notification_invoice_bounced_subject' => 'No fue posible entregar la Factura :invoice', 'notification_quote_bounced' => 'No nos fue posible entregar la Cotización :invoice a :contact.', 'notification_quote_bounced_subject' => 'No nos fue posible entregar la Cotización :invoice', - 'custom_invoice_link' => 'Link Personalizado de Factura', 'total_invoiced' => 'Total Facturado', 'open_balance' => 'Abrir Balance', @@ -795,15 +704,12 @@ return array( 'basic_settings' => 'Configuración Básica', 'pro' => 'Pro', 'gateways' => 'Pasarelas de Pago', - 'recurring_too_soon' => 'Es my pronto para crear la siguiente factura recurrente, it\'s scheduled for :date', - 'next_send_on' => 'Enviar Siguiente: :date', 'no_longer_running' => 'La ejecución de esta factura no está programada', 'general_settings' => 'Configuración General', 'customize' => 'Personalizar', 'oneclick_login_help' => 'Conecta una cuenta para ingresar sin contraseña', 'referral_code_help' => 'Gana dinero compartiendo nuestra app en linea', - 'enable_with_stripe' => 'Habilitar | Requiere Stripe', 'tax_settings' => 'Configuración de Impuestos', 'create_tax_rate' => 'Agregar Tasa de Impuesto', @@ -824,7 +730,6 @@ return array( 'invoice_counter' => 'Contador de Facturas', 'quote_counter' => 'Contador de Cotizaciones', 'type' => 'Tipo', - 'activity_1' => ':user creó el cliente :client', 'activity_2' => ':user archivó el cliente :client', 'activity_3' => ':user eliminó el cliente :client', @@ -854,18 +759,24 @@ return array( 'activity_27' => ':user restauró el pago :payment', 'activity_28' => ':user restauró :credit créditos', 'activity_29' => ':contact aprovó la cotización :quote', - + 'activity_30' => ':user created :vendor', + 'activity_31' => ':user created :vendor', + 'activity_32' => ':user created :vendor', + 'activity_33' => ':user created :vendor', + 'activity_34' => ':user created expense :expense', + 'activity_35' => ':user created :vendor', + 'activity_36' => ':user created :vendor', + 'activity_37' => ':user created :vendor', 'payment' => 'pago', 'system' => 'Sistema', 'signature' => 'Email Signature', 'default_messages' => 'Default Messages', 'quote_terms' => 'Quote Terms', 'default_quote_terms' => 'Default Quote Terms', - 'default_invoice_terms' => 'Default Invoice Terms', - 'default_invoice_footer' => 'Default Invoice Footer', + 'default_invoice_terms' => 'Configurar términos de factura por defecto', + 'default_invoice_footer' => 'Asignar pié de página por defecto para la factura', 'quote_footer' => 'Quote Footer', 'free' => 'Free', - 'quote_is_approved' => 'This quote is approved', 'apply_credit' => 'Apply Credit', 'system_settings' => 'System Settings', @@ -883,7 +794,6 @@ return array( 'restored_recurring_invoice' => 'Successfully restored recurring invoice', 'archived' => 'Archived', 'untitled_account' => 'Untitled Company', - 'before' => 'Before', 'after' => 'After', 'reset_terms_help' => 'Reset to the default account terms', @@ -892,7 +802,6 @@ return array( 'user' => 'User', 'country' => 'Country', 'include' => 'Include', - '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_data' => 'Import Data', @@ -903,16 +812,6 @@ return array( 'task_file' => 'Task File', 'no_mapper' => 'No valid mapping for file', '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', 'admin' => 'Admin', 'disabled' => 'Disabled', @@ -921,11 +820,9 @@ return array( 'invoice_will_create' => 'client will be created', 'invoices_will_create' => 'invoices will be created', 'failed_to_import' => 'The following records failed to import, they either already exist or are missing required fields.', - 'publishable_key' => 'Publishable Key', 'secret_key' => 'Secret Key', 'missing_publishable_key' => 'Set your Stripe publishable key for an improved checkout process', - 'email_design' => 'Email Design', 'due_by' => 'Due by :date', 'enable_email_markup' => 'Enable Markup', @@ -937,7 +834,6 @@ return array( 'plain' => 'Plain', 'light' => 'Light', 'dark' => 'Dark', - '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.', 'invoice_number_help' => 'Specify a prefix or use a custom pattern to dynamically set the invoice number.', @@ -946,8 +842,6 @@ return array( '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_charges_helps' => 'Add a text input to the invoice create/edit page and include the charge in the invoice subtotals.', - 'color_help' => 'Note: the primary color is also used in the client portal and custom email designs.', - 'token_expired' => 'Validation token was expired. Please try again.', 'invoice_link' => 'Invoice Link', 'button_confirmation_message' => 'Click to confirm your email address.', @@ -956,7 +850,6 @@ return array( 'created_invoices' => 'Successfully created :count invoice(s)', 'next_invoice_number' => 'The next invoice number is :number.', 'next_quote_number' => 'The next quote number is :number.', - 'days_before' => 'days before', 'days_after' => 'days after', 'field_due_date' => 'due date', @@ -964,10 +857,7 @@ return array( 'schedule' => 'Schedule', 'email_designs' => 'Email Designs', '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', - - // Expense / vendor 'expense' => 'Expense', 'expenses' => 'Expenses', 'new_expense' => 'Enter Expense', @@ -984,8 +874,6 @@ return array( 'archived_expense' => 'Successfully archived expense', 'deleted_expenses' => 'Successfully deleted expenses', 'archived_expenses' => 'Successfully archived expenses', - - // Expenses 'expense_amount' => 'Expense Amount', 'expense_balance' => 'Expense Balance', 'expense_date' => 'Expense Date', @@ -1010,15 +898,11 @@ return array( 'expense_error_multiple_clients' => 'The expenses can\'t belong to different clients', 'expense_error_invoiced' => 'Expense has already been invoiced', 'convert_currency' => 'Convert currency', - - // Payment terms 'num_days' => 'Number of days', 'create_payment_term' => 'Create Payment Term', 'edit_payment_terms' => 'Edit Payment Term', 'edit_payment_term' => 'Edit Payment Term', 'archive_payment_term' => 'Archive Payment Term', - - // recurring due dates 'recurring_due_dates' => 'Recurring Invoice Due Dates', 'recurring_due_date_help' => '

    Automatically sets a due date for the invoice.

    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.

    @@ -1046,15 +930,11 @@ return array( 'thursday' => 'Thursday', 'friday' => 'Friday', 'saturday' => 'Saturday', - - // Fonts 'header_font_id' => 'Header 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.', - 'live_preview' => 'Live Preview', '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.', 'quote_message_button' => 'To view your quote for :amount, click the button below.', 'payment_message_button' => 'Thank you for your payment of :amount.', @@ -1071,7 +951,6 @@ return array( 'archived_bank_account' => 'Successfully archived bank account', 'created_bank_account' => 'Successfully created 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 400+ US banks.', '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.', 'username' => 'Username', @@ -1085,7 +964,6 @@ return array( 'validate' => 'Validate', 'info' => 'Info', '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.', '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.', @@ -1106,7 +984,28 @@ return array( 'trial_call_to_action' => 'Start Free Trial', '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.', + + + 'white_label_text' => 'Purchase a ONE YEAR white label license for $:price to remove the Invoice Ninja branding from the client portal and help support our project.', + 'user_email_footer' => 'Para ajustar la configuración de las notificaciones de tu correo, visita :link', + 'reset_password_footer' => 'Si no has solicitado un cambio de contraseña, por favor contactate con nosostros: :email', + 'limit_users' => 'Lo sentimos, esta acción excederá el límite de :limit usarios', + 'more_designs_self_host_header' => 'Adquiera 6 diseños adicionales de facturas por solo $:price', + 'old_browser' => 'Por favor utiliza más reciente', + 'white_label_custom_css' => ':link for $: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 400+ US banks.', + + 'pro_plan_remove_logo' => ':link haz click para eliminar el logo de Invoice Ninja', + 'pro_plan_remove_logo_link' => 'Haz clic aquí', + 'invitation_status_sent' => 'Correo enviado', + 'invitation_status_opened' => 'Correo Abierto', + 'invitation_status_viewed' => 'Factura Vista', + 'email_error_inactive_client' => 'Emails can not be sent to inactive clients', + 'email_error_inactive_contact' => 'Emails can not be sent to inactive contacts', + 'email_error_inactive_invoice' => 'Emails can not be sent to inactive invoices', + 'email_error_user_unregistered' => 'Please register your account to send emails', + 'email_error_user_unconfirmed' => 'Please confirm your account to send emails', + 'email_error_invalid_contact_email' => 'Invalid contact email', 'navigation' => 'Navigation', 'list_invoices' => 'List Invoices', @@ -1129,22 +1028,20 @@ return array( 'custom_invoice_item_fields_help' => 'Add a field when creating an invoice item and display the label and value on the PDF.', 'recurring_invoice_number' => 'Recurring Invoice Number', 'recurring_invoice_number_prefix_help' => 'Speciy a prefix to be added to the invoice number for recurring invoices. The default value is \'R\'.', - 'enable_client_portal' => 'Dashboard', - 'enable_client_portal_help' => 'Show/hide the dashboard page in the client portal.', // Client Passwords 'enable_portal_password'=>'Password protect invoices', 'enable_portal_password_help'=>'Allows you to set a password for each contact. If a password is set, the contact will be required to enter a password before viewing invoices.', 'send_portal_password'=>'Generate password automatically', 'send_portal_password_help'=>'If no password is set, one will be generated and sent with the first invoice.', - + 'expired' => 'Expired', 'invalid_card_number' => 'The credit card number is not valid.', 'invalid_expiry' => 'The expiration date is not valid.', 'invalid_cvv' => 'The CVV is not valid.', 'cost' => 'Cost', 'create_invoice_for_sample' => 'Note: create your first invoice to see a preview here.', - + // User Permissions 'owner' => 'Owner', 'administrator' => 'Administrator', @@ -1162,8 +1059,8 @@ return array( 'create_all_help' => 'Allow user to create and modify records', 'view_all_help' => 'Allow user to view records they didn\'t create', 'edit_all_help' => 'Allow user to modify records they didn\'t create', - 'view_payment' => 'View Payment', - + 'view_payment' => 'View Payment', + 'january' => 'January', 'february' => 'February', 'march' => 'March', @@ -1189,30 +1086,28 @@ return array( 'document_email_attachment' => 'Attach Documents', 'download_documents' => 'Download Documents (:size)', 'documents_from_expenses' => 'From Expenses:', - 'dropzone' => array(// See http://www.dropzonejs.com/#config-dictDefaultMessage - 'DefaultMessage' => 'Drop files or click to upload', - 'FallbackMessage' => 'Your browser does not support drag\'n\'drop file uploads.', - 'FallbackText' => 'Please use the fallback form below to upload your files like in the olden days.', - 'FileTooBig' => 'File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.', - 'InvalidFileType' => 'You can\'t upload files of this type.', - 'ResponseError' => 'Server responded with {{statusCode}} code.', - 'CancelUpload' => 'Cancel upload', - 'CancelUploadConfirmation' => 'Are you sure you want to cancel this upload?', - 'RemoveFile' => 'Remove file', - ), + 'dropzone_default_message' => 'Drop files or click to upload', + 'dropzone_fallback_message' => 'Your browser does not support drag\'n\'drop file uploads.', + 'dropzone_fallback_text' => 'Please use the fallback form below to upload your files like in the olden days.', + 'dropzone_file_too_big' => 'File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.', + 'dropzone_invalid_file_type' => 'You can\'t upload files of this type.', + 'dropzone_response_error' => 'Server responded with {{statusCode}} code.', + 'dropzone_cancel_upload' => 'Cancel upload', + 'dropzone_cancel_upload_confirmation' => 'Are you sure you want to cancel this upload?', + 'dropzone_remove_file' => 'Remove file', 'documents' => 'Documents', 'document_date' => 'Document Date', 'document_size' => 'Size', - 'enable_client_portal' => 'Client Portal', - 'enable_client_portal_help' => 'Show/hide the client portal.', + 'enable_client_portal' => 'Dashboard', + 'enable_client_portal_help' => 'Show/hide the dashboard page in the client portal.', 'enable_client_portal_dashboard' => 'Dashboard', 'enable_client_portal_dashboard_help' => 'Show/hide the dashboard page in the client portal.', - + // Plans 'account_management' => 'Account Management', 'plan_status' => 'Plan Status', - + 'plan_upgrade' => 'Upgrade', 'plan_change' => 'Change Plan', 'pending_change_to' => 'Changes To', @@ -1242,9 +1137,9 @@ return array( 'plan_paid' => 'Term Started', 'plan_started' => 'Plan Started', 'plan_expires' => 'Plan Expires', - + 'white_label_button' => 'White Label', - + 'pro_plan_year_description' => 'One year enrollment in the Invoice Ninja Pro Plan.', 'pro_plan_month_description' => 'One month enrollment in the Invoice Ninja Pro Plan.', 'enterprise_plan_product' => 'Enterprise Plan', @@ -1262,7 +1157,207 @@ return array( 'preview' => 'Preview', 'list_vendors' => 'List Vendors', 'add_users_not_supported' => 'Upgrade to the Enterprise plan to add additional users to your account.', - 'enterprise_plan_features' => 'The Enterprise plan adds support for multiple users and file attachments.', + 'enterprise_plan_features' => 'The Enterprise plan adds support for multiple users and file attachments, :link to see the full list of features.', 'return_to_app' => 'Return to app', - + + + // Payment updates + 'refund_payment' => 'Refund Payment', + 'refund_max' => 'Max:', + 'refund' => 'Refund', + 'are_you_sure_refund' => 'Refund selected payments?', + 'status_pending' => 'Pending', + 'status_completed' => 'Completed', + 'status_failed' => 'Failed', + 'status_partially_refunded' => 'Partially Refunded', + 'status_partially_refunded_amount' => ':amount Refunded', + 'status_refunded' => 'Refunded', + 'status_voided' => 'Cancelled', + 'refunded_payment' => 'Refunded Payment', + 'activity_39' => ':user cancelled a :payment_amount payment (:payment)', + 'activity_40' => ':user refunded :adjustment of a :payment_amount payment (:payment)', + 'card_expiration' => 'Exp: :expires', + + 'card_creditcardother' => 'Unknown', + 'card_americanexpress' => 'American Express', + 'card_carteblanche' => 'Carte Blanche', + 'card_unionpay' => 'UnionPay', + 'card_diners' => 'Diners Club', + 'card_discover' => 'Discover', + 'card_jcb' => 'JCB', + 'card_laser' => 'Laser', + 'card_maestro' => 'Maestro', + 'card_mastercard' => 'MasterCard', + 'card_solo' => 'Solo', + 'card_switch' => 'Switch', + 'card_visacard' => 'Visa', + 'card_ach' => 'ACH', + + 'payment_type_stripe' => 'Stripe', + 'ach' => 'ACH', + 'enable_ach' => 'Enable ACH', + 'stripe_ach_help' => 'ACH support must also be enabled at Stripe.', + 'ach_disabled' => 'Another gateway is already configured for direct debit.', + + 'plaid' => 'Plaid', + 'client_id' => 'Client Id', + 'secret' => 'Secret', + 'public_key' => 'Public Key', + 'plaid_optional' => '(optional)', + 'plaid_environment_help' => 'When a Stripe test key is given, Plaid\'s development environement (tartan) will be used.', + 'other_providers' => 'Other Providers', + 'country_not_supported' => 'That country is not supported.', + 'invalid_routing_number' => 'The routing number is not valid.', + 'invalid_account_number' => 'The account number is not valid.', + 'account_number_mismatch' => 'The account numbers do not match.', + 'missing_account_holder_type' => 'Please select an individual or company account.', + 'missing_account_holder_name' => 'Please enter the account holder\'s name.', + 'routing_number' => 'Routing Number', + 'confirm_account_number' => 'Confirm Account Number', + 'individual_account' => 'Individual Account', + 'company_account' => 'Company Account', + 'account_holder_name' => 'Account Holder Name', + 'add_account' => 'Add Account', + 'payment_methods' => 'Payment Methods', + 'complete_verification' => 'Complete Verification', + 'verification_amount1' => 'Amount 1', + 'verification_amount2' => 'Amount 2', + 'payment_method_verified' => 'Verification completed successfully', + 'verification_failed' => 'Verification Failed', + 'remove_payment_method' => 'Remove Payment Method', + 'confirm_remove_payment_method' => 'Are you sure you want to remove this payment method?', + 'remove' => 'Remove', + 'payment_method_removed' => 'Removed payment method.', + 'bank_account_verification_help' => 'We have made two deposits into your account with the description "VERIFICATION". These deposits will take 1-2 business days to appear on your statement. Please enter the amounts below.', + 'bank_account_verification_next_steps' => 'We have made two deposits into your account with the description "VERIFICATION". These deposits will take 1-2 business days to appear on your statement. + Once you have the amounts, come back to this payment methods page and click "Complete Verification" next to the account.', + 'unknown_bank' => 'Unknown Bank', + 'ach_verification_delay_help' => 'You will be able to use the account after completing verification. Verification usually takes 1-2 business days.', + 'add_credit_card' => 'Add Credit Card', + 'payment_method_added' => 'Added payment method.', + 'use_for_auto_bill' => 'Use For Autobill', + 'used_for_auto_bill' => 'Autobill Payment Method', + 'payment_method_set_as_default' => 'Set Autobill payment method.', + 'activity_41' => ':payment_amount payment (:payment) failed', + 'webhook_url' => 'Webhook URL', + 'stripe_webhook_help' => 'You must :link.', + 'stripe_webhook_help_link_text' => 'add this URL as an endpoint at Stripe', + 'payment_method_error' => 'There was an error adding your payment methd. Please try again later.', + 'notification_invoice_payment_failed_subject' => 'Payment failed for Invoice :invoice', + 'notification_invoice_payment_failed' => 'A payment made by client :client towards Invoice :invoice failed. The payment has been marked as failed and :amount has been added to the client\'s balance.', + 'link_with_plaid' => 'Link Account Instantly with Plaid', + 'link_manually' => 'Link Manually', + 'secured_by_plaid' => 'Secured by Plaid', + 'plaid_linked_status' => 'Your bank account at :bank', + 'add_payment_method' => 'Add Payment Method', + 'account_holder_type' => 'Account Holder Type', + 'ach_authorization' => 'I authorize :company to use my bank account for future payments and, if necessary, electronically credit my account to correct erroneous debits. I understand that I may cancel this authorization at any time by removing the payment method or by contacting :email.', + 'ach_authorization_required' => 'You must consent to ACH transactions.', + 'off' => 'Off', + 'opt_in' => 'Opt-in', + 'opt_out' => 'Opt-out', + 'always' => 'Always', + 'opted_out' => 'Opted out', + 'opted_in' => 'Opted in', + 'manage_auto_bill' => 'Manage Auto-bill', + 'enabled' => 'Enabled', + 'paypal' => 'PayPal', + 'braintree_enable_paypal' => 'Enable PayPal payments through BrainTree', + 'braintree_paypal_disabled_help' => 'The PayPal gateway is processing PayPal payments', + 'braintree_paypal_help' => 'You must also :link.', + 'braintree_paypal_help_link_text' => 'link PayPal to your BrainTree account', + 'token_billing_braintree_paypal' => 'Save payment details', + 'add_paypal_account' => 'Add PayPal Account', + + + 'no_payment_method_specified' => 'No payment method specified', + 'chart_type' => 'Chart Type', + 'format' => 'Format', + 'import_ofx' => 'Import OFX', + 'ofx_file' => 'OFX File', + 'ofx_parse_failed' => 'Failed to parse OFX file', + + // WePay + 'wepay' => 'WePay', + 'sign_up_with_wepay' => 'Sign up with WePay', + 'use_another_provider' => 'Use another provider', + 'company_name' => 'Company Name', + 'wepay_company_name_help' => 'This will appear on client\'s credit card statements.', + 'wepay_description_help' => 'The purpose of this account.', + 'wepay_tos_agree' => 'I agree to the :link.', + 'wepay_tos_link_text' => 'WePay Terms of Service', + 'resend_confirmation_email' => 'Resend Confirmation Email', + 'manage_wepay_account' => 'Manage WePay Account', + 'action_required' => 'Action Required', + 'finish_setup' => 'Finish Setup', + 'created_wepay_confirmation_required' => 'Please check your email and confirm your email address with WePay.', + 'switch_to_wepay' => 'Switch to WePay', + 'switch' => 'Switch', + 'restore_account_gateway' => 'Restore Gateway', + 'restored_account_gateway' => 'Successfully restored gateway', + 'united_states' => 'United States', + 'canada' => 'Canada', + 'accept_debit_cards' => 'Accept Debit Cards', + 'debit_cards' => 'Debit Cards', + + 'warn_start_date_changed' => 'The next invoice will be sent on the new start date.', + 'original_start_date' => 'Original start date', + 'new_start_date' => 'New start date', + 'security' => 'Security', + 'see_whats_new' => 'See what\'s new in v:version', + 'wait_for_upload' => 'Please wait for the document upload to complete.', + 'upgrade_for_permissions' => 'Upgrade to our Enterprise plan to enable permissions.', + 'enable_second_tax_rate' => 'Enable specifying a second tax rate', + 'payment_file' => 'Payment File', + 'expense_file' => 'Expense File', + 'product_file' => 'Product File', + 'import_products' => 'Import Products', + 'products_will_create' => 'products will be created.', + 'product_key' => 'Product', + 'created_products' => 'Successfully created :count product(s)', + 'export_help' => 'Use JSON if you plan to import the data into Invoice Ninja.', + 'JSON_file' => 'JSON File', + + 'view_dashboard' => 'View Dashboard', + 'client_session_expired' => 'Session Expired', + 'client_session_expired_message' => 'Your session has expired. Please click the link in your email again.', + + 'auto_bill_notification' => 'This invoice will automatically be billed to your :payment_method on file on :due_date.', + 'auto_bill_payment_method_bank_transfer' => 'bank account', + 'auto_bill_payment_method_credit_card' => 'credit card', + 'auto_bill_payment_method_paypal' => 'PayPal account', + 'auto_bill_notification_placeholder' => 'This invoice will automatically be billed to your credit card on file on the due date.', + 'payment_settings' => 'Payment Settings', + + 'on_send_date' => 'On send date', + 'on_due_date' => 'On due date', + 'auto_bill_ach_date_help' => 'ACH auto bill will always happen on the due date', + 'warn_change_auto_bill' => 'Due to NACHA rules, changes to this invoice may prevent ACH auto bill.', + + 'bank_account' => 'Bank Account', + 'payment_processed_through_wepay' => 'ACH payments will be processed using WePay.', + 'wepay_payment_tos_agree' => 'I agree to the WePay :terms and :privacy_policy.', + 'privacy_policy' => 'Privacy Policy', + 'wepay_payment_tos_agree_required' => 'You must agree to the WePay Terms of Service and Privacy Policy.', + 'payment_settings_supported_gateways' => 'These options are supported by the WePay, Stripe, and Braintree gateways.', + 'ach_email_prompt' => 'Please enter your email address:', + 'verification_pending' => 'Verification Pending', + + 'update_font_cache' => 'Please force refresh the page to update the font cache.', + 'more_options' => 'More options', + 'credit_card' => 'Credit Card', + 'bank_transfer' => 'Bank Transfer', + 'no_transaction_reference' => 'We did not recieve a payment transaction reference from the gateway.', + 'use_bank_on_file' => 'Use Bank on File', + 'auto_bill_email_message' => 'This invoice will automatically be billed to the payment method on file on the due date.', + 'bitcoin' => 'Bitcoin', + 'added_on' => 'Added :date', + 'failed_remove_payment_method' => 'Failed to remove the payment method', + 'gateway_exists' => 'This gateway already exists', + 'manual_entry' => 'Manual entry', + ); + +return $LANG; + +?> diff --git a/resources/lang/es_ES/texts.php b/resources/lang/es_ES/texts.php index d6aa9f0aa6..275b21a4e4 100644 --- a/resources/lang/es_ES/texts.php +++ b/resources/lang/es_ES/texts.php @@ -1,8 +1,6 @@ 'Empresa', 'name' => 'Nombre', 'website' => 'Sitio Web', @@ -20,13 +18,11 @@ return array( 'phone' => 'Teléfono', 'email' => 'Email', 'additional_info' => 'Información adicional', - 'payment_terms' => 'Plazos de pago', // + 'payment_terms' => 'Plazos de pago', 'currency_id' => 'Divisa', 'size_id' => 'Tamaño', 'industry_id' => 'Industria', 'private_notes' => 'Notas Privadas', - - // invoice 'invoice' => 'Factura', 'client' => 'Cliente', 'invoice_date' => 'Fecha de factura', @@ -73,8 +69,6 @@ return array( 'settings' => 'Configuración', 'enable_invoice_tax' => 'Activar Impuesto para el Total de la Factura', 'enable_line_item_tax' => 'Activar Impuesto para cada Concepto de la Factura', - - // navigation 'dashboard' => 'Inicio', 'clients' => 'Clientes', 'invoices' => 'Facturas', @@ -99,8 +93,6 @@ return array( 'provide_email' => 'Por favor facilita una dirección de correo válida.', 'powered_by' => 'Creado por', 'no_items' => 'No hay datos', - - // recurring invoices 'recurring_invoices' => 'Facturas periódicas', 'recurring_help' => '

    Enviar facturas automáticamente a clientes semanalmente, bi-mensualmente, mensualmente, trimestral o anualmente.

    Usando :MONTH, :QUARTER or :YEAR para fechas dinámicas. Y utilizando tambien Matemáticas básicas. Por ejemplo: :MONTH-1.

    @@ -110,8 +102,6 @@ return array(
  • ":YEAR+1 suscripción anual" => "2015 suscripción anual"
  • "Pago retenido para :QUARTER+1" => "Pago retenido para T2"
  • ', - - // dashboard 'in_total_revenue' => 'Ingreso Total', 'billed_client' => 'Cliente Facturado', 'billed_clients' => 'Clientes Facturados', @@ -120,8 +110,6 @@ return array( 'invoices_past_due' => 'Facturas Vencidas', 'upcoming_invoices' => 'Próximas Facturas', 'average_invoice' => 'Promedio de Facturación', - - // list pages 'archive' => 'Archivar', 'delete' => 'Eliminar', 'archive_client' => 'Archivar Cliente', @@ -157,42 +145,24 @@ return array( 'select' => 'Seleccionar', 'edit_client' => 'Editar Cliente', 'edit_invoice' => 'Editar Factura', - - // client view page 'create_invoice' => 'Crear Factura', - 'Create Invoice' => 'Crear Factura', 'enter_credit' => 'Agregar Crédito', 'last_logged_in' => 'Último inicio de sesión', 'details' => 'Detalles', - 'standing' => 'Situación', // + 'standing' => 'Situación', 'credit' => 'Crédito', 'activity' => 'Actividad', 'date' => 'Fecha', 'message' => 'Mensaje', 'adjustment' => 'Ajustes', 'are_you_sure' => '¿Está Seguro?', - - // payment pages 'payment_type_id' => 'Tipo de pago', 'amount' => 'Cantidad', - - // Nuevo texto extraido - New text extracted - 'Recommended Gateway' => 'Pasarelas Recomendadas',// - 'Accepted Credit Cards' => 'Tarjetas de Credito Permitidas',// - 'Payment Gateway' => 'Pasarelas de Pago',// - 'Select Gateway' => 'Seleccione Pasarela',// - 'Enable' => 'Activo',// - 'Api Login Id' => 'Introduzca Api Id',// - 'Transaction Key' => 'Clave de Transacción',// - 'Create an account' => 'Crear cuenta nueva',// - 'Other Options' => 'Otras Opciones',// - - // account/company pages 'work_email' => 'Correo electrónico de la empresa', 'language_id' => 'Idioma', 'timezone_id' => 'Zona horaria', 'date_format_id' => 'Formato de fecha', - 'datetime_format_id' => 'Format de fecha/hora', + 'datetime_format_id' => 'Formato de fecha/hora', 'users' => 'Usuarios', 'localization' => 'Localización', 'remove_logo' => 'Eliminar logo', @@ -205,11 +175,7 @@ return array( 'email_paid' => 'Avísame por correo cuando una factura se paga', 'site_updates' => 'Actualizaciones del sitio', 'custom_messages' => 'Mensajes a medida', - 'default_invoice_terms' => 'Configurar términos de factura por defecto', - 'default_email_footer' => 'Configurar firma de email por defecto', - 'import_clients' => 'Importar datos del cliente', - 'csv_file' => 'Seleccionar archivo CSV', - 'export_clients' => 'Exportar datos del cliente', + 'default_email_footer' => 'Configurar firma de email por defecto', 'select_file' => 'Seleccionar archivo', 'first_row_headers' => 'Usar la primera fila como encabezados', 'column' => 'Columna', @@ -217,8 +183,13 @@ return array( 'import_to' => 'Importar a', 'client_will_create' => 'cliente se creará', 'clients_will_create' => 'clientes se crearan', - - // application messages + 'email_settings' => 'Configuración de correo', + 'client_view_styling' => 'Estilo de visualización para el cliente', + 'pdf_email_attachment' => 'Adjuntar PDFs', + 'custom_css' => 'CSS personalizado', + 'import_clients' => 'Importar datos del cliente', + 'csv_file' => 'Seleccionar archivo CSV', + 'export_clients' => 'Exportar datos del cliente', 'created_client' => 'cliente creado con éxito', 'created_clients' => ':count clientes creados con éxito', 'updated_settings' => 'Configuración actualizada con éxito', @@ -229,38 +200,40 @@ return array( 'payment_error' => 'Ha habido un error en el proceso de tu pago. Inténtalo de nuevo más tarde.', 'registration_required' => 'Inscríbete para enviar una factura', 'confirmation_required' => 'Por favor confirma tu dirección de correo electrónico', - - 'updated_client' => 'Cliente actualizado con éxito', - 'created_client' => 'Cliente creado con éxito', - 'archived_client' => 'Cliente archivado con éxito', - 'archived_clients' => ':count clientes archivados con éxito', - 'deleted_client' => 'Cliente eliminado con éxito', - 'deleted_clients' => ':count clientes eliminados con éxito', - - 'updated_invoice' => 'Factura actualizada con éxito', - 'created_invoice' => 'Factura creada con éxito', - 'cloned_invoice' => 'Factura clonada con éxito', - 'emailed_invoice' => 'Factura enviada con éxito', + 'updated_client' => 'Cliente actualizado correctamente', + 'created_client' => 'cliente creado con éxito', + 'archived_client' => 'Cliente archivado correctamente', + 'archived_clients' => ':count clientes archivados correctamente', + 'deleted_client' => 'Cliente eliminado correctamente', + 'deleted_clients' => ':count clientes eliminados correctamente', + 'updated_invoice' => 'Factura actualizada correctamente', + 'created_invoice' => 'Factura creada correctamente', + 'cloned_invoice' => 'Factura clonada correctamente', + 'emailed_invoice' => 'Factura enviada correctamente', 'and_created_client' => 'y cliente creado ', - 'archived_invoice' => 'Factura archivada con éxito', - 'archived_invoices' => ':count facturas archivados con éxito', - 'deleted_invoice' => 'Factura eliminada con éxito', - 'deleted_invoices' => ':count facturas eliminadas con éxito', - - 'created_payment' => 'Pago creado con éxito', - 'archived_payment' => 'Pago archivado con éxito', - 'archived_payments' => ':count pagos archivados con éxito', - 'deleted_payment' => 'Pago eliminado con éxito', - 'deleted_payments' => ':count pagos eliminados con éxito', - 'applied_payment' => 'Pago aplicado con éxito', - - 'created_credit' => 'Crédito creado con éxito', - 'archived_credit' => 'Crédito archivado con éxito', - 'archived_credits' => ':count creditos archivados con éxito', - 'deleted_credit' => 'Créditos eliminados con éxito', - 'deleted_credits' => ':count creditos eliminados con éxito', - - // Emails + 'archived_invoice' => 'Factura archivada correctamente', + 'archived_invoices' => ':count facturas archivados correctamente', + 'deleted_invoice' => 'Factura eliminada correctamente', + 'deleted_invoices' => ':count facturas eliminadas correctamente', + 'created_payment' => 'Pago creado correctamente', + 'created_payments' => ':count pagos creados correctamente.', + 'archived_payment' => 'Pago archivado correctamente', + 'archived_payments' => ':count pagos archivados correctamente', + 'deleted_payment' => 'Pago eliminado correctamente', + 'deleted_payments' => ':count pagos eliminados correctamente', + 'applied_payment' => 'Pago aplicado correctamente', + 'created_credit' => 'Crédito creado correctamente', + 'archived_credit' => 'Crédito archivado correctamente', + 'archived_credits' => ':count creditos archivados correctamente', + 'deleted_credit' => 'Créditos eliminados correctamente', + 'deleted_credits' => ':count creditos eliminados correctamente', + 'imported_file' => 'Fichero importado correctamente', + 'updated_vendor' => 'Successfully updated vendor', + 'created_vendor' => 'Successfully created vendor', + 'archived_vendor' => 'Successfully archived vendor', + 'archived_vendors' => 'Successfully archived :count vendors', + 'deleted_vendor' => 'Successfully deleted vendor', + 'deleted_vendors' => 'Successfully deleted :count vendors', 'confirmation_subject' => 'Corfimación de tu cuenta en Invoice Ninja', 'confirmation_header' => 'Confirmación de Cuenta', 'confirmation_message' => 'Por favor, haz clic en el enlace abajo para confirmar tu cuenta.', @@ -271,7 +244,6 @@ return array( 'email_salutation' => 'Estimado :name,', 'email_signature' => 'Un cordial saludo,', 'email_from' => 'El equipo de Invoice Ninja ', - 'user_email_footer' => 'Para ajustar la configuración de las notificaciones de tu email, visita '.SITE_URL.'/settings/notifications', 'invoice_link_message' => 'Para visualizar la factura de cliente, haz clic en el enlace de abajo:', 'notification_invoice_paid_subject' => 'La factura :invoice ha sido pagada por el cliente :client', 'notification_invoice_sent_subject' => 'La factura :invoice ha sido enviada a el cliente :client', @@ -280,31 +252,11 @@ return array( 'notification_invoice_sent' => 'La factura :invoice por importe de :amount fue enviada al cliente :cliente.', 'notification_invoice_viewed' => 'La factura :invoice por importe de :amount fue visualizada por el cliente :client.', 'reset_password' => 'Puedes reconfigurar la contraseña de tu cuenta haciendo clic en el siguiente enlace:', - 'reset_password_footer' => 'Si no has solicitado un cambio de contraseña, por favor contactate con nosostros: '.CONTACT_EMAIL, - - // Payment page 'secure_payment' => 'Pago seguro', 'card_number' => 'Número de tarjeta', 'expiration_month' => 'Mes de caducidad', 'expiration_year' => 'Año de caducidad', 'cvv' => 'CVV', - - // Security alerts - 'confide' => array( - 'too_many_attempts' => 'Demasiados intentos fallidos. Inténtalo de nuevo en un par de minutos.', - 'wrong_credentials' => 'Contraseña o email incorrecto.', - 'confirmation' => '¡Tu cuenta se ha confirmado!', - 'wrong_confirmation' => 'Código de confirmación incorrecto.', - 'password_forgot' => 'La información sobre el cambio de tu contraseña se ha enviado a tu dirección de correo electrónico.', - 'password_reset' => 'Tu contraseña se ha cambiado con éxito.', - 'wrong_password_reset' => 'Contraseña no válida. Inténtalo de nuevo', - ), - - // Pro Plan - 'pro_plan' => [ - 'remove_logo' => ':link haz click para eliminar el logo de Invoice Ninja', - 'remove_logo_link' => 'Haz click aquí', - ], 'logout' => 'Cerrar sesión', 'sign_up_to_save' => 'Registrate para guardar tu trabajo', 'agree_to_terms' => 'Estoy de acuerdo con los términos de Invoice Ninja :terms', @@ -315,9 +267,7 @@ return array( 'success_message' => 'Te has registrado con éxito. Por favor, haz clic en el enlace del correo de confirmación para verificar tu dirección de correo electrónico.', 'erase_data' => 'Esta acción eliminará todos tus datos de forma permanente.', 'password' => 'Contraseña', - 'pro_plan_product' => 'Plan Pro', - 'pro_plan_description' => 'Un año de inscripción al Plan Pro de Invoice Ninja.', 'pro_plan_success' => '¡Gracias por unirte a Invoice Ninja! Al realizar el pago de tu factura, se iniciara tu PLAN PRO.', 'unsaved_changes' => 'Tienes cambios no guardados', 'custom_fields' => 'Campos personalizados', @@ -326,9 +276,8 @@ return array( 'field_label' => 'Etiqueta del campo', 'field_value' => 'Valor del campo', 'edit' => 'Editar', + 'set_name' => 'Set your company name', 'view_as_recipient' => 'Ver como destinitario', - - // product management 'product_library' => 'Inventario de productos', 'product' => 'Producto', 'products' => 'Productos', @@ -351,8 +300,6 @@ return array( 'chart_builder' => 'Constructor de graficos', 'ninja_email_footer' => 'Usa :site para facturar a tus clientes y recibir pagos de forma gratuita!', 'go_pro' => 'Hazte Pro', - - // Quotes 'quote' => 'Presupuesto', 'quotes' => 'Presupuestos', 'quote_number' => 'Numero de Presupuesto', @@ -362,7 +309,6 @@ return array( 'your_quote' => 'Su Presupuesto', 'total' => 'Total', 'clone' => 'Clonar', - 'new_quote' => 'Nuevo Presupuesto', 'create_quote' => 'Crear Presupuesto', 'edit_quote' => 'Editar Presupuesto', @@ -373,9 +319,8 @@ return array( 'clone_quote' => 'Clonar Presupuesto', 'convert_to_invoice' => 'Convertir a Factura', 'view_invoice' => 'Ver Factura', - 'view_quote' => 'Ver Presupuesto', 'view_client' => 'Ver Cliente', - + 'view_quote' => 'Ver Presupuesto', 'updated_quote' => 'Presupuesto actualizado con éxito', 'created_quote' => 'Presupuesto creado con éxito', 'cloned_quote' => 'Presupuesto clonado con éxito', @@ -385,7 +330,6 @@ return array( 'deleted_quote' => 'Presupuesto eliminado con éxito', 'deleted_quotes' => ':count Presupuestos eliminados con exito', 'converted_to_invoice' => 'Presupuesto convertido a factura con éxito', - 'quote_subject' => 'Nuevo Presupuesto de :account', 'quote_message' => 'Para ver el presupuesto por un importe de :amount, haga click en el enlace de abajo.', 'quote_link_message' => 'Para ver su presupuesto haga click en el enlace de abajo:', @@ -403,7 +347,7 @@ return array( 'charge_taxes' => 'Cargar Impuestos', 'user_management' => 'Gestión de Usuarios', 'add_user' => 'Añadir Usuario', - 'send_invite' => 'Enviar Invitación', //Context for its use + 'send_invite' => 'Enviar Invitación', 'sent_invite' => 'Invitación enviada con éxito', 'updated_user' => 'Usario actualizado con éxito', 'invitation_message' => ':invitor te ha invitado a unirte a su cuenta en G-Factura.', @@ -414,7 +358,6 @@ return array( 'active' => 'Activo', 'pending' => 'Pendiente', 'deleted_user' => 'Usario eliminado con éxito', - 'limit_users' => 'Lo sentimos, esta acción excederá el límite de '.MAX_NUM_USERS.' usarios', 'confirm_email_invoice' => '¿Estás seguro que quieres enviar esta factura?', 'confirm_email_quote' => '¿Estás seguro que quieres enviar este presupuesto?', 'confirm_recurring_email_invoice' => 'Se ha marcado esta factura como recurrente, estás seguro que quieres enviar esta factura?', @@ -434,61 +377,48 @@ return array( 'invoice_issued_to' => 'Factura emitida a', 'invalid_counter' => 'Para evitar posibles conflictos, por favor crea un prefijo de facturación y de presupuesto.', 'mark_sent' => 'Marcar como enviado', - 'gateway_help_1' => ':link para registrarse en Authorize.net.', 'gateway_help_2' => ':link para registrarse en Authorize.net.', 'gateway_help_17' => ':link para obtener su firma API de PayPal.', 'gateway_help_27' => ':link para registrarse en TwoCheckout.', - 'more_designs' => 'Más diseños', 'more_designs_title' => 'Diseños adicionales para factura', 'more_designs_cloud_header' => 'Pase a Pro para añadir más diseños de facturas', 'more_designs_cloud_text' => '', - 'more_designs_self_host_header' => 'Obtenga 6 diseños más para facturas por sólo '.INVOICE_DESIGNS_PRICE, // comprobar 'more_designs_self_host_text' => '', 'buy' => 'Comprar', 'bought_designs' => 'Añadidos con exito los diseños de factura', - 'sent' => 'Enviado', + 'vat_number' => 'NIF/CIF', 'timesheets' => 'Parte de Horas', - 'payment_title' => 'Introduzca su dirección de facturación y la infomración de su tarjeta de crédito', 'payment_cvv' => '*los tres últimos dígitos de la parte posterior de su tarjeta', 'payment_footer1' => '*La dirección de facturación debe coincidir con la de la tarjeta de crédito.', 'payment_footer2' => '*Por favor, haga clic en "Pagar ahora" sólo una vez - esta operación puede tardar hasta 1 minuto en procesarse.', - 'vat_number' => 'NIF/CIF', - 'id_number' => 'Número de Identificación', 'white_label_link' => 'Marca Blanca" ', - 'white_label_link' => 'Marca Blanca" ', + 'white_label_header' => 'White Label', 'bought_white_label' => 'Se ha conseguido con exito la licencia de Marca Blanca', 'white_labeled' => 'Marca Blanca', - 'restore' => 'Restaurar', 'restore_invoice' => 'Restaurar Factura', 'restore_quote' => 'Restaurar Presupuesto', 'restore_client' => 'Restaurar Cliente', 'restore_credit' => 'Restaurar Pendiente', 'restore_payment' => 'Restaurar Pago', - 'restored_invoice' => 'Factura restaurada con éxito', 'restored_quote' => 'Presupuesto restaurada con éxito', 'restored_client' => 'Cliente restaurada con éxito', 'restored_payment' => 'Pago restaurada con éxito', 'restored_credit' => 'Pendiente restaurada con éxito', - 'reason_for_canceling' => 'Ayudenos a mejorar nuestro sitio diciendonos porque se va, Gracias', 'discount_percent' => 'Porcentaje', 'discount_amount' => 'Cantidad', - - // Ver. 1.7.0 - 'invoice_history' => 'Historial de Facturas', 'quote_history' => 'Historial de Presupuestos', 'current_version' => 'Versión Actual', 'select_version' => 'Seleccione la Versión', 'view_history' => 'Ver Historial', - 'edit_payment' => 'Editar Pago', 'updated_payment' => 'Pago actualizado correctamente', 'deleted' => 'Eliminado', @@ -501,20 +431,18 @@ return array( 'quote_email' => 'Email de Presupuestos', 'reset_all' => 'Restablecer Todos', 'approve' => 'Aprobar', - - 'token_billing_type_id' => 'Token Billing', //¿? + 'token_billing_type_id' => 'Token Billing', 'token_billing_help' => 'Permite almacenar tarjetas de crédito para posteriormente realizarles el cobro.', 'token_billing_1' => 'Deshabilitar', 'token_billing_2' => 'La casilla Opt-In se muestra pero no está seleccionada', 'token_billing_3' => 'La casilla Opt-Out se muestra y se selecciona', 'token_billing_4' => 'Siempre', 'token_billing_checkbox' => 'Almacenar datos de la tarjeta de crédito', - 'view_in_stripe' => 'Ver en Stripe', - 'use_card_on_file' => 'Usar tarjeta en fichero', //?? + 'view_in_gateway' => 'Ver en :gateway', + 'use_card_on_file' => 'Use Card on File', 'edit_payment_details' => 'Editar detalles de pago', 'token_billing' => 'Guardar datos de la tarjeta', - 'token_billing_secure' => 'Los datos serán almacenados de forma segura por :stripe_link', - + 'token_billing_secure' => 'Los datos serán almacenados de forma segura por :link', 'support' => 'Soporte', 'contact_information' => 'Información de Contacto', '256_encryption' => 'Encriptación de 256-Bit', @@ -524,12 +452,9 @@ return array( 'order_overview' => 'Lista de pedidos', 'match_address' => '*La dirección debe coincidir con la dirección asociada a la tarjeta de crédito.', 'click_once' => '*Por favor, haga clic en "Pagar ahora" sólo una vez - la operación puede tardar hasta 1 minuto en ser procesada.', - - 'default_invoice_footer' => 'Establecer pie de página por defecto en factura', 'invoice_footer' => 'Pie de página de la factura', 'save_as_default_footer' => 'Guardar como pie de página por defecto', - - 'token_management' => 'Administrar Tokent', //? + 'token_management' => 'Administrar Tokent', 'tokens' => 'Tokens', 'add_token' => 'Agregar Token', 'show_deleted_tokens' => 'Mostrar tokens eliminados', @@ -539,7 +464,6 @@ return array( 'edit_token' => 'Editar Token', 'delete_token' => 'Eliminar Token', 'token' => 'Token', - 'add_gateway' => 'Agregar Pasarela', 'delete_gateway' => 'Eliminar Pasarela', 'edit_gateway' => 'Editar Pasarela', @@ -548,7 +472,6 @@ return array( 'deleted_gateway' => 'Pasarela eliminada correctamente', 'pay_with_paypal' => 'PayPal', 'pay_with_card' => 'Tarjeta de Crédito', - 'change_password' => 'Cambiar Contraseña', 'current_password' => 'Contraseña Actual', 'new_password' => 'Nueva Contraseña', @@ -556,7 +479,6 @@ return array( 'password_error_incorrect' => 'La contraseña actual es incorrecta.', 'password_error_invalid' => 'La nueva contraseña no es válida.', 'updated_password' => 'Contraseña actualizada correctamente', - 'api_tokens' => 'API Tokens', 'users_and_tokens' => 'Usuarios & Tokens', 'account_login' => 'Iniciar Sesión', @@ -568,20 +490,11 @@ return array( 'send_email' => 'Enviar email', 'set_password' => 'Establecer Contraseña', 'converted' => 'Modificada', - - //------Texto extraido ----------------------------------------------------------------------------------------- - 'Manual entry' => 'Entrada Manual', - - // Error - 'Whoops, looks like something went wrong.' => 'Vaya, parece que algo salió mal', - 'Sorry, the page you are looking for could not be found.' => 'Lo sentimos, la página que está buscando no se pudo encontrar.', - 'email_approved' => 'Avísame por correo cuando un presupuesto sea aprobado', 'notification_quote_approved_subject' => 'Presupuesto :invoice fue aprobado por :client', 'notification_quote_approved' => 'El cliente :client aprovó el presupuesto :invoice por :amount.', 'resend_confirmation' => 'Reenviar correo de confirmacion', 'confirmation_resent' => 'El correo de confirmación fué reenviado', - 'gateway_help_42' => ':link to sign up for BitPay.
    Note: use a Legacy API Key, not an API token.', 'payment_type_credit_card' => 'Tarjeta de crédito', 'payment_type_paypal' => 'PayPal', @@ -589,7 +502,6 @@ return array( 'knowledge_base' => 'Ayuda', 'partial' => 'Parcial', 'partial_remaining' => ':partial de :balance', - 'more_fields' => 'Mas campos', 'less_fields' => 'Menos campos', 'client_name' => 'Nombre del cliente', @@ -600,7 +512,6 @@ return array( 'view_documentation' => 'Ver documentación', 'app_title' => 'Facturacion Online Open-Source gratuita', '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' => 'filas', 'www' => 'www', 'logo' => 'Logo', @@ -620,7 +531,6 @@ return array( 'zapier' => 'Zapier', 'recurring' => 'Periódico', 'last_invoice_sent' => 'Última factura enviada el :date', - 'processed_updates' => 'Actualización correcta', 'tasks' => 'Tareas', 'new_task' => 'Nueva tarea', @@ -666,12 +576,10 @@ return array( 'invoice_labels' => 'Etiquetas de factura', 'prefix' => 'Prefijo', 'counter' => 'Contador', - 'payment_type_dwolla' => 'Dwolla', 'gateway_help_43' => ':link to sign up for Dwolla.', 'partial_value' => 'Debe ser mayor que 0 y menos que el total', 'more_actions' => 'Mas Acciones', - 'pro_plan_title' => 'NINJA PRO', 'pro_plan_call_to_action' => 'Upgrade Now!', 'pro_plan_feature1' => 'Create Unlimited Clients', @@ -682,14 +590,12 @@ return array( 'pro_plan_feature6' => 'Create Quotes & Pro-forma Invoices', 'pro_plan_feature7' => 'Customize Invoice Field Titles & Numbering', 'pro_plan_feature8' => 'Option to Attach PDFs to Client Emails', - 'resume' => 'Reanudar', 'break_duration' => 'Interrumpir', 'edit_details' => 'Editar detalles', 'work' => 'Trabajo', 'timezone_unset' => 'Pro favor :link para especificar su timezone', 'click_here' => 'pulse aqui', - 'email_receipt' => 'Enviar recibo de pago al cliente', 'created_payment_emailed_client' => 'Pago creado y enviado al cliente correctamente', 'add_company' => 'Añadir compañía', @@ -699,10 +605,8 @@ return array( 'unlinked_account' => 'Desvínculo de cuentas correcta', 'login' => 'Login', 'or' => 'o', - 'email_error' => 'Ocurrió un problema enviando el correo', 'confirm_recurring_timing' => 'Nota: correos enviados cada hora en punto.', - 'old_browser' => 'Por favor use un navegador mas actual', 'payment_terms_help' => 'Establezca la fecha de pago de factura por defecto', 'unlink_account' => 'Cuenta desvinculada', 'unlink' => 'Desvincular', @@ -723,7 +627,6 @@ return array( 'primary_color' => 'Color Primario', 'secondary_color' => 'Color Secundario', 'customize_design' => 'Personalizar diseño', - 'content' => 'Contenido', 'styles' => 'Estilos', 'defaults' => 'Por defectos', @@ -737,7 +640,6 @@ return array( 'outstanding' => 'Pendiente de Cobro', 'manage_companies' => 'Gestionar compañías', 'total_revenue' => 'Ingresos Totales', - 'current_user' => 'Usuario Actual', 'new_recurring_invoice' => 'Nueva Factura Periódica', 'recurring_invoice' => 'Factura Periódica', @@ -746,9 +648,8 @@ return array( 'primary_user' => 'Usuario Principal', 'help' => 'Ayuda', 'customize_help' => '

    We use pdfmake to define the invoice designs declaratively. The pdfmake playground provide\'s a great way to see the library in action.

    -

    To access a child property using dot notation. For example to show the client name you could use $client.name.

    -

    If you need help figuring something out post a question to our support forum.

    ', - +

    You can access a child property using dot notation. For example to show the client name you could use $client.name.

    +

    If you need help figuring something out post a question to our support forum with the design you\'re using.

    ', 'invoice_due_date' => 'Fecha de Pago', 'quote_due_date' => 'Válido hasta', 'valid_until' => 'Válido hasta', @@ -761,15 +662,12 @@ return array( 'status_partial' => 'Parcial', 'status_paid' => 'Pagada', 'show_line_item_tax' => 'Mostrar importe por concepto en la linea de concepto', - 'iframe_url' => 'Website', 'iframe_url_help1' => 'Copia el siguiente codigo para una pagina de si sitio web.', 'iframe_url_help2' => 'Puedes probar esta caracteristica pulsando \'Ver como destinatario\' para una Factura.', - 'auto_bill' => 'Facturación automática', 'military_time' => '24 Horas', 'last_sent' => 'Última enviada', - 'reminder_emails' => 'Correos recordatorio', 'templates_and_reminders' => 'Plantillas & Recordatorios', 'subject' => 'Asunto', @@ -781,15 +679,12 @@ return array( 'reminder_subject' => 'Recordatorio: Factura :invoice de :account', 'reset' => 'Reiniciar', 'invoice_not_found' => 'La Factura solicitara no está disponible', - 'referral_program' => 'Programa de Recomendaciones', 'referral_code' => 'Codigo de Recomendacion', 'last_sent_on' => 'Enviado la ultima vez en :date', - 'page_expire' => 'Esta página expirará en breve, :click_here para seguir trabajando', 'upcoming_quotes' => 'Próximos Presupuestos', 'expired_quotes' => 'Presupuestos Expirados', - 'sign_up_using' => 'Registrarse usando', 'invalid_credentials' => 'Las credenciales no coinciden con nuestros registros', 'show_all_options' => 'Mostrar todas las opciones', @@ -798,17 +693,10 @@ return array( 'disable' => 'Deshabilitado', 'invoice_quote_number' => 'Números de Factura y Presupuesto', 'invoice_charges' => 'Cargos de factura', - - 'invitation_status' => [ - 'sent' => 'Correo Enviado', - 'opened' => 'Correo abierto', - 'viewed' => 'Factura vista', - ], 'notification_invoice_bounced' => 'No podemos entregar la factura :invoice a :contact.', 'notification_invoice_bounced_subject' => 'No se puede entregar la factura :invoice', 'notification_quote_bounced' => 'No podemos entregar el presupuesto :invoice a :contact.', 'notification_quote_bounced_subject' => 'No se puede entregar el presupuesto :invoice', - 'custom_invoice_link' => 'Enlace a factura personalizado', 'total_invoiced' => 'Total facturado', 'open_balance' => 'Saldo abierto', @@ -816,14 +704,12 @@ return array( 'basic_settings' => 'Configuraciones Básicas', 'pro' => 'Pro', 'gateways' => 'Pasarelas de Pago', - 'next_send_on' => 'Próximo envío: :date', 'no_longer_running' => 'Esta factura no esta programada para su ejecución', 'general_settings' => 'Configuraciones Generales', 'customize' => 'Personalizar', 'oneclick_login_help' => 'Conectar una cuenta a un login sin password', 'referral_code_help' => 'Gana dinero compartiendo nuestras aplicacion online', - 'enable_with_stripe' => 'Habilitado | Requiere Stripe', 'tax_settings' => 'Configuraciones de Impuestos', 'create_tax_rate' => 'Añadir Tipo Impositivo', @@ -844,7 +730,6 @@ return array( 'invoice_counter' => 'Contador de Factura', 'quote_counter' => 'Contador de Presupuesto', 'type' => 'Tipo', - 'activity_1' => ':user creó el cliente :client', 'activity_2' => ':user archivó el cliente :client', 'activity_3' => ':user borró el cliente :client', @@ -874,18 +759,24 @@ return array( 'activity_27' => ':user restauró el pago :payment', 'activity_28' => ':user restauró :credit credito', 'activity_29' => ':contact approved presupuesto :quote', - + 'activity_30' => ':user created :vendor', + 'activity_31' => ':user created :vendor', + 'activity_32' => ':user created :vendor', + 'activity_33' => ':user created :vendor', + 'activity_34' => ':user created expense :expense', + 'activity_35' => ':user created :vendor', + 'activity_36' => ':user created :vendor', + 'activity_37' => ':user created :vendor', 'payment' => 'Pago', 'system' => 'Sistema', 'signature' => 'Firma del correo', 'default_messages' => 'Mensajes por defecto', 'quote_terms' => 'Terminos del presupuesto', 'default_quote_terms' => 'Terminos del presupuesto por defecto', - 'default_invoice_terms' => 'Terminos de la factura por defecto', - 'default_invoice_footer' => 'Pie de la factura por defecto', + 'default_invoice_terms' => 'Configurar términos de factura por defecto', + 'default_invoice_footer' => 'Establecer pie de página por defecto en factura', 'quote_footer' => 'Pie del presupuesto', 'free' => 'Gratis', - 'quote_is_approved' => 'Este presupuesto esta aprovado', 'apply_credit' => 'Aplicar Crédito', 'system_settings' => 'Configuración del Sistema', @@ -903,7 +794,6 @@ return array( 'restored_recurring_invoice' => 'Factura periódica restaurada', 'archived' => 'Archivado', 'untitled_account' => 'Compañía sin Nombre', - 'before' => 'Antes', 'after' => 'Despues', 'reset_terms_help' => 'Reset to the default account terms', @@ -912,7 +802,6 @@ return array( 'user' => 'Usuario', 'country' => 'Pais', 'include' => 'Incluir', - 'logo_too_large' => 'El logo es :size, para un buen rendimiento del PDF, sugerimos cargar una imagen de menos de 200KB', 'import_freshbooks' => 'Importar desde FreshBooks', 'import_data' => 'Importar datos', @@ -923,16 +812,6 @@ return array( 'task_file' => 'Fichero de Tareas', 'no_mapper' => 'Mapeo no válido para el fichero', 'invalid_csv_header' => 'Cabecera CSV no Válida', - - 'email_errors' => [ - 'inactive_client' => 'No se pueden enviar correos a Clientes inactivos', - 'inactive_contact' => 'No se pueden enviar correos a Contactos inactivos', - 'inactive_invoice' => 'No se pueden enviar correos de Facturas inactivas', - 'user_unregistered' => 'Por favor registra tu cuenta para enviar correos', - 'user_unconfirmed' => 'Por favor confirma tu cuenta para enviar correos', - 'invalid_contact_email' => 'Correo de contacto no válido', - ], - 'client_portal' => 'Portal Cliente', 'admin' => 'Admin.', 'disabled' => 'Deshabilitado', @@ -941,11 +820,9 @@ return array( 'invoice_will_create' => 'cliente será creado', 'invoices_will_create' => 'facturas seran creadas', 'failed_to_import' => 'Los siguientes registros fallaron al importar', - 'publishable_key' => 'Clave pública', 'secret_key' => 'Clave Privada', 'missing_publishable_key' => 'Establece tu clacve publica de Stripe para mejorar el proceso de checkout', - 'email_design' => 'Diseño de Correo', 'due_by' => 'Pagado en :date', 'enable_email_markup' => 'Habilitar Markup', @@ -957,7 +834,6 @@ return array( 'plain' => 'Plano', 'light' => 'Claro', 'dark' => 'Oscuro', - 'industry_help' => 'Usado para proporcionar comparaciones de las medias de las empresas de tamaño y industria similar.', 'subdomain_help' => 'Personaliza el subdominio para el enlace de la factura o mostrar la factura en su propio sitio web.', 'invoice_number_help' => 'Especifique un prefijo o utilice un patrón a medida para establecer dinámicamente el número de factura.', @@ -966,8 +842,6 @@ return array( 'custom_account_fields_helps' => 'Añadir una etiqueta y valor a la sección de detalles de la empresa del PDF.', 'custom_invoice_fields_helps' => 'Agregar una entrada de texto a la pagina de crear/editar factura y mostrar la etiqueta y el valor en el PDF.', 'custom_invoice_charges_helps' => 'gregar una entrada de texto a la pagina de crear/editar factura y mostrar la carga en los subtotales de la factura.', - 'color_help' => 'Nota: el color primario también se utiliza en el portal del cliente y los diseños de correo electrónico personalizado.', - 'token_expired' => 'Token de validación ha caducado. Por favor, vuelva a intentarlo.', 'invoice_link' => 'Enlace a Factura', 'button_confirmation_message' => 'Pulse aqui para confirmar su dirección de correo.', @@ -976,7 +850,6 @@ return array( 'created_invoices' => ':count factura(s) creada(s) correctamente', 'next_invoice_number' => 'El próximo número de factura es :number.', 'next_quote_number' => 'El próximo número de presupuesto es :number.', - 'days_before' => 'dias antes', 'days_after' => 'dias despues', 'field_due_date' => 'fecha de pago', @@ -984,11 +857,7 @@ return array( 'schedule' => 'Programar', 'email_designs' => 'Diseños de correo', 'assigned_when_sent' => 'Asignado al enviar', - - 'white_label_custom_css' => ':link para $'.WHITE_LABEL_PRICE.' to enable custom styling and help support our project.', 'white_label_purchase_link' => 'Comprar licencia de marca blanca', - - // Expense / vendor 'expense' => 'Gasto', 'expenses' => 'Gastos', 'new_expense' => 'Nuevo Gasto', @@ -1005,8 +874,6 @@ return array( 'archived_expense' => 'Gasto archivado correctamente', 'deleted_expenses' => 'Gastos borrados correctamente', 'archived_expenses' => 'Gastos archivados correctamente', - - // Expenses 'expense_amount' => 'Importe del Gasto', 'expense_balance' => 'Saldo del Gasto', 'expense_date' => 'Fecha del Gasto', @@ -1031,15 +898,11 @@ return array( 'expense_error_multiple_clients' => 'Los gastos no pertenecen a diferentes clientes', 'expense_error_invoiced' => 'El gasto ya ha sido Facturado', 'convert_currency' => 'Convertir moneda', - - // Payment terms 'num_days' => 'Número de días', 'create_payment_term' => 'Crear Término de Pago', 'edit_payment_terms' => 'Editar los Términos de Pago', 'edit_payment_term' => 'Editar el Término de Pago', 'archive_payment_term' => 'Archivar Término de Pago', - - // recurring due dates 'recurring_due_dates' => 'Fecha de Vencimiento de Factura Periodica', 'recurring_due_date_help' => '

    Define automáticamente una fecha de vencimiento de la factura..

    Facturas en un ciclo mensual o anual preparadas para vencer el día que se crearon o antes, vencerán al siguiente mes. Facturas preparadas para vencer el 29 o el 30, en los meses que no tienen ese día, vencerán el último día del mes

    @@ -1066,15 +929,11 @@ return array( 'thursday' => 'Jueves', 'friday' => 'Viernes', 'saturday' => 'Sabado', - - // Fonts 'header_font_id' => 'Tipo de letra de la cabecera', 'body_font_id' => 'Tipo de letra del cuerpo', 'color_font_help' => 'Nota: el color primario y las fuentes también se utilizan en el portal del cliente y los diseños de correo electrónico personalizados.', - 'live_preview' => 'Live Preview', 'invalid_mail_config' => 'Imposible enviar el correo, por favor, comprobar que la configuración de correo es correcta..', - 'invoice_message_button' => 'Para ver su factura con importe :amount, pulse el siguiente botón.', 'quote_message_button' => 'Para ver su presupuesto con importe :amount, pulse el siguiente botón.', 'payment_message_button' => 'Gracias por su pago de :amount.', @@ -1091,7 +950,6 @@ return array( 'archived_bank_account' => 'Cuenta Bancaria archivada correctamente', 'created_bank_account' => 'Cuenta Bancaria creada correctamente', 'validate_bank_account' => 'Validar Cuenta Bancaria', - 'bank_accounts_help' => 'Connect a bank account to automatically import expenses and create vendors. Supports American Express and 400+ US banks.', '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.', 'username' => 'Usuario', @@ -1105,7 +963,6 @@ return array( 'validate' => 'Validar', 'info' => 'Info', 'imported_expenses' => ' :count_vendors proveedor(es) and :count_expenses gasto(s) importados correctamente', - 'iframe_url_help3' => 'Nota: Si piensas aceptar tarjetas de credito recomendamos tener habilitado HTTPS.', '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.', @@ -1126,7 +983,28 @@ return array( 'trial_call_to_action' => 'Start Free Trial', '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.', + + + 'white_label_text' => 'Purchase a ONE YEAR white label license for $:price to remove the Invoice Ninja branding from the client portal and help support our project.', + 'user_email_footer' => 'Para ajustar la configuración de las notificaciones de tu email, visita :link', + 'reset_password_footer' => 'Si no has solicitado un cambio de contraseña, por favor contactate con nosostros: :email', + 'limit_users' => 'Lo sentimos, esta acción excederá el límite de :limit usarios', + 'more_designs_self_host_header' => 'Obtenga 6 diseños más para facturas por sólo $:price', + 'old_browser' => 'Por favor use un navegador mas actual', + 'white_label_custom_css' => ':link para $: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 400+ US banks.', + + 'pro_plan_remove_logo' => ':link haz click para eliminar el logo de Invoice Ninja', + 'pro_plan_remove_logo_link' => 'Haz click aquí', + 'invitation_status_sent' => 'Correo Enviado', + 'invitation_status_opened' => 'Correo abierto', + 'invitation_status_viewed' => 'Factura vista', + 'email_error_inactive_client' => 'No se pueden enviar correos a Clientes inactivos', + 'email_error_inactive_contact' => 'No se pueden enviar correos a Contactos inactivos', + 'email_error_inactive_invoice' => 'No se pueden enviar correos de Facturas inactivas', + 'email_error_user_unregistered' => 'Por favor registra tu cuenta para enviar correos', + 'email_error_user_unconfirmed' => 'Por favor confirma tu cuenta para enviar correos', + 'email_error_invalid_contact_email' => 'Correo de contacto no válido', 'navigation' => 'Navigation', 'list_invoices' => 'List Invoices', @@ -1149,22 +1027,20 @@ return array( 'custom_invoice_item_fields_help' => 'Add a field when creating an invoice item and display the label and value on the PDF.', 'recurring_invoice_number' => 'Recurring Invoice Number', 'recurring_invoice_number_prefix_help' => 'Speciy a prefix to be added to the invoice number for recurring invoices. The default value is \'R\'.', - 'enable_client_portal' => 'Dashboard', - 'enable_client_portal_help' => 'Show/hide the dashboard page in the client portal.', // Client Passwords 'enable_portal_password'=>'Password protect invoices', 'enable_portal_password_help'=>'Allows you to set a password for each contact. If a password is set, the contact will be required to enter a password before viewing invoices.', 'send_portal_password'=>'Generate password automatically', 'send_portal_password_help'=>'If no password is set, one will be generated and sent with the first invoice.', - + 'expired' => 'Expired', 'invalid_card_number' => 'The credit card number is not valid.', 'invalid_expiry' => 'The expiration date is not valid.', 'invalid_cvv' => 'The CVV is not valid.', 'cost' => 'Cost', 'create_invoice_for_sample' => 'Note: create your first invoice to see a preview here.', - + // User Permissions 'owner' => 'Owner', 'administrator' => 'Administrator', @@ -1182,8 +1058,8 @@ return array( 'create_all_help' => 'Allow user to create and modify records', 'view_all_help' => 'Allow user to view records they didn\'t create', 'edit_all_help' => 'Allow user to modify records they didn\'t create', - 'view_payment' => 'View Payment', - + 'view_payment' => 'View Payment', + 'january' => 'January', 'february' => 'February', 'march' => 'March', @@ -1209,30 +1085,28 @@ return array( 'document_email_attachment' => 'Attach Documents', 'download_documents' => 'Download Documents (:size)', 'documents_from_expenses' => 'From Expenses:', - 'dropzone' => array(// See http://www.dropzonejs.com/#config-dictDefaultMessage - 'DefaultMessage' => 'Drop files or click to upload', - 'FallbackMessage' => 'Your browser does not support drag\'n\'drop file uploads.', - 'FallbackText' => 'Please use the fallback form below to upload your files like in the olden days.', - 'FileTooBig' => 'File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.', - 'InvalidFileType' => 'You can\'t upload files of this type.', - 'ResponseError' => 'Server responded with {{statusCode}} code.', - 'CancelUpload' => 'Cancel upload', - 'CancelUploadConfirmation' => 'Are you sure you want to cancel this upload?', - 'RemoveFile' => 'Remove file', - ), + 'dropzone_default_message' => 'Drop files or click to upload', + 'dropzone_fallback_message' => 'Your browser does not support drag\'n\'drop file uploads.', + 'dropzone_fallback_text' => 'Please use the fallback form below to upload your files like in the olden days.', + 'dropzone_file_too_big' => 'File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.', + 'dropzone_invalid_file_type' => 'You can\'t upload files of this type.', + 'dropzone_response_error' => 'Server responded with {{statusCode}} code.', + 'dropzone_cancel_upload' => 'Cancel upload', + 'dropzone_cancel_upload_confirmation' => 'Are you sure you want to cancel this upload?', + 'dropzone_remove_file' => 'Remove file', 'documents' => 'Documents', 'document_date' => 'Document Date', 'document_size' => 'Size', - 'enable_client_portal' => 'Client Portal', - 'enable_client_portal_help' => 'Show/hide the client portal.', + 'enable_client_portal' => 'Dashboard', + 'enable_client_portal_help' => 'Show/hide the dashboard page in the client portal.', 'enable_client_portal_dashboard' => 'Dashboard', 'enable_client_portal_dashboard_help' => 'Show/hide the dashboard page in the client portal.', - + // Plans 'account_management' => 'Account Management', 'plan_status' => 'Plan Status', - + 'plan_upgrade' => 'Upgrade', 'plan_change' => 'Change Plan', 'pending_change_to' => 'Changes To', @@ -1262,9 +1136,9 @@ return array( 'plan_paid' => 'Term Started', 'plan_started' => 'Plan Started', 'plan_expires' => 'Plan Expires', - + 'white_label_button' => 'White Label', - + 'pro_plan_year_description' => 'One year enrollment in the Invoice Ninja Pro Plan.', 'pro_plan_month_description' => 'One month enrollment in the Invoice Ninja Pro Plan.', 'enterprise_plan_product' => 'Enterprise Plan', @@ -1282,7 +1156,207 @@ return array( 'preview' => 'Preview', 'list_vendors' => 'List Vendors', 'add_users_not_supported' => 'Upgrade to the Enterprise plan to add additional users to your account.', - 'enterprise_plan_features' => 'The Enterprise plan adds support for multiple users and file attachments.', + 'enterprise_plan_features' => 'The Enterprise plan adds support for multiple users and file attachments, :link to see the full list of features.', 'return_to_app' => 'Return to app', - + + + // Payment updates + 'refund_payment' => 'Refund Payment', + 'refund_max' => 'Max:', + 'refund' => 'Refund', + 'are_you_sure_refund' => 'Refund selected payments?', + 'status_pending' => 'Pending', + 'status_completed' => 'Completed', + 'status_failed' => 'Failed', + 'status_partially_refunded' => 'Partially Refunded', + 'status_partially_refunded_amount' => ':amount Refunded', + 'status_refunded' => 'Refunded', + 'status_voided' => 'Cancelled', + 'refunded_payment' => 'Refunded Payment', + 'activity_39' => ':user cancelled a :payment_amount payment (:payment)', + 'activity_40' => ':user refunded :adjustment of a :payment_amount payment (:payment)', + 'card_expiration' => 'Exp: :expires', + + 'card_creditcardother' => 'Unknown', + 'card_americanexpress' => 'American Express', + 'card_carteblanche' => 'Carte Blanche', + 'card_unionpay' => 'UnionPay', + 'card_diners' => 'Diners Club', + 'card_discover' => 'Discover', + 'card_jcb' => 'JCB', + 'card_laser' => 'Laser', + 'card_maestro' => 'Maestro', + 'card_mastercard' => 'MasterCard', + 'card_solo' => 'Solo', + 'card_switch' => 'Switch', + 'card_visacard' => 'Visa', + 'card_ach' => 'ACH', + + 'payment_type_stripe' => 'Stripe', + 'ach' => 'ACH', + 'enable_ach' => 'Enable ACH', + 'stripe_ach_help' => 'ACH support must also be enabled at Stripe.', + 'ach_disabled' => 'Another gateway is already configured for direct debit.', + + 'plaid' => 'Plaid', + 'client_id' => 'Client Id', + 'secret' => 'Secret', + 'public_key' => 'Public Key', + 'plaid_optional' => '(optional)', + 'plaid_environment_help' => 'When a Stripe test key is given, Plaid\'s development environement (tartan) will be used.', + 'other_providers' => 'Other Providers', + 'country_not_supported' => 'That country is not supported.', + 'invalid_routing_number' => 'The routing number is not valid.', + 'invalid_account_number' => 'The account number is not valid.', + 'account_number_mismatch' => 'The account numbers do not match.', + 'missing_account_holder_type' => 'Please select an individual or company account.', + 'missing_account_holder_name' => 'Please enter the account holder\'s name.', + 'routing_number' => 'Routing Number', + 'confirm_account_number' => 'Confirm Account Number', + 'individual_account' => 'Individual Account', + 'company_account' => 'Company Account', + 'account_holder_name' => 'Account Holder Name', + 'add_account' => 'Add Account', + 'payment_methods' => 'Payment Methods', + 'complete_verification' => 'Complete Verification', + 'verification_amount1' => 'Amount 1', + 'verification_amount2' => 'Amount 2', + 'payment_method_verified' => 'Verification completed successfully', + 'verification_failed' => 'Verification Failed', + 'remove_payment_method' => 'Remove Payment Method', + 'confirm_remove_payment_method' => 'Are you sure you want to remove this payment method?', + 'remove' => 'Remove', + 'payment_method_removed' => 'Removed payment method.', + 'bank_account_verification_help' => 'We have made two deposits into your account with the description "VERIFICATION". These deposits will take 1-2 business days to appear on your statement. Please enter the amounts below.', + 'bank_account_verification_next_steps' => 'We have made two deposits into your account with the description "VERIFICATION". These deposits will take 1-2 business days to appear on your statement. + Once you have the amounts, come back to this payment methods page and click "Complete Verification" next to the account.', + 'unknown_bank' => 'Unknown Bank', + 'ach_verification_delay_help' => 'You will be able to use the account after completing verification. Verification usually takes 1-2 business days.', + 'add_credit_card' => 'Add Credit Card', + 'payment_method_added' => 'Added payment method.', + 'use_for_auto_bill' => 'Use For Autobill', + 'used_for_auto_bill' => 'Autobill Payment Method', + 'payment_method_set_as_default' => 'Set Autobill payment method.', + 'activity_41' => ':payment_amount payment (:payment) failed', + 'webhook_url' => 'Webhook URL', + 'stripe_webhook_help' => 'You must :link.', + 'stripe_webhook_help_link_text' => 'add this URL as an endpoint at Stripe', + 'payment_method_error' => 'There was an error adding your payment methd. Please try again later.', + 'notification_invoice_payment_failed_subject' => 'Payment failed for Invoice :invoice', + 'notification_invoice_payment_failed' => 'A payment made by client :client towards Invoice :invoice failed. The payment has been marked as failed and :amount has been added to the client\'s balance.', + 'link_with_plaid' => 'Link Account Instantly with Plaid', + 'link_manually' => 'Link Manually', + 'secured_by_plaid' => 'Secured by Plaid', + 'plaid_linked_status' => 'Your bank account at :bank', + 'add_payment_method' => 'Add Payment Method', + 'account_holder_type' => 'Account Holder Type', + 'ach_authorization' => 'I authorize :company to use my bank account for future payments and, if necessary, electronically credit my account to correct erroneous debits. I understand that I may cancel this authorization at any time by removing the payment method or by contacting :email.', + 'ach_authorization_required' => 'You must consent to ACH transactions.', + 'off' => 'Off', + 'opt_in' => 'Opt-in', + 'opt_out' => 'Opt-out', + 'always' => 'Always', + 'opted_out' => 'Opted out', + 'opted_in' => 'Opted in', + 'manage_auto_bill' => 'Manage Auto-bill', + 'enabled' => 'Enabled', + 'paypal' => 'PayPal', + 'braintree_enable_paypal' => 'Enable PayPal payments through BrainTree', + 'braintree_paypal_disabled_help' => 'The PayPal gateway is processing PayPal payments', + 'braintree_paypal_help' => 'You must also :link.', + 'braintree_paypal_help_link_text' => 'link PayPal to your BrainTree account', + 'token_billing_braintree_paypal' => 'Save payment details', + 'add_paypal_account' => 'Add PayPal Account', + + + 'no_payment_method_specified' => 'No payment method specified', + 'chart_type' => 'Chart Type', + 'format' => 'Format', + 'import_ofx' => 'Import OFX', + 'ofx_file' => 'OFX File', + 'ofx_parse_failed' => 'Failed to parse OFX file', + + // WePay + 'wepay' => 'WePay', + 'sign_up_with_wepay' => 'Sign up with WePay', + 'use_another_provider' => 'Use another provider', + 'company_name' => 'Company Name', + 'wepay_company_name_help' => 'This will appear on client\'s credit card statements.', + 'wepay_description_help' => 'The purpose of this account.', + 'wepay_tos_agree' => 'I agree to the :link.', + 'wepay_tos_link_text' => 'WePay Terms of Service', + 'resend_confirmation_email' => 'Resend Confirmation Email', + 'manage_wepay_account' => 'Manage WePay Account', + 'action_required' => 'Action Required', + 'finish_setup' => 'Finish Setup', + 'created_wepay_confirmation_required' => 'Please check your email and confirm your email address with WePay.', + 'switch_to_wepay' => 'Switch to WePay', + 'switch' => 'Switch', + 'restore_account_gateway' => 'Restore Gateway', + 'restored_account_gateway' => 'Successfully restored gateway', + 'united_states' => 'United States', + 'canada' => 'Canada', + 'accept_debit_cards' => 'Accept Debit Cards', + 'debit_cards' => 'Debit Cards', + + 'warn_start_date_changed' => 'The next invoice will be sent on the new start date.', + 'original_start_date' => 'Original start date', + 'new_start_date' => 'New start date', + 'security' => 'Security', + 'see_whats_new' => 'See what\'s new in v:version', + 'wait_for_upload' => 'Please wait for the document upload to complete.', + 'upgrade_for_permissions' => 'Upgrade to our Enterprise plan to enable permissions.', + 'enable_second_tax_rate' => 'Enable specifying a second tax rate', + 'payment_file' => 'Payment File', + 'expense_file' => 'Expense File', + 'product_file' => 'Product File', + 'import_products' => 'Import Products', + 'products_will_create' => 'products will be created.', + 'product_key' => 'Product', + 'created_products' => 'Successfully created :count product(s)', + 'export_help' => 'Use JSON if you plan to import the data into Invoice Ninja.', + 'JSON_file' => 'JSON File', + + 'view_dashboard' => 'View Dashboard', + 'client_session_expired' => 'Session Expired', + 'client_session_expired_message' => 'Your session has expired. Please click the link in your email again.', + + 'auto_bill_notification' => 'This invoice will automatically be billed to your :payment_method on file on :due_date.', + 'auto_bill_payment_method_bank_transfer' => 'bank account', + 'auto_bill_payment_method_credit_card' => 'credit card', + 'auto_bill_payment_method_paypal' => 'PayPal account', + 'auto_bill_notification_placeholder' => 'This invoice will automatically be billed to your credit card on file on the due date.', + 'payment_settings' => 'Payment Settings', + + 'on_send_date' => 'On send date', + 'on_due_date' => 'On due date', + 'auto_bill_ach_date_help' => 'ACH auto bill will always happen on the due date', + 'warn_change_auto_bill' => 'Due to NACHA rules, changes to this invoice may prevent ACH auto bill.', + + 'bank_account' => 'Bank Account', + 'payment_processed_through_wepay' => 'ACH payments will be processed using WePay.', + 'wepay_payment_tos_agree' => 'I agree to the WePay :terms and :privacy_policy.', + 'privacy_policy' => 'Privacy Policy', + 'wepay_payment_tos_agree_required' => 'You must agree to the WePay Terms of Service and Privacy Policy.', + 'payment_settings_supported_gateways' => 'These options are supported by the WePay, Stripe, and Braintree gateways.', + 'ach_email_prompt' => 'Please enter your email address:', + 'verification_pending' => 'Verification Pending', + + 'update_font_cache' => 'Please force refresh the page to update the font cache.', + 'more_options' => 'More options', + 'credit_card' => 'Credit Card', + 'bank_transfer' => 'Bank Transfer', + 'no_transaction_reference' => 'We did not recieve a payment transaction reference from the gateway.', + 'use_bank_on_file' => 'Use Bank on File', + 'auto_bill_email_message' => 'This invoice will automatically be billed to the payment method on file on the due date.', + 'bitcoin' => 'Bitcoin', + 'added_on' => 'Added :date', + 'failed_remove_payment_method' => 'Failed to remove the payment method', + 'gateway_exists' => 'This gateway already exists', + 'manual_entry' => 'Manual entry', + ); + +return $LANG; + +?> diff --git a/resources/lang/fr/texts.php b/resources/lang/fr/texts.php index 10d994d8d8..75a2be95a4 100644 --- a/resources/lang/fr/texts.php +++ b/resources/lang/fr/texts.php @@ -1,8 +1,6 @@ 'Entreprise', 'name' => 'Nom', 'website' => 'Site web', @@ -25,8 +23,6 @@ return array( 'size_id' => 'Taille', 'industry_id' => 'Secteur', 'private_notes' => 'Note personnelle', - - // invoice 'invoice' => 'Facture', 'client' => 'Client', 'invoice_date' => 'Date de la facture', @@ -50,7 +46,6 @@ return array( 'invoice_design_id' => 'Design', 'terms' => 'Conditions', 'your_invoice' => 'Votre facture', - 'remove_contact' => 'Supprimer un contact', 'add_contact' => 'Ajouter un contact', 'create_new_client' => 'Ajouter un nouveau client', @@ -74,8 +69,6 @@ return array( 'settings' => 'Paramètres', 'enable_invoice_tax' => 'Spécifier une
    taxe pour la facture', 'enable_line_item_tax' => 'Spécifier une taxe pour chaque ligne', - - // navigation 'dashboard' => 'Tableau de bord', 'clients' => 'Clients', 'invoices' => 'Factures', @@ -100,8 +93,6 @@ return array( 'provide_email' => 'Veuillez renseigner une adresse courriel valide', 'powered_by' => 'Propulsé par', 'no_items' => 'Aucun élément', - - // recurring invoices 'recurring_invoices' => 'Factures récurrentes', 'recurring_help' => '

    Envoyer automatiquement la même facture à vos clients de façon hebdomadaire, bimensuelle, mensuelle, trimestrielle ou annuelle.

    Utiliser :MONTH, :QUARTER ou :YEAR pour des dates dynamiques. Les opérations simples fonctionnent également, par exemple :MONTH-1.

    @@ -111,8 +102,6 @@ return array(
  • ":YEAR+1 - abonnement annuel" => "2015 - abonnement annuel"
  • "Acompte pour le :QUARTER+1" => "Acompte pour le Q2"
  • ', - - // dashboard 'in_total_revenue' => 'de bénéfice total', 'billed_client' => 'client facturé', 'billed_clients' => 'clients facturés', @@ -121,8 +110,6 @@ return array( 'invoices_past_due' => 'Date limite de paiement dépassée', 'upcoming_invoices' => 'Factures à venir', 'average_invoice' => 'Facture moyenne', - - // list pages 'archive' => 'Archiver', 'delete' => 'Supprimer', 'archive_client' => 'Archiver ce client', @@ -158,8 +145,6 @@ return array( 'select' => 'Sélectionner', 'edit_client' => 'Éditer le client', 'edit_invoice' => 'Éditer la facture', - - // client view page 'create_invoice' => 'Créer une facture', 'enter_credit' => 'Saisissez un crédit', 'last_logged_in' => 'Dernière connexion', @@ -171,12 +156,8 @@ return array( 'message' => 'Message', 'adjustment' => 'Réglements', 'are_you_sure' => 'Voulez-vous vraiment effectuer cette action ?', - - // payment pages 'payment_type_id' => 'Type de paiement', 'amount' => 'Montant', - - // account/company pages 'work_email' => 'Courriel', 'language_id' => 'Langage', 'timezone_id' => 'Fuseau horaire', @@ -194,11 +175,7 @@ return array( 'email_paid' => 'm\'envoyer un courriel quand une facture est payée', 'site_updates' => 'Mises à jour du site', 'custom_messages' => 'Messages personnalisés', - 'default_invoice_terms' => 'Définir comme les conditions par défaut', 'default_email_footer' => 'Définir comme la signature de courriel par défaut', - 'import_clients' => 'Importer des données clients', - 'csv_file' => 'Sélectionner un fichier CSV', - 'export_clients' => 'Exporter des données clients', 'select_file' => 'Veuillez sélectionner un fichier', 'first_row_headers' => 'Utiliser la première ligne comme en-tête', 'column' => 'Colonne', @@ -207,9 +184,12 @@ return array( 'client_will_create' => 'client sera créé', 'clients_will_create' => 'clients seront créés', 'email_settings' => 'Paramètres mail', + 'client_view_styling' => 'Client View Styling', 'pdf_email_attachment' => 'Joindre PDF aux emails', - - // application messages + 'custom_css' => 'Custom CSS', + 'import_clients' => 'Importer des données clients', + 'csv_file' => 'Sélectionner un fichier CSV', + 'export_clients' => 'Exporter des données clients', 'created_client' => 'Client créé avec succès', 'created_clients' => ':count clients créés avec succès', 'updated_settings' => 'Paramètres mis à jour avec succès', @@ -220,14 +200,12 @@ return array( 'payment_error' => 'Il y a eu une erreur lors du traitement de votre paiement. Veuillez réessayer ultérieurement', 'registration_required' => 'Veuillez vous enregistrer pour envoyer une facture par courriel', 'confirmation_required' => 'Veuillez confirmer votre adresse courriel', - 'updated_client' => 'Client modifié avec succès', 'created_client' => 'Client créé avec succès', 'archived_client' => 'Client archivé avec succès', 'archived_clients' => ':count clients archivés avec succès', 'deleted_client' => 'Client supprimé avec succès', 'deleted_clients' => ':count clients supprimés avec succès', - 'updated_invoice' => 'Facture modifiée avec succès', 'created_invoice' => 'Facture créée avec succès', 'cloned_invoice' => 'Facture dupliquée avec succès', @@ -237,21 +215,25 @@ return array( 'archived_invoices' => ':count factures archivées avec succès', 'deleted_invoice' => 'Facture supprimée avec succès', 'deleted_invoices' => ':count factures supprimées avec succès', - 'created_payment' => 'Paiement créé avec succès', + 'created_payments' => 'Successfully created :count payment(s)', 'archived_payment' => 'Paiement archivé avec succès', 'archived_payments' => ':count paiement archivés avec succès', 'deleted_payment' => 'Paiement supprimé avec succès', 'deleted_payments' => ':count paiement supprimés avec succès', 'applied_payment' => 'Paiement appliqué avec succès', - 'created_credit' => 'Crédit créé avec succès', 'archived_credit' => 'Crédit archivé avec succès', 'archived_credits' => ':count crédits archivés avec succès', 'deleted_credit' => 'Crédit supprimé avec succès', 'deleted_credits' => ':count crédits supprimés avec succès', - - // Emails + 'imported_file' => 'Successfully imported file', + 'updated_vendor' => 'Successfully updated vendor', + 'created_vendor' => 'Successfully created vendor', + 'archived_vendor' => 'Successfully archived vendor', + 'archived_vendors' => 'Successfully archived :count vendors', + 'deleted_vendor' => 'Successfully deleted vendor', + 'deleted_vendors' => 'Successfully deleted :count vendors', 'confirmation_subject' => 'Validation du compte Invoice Ninja', 'confirmation_header' => 'Validation du compte', 'confirmation_message' => 'Veuillez cliquer sur le lien ci-après pour valider votre compte.', @@ -262,7 +244,6 @@ return array( 'email_salutation' => 'Cher :name,', 'email_signature' => 'Cordialement,', 'email_from' => 'L\'équipe Invoice Ninja', - 'user_email_footer' => 'Pour modifier vos paramètres de notification par courriel, veuillez visiter '.SITE_URL.'/settings/notifications', 'invoice_link_message' => 'Pour voir la facture de votre client cliquez sur le lien ci-après :', 'notification_invoice_paid_subject' => 'La facture :invoice a été payée par le client :client', 'notification_invoice_sent_subject' => 'La facture :invoice a été envoyée au client :client', @@ -271,32 +252,11 @@ return array( 'notification_invoice_sent' => 'Le client suivant :client a reçu par courriel la facture :invoice d\'un montant de :amount', 'notification_invoice_viewed' => 'Le client suivant :client a vu la facture :invoice d\'un montant de :amount', 'reset_password' => 'Vous pouvez réinitialiser votre mot de passe en cliquant sur le lien suivant :', - 'reset_password_footer' => 'Si vous n\'avez pas effectué de demande de réinitalisation de mot de passe veuillez contacter notre support :'.CONTACT_EMAIL, - - // Payment page 'secure_payment' => 'Paiement sécurisé', 'card_number' => 'Numéro de carte', 'expiration_month' => 'Mois d\'expiration', 'expiration_year' => 'Année d\'expiration', 'cvv' => 'Cryptogramme visuel', - - // Security alerts - 'security' => array( - 'too_many_attempts' => 'Trop de tentatives. Essayez à nouveau dans quelques minutes.', - 'wrong_credentials' => 'Courriel ou mot de passe incorrect', - 'confirmation' => 'Votre compte a été validé !', - 'wrong_confirmation' => 'Code de confirmation incorrect.', - 'password_forgot' => 'Les informations de réinitialisation de votre mot de passe vous ont été envoyées par courriel.', - 'password_reset' => 'Votre mot de passe a été modifié avec succès.', - 'wrong_password_reset' => 'Mot de passe incorrect. Veuillez réessayer', - ), - - // Pro Plan - 'pro_plan' => [ - 'remove_logo' => ':link pour supprimer le logo Invoice Ninja en souscrivant au Plan Pro', - 'remove_logo_link' => 'Cliquez ici', - ], - 'logout' => 'Se déconnecter', 'sign_up_to_save' => 'Connectez vous pour sauvegarder votre travail', 'agree_to_terms' => 'J\'accepte les conditions d\'utilisation d\'Invoice ninja :terms', @@ -307,11 +267,8 @@ return array( 'success_message' => 'Inscription réussie avec succès. Veuillez cliquer sur le lien dans le courriel de confirmation de compte pour vérifier votre adresse courriel.', 'erase_data' => 'Cela supprimera vos données de façon permanente.', 'password' => 'Mot de passe', - 'pro_plan_product' => 'Plan Pro', - 'pro_plan_description' => 'Inscription d\'une durée d\'un an au Plan Pro d\'Invoice ninja', 'pro_plan_success' => 'Merci pour votre inscription ! Une fois la facture réglée, votre adhésion au Plan Pro commencera.', - 'unsaved_changes' => 'Vous avez des modifications non enregistrées', 'custom_fields' => 'Champs personnalisés', 'company_fields' => 'Champs de société', @@ -319,9 +276,8 @@ return array( 'field_label' => 'Nom du champ', 'field_value' => 'Valeur du champ', 'edit' => 'Éditer', + 'set_name' => 'Set your company name', 'view_as_recipient' => 'Voir en tant que destinataire', - - // product management 'product_library' => 'Inventaire', 'product' => 'Produit', 'products' => 'Produits', @@ -336,18 +292,14 @@ return array( 'created_product' => 'Produit créé', 'archived_product' => 'Produit archivé', 'pro_plan_custom_fields' => ':link pour activer les champs personnalisés en rejoingant le Plan Pro', - 'advanced_settings' => 'Paramètres avancés', 'pro_plan_advanced_settings' => ':link pour activer les paramètres avancés en rejoingant le Plan Pro', 'invoice_design' => 'Modèle de facture', 'specify_colors' => 'Spécifiez les couleurs', 'specify_colors_label' => 'Sélectionnez les couleurs utilisés dans les factures', - 'chart_builder' => 'Concepteur de graphiques', 'ninja_email_footer' => 'Utilisez :site pour facturer vos clients et être payés en ligne gratuitement!', 'go_pro' => 'Passez au Plan Pro', - - // Quotes 'quote' => 'Devis', 'quotes' => 'Devis', 'quote_number' => 'Devis numéro', @@ -357,7 +309,6 @@ return array( 'your_quote' => 'Votre devis', 'total' => 'Total', 'clone' => 'Dupliquer', - 'new_quote' => 'Nouveau devis', 'create_quote' => 'Créer un devis', 'edit_quote' => 'Éditer le devis', @@ -368,9 +319,8 @@ return array( 'clone_quote' => 'Dupliquer le devis', 'convert_to_invoice' => 'Convertir en facture', 'view_invoice' => 'Nouvelle facture', - 'view_quote' => 'Voir le devis', 'view_client' => 'Voir le client', - + 'view_quote' => 'Voir le devis', 'updated_quote' => 'Devis mis à jour', 'created_quote' => 'Devis créé', 'cloned_quote' => 'Devis dupliqué avec succès', @@ -380,7 +330,6 @@ return array( 'deleted_quote' => 'Devis supprimé', 'deleted_quotes' => ':count devis ont bien été supprimés', 'converted_to_invoice' => 'Le devis a bien été converti en facture', - 'quote_subject' => 'Nouveau devis de :account', 'quote_message' => 'Pour visionner votre devis de :amount, cliquez sur le lien ci-dessous.', 'quote_link_message' => 'Pour visionner votre soumission, cliquez sur le lien ci-dessous:', @@ -388,16 +337,13 @@ return array( 'notification_quote_viewed_subject' => 'Le devis :invoice a été visionné par :client', 'notification_quote_sent' => 'Le devis :invoice de :amount a été envoyé au client :client.', 'notification_quote_viewed' => 'Le devis :invoice de :amount a été visioné par le client :client.', - 'session_expired' => 'Votre session a expiré.', - 'invoice_fields' => 'Champs de facture', 'invoice_options' => 'Options de facturation', 'hide_quantity' => 'Masquer la quantité', 'hide_quantity_help' => 'Si la quantité de vos produits sont toujours 1, vous pouvez alors masquer la colonne "Quantité".', 'hide_paid_to_date' => 'Masquer "Payé à ce jour"', 'hide_paid_to_date_help' => 'Afficher seulement la ligne "Payé à ce jour"sur les factures pour lesquelles il y a au moins un paiement.', - 'charge_taxes' => 'Taxe supplémentaire', 'user_management' => 'Gestion des utilisateurs', 'add_user' => 'Ajouter utilisateur', @@ -412,21 +358,16 @@ return array( 'active' => 'Actif', 'pending' => 'En attente', 'deleted_user' => 'Utilisateur supprimé', - 'limit_users' => 'Désolé, ceci excédera la limite de '.MAX_NUM_USERS.' utilisateurs', - 'confirm_email_invoice' => 'Voulez-vous vraiment envoyer cette facture par courriel ?', 'confirm_email_quote' => 'Voulez-vous vraiment envoyer ce devis par courriel ?', 'confirm_recurring_email_invoice' => 'Les factures récurrentes sont activées, voulez-vous vraiment envoyer cette facture par courriel ?', - 'cancel_account' => 'Supprimer le compte', 'cancel_account_message' => 'Attention: Ceci supprimera de façon permanente toutes vos données; cette action est irréversible.', 'go_back' => 'Retour', - 'data_visualizations' => 'Visualisation des données', 'sample_data' => 'Données fictives présentées', 'hide' => 'Cacher', 'new_version_available' => 'Une nouvelle version de :releases_link est disponible. Vous utilisez v:user_version, la plus récente est v:latest_version', - 'invoice_settings' => 'Paramètres des factures', 'invoice_number_prefix' => 'Préfixe du numéro de facture', 'invoice_number_counter' => 'Compteur du numéro de facture', @@ -436,59 +377,48 @@ return array( 'invoice_issued_to' => 'Facture destinée à', 'invalid_counter' => 'Pour éviter un éventuel conflit, merci de définir un préfixe pour le numéro de facture ou pour le numéro de devis', 'mark_sent' => 'Marquer comme envoyé', - 'gateway_help_1' => ':link pour vous inscrire à Authorize.net.', 'gateway_help_2' => ':link pour vous inscrire à Authorize.net.', 'gateway_help_17' => ':link pour obtenir votre signature PayPal API.', 'gateway_help_27' => ':link pour vous enregistrer sur TwoCheckout.', - 'more_designs' => 'Plus de modèles', 'more_designs_title' => 'Modèles de factures additionnels', 'more_designs_cloud_header' => 'Passez au Plan Pro pour plus de modèles', 'more_designs_cloud_text' => '', - 'more_designs_self_host_header' => 'Obtenez 6 modèles de factures additionnels pour seulement '.INVOICE_DESIGNS_PRICE.'$', 'more_designs_self_host_text' => '', 'buy' => 'Acheter', 'bought_designs' => 'Les nouveaux modèles ont été ajoutés avec succès', - 'sent' => 'envoyé', + 'vat_number' => 'Numéro de TVA', 'timesheets' => 'Feuilles de temps', - 'payment_title' => 'Entrez votre adresse de facturation et vos informations bancaires', 'payment_cvv' => '*Numéro à 3 ou 4 chiffres au dos de votre carte', 'payment_footer1' => '*L\'adresse de facturation doit correspondre à celle enregistrée avec votre carte bancaire', 'payment_footer2' => '*Merci de cliquer sur "Payer maintenant" une seule fois. Le processus peut prendre jusqu\'à 1 minute.', - 'vat_number' => 'Numéro de TVA', - 'id_number' => 'Numéro ID', 'white_label_link' => 'Marque blanche', 'white_label_header' => 'Marque blanche', 'bought_white_label' => 'Licence marque blanche entrée avec succès', 'white_labeled' => 'Marque blanche', - 'restore' => 'Restaurer', 'restore_invoice' => 'Restaurer la facture', 'restore_quote' => 'Restaurer le devis', 'restore_client' => 'Restaurer le client', 'restore_credit' => 'Restaurer le crédit', 'restore_payment' => 'Restaurer le paiement', - 'restored_invoice' => 'Facture restaurée avec succès', 'restored_quote' => 'Devis restauré avec succès', 'restored_client' => 'Client restauré avec succès', 'restored_payment' => 'Paiement restauré avec succès', 'restored_credit' => 'Crédit restauré avec succès', - 'reason_for_canceling' => 'Aidez nous à améliorer notre site en nous disant pourquoi vous partez.', 'discount_percent' => 'Pourcent', 'discount_amount' => 'Montant', - 'invoice_history' => 'Historique des factures', 'quote_history' => 'Historique des devis', 'current_version' => 'Version courante', - 'select_versiony' => 'Choix de la verison', + 'select_version' => 'Select version', 'view_history' => 'Consulter l\'historique', - 'edit_payment' => 'Editer le paiement', 'updated_payment' => 'Paiement édité avec succès', 'deleted' => 'Supprimé', @@ -501,7 +431,6 @@ return array( 'quote_email' => 'Email de déclaration', 'reset_all' => 'Réinitialiser', 'approve' => 'Accepter', - 'token_billing_type_id' => 'Jeton de paiement', 'token_billing_help' => 'Permet de stocker des cartes de crédit avec votre passerelle, et de déclancher le paiement à une date ultérieure.', 'token_billing_1' => 'Désactiver', @@ -509,12 +438,11 @@ return array( 'token_billing_3' => 'Opt-out - Case à cocher affichée et sélectionné', 'token_billing_4' => 'Toujours', 'token_billing_checkbox' => 'Enregistrer les informations de paiement', - 'view_in_stripe' => 'Voir sur Stripe', - 'use_card_on_file' => 'Use card on file', + 'view_in_gateway' => 'Voir sur :gateway', + 'use_card_on_file' => 'Use Card on File', 'edit_payment_details' => 'Editer les détails de pauement', 'token_billing' => 'Enregister les détails de paiement', - 'token_billing_secure' => 'Les données sont enregistrées de manière sécurisée par :stripe_link', - + 'token_billing_secure' => 'Les données sont enregistrées de manière sécurisée par :link', 'support' => 'Support', 'contact_information' => 'Information de contact', '256_encryption' => 'Cryptage 256 bit', @@ -524,11 +452,8 @@ return array( 'order_overview' => 'Résumé de la commande', 'match_address' => '*L\'adresse doit correspondre à l\'adresse associée à la carte de crédit.', 'click_once' => '*S\'il vous plaît cliquer sur "PAYER MAINTENANT" une seule fois - la transaction peut prendre jusqu\'à 1 minute.', - - 'default_invoice_footer' => 'Définir par défaut', 'invoice_footer' => 'Pied de facture', 'save_as_default_footer' => 'Définir comme pied de facture par défaut', - 'token_management' => 'Gestion des jetons', 'tokens' => 'Jetons', 'add_token' => 'Ajouter jeton', @@ -539,7 +464,6 @@ return array( 'edit_token' => 'Editer jeton', 'delete_token' => 'Supprimer jeton', 'token' => 'Jeton', - 'add_gateway' => 'Ajouter passerelle', 'delete_gateway' => 'Supprimer passerelle', 'edit_gateway' => 'Editer passerelle', @@ -548,7 +472,6 @@ return array( 'deleted_gateway' => 'Passerelle supprimée avec succès', 'pay_with_paypal' => 'PayPal', 'pay_with_card' => 'Carte bancaire', - 'change_password' => 'Changer le mot de passe', 'current_password' => 'Mot de passe actuel', 'new_password' => 'Nouveau mot de passe', @@ -556,7 +479,6 @@ return array( 'password_error_incorrect' => 'Le mot de passe actuel est incorrect.', 'password_error_invalid' => 'Le nouveau mot de passe est invalide', 'updated_password' => 'Mot de passe mis à jour avec succès', - 'api_tokens' => 'Jetons d\'API', 'users_and_tokens' => 'Utilisateurs & jetons', 'account_login' => 'Connexion à votre compte', @@ -568,13 +490,11 @@ return array( 'send_email' => 'Envoyer email', 'set_password' => 'Ajouter mot de passe', 'converted' => 'Converti', - 'email_approved' => 'M\'envoyer un email quand un devis est approuvé', 'notification_quote_approved_subject' => 'Le devis :invoice a été approuvé par :client', 'notification_quote_approved' => 'Le client :client a approuvé le devis :invoice pour un montant de :amount.', 'resend_confirmation' => 'Renvoyer l\'email de confirmation', 'confirmation_resent' => 'L\'email de confirmation a été renvoyé', - 'gateway_help_42' => ':link pour vous inscrire à BitPay
    Remarque:. utiliser une clé API "Legacy", pas un jeton.', 'payment_type_credit_card' => 'Carte de crédit', 'payment_type_paypal' => 'PayPal', @@ -582,7 +502,6 @@ return array( 'knowledge_base' => 'Base de connaissances', 'partial' => 'Partiel', 'partial_remaining' => ':partial de :balance', - 'more_fields' => 'Plus de champs', 'less_fields' => 'Moins de champs', 'client_name' => 'Nom du client', @@ -593,7 +512,6 @@ return array( 'view_documentation' => 'Voir documentation', 'app_title' => 'Outil de facturation gratuit & Open-Source', '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' => 'lignes', 'www' => 'www', 'logo' => 'Logo', @@ -613,7 +531,6 @@ return array( 'zapier' => 'Zapier', 'recurring' => 'Récurrent', 'last_invoice_sent' => 'Dernière facture envoyée le :date', - 'processed_updates' => 'Mise à jour effectuée avec succès', 'tasks' => 'Tâches', 'new_task' => 'Nouvelle tâche', @@ -659,12 +576,10 @@ return array( 'invoice_labels' => 'Champs facture', 'prefix' => 'Préfixe', 'counter' => 'Compteur', - 'payment_type_dwolla' => 'Dwolla', 'gateway_help_43' => ':link pour vous inscrire à Dwolla.', 'partial_value' => 'Doit être supérieur à zéro et inférieur au total', 'more_actions' => 'Plus d\'actions', - 'pro_plan_title' => 'Pro Plan', 'pro_plan_call_to_action' => 'Mettre à jour maintenant !', 'pro_plan_feature1' => 'Créer un nombre illimité de clients', @@ -675,14 +590,12 @@ return array( 'pro_plan_feature6' => 'Créer des factures Quotes & Pro-forma', 'pro_plan_feature7' => 'Personnaliser les champs Titres et Numérotation des factures', 'pro_plan_feature8' => 'Option pour attacher des PDFs aux courriels pour le client', - 'resume' => 'Reprendre', 'break_duration' => 'Pause', 'edit_details' => 'Modifier', 'work' => 'Travail', 'timezone_unset' => 'Merci de :link pour définir votre fuseau horaire', 'click_here' => 'cliquer ici', - 'email_receipt' => 'Envoyer le reçu par courriel au client', 'created_payment_emailed_client' => 'Paiement crée avec succès et envoyé au client', 'add_company' => 'Ajouter compte', @@ -692,10 +605,8 @@ return array( 'unlinked_account' => 'Compte déliés avec succès.', 'login' => 'Connexion', 'or' => 'ou', - 'email_error' => 'Il y a eu un problème en envoyant le courriel', 'confirm_recurring_timing' => 'Note : les courriels sont envoyés au début de l\'heure.', - 'old_browser' => 'Merci d\'utiliser un navigateur plus récent', 'payment_terms_help' => 'Définir la date d\'échéance par défaut de la facture', 'unlink_account' => 'Dissocier le compte', 'unlink' => 'Dissocier', @@ -716,7 +627,6 @@ return array( 'primary_color' => 'Couleur principale', 'secondary_color' => 'Couleur secondaire', 'customize_design' => 'Design personnalisé', - 'content' => 'Contenu', 'styles' => 'Styles', 'defaults' => 'Valeurs par défaut', @@ -730,17 +640,16 @@ return array( 'outstanding' => 'Impayé', 'manage_companies' => 'Gérer les sociétés', 'total_revenue' => 'Revenu total', - 'current_user' => 'Utilisateur actuel', 'new_recurring_invoice' => 'Nouvelle facture récurrente', 'recurring_invoice' => 'Facture récurrente', + 'recurring_too_soon' => 'Il est trop tôt pour créer la prochaine facture récurrente, prévue pour le :date', 'created_by_invoice' => 'Créé par :invoice', 'primary_user' => 'Utilisateur principal', 'help' => 'Aide', - 'customize_help' => '

    Nous utilisons pdfmake pour définir le design des factures. Le bac à sable de pdfmake est une bonne façon de voir cette bibliothèque en action.

    -

    Pour accéder à une propriété héritée avec la notation par point. Par exemple pour montrer le nom du client vous pouvez utiliser $client.name.

    -

    Si vous avez besoin d\'aide pour comprendre quelque chose envoyez une question à notre forum de support.

    ', - + 'customize_help' => '

    We use pdfmake to define the invoice designs declaratively. The pdfmake playground provide\'s a great way to see the library in action.

    +

    You can access a child property using dot notation. For example to show the client name you could use $client.name.

    +

    If you need help figuring something out post a question to our support forum with the design you\'re using.

    ', 'invoice_due_date' => 'Date limite', 'quote_due_date' => 'Date limite', 'valid_until' => 'Valide jusqu\'au', @@ -753,15 +662,12 @@ return array( 'status_partial' => 'Partiel', 'status_paid' => 'Payé', 'show_line_item_tax' => 'Display line item taxes inline', - 'iframe_url' => 'Site internet', 'iframe_url_help1' => 'Copiez le code suivant sur une page de votre site.', 'iframe_url_help2' => 'Vous pouvez tester la fonctionnalité en cliquant sur \'Voir en tant que destinataire\' pour une facture.', - 'auto_bill' => 'Facturation automatique', 'military_time' => '24H', 'last_sent' => 'Dernier envoi', - 'reminder_emails' => 'Emails de rappel', 'templates_and_reminders' => 'Templates & Rappels', 'subject' => 'Sujet', @@ -773,15 +679,12 @@ return array( 'reminder_subject' => 'Rappel: Facture :invoice de :account', 'reset' => 'Remettre à zéro', 'invoice_not_found' => 'La facture demandée n\'est pas disponible', - 'referral_program' => 'Programme de parrainage', 'referral_code' => 'Code de Parrainage', 'last_sent_on' => 'Dernier envoi le :date', - 'page_expire' => 'Cette page va bientôt expirer, :click_here pour continuer à travailler', 'upcoming_quotes' => 'Devis à venir', 'expired_quotes' => 'Devis expirés', - 'sign_up_using' => 'Connexion avec', 'invalid_credentials' => 'Ces informations de connexion sont invalides', 'show_all_options' => 'Voir toutes les options', @@ -790,17 +693,10 @@ return array( 'disable' => 'Désactiver', 'invoice_quote_number' => 'Numéro des devis & factures', 'invoice_charges' => 'Charges de facturation', - - 'invitation_status' => [ - 'sent' => 'Email envoyé', - 'opened' => 'Email ouvert', - 'viewed' => 'Facture vue', - ], 'notification_invoice_bounced' => 'We were unable to deliver Invoice :invoice to :contact.', 'notification_invoice_bounced_subject' => 'Unable to deliver Invoice :invoice', 'notification_quote_bounced' => 'We were unable to deliver Quote :invoice to :contact.', 'notification_quote_bounced_subject' => 'Unable to deliver Quote :invoice', - 'custom_invoice_link' => 'Personnaliser le lien de la facture', 'total_invoiced' => 'Total facturé', 'open_balance' => 'Open Balance', @@ -808,16 +704,12 @@ return array( 'basic_settings' => 'Paramètres généraux', 'pro' => 'Pro', 'gateways' => 'Passerelles de paiement', - 'recurring_too_soon' => 'Il est trop tôt pour créer la prochaine facture récurrente, prévue pour le :date', - 'next_send_on' => 'Envoi suivant: :date', 'no_longer_running' => 'This invoice is not scheduled to run', 'general_settings' => 'Réglages généraux', 'customize' => 'Personnaliser', - 'oneclick_login_help' => 'Connectez un compte pour vous connecter sans votre mot de passe', 'referral_code_help' => 'Gagnez de l\'argent en partagent notre outil en ligne', - 'enable_with_stripe' => 'Activer | Stripe est requis', 'tax_settings' => 'Réglages des taxes', 'create_tax_rate' => 'Ajouter un taux de taxe.', @@ -838,7 +730,6 @@ return array( 'invoice_counter' => 'Compteur de factures', 'quote_counter' => 'Compteur de devis', 'type' => 'Type', - 'activity_1' => ':user a crée le client :client', 'activity_2' => ':user a archivé le client :client', 'activity_3' => ':user a supprimé le client :client', @@ -868,18 +759,24 @@ return array( 'activity_27' => ':user a restauré le paiement :payment', 'activity_28' => ':user a restauré le crédit :credit', 'activity_29' => ':contact a approuvé le devis :quote', - + 'activity_30' => ':user created :vendor', + 'activity_31' => ':user created :vendor', + 'activity_32' => ':user created :vendor', + 'activity_33' => ':user created :vendor', + 'activity_34' => ':user created expense :expense', + 'activity_35' => ':user created :vendor', + 'activity_36' => ':user created :vendor', + 'activity_37' => ':user created :vendor', 'payment' => 'Paiement', 'system' => 'Système', 'signature' => 'Signature email', 'default_messages' => 'Messages par défaut', 'quote_terms' => 'Conditions des devis', 'default_quote_terms' => 'Conditions des devis par défaut', - 'default_invoice_terms' => 'Conditions des factures par défaut', - 'default_invoice_footer' => 'Pied de page des factures par défaut', + 'default_invoice_terms' => 'Définir comme les conditions par défaut', + 'default_invoice_footer' => 'Définir par défaut', 'quote_footer' => 'Pied de page des devis', 'free' => 'Gratuit', - 'quote_is_approved' => 'Ce devis est approuvé', 'apply_credit' => 'Appliquer crédit', 'system_settings' => 'Paramètres système', @@ -897,7 +794,6 @@ return array( 'restored_recurring_invoice' => 'Facture récurrente restaurée avec succès', 'archived' => 'Archivé', 'untitled_account' => 'Société sans nom', - 'before' => 'Avant', 'after' => 'Après', 'reset_terms_help' => 'Remettre les conditions par défaut', @@ -906,7 +802,6 @@ return array( 'user' => 'Utilisateur', 'country' => 'Pays', 'include' => 'Inclure', - 'logo_too_large' => 'Your logo is :size, for better PDF performance we suggest uploading an image file less than 200KB', 'import_freshbooks' => 'Importer depuis FreshBooks', 'import_data' => 'Importer des données', @@ -917,16 +812,6 @@ return array( 'task_file' => 'Fichier de tâches', 'no_mapper' => 'Mappage invalide pour ce fichier', 'invalid_csv_header' => 'En-tête du fichier CSV invalide', - - 'email_errors' => [ - 'inactive_client' => 'Les mails ne peuvent être envoyés aux clients inactifs', - 'inactive_contact' => 'Les mails ne peuvent être envoyés aux contacts inactifs', - 'inactive_invoice' => 'Les mails ne peuvent être envoyés aux factures inactives', - 'user_unregistered' => 'Veuillez vous inscrire afin d\'envoyer des mails', - 'user_unconfirmed' => 'Veuillez confirmer votre compte afin de permettre l\'envoi de mail', - 'invalid_contact_email' => 'Adresse mail du contact invalide', - ], - 'client_portal' => 'Portail client', 'admin' => 'Admin', 'disabled' => 'Désactivé', @@ -935,11 +820,9 @@ return array( 'invoice_will_create' => 'client will be created', 'invoices_will_create' => 'invoices will be created', 'failed_to_import' => 'The following records failed to import, they either already exist or are missing required fields.', - 'publishable_key' => 'Clé publique', 'secret_key' => 'Clé secrète', 'missing_publishable_key' => 'Saisissez votre clé publique Stripe pour un processus de commande amélioré', - 'email_design' => 'Email Design', 'due_by' => 'A échéanche du :date', 'enable_email_markup' => 'Enable Markup', @@ -951,7 +834,6 @@ return array( 'plain' => 'Brut', 'light' => 'Clair', 'dark' => 'Sombre', - 'industry_help' => 'Utilisé dans le but de fournir des statistiques la taille et le secteur de l\'entreprise.', '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.', @@ -960,8 +842,6 @@ return array( '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_charges_helps' => 'Add a text input to the invoice create/edit page and include the charge in the invoice subtotals.', - 'color_help' => 'Note: the primary color is also used in the client portal and custom email designs.', - 'token_expired' => 'Validation jeton expiré. Veuillez réessayer.', 'invoice_link' => 'Lien vers la facture', 'button_confirmation_message' => 'Cliquez pour confirmer votre adresse e-mail.', @@ -970,7 +850,6 @@ return array( 'created_invoices' => ':count factures(s) créées avec succès', 'next_invoice_number' => 'Le prochain numéro de facture est :number.', 'next_quote_number' => 'Le prochain numéro de devis est :number.', - 'days_before' => 'days before', 'days_after' => 'days after', 'field_due_date' => 'date d\'échéance', @@ -978,11 +857,7 @@ return array( 'schedule' => 'Schedule', 'email_designs' => 'Email Designs', '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' => 'Acheter une licence marque blanche', - - // Expense / vendor 'expense' => 'Dépense', 'expenses' => 'Dépenses', 'new_expense' => 'Enter Expense', @@ -999,8 +874,6 @@ return array( 'archived_expense' => 'Successfully archived expense', 'deleted_expenses' => 'Successfully deleted expenses', 'archived_expenses' => 'Successfully archived expenses', - - // Expenses 'expense_amount' => 'Montant de la dépense', 'expense_balance' => 'Expense Balance', 'expense_date' => 'Date de la dépense', @@ -1018,22 +891,18 @@ return array( 'view_expense_num' => 'Dépense # :expense', 'updated_expense' => 'Successfully updated expense', 'created_expense' => 'Successfully created expense', - 'enter_expense' => 'Entrer la dépense', + 'enter_expense' => 'Enter Expense', 'view' => 'Voir', 'restore_expense' => 'Restorer la dépense', 'invoice_expense' => 'Invoice Expense', 'expense_error_multiple_clients' => 'The expenses can\'t belong to different clients', 'expense_error_invoiced' => 'Expense has already been invoiced', 'convert_currency' => 'Convert currency', - - // Payment terms 'num_days' => 'Nombre de jours', 'create_payment_term' => 'Créer une condition de paiement', 'edit_payment_terms' => 'Editer condition de paiement', 'edit_payment_term' => 'Editer la condition de paiement', 'archive_payment_term' => 'Archiver la condition de paiement', - - // recurring due dates 'recurring_due_dates' => 'Recurring Invoice Due Dates', 'recurring_due_date_help' => '

    Automatically sets a due date for the invoice.

    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.

    @@ -1061,15 +930,11 @@ return array( 'thursday' => 'Jeudi', 'friday' => 'Vendredi', 'saturday' => 'Samedi', - - // Fonts 'header_font_id' => 'Header 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.', - 'live_preview' => 'Aperçu', 'invalid_mail_config' => 'Impossible d\'envoyer le mail, veuillez vérifier que les paramètres de messagerie sont corrects.', - 'invoice_message_button' => 'Pour visionner votre facture de :amount, cliquer sur le lien ci-dessous', 'quote_message_button' => 'Pour visionner votre devis de :amount, cliquer sur le lien ci-dessous', 'payment_message_button' => 'Merci pour votre paiement de :amount.', @@ -1086,7 +951,6 @@ return array( 'archived_bank_account' => 'Compte bancaire archivé', 'created_bank_account' => 'Compte bancaire créé', 'validate_bank_account' => 'Valider le compte bancaire', - 'bank_accounts_help' => 'Connect a bank account to automatically import expenses and create vendors. Supports American Express and 400+ US banks.', 'bank_password_help' => 'Note: your password is transmitted securely and never stored on our servers.', 'bank_password_warning' => 'Attention: votre mot de passe peut être transmis en clair, pensez à activer HTTPS.', 'username' => 'Nom d\'utilisateur', @@ -1100,7 +964,6 @@ return array( 'validate' => 'Valider', 'info' => 'Info', '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.', '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.', @@ -1121,7 +984,28 @@ return array( 'trial_call_to_action' => 'Commencer l\'essai gratuit', 'trial_success' => 'Successfully enabled two week free pro plan trial', 'overdue' => 'Impayé', - '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 $:price to remove the Invoice Ninja branding from the client portal and help support our project.', + 'user_email_footer' => 'Pour modifier vos paramètres de notification par courriel, veuillez visiter :link', + 'reset_password_footer' => 'Si vous n\'avez pas effectué de demande de réinitalisation de mot de passe veuillez contacter notre support : :email', + 'limit_users' => 'Désolé, ceci excédera la limite de :limit utilisateurs', + 'more_designs_self_host_header' => 'Obtenez 6 modèles de factures additionnels pour seulement $:price', + 'old_browser' => 'Merci d\'utiliser un navigateur plus récent', + 'white_label_custom_css' => ':link for $: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 400+ US banks.', + + 'pro_plan_remove_logo' => ':link pour supprimer le logo Invoice Ninja en souscrivant au Plan Pro', + 'pro_plan_remove_logo_link' => 'Cliquez ici', + 'invitation_status_sent' => 'Email envoyé', + 'invitation_status_opened' => 'Email ouvert', + 'invitation_status_viewed' => 'Facture vue', + 'email_error_inactive_client' => 'Les mails ne peuvent être envoyés aux clients inactifs', + 'email_error_inactive_contact' => 'Les mails ne peuvent être envoyés aux contacts inactifs', + 'email_error_inactive_invoice' => 'Les mails ne peuvent être envoyés aux factures inactives', + 'email_error_user_unregistered' => 'Veuillez vous inscrire afin d\'envoyer des mails', + 'email_error_user_unconfirmed' => 'Veuillez confirmer votre compte afin de permettre l\'envoi de mail', + 'email_error_invalid_contact_email' => 'Adresse mail du contact invalide', 'navigation' => 'Navigation', 'list_invoices' => 'Liste des factures', @@ -1144,22 +1028,20 @@ return array( 'custom_invoice_item_fields_help' => 'Add a field when creating an invoice item and display the label and value on the PDF.', 'recurring_invoice_number' => 'Recurring Invoice Number', 'recurring_invoice_number_prefix_help' => 'Speciy a prefix to be added to the invoice number for recurring invoices. The default value is \'R\'.', - 'enable_client_portal' => 'Tableau de bord', - 'enable_client_portal_help' => 'Afficher / masquer le tableau de bord sur le portail client.', // Client Passwords 'enable_portal_password'=>'Protéger les factures avec un mot de passe', 'enable_portal_password_help'=>'Allows you to set a password for each contact. If a password is set, the contact will be required to enter a password before viewing invoices.', 'send_portal_password'=>'Générer un mot de passe automatiquement', 'send_portal_password_help'=>'If no password is set, one will be generated and sent with the first invoice.', - + 'expired' => 'Expiré', 'invalid_card_number' => 'Le numéro de carte bancaire est invalide.', 'invalid_expiry' => 'La date d\'expiration est invalide.', 'invalid_cvv' => 'Le code de sécurité est incorrect.', 'cost' => 'Coût', 'create_invoice_for_sample' => 'Note: create your first invoice to see a preview here.', - + // User Permissions 'owner' => 'Propriétaire', 'administrator' => 'Administrateur', @@ -1177,8 +1059,8 @@ return array( 'create_all_help' => 'Autoriser l\'utilisateur à créer et éditer tous les enregistrements', 'view_all_help' => 'Allow user to view records they didn\'t create', 'edit_all_help' => 'Allow user to modify records they didn\'t create', - 'view_payment' => 'Voir le paiement', - + 'view_payment' => 'Voir le paiement', + 'january' => 'Janvier', 'february' => 'Février', 'march' => 'Mars', @@ -1204,30 +1086,28 @@ return array( 'document_email_attachment' => 'Attach Documents', 'download_documents' => 'Download Documents (:size)', 'documents_from_expenses' => 'From Expenses:', - 'dropzone' => array(// See http://www.dropzonejs.com/#config-dictDefaultMessage - 'DefaultMessage' => 'Drop files or click to upload', - 'FallbackMessage' => 'Your browser does not support drag\'n\'drop file uploads.', - 'FallbackText' => 'Please use the fallback form below to upload your files like in the olden days.', - 'FileTooBig' => 'File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.', - 'InvalidFileType' => 'You can\'t upload files of this type.', - 'ResponseError' => 'Server responded with {{statusCode}} code.', - 'CancelUpload' => 'Cancel upload', - 'CancelUploadConfirmation' => 'Are you sure you want to cancel this upload?', - 'RemoveFile' => 'Remove file', - ), + 'dropzone_default_message' => 'Drop files or click to upload', + 'dropzone_fallback_message' => 'Your browser does not support drag\'n\'drop file uploads.', + 'dropzone_fallback_text' => 'Please use the fallback form below to upload your files like in the olden days.', + 'dropzone_file_too_big' => 'File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.', + 'dropzone_invalid_file_type' => 'You can\'t upload files of this type.', + 'dropzone_response_error' => 'Server responded with {{statusCode}} code.', + 'dropzone_cancel_upload' => 'Cancel upload', + 'dropzone_cancel_upload_confirmation' => 'Are you sure you want to cancel this upload?', + 'dropzone_remove_file' => 'Remove file', 'documents' => 'Documents', 'document_date' => 'Document Date', 'document_size' => 'Size', - 'enable_client_portal' => 'Client Portal', - 'enable_client_portal_help' => 'Show/hide the client portal.', + 'enable_client_portal' => 'Tableau de bord', + 'enable_client_portal_help' => 'Afficher / masquer le tableau de bord sur le portail client.', 'enable_client_portal_dashboard' => 'Dashboard', 'enable_client_portal_dashboard_help' => 'Show/hide the dashboard page in the client portal.', - + // Plans 'account_management' => 'Account Management', 'plan_status' => 'Plan Status', - + 'plan_upgrade' => 'Upgrade', 'plan_change' => 'Change Plan', 'pending_change_to' => 'Changes To', @@ -1257,9 +1137,9 @@ return array( 'plan_paid' => 'Term Started', 'plan_started' => 'Plan Started', 'plan_expires' => 'Plan Expires', - + 'white_label_button' => 'White Label', - + 'pro_plan_year_description' => 'One year enrollment in the Invoice Ninja Pro Plan.', 'pro_plan_month_description' => 'One month enrollment in the Invoice Ninja Pro Plan.', 'enterprise_plan_product' => 'Enterprise Plan', @@ -1270,14 +1150,214 @@ return array( 'plan_pending_monthly' => 'Will switch to monthly on :date', 'plan_refunded' => 'A refund has been issued.', - 'live_preview' => 'Live Preview', + 'live_preview' => 'Aperçu', 'page_size' => 'Page Size', 'live_preview_disabled' => 'Live preview has been disabled to support selected font', 'invoice_number_padding' => 'Padding', 'preview' => 'Preview', 'list_vendors' => 'List Vendors', 'add_users_not_supported' => 'Upgrade to the Enterprise plan to add additional users to your account.', - 'enterprise_plan_features' => 'The Enterprise plan adds support for multiple users and file attachments.', + 'enterprise_plan_features' => 'The Enterprise plan adds support for multiple users and file attachments, :link to see the full list of features.', 'return_to_app' => 'Return to app', - + + + // Payment updates + 'refund_payment' => 'Refund Payment', + 'refund_max' => 'Max:', + 'refund' => 'Refund', + 'are_you_sure_refund' => 'Refund selected payments?', + 'status_pending' => 'Pending', + 'status_completed' => 'Completed', + 'status_failed' => 'Failed', + 'status_partially_refunded' => 'Partially Refunded', + 'status_partially_refunded_amount' => ':amount Refunded', + 'status_refunded' => 'Refunded', + 'status_voided' => 'Cancelled', + 'refunded_payment' => 'Refunded Payment', + 'activity_39' => ':user cancelled a :payment_amount payment (:payment)', + 'activity_40' => ':user refunded :adjustment of a :payment_amount payment (:payment)', + 'card_expiration' => 'Exp: :expires', + + 'card_creditcardother' => 'Unknown', + 'card_americanexpress' => 'American Express', + 'card_carteblanche' => 'Carte Blanche', + 'card_unionpay' => 'UnionPay', + 'card_diners' => 'Diners Club', + 'card_discover' => 'Discover', + 'card_jcb' => 'JCB', + 'card_laser' => 'Laser', + 'card_maestro' => 'Maestro', + 'card_mastercard' => 'MasterCard', + 'card_solo' => 'Solo', + 'card_switch' => 'Switch', + 'card_visacard' => 'Visa', + 'card_ach' => 'ACH', + + 'payment_type_stripe' => 'Stripe', + 'ach' => 'ACH', + 'enable_ach' => 'Enable ACH', + 'stripe_ach_help' => 'ACH support must also be enabled at Stripe.', + 'ach_disabled' => 'Another gateway is already configured for direct debit.', + + 'plaid' => 'Plaid', + 'client_id' => 'Client Id', + 'secret' => 'Secret', + 'public_key' => 'Public Key', + 'plaid_optional' => '(optional)', + 'plaid_environment_help' => 'When a Stripe test key is given, Plaid\'s development environement (tartan) will be used.', + 'other_providers' => 'Other Providers', + 'country_not_supported' => 'That country is not supported.', + 'invalid_routing_number' => 'The routing number is not valid.', + 'invalid_account_number' => 'The account number is not valid.', + 'account_number_mismatch' => 'The account numbers do not match.', + 'missing_account_holder_type' => 'Please select an individual or company account.', + 'missing_account_holder_name' => 'Please enter the account holder\'s name.', + 'routing_number' => 'Routing Number', + 'confirm_account_number' => 'Confirm Account Number', + 'individual_account' => 'Individual Account', + 'company_account' => 'Company Account', + 'account_holder_name' => 'Account Holder Name', + 'add_account' => 'Add Account', + 'payment_methods' => 'Payment Methods', + 'complete_verification' => 'Complete Verification', + 'verification_amount1' => 'Amount 1', + 'verification_amount2' => 'Amount 2', + 'payment_method_verified' => 'Verification completed successfully', + 'verification_failed' => 'Verification Failed', + 'remove_payment_method' => 'Remove Payment Method', + 'confirm_remove_payment_method' => 'Are you sure you want to remove this payment method?', + 'remove' => 'Remove', + 'payment_method_removed' => 'Removed payment method.', + 'bank_account_verification_help' => 'We have made two deposits into your account with the description "VERIFICATION". These deposits will take 1-2 business days to appear on your statement. Please enter the amounts below.', + 'bank_account_verification_next_steps' => 'We have made two deposits into your account with the description "VERIFICATION". These deposits will take 1-2 business days to appear on your statement. + Once you have the amounts, come back to this payment methods page and click "Complete Verification" next to the account.', + 'unknown_bank' => 'Unknown Bank', + 'ach_verification_delay_help' => 'You will be able to use the account after completing verification. Verification usually takes 1-2 business days.', + 'add_credit_card' => 'Add Credit Card', + 'payment_method_added' => 'Added payment method.', + 'use_for_auto_bill' => 'Use For Autobill', + 'used_for_auto_bill' => 'Autobill Payment Method', + 'payment_method_set_as_default' => 'Set Autobill payment method.', + 'activity_41' => ':payment_amount payment (:payment) failed', + 'webhook_url' => 'Webhook URL', + 'stripe_webhook_help' => 'You must :link.', + 'stripe_webhook_help_link_text' => 'add this URL as an endpoint at Stripe', + 'payment_method_error' => 'There was an error adding your payment methd. Please try again later.', + 'notification_invoice_payment_failed_subject' => 'Payment failed for Invoice :invoice', + 'notification_invoice_payment_failed' => 'A payment made by client :client towards Invoice :invoice failed. The payment has been marked as failed and :amount has been added to the client\'s balance.', + 'link_with_plaid' => 'Link Account Instantly with Plaid', + 'link_manually' => 'Link Manually', + 'secured_by_plaid' => 'Secured by Plaid', + 'plaid_linked_status' => 'Your bank account at :bank', + 'add_payment_method' => 'Add Payment Method', + 'account_holder_type' => 'Account Holder Type', + 'ach_authorization' => 'I authorize :company to use my bank account for future payments and, if necessary, electronically credit my account to correct erroneous debits. I understand that I may cancel this authorization at any time by removing the payment method or by contacting :email.', + 'ach_authorization_required' => 'You must consent to ACH transactions.', + 'off' => 'Off', + 'opt_in' => 'Opt-in', + 'opt_out' => 'Opt-out', + 'always' => 'Always', + 'opted_out' => 'Opted out', + 'opted_in' => 'Opted in', + 'manage_auto_bill' => 'Manage Auto-bill', + 'enabled' => 'Enabled', + 'paypal' => 'PayPal', + 'braintree_enable_paypal' => 'Enable PayPal payments through BrainTree', + 'braintree_paypal_disabled_help' => 'The PayPal gateway is processing PayPal payments', + 'braintree_paypal_help' => 'You must also :link.', + 'braintree_paypal_help_link_text' => 'link PayPal to your BrainTree account', + 'token_billing_braintree_paypal' => 'Save payment details', + 'add_paypal_account' => 'Add PayPal Account', + + + 'no_payment_method_specified' => 'No payment method specified', + 'chart_type' => 'Chart Type', + 'format' => 'Format', + 'import_ofx' => 'Import OFX', + 'ofx_file' => 'OFX File', + 'ofx_parse_failed' => 'Failed to parse OFX file', + + // WePay + 'wepay' => 'WePay', + 'sign_up_with_wepay' => 'Sign up with WePay', + 'use_another_provider' => 'Use another provider', + 'company_name' => 'Company Name', + 'wepay_company_name_help' => 'This will appear on client\'s credit card statements.', + 'wepay_description_help' => 'The purpose of this account.', + 'wepay_tos_agree' => 'I agree to the :link.', + 'wepay_tos_link_text' => 'WePay Terms of Service', + 'resend_confirmation_email' => 'Resend Confirmation Email', + 'manage_wepay_account' => 'Manage WePay Account', + 'action_required' => 'Action Required', + 'finish_setup' => 'Finish Setup', + 'created_wepay_confirmation_required' => 'Please check your email and confirm your email address with WePay.', + 'switch_to_wepay' => 'Switch to WePay', + 'switch' => 'Switch', + 'restore_account_gateway' => 'Restore Gateway', + 'restored_account_gateway' => 'Successfully restored gateway', + 'united_states' => 'United States', + 'canada' => 'Canada', + 'accept_debit_cards' => 'Accept Debit Cards', + 'debit_cards' => 'Debit Cards', + + 'warn_start_date_changed' => 'The next invoice will be sent on the new start date.', + 'original_start_date' => 'Original start date', + 'new_start_date' => 'New start date', + 'security' => 'Security', + 'see_whats_new' => 'See what\'s new in v:version', + 'wait_for_upload' => 'Please wait for the document upload to complete.', + 'upgrade_for_permissions' => 'Upgrade to our Enterprise plan to enable permissions.', + 'enable_second_tax_rate' => 'Enable specifying a second tax rate', + 'payment_file' => 'Payment File', + 'expense_file' => 'Expense File', + 'product_file' => 'Product File', + 'import_products' => 'Import Products', + 'products_will_create' => 'products will be created.', + 'product_key' => 'Product', + 'created_products' => 'Successfully created :count product(s)', + 'export_help' => 'Use JSON if you plan to import the data into Invoice Ninja.', + 'JSON_file' => 'JSON File', + + 'view_dashboard' => 'View Dashboard', + 'client_session_expired' => 'Session Expired', + 'client_session_expired_message' => 'Your session has expired. Please click the link in your email again.', + + 'auto_bill_notification' => 'This invoice will automatically be billed to your :payment_method on file on :due_date.', + 'auto_bill_payment_method_bank_transfer' => 'bank account', + 'auto_bill_payment_method_credit_card' => 'credit card', + 'auto_bill_payment_method_paypal' => 'PayPal account', + 'auto_bill_notification_placeholder' => 'This invoice will automatically be billed to your credit card on file on the due date.', + 'payment_settings' => 'Payment Settings', + + 'on_send_date' => 'On send date', + 'on_due_date' => 'On due date', + 'auto_bill_ach_date_help' => 'ACH auto bill will always happen on the due date', + 'warn_change_auto_bill' => 'Due to NACHA rules, changes to this invoice may prevent ACH auto bill.', + + 'bank_account' => 'Bank Account', + 'payment_processed_through_wepay' => 'ACH payments will be processed using WePay.', + 'wepay_payment_tos_agree' => 'I agree to the WePay :terms and :privacy_policy.', + 'privacy_policy' => 'Privacy Policy', + 'wepay_payment_tos_agree_required' => 'You must agree to the WePay Terms of Service and Privacy Policy.', + 'payment_settings_supported_gateways' => 'These options are supported by the WePay, Stripe, and Braintree gateways.', + 'ach_email_prompt' => 'Please enter your email address:', + 'verification_pending' => 'Verification Pending', + + 'update_font_cache' => 'Please force refresh the page to update the font cache.', + 'more_options' => 'More options', + 'credit_card' => 'Credit Card', + 'bank_transfer' => 'Bank Transfer', + 'no_transaction_reference' => 'We did not recieve a payment transaction reference from the gateway.', + 'use_bank_on_file' => 'Use Bank on File', + 'auto_bill_email_message' => 'This invoice will automatically be billed to the payment method on file on the due date.', + 'bitcoin' => 'Bitcoin', + 'added_on' => 'Added :date', + 'failed_remove_payment_method' => 'Failed to remove the payment method', + 'gateway_exists' => 'This gateway already exists', + 'manual_entry' => 'Manual entry', + ); + +return $LANG; + +?> diff --git a/resources/lang/fr_CA/texts.php b/resources/lang/fr_CA/texts.php index 3661ad15b1..ed3e4c8456 100644 --- a/resources/lang/fr_CA/texts.php +++ b/resources/lang/fr_CA/texts.php @@ -1,8 +1,6 @@ 'Entreprise', 'name' => 'Nom', 'website' => 'Site web', @@ -12,7 +10,7 @@ return array( 'address2' => 'Adresse 2', 'city' => 'Ville', 'state' => 'Province', - 'postal_code' => 'Code Postal', + 'postal_code' => 'Code postal', 'country_id' => 'Pays', 'contacts' => 'Contact', 'first_name' => 'Prénom', @@ -24,9 +22,7 @@ return array( 'currency_id' => 'Devise', 'size_id' => 'Taille de l\'entreprise', 'industry_id' => 'Secteur d\'activité', - 'private_notes' => 'Note personnelle', - - // invoice + 'private_notes' => 'Notes personnelle', 'invoice' => 'Facture', 'client' => 'Client', 'invoice_date' => 'Date', @@ -44,19 +40,18 @@ return array( 'unit_cost' => 'Coût unitaire', 'quantity' => 'Quantité', 'line_total' => 'Total', - 'subtotal' => 'Total', + 'subtotal' => 'Sous total', 'paid_to_date' => 'Montant reçu', 'balance_due' => 'Montant total', 'invoice_design_id' => 'Modèle', 'terms' => 'Termes', 'your_invoice' => 'Votre Facture', - 'remove_contact' => 'Supprimer un contact', 'add_contact' => 'Ajouter un contact', 'create_new_client' => 'Ajouter un nouveau client', 'edit_client_details' => 'Modifier les informations du client', 'enable' => 'Autoriser', - 'learn_more' => 'En savoir +', + 'learn_more' => 'En savoir plus', 'manage_rates' => 'Gérer les taux', 'note_to_client' => 'Commentaire pour le client', 'invoice_terms' => 'Conditions de facturation', @@ -74,8 +69,6 @@ return array( 'settings' => 'Paramètres', 'enable_invoice_tax' => 'Spécifier une taxe pour la facture', 'enable_line_item_tax' => 'Spécifier une taxe pour chaque ligne', - - // navigation 'dashboard' => 'Tableau de bord', 'clients' => 'Clients', 'invoices' => 'Factures', @@ -100,8 +93,6 @@ return array( 'provide_email' => 'Veuillez renseigner une adresse courriel valide', 'powered_by' => 'Propulsé par', 'no_items' => 'Aucun élément', - - // recurring invoices 'recurring_invoices' => 'Factures récurrentes', 'recurring_help' => '

    Envoyer automatiquement la même facture à vos clients de façon hebdomadaire, bimensuelle, mensuelle, trimestrielle ou annuelle.

    Utiliser :MONTH, :QUARTER ou :YEAR pour des dates dynamiques. Les opérations simples fonctionnent également, par exemple :MONTH-1.

    @@ -111,8 +102,6 @@ return array(
  • ":YEAR+1 - abonnement annuel" => "2016 - abonnement annuel"
  • "Acompte pour le :QUARTER+1" => "Acompte pour le Q2"
  • ', - - // dashboard 'in_total_revenue' => 'de bénéfice total', 'billed_client' => 'client facturé', 'billed_clients' => 'clients facturés', @@ -121,8 +110,6 @@ return array( 'invoices_past_due' => 'Paiements en souffrance', 'upcoming_invoices' => 'Paiements à venir', 'average_invoice' => 'Moyenne', - - // list pages 'archive' => 'Archiver', 'delete' => 'Supprimer', 'archive_client' => 'Archiver ce client', @@ -158,8 +145,6 @@ return array( 'select' => 'Sélectionner', 'edit_client' => 'Éditer le client', 'edit_invoice' => 'Éditer la facture', - - // client view page 'create_invoice' => 'Créer une facture', 'enter_credit' => 'Saisissez un crédit', 'last_logged_in' => 'Dernière connexion', @@ -171,12 +156,8 @@ return array( 'message' => 'Message', 'adjustment' => 'Réglements', 'are_you_sure' => 'Voulez-vous vraiment effectuer cette action ?', - - // payment pages 'payment_type_id' => 'Type de paiement', 'amount' => 'Montant', - - // account/company pages 'work_email' => 'Courriel', 'language_id' => 'Langue', 'timezone_id' => 'Fuseau horaire', @@ -187,18 +168,14 @@ return array( 'remove_logo' => 'Supprimer le logo', 'logo_help' => 'Formats supportés: JPEG, GIF et PNG', 'payment_gateway' => 'Passerelle de paiement', - 'gateway_id' => 'Fournisseur', + 'gateway_id' => 'Passerelle', 'email_notifications' => 'Notifications par courriel', 'email_sent' => 'm\'envoyer un courriel quand une facture est envoyée', 'email_viewed' => 'm\'envoyer un courriel quand une facture est vue', 'email_paid' => 'm\'envoyer un courriel quand une facture est payée', 'site_updates' => 'Mises à jour du site', 'custom_messages' => 'Messages personnalisés', - 'default_invoice_terms' => 'Définir comme les conditions par défaut', 'default_email_footer' => 'Définir comme la signature de courriel par défaut', - 'import_clients' => 'Importer des données clients', - 'csv_file' => 'Sélectionner un fichier CSV', - 'export_clients' => 'Exporter des données clients', 'select_file' => 'Veuillez sélectionner un fichier', 'first_row_headers' => 'Utiliser la première ligne comme entête', 'column' => 'Colonne', @@ -207,9 +184,12 @@ return array( 'client_will_create' => 'client sera créé', 'clients_will_create' => 'clients seront créés', 'email_settings' => 'Paramètres courriel', + 'client_view_styling' => 'Style de la vue client', 'pdf_email_attachment' => 'Joindre PDF aux courriels', - - // application messages + 'custom_css' => 'CSS personnalisé', + 'import_clients' => 'Importer des données clients', + 'csv_file' => 'Sélectionner un fichier CSV', + 'export_clients' => 'Exporter des données clients', 'created_client' => 'Le client a été créé', 'created_clients' => 'les :count clients ont été créés', 'updated_settings' => 'Les paramètres ont été mis à jour', @@ -220,14 +200,12 @@ return array( 'payment_error' => 'Il y a eu une erreur lors du traitement de votre paiement. Veuillez réessayer ultérieurement', 'registration_required' => 'Veuillez vous enregistrer pour envoyer une facture par courriel', 'confirmation_required' => 'Veuillez confirmer votre adresse courriel', - 'updated_client' => 'Le client a été modifié', 'created_client' => 'Le client a été créé', 'archived_client' => 'Le client a été archivé', 'archived_clients' => ':count clients archivés', 'deleted_client' => 'Le client a été supprimé', 'deleted_clients' => ':count clients supprimés', - 'updated_invoice' => 'La facture a été modifiée', 'created_invoice' => 'La facture a été créée', 'cloned_invoice' => 'La facture a été dupliquée', @@ -237,21 +215,25 @@ return array( 'archived_invoices' => ':count factures ont été archivées', 'deleted_invoice' => 'La facture a été supprimée', 'deleted_invoices' => ':count factures supprimées', - 'created_payment' => 'Le paiement a été créé', + 'created_payments' => ':count paiement(s) créé(s)', 'archived_payment' => 'Le paiement a été archivé', 'archived_payments' => ':count paiement archivés', 'deleted_payment' => 'Le paiement a été supprimé', 'deleted_payments' => ':count paiement supprimés', 'applied_payment' => 'Le paiement a été appliqué', - 'created_credit' => 'Le crédit a été créé', 'archived_credit' => 'Le crédit a été archivé', 'archived_credits' => ':count crédits archivés', 'deleted_credit' => 'Le crédit a été supprimé', 'deleted_credits' => ':count crédits supprimés', - - // Emails + 'imported_file' => 'Fichier importé', + 'updated_vendor' => 'Le vendeur a été mis à jour', + 'created_vendor' => 'Le vendeur a été créé', + 'archived_vendor' => 'Le vendeur a été archivé', + 'archived_vendors' => ':count vendeurs archivés', + 'deleted_vendor' => 'Le vendeur a été supprimé', + 'deleted_vendors' => ':count vendeurs supprimés', 'confirmation_subject' => 'Validation du compte Invoice Ninja', 'confirmation_header' => 'Validation du compte', 'confirmation_message' => 'Veuillez cliquer sur le lien ci-après pour valider votre compte.', @@ -262,7 +244,6 @@ return array( 'email_salutation' => 'Cher :name,', 'email_signature' => 'Cordialement,', 'email_from' => 'L\'équipe Invoice Ninja', - 'user_email_footer' => 'Pour modifier vos paramètres de notification par courriel, veuillez visiter '.SITE_URL.'/settings/notifications', 'invoice_link_message' => 'Pour voir la facture de votre client cliquez sur le lien ci-après :', 'notification_invoice_paid_subject' => 'La facture :invoice a été payée par le client :client', 'notification_invoice_sent_subject' => 'La facture :invoice a été envoyée au client :client', @@ -271,35 +252,14 @@ return array( 'notification_invoice_sent' => 'Le client suivant :client a reçu par courriel la facture :invoice d\'un montant de :amount', 'notification_invoice_viewed' => 'Le client suivant :client a vu la facture :invoice d\'un montant de :amount', 'reset_password' => 'Vous pouvez réinitialiser votre mot de passe en cliquant sur le lien suivant :', - 'reset_password_footer' => 'Si vous n\'avez pas effectué de demande de réinitalisation de mot de passe veuillez contacter notre support :' . CONTACT_EMAIL, - - // Payment page 'secure_payment' => 'Paiement sécurisé', 'card_number' => 'N° de carte', 'expiration_month' => 'Mois d\'expiration', 'expiration_year' => 'Année d\'expiration', 'cvv' => 'CVV', - - // Security alerts - 'confide' => array( - 'too_many_attempts' => 'Trop de tentatives. Veuillez réessayer dans quelques minutes.', - 'wrong_credentials' => 'Courriel ou mot de passe incorrect', - 'confirmation' => 'Votre compte a été validé !', - 'wrong_confirmation' => 'Code de confirmation incorrect.', - 'password_forgot' => 'Les informations de réinitialisation de votre mot de passe vous ont été envoyées par courriel.', - 'password_reset' => 'Votre mot de passe a été modifié avec succès.', - 'wrong_password_reset' => 'Mot de passe incorrect. Veuillez réessayer', - ), - - // Pro Plan - 'pro_plan' => [ - 'remove_logo' => ':link pour supprimer le logo Invoice Ninja en souscrivant au plan pro', - 'remove_logo_link' => 'Cliquez ici', - ], - 'logout' => 'Déconnexion', 'sign_up_to_save' => 'Connectez-vous pour sauvegarder votre travail', - 'agree_to_terms' =>'J\'accepte les conditions d\'utilisation d\'Invoice Ninja :terms', + 'agree_to_terms' => 'J\'accepte les conditions d\'utilisation d\'Invoice Ninja :terms', 'terms_of_service' => 'Conditions d\'utilisation', 'email_taken' => 'L\'adresse courriel existe déjà', 'working' => 'En cours', @@ -307,11 +267,8 @@ return array( 'success_message' => 'Inscription réussie avec succès. Veuillez cliquer sur le lien dans le courriel de confirmation de compte pour vérifier votre adresse courriel.', 'erase_data' => 'Cela supprimera vos données de façon permanente.', 'password' => 'Mot de passe', - 'pro_plan_product' => 'Plan Pro', - 'pro_plan_description' => 'Inscription d\'une durée d\'un an au Plan Pro d\'Invoice Ninja', 'pro_plan_success' => 'Merci pour votre inscription ! Une fois la facture réglée, votre adhésion au Plan Pro commencera.', - 'unsaved_changes' => 'Vous avez des modifications non enregistrées', 'custom_fields' => 'Champs personnalisés', 'company_fields' => 'Champs de société', @@ -319,9 +276,8 @@ return array( 'field_label' => 'Nom du champ', 'field_value' => 'Valeur du champ', 'edit' => 'Éditer', + 'set_name' => 'Entrez le nom de votre entreprise', 'view_as_recipient' => 'Voir en tant que destinataire', - - // product management 'product_library' => 'Inventaire', 'product' => 'Produit', 'products' => 'Produits', @@ -336,18 +292,14 @@ return array( 'created_product' => 'Produit créé', 'archived_product' => 'Produit archivé', 'pro_plan_custom_fields' => ':link pour activer les champs personnalisés en rejoingant le Plan Pro', - 'advanced_settings' => 'Paramètres avancés', 'pro_plan_advanced_settings' => ':link pour activer les paramètres avancés en rejoingant le Plan Pro', 'invoice_design' => 'Modèle de facture', 'specify_colors' => 'Spécifiez les couleurs', 'specify_colors_label' => 'Sélectionnez les couleurs utilisés dans les factures', - 'chart_builder' => 'Concepteur de graphiques', 'ninja_email_footer' => 'Utilisez :site pour facturer vos clients et être payés en ligne gratuitement!', 'go_pro' => 'Devenez Pro', - - // Quotes 'quote' => 'Soumission', 'quotes' => 'Soumissions', 'quote_number' => 'N° de soumission', @@ -357,7 +309,6 @@ return array( 'your_quote' => 'Votre soumission', 'total' => 'Total', 'clone' => 'Dupliquer', - 'new_quote' => 'Nouvelle soumission', 'create_quote' => 'Créer une soumission', 'edit_quote' => 'Éditer la soumission', @@ -368,9 +319,8 @@ return array( 'clone_quote' => 'Dupliquer la soumission', 'convert_to_invoice' => 'Convertir en facture', 'view_invoice' => 'Nouvelle facture', - 'view_quote' => 'Voir la soumission', 'view_client' => 'Voir le client', - + 'view_quote' => 'Voir la soumission', 'updated_quote' => 'La soumission a été mise à jour', 'created_quote' => 'La soumission a été créée', 'cloned_quote' => 'La soumission a été dupliquée', @@ -380,7 +330,6 @@ return array( 'deleted_quote' => 'La soumission a été supprimée', 'deleted_quotes' => ':count soumissions ont été supprimées', 'converted_to_invoice' => 'La soumission a été convertie en facture', - 'quote_subject' => 'Nouvelle soumission de :account', 'quote_message' => 'Pour visionner votre soumission de :amount, cliquez sur le lien ci-dessous.', 'quote_link_message' => 'Pour visionner votre soumission, cliquez sur le lien ci-dessous:', @@ -388,16 +337,13 @@ return array( 'notification_quote_viewed_subject' => 'La soumission :invoice a été visionnée par :client', 'notification_quote_sent' => 'La soumission :invoice de :amount a été envoyée au client :client.', 'notification_quote_viewed' => 'La soumission :invoice de :amount a été visionnée par le client :client.', - 'session_expired' => 'Votre session a expiré.', - 'invoice_fields' => 'Champs de facture', 'invoice_options' => 'Options de facturation', 'hide_quantity' => 'Masquer la quantité', 'hide_quantity_help' => 'Si la quantité de vos produits sont toujours 1, vous pouvez alors masquer la colonne "Quantité".', 'hide_paid_to_date' => 'Masquer "Payé à ce jour"', 'hide_paid_to_date_help' => 'Afficher seulement la ligne "Payé à ce jour"sur les factures pour lesquelles il y a au moins un paiement.', - 'charge_taxes' => 'Taxe supplémentaire', 'user_management' => 'Gestion des utilisateurs', 'add_user' => 'Ajouter utilisateur', @@ -412,22 +358,16 @@ return array( 'active' => 'Actif', 'pending' => 'En attente', 'deleted_user' => 'Utilisateur supprimé', - 'limit_users' => 'Désolé, ceci excédera la limite de ' . MAX_NUM_USERS . ' utilisateurs', - 'confirm_email_invoice' => 'Voulez-vous vraiment envoyer cette facture par courriel ?', 'confirm_email_quote' => 'Voulez-vous vraiment envoyer cette soumission par courriel ?', 'confirm_recurring_email_invoice' => 'Les factures récurrentes sont activées, voulez-vous vraiment envoyer cette facture par courriel ?', - 'cancel_account' => 'Supprimer le compte', 'cancel_account_message' => 'Attention: Ceci supprimera de façon permanente toutes vos données; cette action est irréversible.', 'go_back' => 'Retour', - 'data_visualizations' => 'Visualisation des données', 'sample_data' => 'Données fictives présentées', 'hide' => 'Cacher', 'new_version_available' => 'Une nouvelle version de :releases_link est disponible. Vous utilisez v:user_version, la plus récente est v:latest_version', - - 'invoice_settings' => 'Paramètres des factures', 'invoice_number_prefix' => 'Préfixe du numéro de facture', 'invoice_number_counter' => 'Compteur du numéro de facture', @@ -437,59 +377,48 @@ return array( 'invoice_issued_to' => 'Facture destinée à', 'invalid_counter' => 'Pour éviter un éventuel conflit, merci de définir un préfixe pour le numéro de facture ou pour le numéro de soumission', 'mark_sent' => 'Marquer comme envoyé', - 'gateway_help_1' => ':link pour vous inscrire à Authorize.net.', 'gateway_help_2' => ':link pour vous inscrire à Authorize.net.', 'gateway_help_17' => ':link pour obtenir votre signature API PayPal.', 'gateway_help_27' => ':link pour vous inscrire à TwoCheckout.', - 'more_designs' => 'Plus de modèles', 'more_designs_title' => 'Modèles de factures additionnels', 'more_designs_cloud_header' => 'Passez au Plan Pro pour obtenir plus de modèles', 'more_designs_cloud_text' => '', - 'more_designs_self_host_header' => 'Obtenez 6 modèles de factures additionnels pour seulement '.INVOICE_DESIGNS_PRICE.'$', 'more_designs_self_host_text' => '', 'buy' => 'Acheter', 'bought_designs' => 'Les nouveaux modèles ont été ajoutés avec succès', - 'sent' => 'envoyé', + 'vat_number' => 'N° de taxe', 'timesheets' => 'Feuilles de temps', - 'payment_title' => 'Veuillez entrer votre adresse de facturation et vos information de carte de crédit', 'payment_cvv' => '*Les 3 ou 4 chiffres au dos de votre carte', 'payment_footer1' => '*L\'adresse de facturation doit correspondre à l\'adresse associée à votre carte de crédit.', 'payment_footer2' => '*Veuillez cliquer sur "PAYER MAINTENANT" une seule fois - la transaction peut prendre jusqu\'à 1 minute.', - 'vat_number' => 'N° de taxe', - 'id_number' => 'N° d\'entreprise', 'white_label_link' => 'Version sans pub', 'white_label_header' => 'Entête de version sans pub', 'bought_white_label' => 'Licence de version sans pub activée', 'white_labeled' => 'Sans pub', - 'restore' => 'Restaurer', 'restore_invoice' => 'Restaurer la facture', 'restore_quote' => 'Restaurer la soumission', 'restore_client' => 'Restaurer le client', 'restore_credit' => 'Restaurer le crédit', 'restore_payment' => 'Restaurer le paiement', - 'restored_invoice' => 'La facture a été restaurée', 'restored_quote' => 'La soumission a été restaurée', 'restored_client' => 'Le client a été restauré', 'restored_payment' => 'Le paiement a été restauré', 'restored_credit' => 'Le crédit a été restauré', - 'reason_for_canceling' => 'Aidez-nous à améliorer notre site en nous disant pourquoi vous partez.', 'discount_percent' => 'Pourcent', 'discount_amount' => 'Montant', - 'invoice_history' => 'Historique des factures', 'quote_history' => 'Historique des soumissions', 'current_version' => 'Version courante', 'select_version' => 'Choix de la verison', 'view_history' => 'Consulter l\'historique', - 'edit_payment' => 'Éditer le paiement', 'updated_payment' => 'Le paiement a été mis à jour', 'deleted' => 'Supprimé', @@ -502,7 +431,6 @@ return array( 'quote_email' => 'Courriel de soumission', 'reset_all' => 'Remise à zéro', 'approve' => 'Approuver', - 'token_billing_type_id' => 'Jeton de facturation', 'token_billing_help' => 'Permet de mémoriser les cartes de crédit avec votre passerelle de paiement et encaisser plus tard.', 'token_billing_1' => 'Désactivé', @@ -510,12 +438,11 @@ return array( 'token_billing_3' => 'Désengagement - case à cocher affichée avec sélection', 'token_billing_4' => 'Toujours', 'token_billing_checkbox' => 'Mémoriser les informations de carte de crédit', - 'view_in_stripe' => 'Visualiser dans Stripe', - 'use_card_on_file' => 'Mémoriser les informations de la carte pour usage ultérieur', + 'view_in_gateway' => 'Visualiser dans :gateway', + 'use_card_on_file' => 'Use Card on File', 'edit_payment_details' => 'Éditer les informations de paiement', 'token_billing' => 'Sauvegarder les informations de carte de crédit', - 'token_billing_secure' => 'Les données sont mémorisées de façon sécuritaire avec :stripe_link', - + 'token_billing_secure' => 'Les données sont mémorisées de façon sécuritaire avec :link', 'support' => 'Support', 'contact_information' => 'Contact', '256_encryption' => 'Chiffrage 256-Bit', @@ -525,11 +452,8 @@ return array( 'order_overview' => 'Récapitualtion de commande', 'match_address' => '*L\'adresse doit correspondre à l\'adresse associée à la carte de crédit.', 'click_once' => '*Please click "PAY NOW" only once - transaction may take up to 1 minute to process.', - - 'default_invoice_footer' => 'Définir le pied de facture par défaut', 'invoice_footer' => 'Pied de facture', 'save_as_default_footer' => 'Sauvegarder comme pied de facture par défaut', - 'token_management' => 'Gestion des jeton', 'tokens' => 'Jetons', 'add_token' => 'Ajouter un jeton', @@ -540,7 +464,6 @@ return array( 'edit_token' => 'Éditer le jeton', 'delete_token' => 'Supprimer le jeton', 'token' => 'Jeton', - 'add_gateway' => 'Ajouter une passerelle', 'delete_gateway' => 'Supprimer la passerelle', 'edit_gateway' => 'Éditer la passerelle', @@ -549,7 +472,6 @@ return array( 'deleted_gateway' => 'La passerelle a été supprimée', 'pay_with_paypal' => 'PayPal', 'pay_with_card' => 'Carte de crédit', - 'change_password' => 'Changer le mot de passe', 'current_password' => 'Mot de passe actuel', 'new_password' => 'Nouveau mot de passe', @@ -557,25 +479,22 @@ return array( 'password_error_incorrect' => 'Le mot de passe est incorrect.', 'password_error_invalid' => 'Le nouveau mot de passe est invalide.', 'updated_password' => 'Le mot de passe a été mis à jour', - 'api_tokens' => 'Jetons API', 'users_and_tokens' => 'Utilisateurs et jetons', 'account_login' => 'Connexion', 'recover_password' => 'Récupérez votre mot de passe', 'forgot_password' => 'Mot de passe oublié?', 'email_address' => 'Votre courriel', - 'lets_go' => 'Let’s go', // Deprecated + 'lets_go' => 'Let’s go', 'password_recovery' => 'Récupération de mot de passe', 'send_email' => 'Envoyer', 'set_password' => 'Nouveau mot de passe', 'converted' => 'Convertie', - 'email_approved' => 'Envoyer un courriel lorsqu\'une soumission a été acceptée', 'notification_quote_approved_subject' => 'La soumission :invoice a été acceptée par :client', 'notification_quote_approved' => 'Le client :client a accepté la soumission :invoice pour :amount.', 'resend_confirmation' => 'Renvoyer la confirmation par courriel', 'confirmation_resent' => 'La confirmation a été renvoyée', - 'gateway_help_42' => ':link pour s\'inscrire à BitPay.
    Note: utilisez une clé API ancienne et non un jeton API.', 'payment_type_credit_card' => 'Carte de crédit', 'payment_type_paypal' => 'PayPal', @@ -583,7 +502,6 @@ return array( 'knowledge_base' => 'Base de connaissance', 'partial' => 'Partiel', 'partial_remaining' => ':partiel de :balance', - 'more_fields' => 'Plus de champs', 'less_fields' => 'Moins de champs', 'client_name' => 'Nom du client', @@ -594,7 +512,6 @@ return array( 'view_documentation' => 'Voir la documentation', 'app_title' => 'Gestionnaire de facturation en ligne, gratuit et open-source', 'app_description' => 'Invoice Ninja est une solution de facturation et de paiement gratuite et open-source. Avec Invoice Ninja, vous pouvez facilement construire et envoyer des factures de n\'importe quel appareil ayant accès au web. Vos clients peuvent imprimer leurs factures, les télécharger au format PDF, et même les payer en ligne à partir du système.', - 'rows' => 'lignes', 'www' => 'www', 'logo' => 'Logo', @@ -614,7 +531,6 @@ return array( 'zapier' => 'Zapier', 'recurring' => 'Récurrente', 'last_invoice_sent' => 'Dernière facture envoyée le :date', - 'processed_updates' => 'La mise à jour été complétée', 'tasks' => 'Tâches', 'new_task' => 'Nouvelle tâche', @@ -660,13 +576,10 @@ return array( 'invoice_labels' => 'Champs des produits', 'prefix' => 'Préfixe', 'counter' => 'Compteur', - 'payment_type_dwolla' => 'Dwolla', 'gateway_help_43' => ':link pour s\'inscrire à Dwolla.', 'partial_value' => 'Doit être plus grand que zéro et moins que le total', 'more_actions' => 'Plus d\'actions', - - 'pro_plan_title' => 'NINJA PRO', 'pro_plan_call_to_action' => 'Mettre à niveau!', 'pro_plan_feature1' => 'Nombre illimité de client', @@ -677,14 +590,12 @@ return array( 'pro_plan_feature6' => 'Création de soumission et de factures Pro-forma', 'pro_plan_feature7' => 'Personnalisation des champs de facture', 'pro_plan_feature8' => 'Pièces jointes PDF pour les envois de courriel aux clients', - 'resume' => 'Continuer', 'break_duration' => 'Pause', 'edit_details' => 'Modifier', 'work' => 'Travail', 'timezone_unset' => 'Veuillez :link pour définir votre fuseau horaire', 'click_here' => 'cliquer içi', - 'email_receipt' => 'Envoyer le reçu de paiement au client par courriel', 'created_payment_emailed_client' => 'Le paiement a été créé et envoyé au client', 'add_company' => 'Ajouter une entreprise', @@ -694,10 +605,8 @@ return array( 'unlinked_account' => 'Les comptes ont été déliés', 'login' => 'Connexion', 'or' => 'ou', - 'email_error' => 'Il y a eu un problème avec l\'envoi du courriel', 'confirm_recurring_timing' => 'Note: Les courriels sont envoyés au début de chaque heure.', - 'old_browser' => 'Veuillez utiliser un navigateur plus récent', 'payment_terms_help' => 'Défini la date d\'échéance par défaut', 'unlink_account' => 'Délié le compte', 'unlink' => 'Délié', @@ -705,7 +614,7 @@ return array( 'show_address_help' => 'Le client doit fournir son adresse de facturation', 'update_address' => 'Mise à jour de l\adresse', 'update_address_help' => 'Met à jour l\'adresse du client avec les informations fournies', - 'times' => 'Times', // Deprecated + 'times' => 'Times', 'set_now' => 'Définir', 'dark_mode' => 'Mode foncé', 'dark_mode_help' => 'Affiche le texte blanc sur noir', @@ -718,7 +627,6 @@ return array( 'primary_color' => 'Couleur principale', 'secondary_color' => 'Couleur secondaire', 'customize_design' => 'Personnalisation', - 'content' => 'Contenu', 'styles' => 'Styles', 'defaults' => 'Pré-définis', @@ -731,8 +639,7 @@ return array( 'recent_payments' => 'Paiements reçus', 'outstanding' => 'Impayés', 'manage_companies' => 'Gérer les entreprises', - 'total_revenue' => 'Revenus', - + 'total_revenue' => 'Revenus', 'current_user' => 'Utilisateur en cours', 'new_recurring_invoice' => 'Nouvelle facture récurrente', 'recurring_invoice' => 'Facture récurrente', @@ -740,10 +647,9 @@ return array( 'created_by_invoice' => 'Créée par :invoice', 'primary_user' => 'Utilisateur principal', 'help' => 'Aide', - 'customize_help' => '

    Nous utilisons pdfmake pour définir le design des factures de façon déclarative. L\'environnement pdfmake permet de voir la librairie en action.

    -

    Pour accéder à une propriété enfant en utilisant la notation par point. Par exemple $client.nameaffiche le nom du client.

    -

    Si vous avez besoin d\'aide à cet effet, n\'hésitez pas à publier une question sur notre forum d\'aide (en anglais).

    ', - + 'customize_help' => '

    We use pdfmake to define the invoice designs declaratively. The pdfmake playground provide\'s a great way to see the library in action.

    +

    You can access a child property using dot notation. For example to show the client name you could use $client.name.

    +

    If you need help figuring something out post a question to our support forum with the design you\'re using.

    ', 'invoice_due_date' => 'Échéance', 'quote_due_date' => 'Échéance', 'valid_until' => 'Échéance', @@ -756,15 +662,12 @@ return array( 'status_partial' => 'Partiel', 'status_paid' => 'Payée', 'show_line_item_tax' => 'Afficher la taxe sur la même ligne', - 'iframe_url' => 'Site web', 'iframe_url_help1' => 'Copier ce code sur une page de votre site.', 'iframe_url_help2' => 'Vous pouvez tester cette fonctionnalité en cliquant \'Visualiser en tant que destinataire\' pour uen facture.', - 'auto_bill' => 'Facturation automatique', 'military_time' => 'Format d\'heure 24 h', 'last_sent' => 'Dernier envoi', - 'reminder_emails' => 'Courriels de rappel', 'templates_and_reminders' => 'Modèles et rappels', 'subject' => 'Sujet', @@ -776,15 +679,12 @@ return array( 'reminder_subject' => 'Rappel: facture :invoice de :account', 'reset' => 'Remise à zéro', 'invoice_not_found' => 'La facture demandée n\'est pas disponible', - 'referral_program' => 'Programme de référencement', 'referral_code' => 'Code de référencement', 'last_sent_on' => 'Dernier envoi le :date', - 'page_expire' => 'Cette page va expirer bientôt, :click_here popur continuer', 'upcoming_quotes' => 'Soumissions à venir', 'expired_quotes' => 'Soumissions expirées', - 'sign_up_using' => 'Connectez-vous avec', 'invalid_credentials' => 'Ces informations ne correspondent pas', 'show_all_options' => 'Afficher toutes les options', @@ -793,17 +693,10 @@ return array( 'disable' => 'Desactiver', 'invoice_quote_number' => 'Numéros de factures et de soumissions', 'invoice_charges' => 'Frais de facturation', - - 'invitation_status' => [ - 'sent' => 'Courriel envoyé', - 'opened' => 'Courriel ouvert', - 'viewed' => 'Facture consultée', - ], 'notification_invoice_bounced' => 'Impossible d\'envoyer la facture :invoice à :contact.', 'notification_invoice_bounced_subject' => 'Impossible d\'envoyer la facture :invoice', 'notification_quote_bounced' => 'Impossible d\'envoyer la soumission :invoice à :contact.', 'notification_quote_bounced_subject' => 'Impossible d\'envoyer la soumission :invoice', - 'custom_invoice_link' => 'Lien de facture personnalisé', 'total_invoiced' => 'Total facturé', 'open_balance' => 'Solde', @@ -811,14 +704,12 @@ return array( 'basic_settings' => 'Paramètres généraux', 'pro' => 'Pro', 'gateways' => 'Passerelles de paiements', - 'next_send_on' => 'Prochain envoi: :date', 'no_longer_running' => 'Cette facture n\'est pas planifié pour un envoi', 'general_settings' => 'Paramètres généraux', 'customize' => 'Personnalisation', 'oneclick_login_help' => 'Connectez-vous à un compte pour une connexion sans mot de passe', 'referral_code_help' => 'Gagnes de l\'argent en faisnat connaître notre application', - 'enable_with_stripe' => 'Activer | Requiert Stripe', 'tax_settings' => 'Paramètres de taxe', 'create_tax_rate' => 'Ajouter un taux de taxe', @@ -839,7 +730,6 @@ return array( 'invoice_counter' => 'Numéros de factures', 'quote_counter' => 'Numéros de soumissions', 'type' => 'Type', - 'activity_1' => ':user a créé le client :client', 'activity_2' => ':user a archivé le client :client', 'activity_3' => ':user a supprimé le client :client', @@ -869,18 +759,24 @@ return array( 'activity_27' => ':user a restauré le paiement :payment', 'activity_28' => ':user a restauré le crédit :credit', 'activity_29' => ':contact accepté la soumission :quote', - + 'activity_30' => ':user a créé :vendor', + 'activity_31' => ':user a créé :vendor', + 'activity_32' => ':user a créé :vendor', + 'activity_33' => ':user a créé :vendor', + 'activity_34' => ':user a créé la dépense :expense', + 'activity_35' => ':user a créé :vendor', + 'activity_36' => ':user a créé :vendor', + 'activity_37' => ':user a créé :vendor', 'payment' => 'Paiement', 'system' => 'Système', 'signature' => 'Signature de courriel', 'default_messages' => 'Message par défaut', 'quote_terms' => 'Conditions de soumission', 'default_quote_terms' => 'Conditions par défaut pour les soumissions', - 'default_invoice_terms' => 'Conditions par défaut pour les factures', - 'default_invoice_footer' => 'Pied de facture par défaut', + 'default_invoice_terms' => 'Définir comme les conditions par défaut', + 'default_invoice_footer' => 'Définir le pied de facture par défaut', 'quote_footer' => 'Pied de soumission par défaut', 'free' => 'Gratuit', - 'quote_is_approved' => 'Cette soumission a été acceptée', 'apply_credit' => 'Appliquer le crédit', 'system_settings' => 'Paramètres système', @@ -898,7 +794,6 @@ return array( 'restored_recurring_invoice' => 'La facture récurrente a été restaurée', 'archived' => 'Archivée', 'untitled_account' => 'Entreprise sans nom', - 'before' => 'Avant', 'after' => 'Après', 'reset_terms_help' => 'Remise à zéro', @@ -907,7 +802,6 @@ return array( 'user' => 'Utilisateur', 'country' => 'Pays', 'include' => 'Inclus', - 'logo_too_large' => 'Votre logo est :size, pour de meilleures performances PDF, veuillez charger une image de moins de 200KB', 'import_freshbooks' => 'Importer de FreshBooks', 'import_data' => 'Importer les données', @@ -918,16 +812,6 @@ return array( 'task_file' => 'Fichier des tâches', 'no_mapper' => 'Aucun liens de champs valides pour ce fichier', 'invalid_csv_header' => 'Entête CSV invalide', - - 'email_errors' => [ - 'inactive_client' => 'Aucun courriel ne peut être envoyé à un client inactif', - 'inactive_contact' => 'Aucun courriel ne peut être envoyé à un contact inactif', - 'inactive_invoice' => 'Aucun courriel ne peut être envoyé à une facture inactive', - 'user_unregistered' => 'Veuillez vous créer un compte pour envoyer des courriels', - 'user_unconfirmed' => 'Veuillez confirmer votre compte pour pouvoir envoyer des courriels', - 'invalid_contact_email' => 'Ce courriel est invalide', - ], - 'client_portal' => 'Portail client', 'admin' => 'Admin', 'disabled' => 'Désactivé', @@ -936,11 +820,9 @@ return array( 'invoice_will_create' => 'Le client sera créé', 'invoices_will_create' => 'Les factures seront créées', 'failed_to_import' => 'Cet enregistrement n\'a pu être importé', - 'publishable_key' => 'Clé publique', 'secret_key' => 'Clé secrète', 'missing_publishable_key' => 'Entrez votre lcé publique de Stripe pour une meilleur expérience de paiement', - 'email_design' => 'Modèle de courriel', 'due_by' => 'Due pour :date', 'enable_email_markup' => 'Autoriser le marquage', @@ -952,7 +834,6 @@ return array( 'plain' => 'Ordinaire', 'light' => 'Clair', 'dark' => 'Foncé', - 'industry_help' => 'Pour des fins de comparaison entre des entreprises de même taille et du même secteur d\'activité.', 'subdomain_help' => 'Personnalisez le lien de sous-domaine de la facture ou en affichant la facture sur votre site web.', 'invoice_number_help' => 'Spécifiez un préfixe ou utilisez un modèle personnalisé pour la création du numéro de facture.', @@ -961,8 +842,6 @@ return array( 'custom_account_fields_helps' => 'Ajoutez un titre et une valeur à la section des informations de l\'entreprise dans le fichier PDF.', 'custom_invoice_fields_helps' => 'Ajoutez un champ personnalisé à la page de création/édition de facture et affichez le titre et la valeur dans le fichier PDF.', 'custom_invoice_charges_helps' => 'Ajoutez un champ personnalisé à la page de création/édition de facture pour inclure les frais au sous-totaux de la facture.', - 'color_help' => 'Note: la couleur principale est également utilisée dans le portail du client et les modèles personnalisés de courriels.', - 'token_expired' => 'Le jeton de validation a expiré. Veuillez réessayer.', 'invoice_link' => 'Lien de facture', 'button_confirmation_message' => 'Veuillez confirmer votre courriel.', @@ -971,7 +850,6 @@ return array( 'created_invoices' => ':count factures ont été créées', 'next_invoice_number' => 'Le prochain numéro de facture est :number.', 'next_quote_number' => 'Le prochain numéro de soumission est :number.', - 'days_before' => 'jours avant', 'days_after' => 'jours après', 'field_due_date' => 'Échéance', @@ -979,16 +857,12 @@ return array( 'schedule' => 'Calendrier', 'email_designs' => 'Modèles de courriel', 'assigned_when_sent' => 'Assignée lors de l\'envoi', - - 'white_label_custom_css' => ':link à $'.WHITE_LABEL_PRICE.' pour activer les styles personnalisés et supporter notre projet.', 'white_label_purchase_link' => 'Achetez une licence sans pub', - - // Expense / vendor 'expense' => 'Dépense', 'expenses' => 'Dépenses', 'new_expense' => 'Nouvelle dépense', 'enter_expense' => 'Nouvelle dépense', - 'vendors' => 'Fournisseurs', // et non pas Vendeurs, ce qui n'a pas la même signification + 'vendors' => 'Fournisseurs', 'new_vendor' => 'Nouveau fournisseur', 'payment_terms_net' => 'Net', 'vendor' => 'Fournisseur', @@ -1000,8 +874,6 @@ return array( 'archived_expense' => 'La dépense a été archivée', 'deleted_expenses' => 'Les dépenses ont été supprimées', 'archived_expenses' => 'Les dépenses ont été archivées', - - // Expenses 'expense_amount' => 'Montant de la dépense', 'expense_balance' => 'Solde de la dépense', 'expense_date' => 'Date de la dépense', @@ -1026,15 +898,11 @@ return array( 'expense_error_multiple_clients' => 'Les dépenses ne peuvent pas appartenir à plusieus clients', 'expense_error_invoiced' => 'Ces dépenses ont déjà été facturées', 'convert_currency' => 'Conversion de devise', - - // Payment terms 'num_days' => 'Nombre de jours', 'create_payment_term' => 'Nouveau terme de paiement', 'edit_payment_terms' => 'Editer les termes de paiement', 'edit_payment_term' => 'Editer le terme de paiement', 'archive_payment_term' => 'Archiver le terme de paiement', - - // recurring due dates 'recurring_due_dates' => 'Dates d\'échéances des factures récurrentes', 'recurring_due_date_help' => '

    Définissez automatiquement une date d\'échéance pour la facture.

    Les factures de type mensuel ou annuel dont la date d\'échéance est définie le jour même ou le jour précédent de leur création seront dues pour le prochain mois. Les factures dont la date d\'échéance est définie le 29 ou le 30 des mois qui n\'ont pas ces jours seront dues le dernier jour de ce mois.

    @@ -1059,15 +927,11 @@ return array( 'thursday' => 'Jeudi', 'friday' => 'Vendredi', 'saturday' => 'Samedi', - - // Fonts 'header_font_id' => 'Police de l\'entête', 'body_font_id' => 'Police du message', 'color_font_help' => 'Note: la couleur principale et les polices sont aussi utilisées dans le portail client et dans les modèles de courriels personnalisés.', - 'live_preview' => 'Prévisualisation', 'invalid_mail_config' => 'impossible d\'envoyer le courriel, veuillez vérifier vos paramètres courriel.', - 'invoice_message_button' => 'Pour voir la facture de :amount, cliquez sur le bouton ci-dessous.', 'quote_message_button' => 'Pour voir la soumission de :amount, cliquez sur le bouton ci-dessous.', 'payment_message_button' => 'Merci pour votre paiement de :amount.', @@ -1084,7 +948,6 @@ return array( 'archived_bank_account' => 'Le compte bancaire a été archivé', 'created_bank_account' => 'Le compte bancaire a été créé', 'validate_bank_account' => 'Valider le compte bancaire', - 'bank_accounts_help' => 'Veuillez vous connecter à un compte bancaire pour importer automatiquement les dépenses et créer les fournisseurs. Supporte American Express et plus de 400 banques américaines.', 'bank_password_help' => 'Note: votre mot de passe est transmis de façon sécuritaire et n\'est jamais enregistré sur nos serveurs.', 'bank_password_warning' => 'Avertissement: votre mot de passe pourrait être transmis sans cryptage, pensez à activer HTTPS.', 'username' => 'Nom d\'utilisateur', @@ -1098,7 +961,6 @@ return array( 'validate' => 'Valider', 'info' => 'Info', 'imported_expenses' => ':count_vendors fournisseur(s) et :count_expenses dépense(s) ont été créés', - 'iframe_url_help3' => 'Note: si vous pensez accepter le paiement par carte de crédit, Nous vous recommandons fortement d\'activer le HTTPS.', 'expense_error_multiple_currencies' => 'La dépense ne peut pas utiliser des devises différentes.', 'expense_error_mismatch_currencies' => 'La devise du client ne correspond par à la devise de la dépense.', @@ -1119,164 +981,380 @@ return array( 'trial_call_to_action' => 'Démarrez votre essai gratuit', 'trial_success' => 'Le Plan Pro, version d\'essai gratuit pour 2 semaines a été activé', 'overdue' => 'En souffrance', - 'white_label_text' => 'Achetez une licence sans pub d\'un an à $'.WHITE_LABEL_PRICE.' pour retirer le logo de Invoice Ninja du portail client et supporter notre projet.', + + + 'white_label_text' => 'Achetez une licence sans pub d\'un an à $:price pour retirer le logo de Invoice Ninja du portail client et supporter notre projet.', + 'user_email_footer' => 'Pour modifier vos paramètres de notification par courriel, veuillez visiter :link', + 'reset_password_footer' => 'Si vous n\'avez pas effectué de demande de réinitalisation de mot de passe veuillez contacter notre support : :email', + 'limit_users' => 'Désolé, ceci excédera la limite de :limit utilisateurs', + 'more_designs_self_host_header' => 'Obtenez 6 modèles de factures additionnels pour seulement $:price', + 'old_browser' => 'Veuillez utiliser un navigateur plus récent', + 'white_label_custom_css' => ':link à $:price pour activer les styles personnalisés et supporter notre projet.', + 'bank_accounts_help' => 'Veuillez vous connecter à un compte bancaire pour importer automatiquement les dépenses et créer les fournisseurs. Supporte American Express et plus de 400 banques américaines.', + + 'pro_plan_remove_logo' => ':link pour supprimer le logo Invoice Ninja en souscrivant au plan pro', + 'pro_plan_remove_logo_link' => 'Cliquez ici', + 'invitation_status_sent' => 'Courriel envoyé', + 'invitation_status_opened' => 'Courriel ouvert', + 'invitation_status_viewed' => 'Facture consultée', + 'email_error_inactive_client' => 'Aucun courriel ne peut être envoyé à un client inactif', + 'email_error_inactive_contact' => 'Aucun courriel ne peut être envoyé à un contact inactif', + 'email_error_inactive_invoice' => 'Aucun courriel ne peut être envoyé à une facture inactive', + 'email_error_user_unregistered' => 'Veuillez vous créer un compte pour envoyer des courriels', + 'email_error_user_unconfirmed' => 'Veuillez confirmer votre compte pour pouvoir envoyer des courriels', + 'email_error_invalid_contact_email' => 'Ce courriel est invalide', 'navigation' => 'Navigation', - 'list_invoices' => 'List Invoices', - 'list_clients' => 'List Clients', - 'list_quotes' => 'List Quotes', - 'list_tasks' => 'List Tasks', - 'list_expenses' => 'List Expenses', - 'list_recurring_invoices' => 'List Recurring Invoices', - 'list_payments' => 'List Payments', - 'list_credits' => 'List Credits', - 'tax_name' => 'Tax Name', - 'report_settings' => 'Report Settings', - 'search_hotkey' => 'shortcut is /', + 'list_invoices' => 'Liste des factures', + 'list_clients' => 'Liste des clients', + 'list_quotes' => 'Liste des soumissions', + 'list_tasks' => 'Liste des tâches', + 'list_expenses' => 'Liste des factures récurrentes', + 'list_recurring_invoices' => 'Liste des factures récurrentes', + 'list_payments' => 'Liste des paiements', + 'list_credits' => 'Liste des crédits', + 'tax_name' => 'Nom de la taxe', + 'report_settings' => 'Paramètres des rapports', + 'search_hotkey' => 'raccourci /', - 'new_user' => 'New User', - 'new_product' => 'New Product', - 'new_tax_rate' => 'New Tax Rate', - 'invoiced_amount' => 'Invoiced Amount', - 'invoice_item_fields' => 'Invoice Item Fields', - 'custom_invoice_item_fields_help' => 'Add a field when creating an invoice item and display the label and value on the PDF.', - 'recurring_invoice_number' => 'Recurring Invoice Number', - 'recurring_invoice_number_prefix_help' => 'Speciy a prefix to be added to the invoice number for recurring invoices. The default value is \'R\'.', - 'enable_client_portal' => 'Dashboard', - 'enable_client_portal_help' => 'Show/hide the dashboard page in the client portal.', + 'new_user' => 'Nouvel utilisateur', + 'new_product' => 'Nouveau produit', + 'new_tax_rate' => 'Nouveau taux de taxe', + 'invoiced_amount' => 'Montant facturé', + 'invoice_item_fields' => 'Champs d\'items de facture', + 'custom_invoice_item_fields_help' => 'Ajoutez un champ lors de la création d\'une facture pour afficher le libellé et la valeur du champ sur le PDF.', + 'recurring_invoice_number' => 'Numéro de facture récurrente', + 'recurring_invoice_number_prefix_help' => 'Spécifiez un préfixe qui sera ajouté au numéro de la facture récurrente. La valeur par défaut est \'R\'.', // Client Passwords - 'enable_portal_password'=>'Password protect invoices', - 'enable_portal_password_help'=>'Allows you to set a password for each contact. If a password is set, the contact will be required to enter a password before viewing invoices.', - 'send_portal_password'=>'Generate password automatically', - 'send_portal_password_help'=>'If no password is set, one will be generated and sent with the first invoice.', - - 'expired' => 'Expired', - 'invalid_card_number' => 'The credit card number is not valid.', - 'invalid_expiry' => 'The expiration date is not valid.', - 'invalid_cvv' => 'The CVV is not valid.', - 'cost' => 'Cost', - 'create_invoice_for_sample' => 'Note: create your first invoice to see a preview here.', - + 'enable_portal_password'=>'Factures protégées', + 'enable_portal_password_help'=>'Permet de spécifier un mot de passe pour chaque contact. Si un mot de passe est spécifié, le contact devra saisir ce mot de passe pour visualiser ses factures.', + 'send_portal_password'=>'Génère automatiquement un mot de passe', + 'send_portal_password_help'=>'Si aucun mot de passe n\\'est spécifié, le client recevra un mot de passe autogénéré lors de l\'envoi de la première facture.', + + 'expired' => 'Expiré', + 'invalid_card_number' => 'Le numéro de carte de crédit n\'est pas valide.', + 'invalid_expiry' => 'La date d\'expiration n\'est pas valide.', + 'invalid_cvv' => 'Le CVV n\'est pas valide.', + 'cost' => 'Coût', + 'create_invoice_for_sample' => 'Note: créez votre première facture pour la visualiser ici.', + // User Permissions - 'owner' => 'Owner', - 'administrator' => 'Administrator', - 'administrator_help' => 'Allow user to manage users, change settings and modify all records', - 'user_create_all' => 'Create clients, invoices, etc.', - 'user_view_all' => 'View all clients, invoices, etc.', - 'user_edit_all' => 'Edit all clients, invoices, etc.', - 'gateway_help_20' => ':link to sign up for Sage Pay.', - 'gateway_help_21' => ':link to sign up for Sage Pay.', - 'partial_due' => 'Partial Due', - 'restore_vendor' => 'Restore Vendor', - 'restored_vendor' => 'Successfully restored vendor', - 'restored_expense' => 'Successfully restored expense', + 'owner' => 'Propriétaire', + 'administrator' => 'Administrateur', + 'administrator_help' => 'Permet à un utilisateur de gérer d\'autres utilisateurs, modifier les paramètres et tous les enregistrements.', + 'user_create_all' => 'Créer des clients, factures, etc.', + 'user_view_all' => 'Visualiser tous les clients, factures, etc.', + 'user_edit_all' => 'Éditer tous les clients, factures, etc.', + 'gateway_help_20' => ':link pour s\'inscrire à Sage Pay.', + 'gateway_help_21' => ':link pour s\'inscrire à Sage Pay.', + 'partial_due' => 'Montant partiel du', + 'restore_vendor' => 'Restaurer un vendeur', + 'restored_vendor' => 'Le vendeur a été restauré', + 'restored_expense' => 'La dépense a été restaurée', 'permissions' => 'Permissions', - 'create_all_help' => 'Allow user to create and modify records', - 'view_all_help' => 'Allow user to view records they didn\'t create', - 'edit_all_help' => 'Allow user to modify records they didn\'t create', - 'view_payment' => 'View Payment', - - 'january' => 'January', - 'february' => 'February', - 'march' => 'March', - 'april' => 'April', - 'may' => 'May', - 'june' => 'June', - 'july' => 'July', - 'august' => 'August', - 'september' => 'September', - 'october' => 'October', - 'november' => 'November', - 'december' => 'December', + 'create_all_help' => 'Autoriser un utilisateur à créer et modifier ses enregistrements', + 'view_all_help' => 'Autoriser un utilisateur à visualiser des enregistrements d\'autres utilisateurs', + 'edit_all_help' => 'Autoriser un utilisateur à modifier des enregistrements d\'autres utilisateurs', + 'view_payment' => 'Visualiser un paiement', + + 'january' => 'Janvier', + 'february' => 'Février', + 'march' => 'Mars', + 'april' => 'Avril', + 'may' => 'Mai', + 'june' => 'Juin', + 'july' => 'Juillet', + 'august' => 'Août', + 'september' => 'Septembre', + 'october' => 'Octobre', + 'november' => 'Novembre', + 'december' => 'Décembre', // Documents 'documents_header' => 'Documents:', 'email_documents_header' => 'Documents:', - 'email_documents_example_1' => 'Widgets Receipt.pdf', - 'email_documents_example_2' => 'Final Deliverable.zip', + 'email_documents_example_1' => 'Recu du widget.pdf', + 'email_documents_example_2' => 'Livraison finale.zip', 'invoice_documents' => 'Documents', - 'expense_documents' => 'Attached Documents', - 'invoice_embed_documents' => 'Embed Documents', - 'invoice_embed_documents_help' => 'Include attached images in the invoice.', - 'document_email_attachment' => 'Attach Documents', - 'download_documents' => 'Download Documents (:size)', - 'documents_from_expenses' => 'From Expenses:', - 'dropzone' => array(// See http://www.dropzonejs.com/#config-dictDefaultMessage - 'DefaultMessage' => 'Drop files or click to upload', - 'FallbackMessage' => 'Your browser does not support drag\'n\'drop file uploads.', - 'FallbackText' => 'Please use the fallback form below to upload your files like in the olden days.', - 'FileTooBig' => 'File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.', - 'InvalidFileType' => 'You can\'t upload files of this type.', - 'ResponseError' => 'Server responded with {{statusCode}} code.', - 'CancelUpload' => 'Cancel upload', - 'CancelUploadConfirmation' => 'Are you sure you want to cancel this upload?', - 'RemoveFile' => 'Remove file', - ), + 'expense_documents' => 'Documents joints', + 'invoice_embed_documents' => 'Documents intégrés', + 'invoice_embed_documents_help' => 'Inclure les images jointes dans la facture.', + 'document_email_attachment' => 'Documents joints', + 'download_documents' => 'Télécharger les documents (:size)', + 'documents_from_expenses' => 'Des dépenses:', + 'dropzone_default_message' => 'Glissez-déposez des fichiers ou parcourez pour charger des fichiers', + 'dropzone_fallback_message' => 'Votre navigateur ne supporte pas le glisser-déposer de documents pour le chargement.', + 'dropzone_fallback_text' => 'Veuillez utiliser le formulaire ci-dessous pour charger vos fichiers à la veille façon.', + 'dropzone_file_too_big' => 'Le fichier est tros lourd ({{filesize}}MiB). Taille maximale: {{maxFilesize}}MiB.', + 'dropzone_invalid_file_type' => 'Vous ne pouvez pas charger des fichiers de ce type.', + 'dropzone_response_error' => 'Le serveur a répondu avec le code {{statusCode}}.', + 'dropzone_cancel_upload' => 'Chargement annulé', + 'dropzone_cancel_upload_confirmation' => 'Souhaitez-vous vraiment annuler ce chargement ?', + 'dropzone_remove_file' => 'Retirer le fichier', 'documents' => 'Documents', - 'document_date' => 'Document Date', - 'document_size' => 'Size', + 'document_date' => 'Date du document', + 'document_size' => 'Taille', + + 'enable_client_portal' => 'Portail client', + 'enable_client_portal_help' => 'Afficher/masquer le portail client.', + 'enable_client_portal_dashboard' => 'Tableau de bord', + 'enable_client_portal_dashboard_help' => 'Afficher/masquer la page du tableau de bord dans le portail client.', - 'enable_client_portal' => 'Client Portal', - 'enable_client_portal_help' => 'Show/hide the client portal.', - 'enable_client_portal_dashboard' => 'Dashboard', - 'enable_client_portal_dashboard_help' => 'Show/hide the dashboard page in the client portal.', - // Plans - 'account_management' => 'Account Management', - 'plan_status' => 'Plan Status', - - 'plan_upgrade' => 'Upgrade', - 'plan_change' => 'Change Plan', - 'pending_change_to' => 'Changes To', - 'plan_changes_to' => ':plan on :date', - 'plan_term_changes_to' => ':plan (:term) on :date', - 'cancel_plan_change' => 'Cancel Change', + 'account_management' => 'Gestion du compte', + 'plan_status' => 'État du plan', + + 'plan_upgrade' => 'Mise à jour', + 'plan_change' => 'Changer de plan', + 'pending_change_to' => 'Changer pour', + 'plan_changes_to' => ':plan le :date', + 'plan_term_changes_to' => ':plan (:term) le :date', + 'cancel_plan_change' => 'Annuler', 'plan' => 'Plan', - 'expires' => 'Expires', - 'renews' => 'Renews', - 'plan_expired' => ':plan Plan Expired', - 'trial_expired' => ':plan Plan Trial Ended', - 'never' => 'Never', - 'plan_free' => 'Free', + 'expires' => 'Expiration', + 'renews' => 'Renouvellement', + 'plan_expired' => 'Le plan :plan est expiré', + 'trial_expired' => 'L\'essai du plan :plan est terminé', + 'never' => 'Jamais', + 'plan_free' => 'Gratuit', 'plan_pro' => 'Pro', 'plan_enterprise' => 'Enterprise', - 'plan_white_label' => 'Self Hosted (White labeled)', - 'plan_free_self_hosted' => 'Self Hosted (Free)', - 'plan_trial' => 'Trial', - 'plan_term' => 'Term', - 'plan_term_monthly' => 'Monthly', - 'plan_term_yearly' => 'Yearly', - 'plan_term_month' => 'Month', - 'plan_term_year' => 'Year', - 'plan_price_monthly' => '$:price/Month', - 'plan_price_yearly' => '$:price/Year', - 'updated_plan' => 'Updated plan settings', - 'plan_paid' => 'Term Started', - 'plan_started' => 'Plan Started', - 'plan_expires' => 'Plan Expires', - - 'white_label_button' => 'White Label', - - 'pro_plan_year_description' => 'One year enrollment in the Invoice Ninja Pro Plan.', - 'pro_plan_month_description' => 'One month enrollment in the Invoice Ninja Pro Plan.', - 'enterprise_plan_product' => 'Enterprise Plan', - 'enterprise_plan_year_description' => 'One year enrollment in the Invoice Ninja Enterprise Plan.', - 'enterprise_plan_month_description' => 'One month enrollment in the Invoice Ninja Enterprise Plan.', - 'plan_credit_product' => 'Credit', - 'plan_credit_description' => 'Credit for unused time', - 'plan_pending_monthly' => 'Will switch to monthly on :date', - 'plan_refunded' => 'A refund has been issued.', + 'plan_white_label' => 'Autohébergé (sans pub)', + 'plan_free_self_hosted' => 'Autohébergé (gratuit)', + 'plan_trial' => 'Essai', + 'plan_term' => 'Terme', + 'plan_term_monthly' => 'Mensuel', + 'plan_term_yearly' => 'Annuel', + 'plan_term_month' => 'Mois', + 'plan_term_year' => 'Année', + 'plan_price_monthly' => '$:price/mois', + 'plan_price_yearly' => '$:price/année', + 'updated_plan' => 'Paramètres de mise à jour du plan', + 'plan_paid' => 'Terme depuis le', + 'plan_started' => 'Plan depuis le', + 'plan_expires' => 'Plan expire le', - 'live_preview' => 'Live Preview', - 'page_size' => 'Page Size', - 'live_preview_disabled' => 'Live preview has been disabled to support selected font', - 'invoice_number_padding' => 'Padding', - 'preview' => 'Preview', - 'list_vendors' => 'List Vendors', - 'add_users_not_supported' => 'Upgrade to the Enterprise plan to add additional users to your account.', - 'enterprise_plan_features' => 'The Enterprise plan adds support for multiple users and file attachments.', - 'return_to_app' => 'Return to app', - - -); \ No newline at end of file + 'white_label_button' => 'Sans pub', + + 'pro_plan_year_description' => 'Abonnement à une année du plan Invoice Ninja Pro.', + 'pro_plan_month_description' => 'Abonnement à un mois du plan Invoice Ninja Pro.', + 'enterprise_plan_product' => 'Plan Enterprise', + 'enterprise_plan_year_description' => 'Abonnement à une année du plan Invoice Ninja Enterprise.', + 'enterprise_plan_month_description' => 'Abonnement à une année du plan Invoice Ninja Enterprise.', + 'plan_credit_product' => 'Crédit', + 'plan_credit_description' => 'Crédit inutilisé', + 'plan_pending_monthly' => 'Passer au plan mensuel le :date', + 'plan_refunded' => 'Un remboursement vous a été émis.', + + 'live_preview' => 'Prévisualisation', + 'page_size' => 'Taille de page', + 'live_preview_disabled' => 'La prévisualisation en direct a été désactivée pour cette police', + 'invoice_number_padding' => 'Remplissage (padding)', + 'preview' => 'Prévisualistation', + 'list_vendors' => 'Liste des vendeurs', + 'add_users_not_supported' => 'Mettre à jour vers le plan Enterprise plan pour ajouter des utilisateurs à votre compte.', + 'enterprise_plan_features' => 'The Enterprise plan adds support for multiple users and file attachments, :link to see the full list of features.', + 'return_to_app' => 'Retour à l\'application', + + + // Payment updates + 'refund_payment' => 'Remboursement', + 'refund_max' => 'Max:', + 'refund' => 'Rembousement', + 'are_you_sure_refund' => 'Rembourser les paiements sélectionnés?', + 'status_pending' => 'En attente', + 'status_completed' => 'Terminée', + 'status_failed' => 'Échouée', + 'status_partially_refunded' => 'Remboursement partiel', + 'status_partially_refunded_amount' => ':amount remboursé', + 'status_refunded' => 'Remboursé', + 'status_voided' => 'Annulé', + 'refunded_payment' => 'Paiement remboursé', + 'activity_39' => ':user a annulé le paiement de :payment_amount (:payment)', + 'activity_40' => ':user a remboursé :adjustment du paiement de :payment_amount (:payment)', + 'card_expiration' => 'Exp: :expire', + + 'card_creditcardother' => 'Inconnu', + 'card_americanexpress' => 'American Express', + 'card_carteblanche' => 'Carte Blanche', + 'card_unionpay' => 'UnionPay', + 'card_diners' => 'Diners Club', + 'card_discover' => 'Discover', + 'card_jcb' => 'JCB', + 'card_laser' => 'Laser', + 'card_maestro' => 'Maestro', + 'card_mastercard' => 'MasterCard', + 'card_solo' => 'Solo', + 'card_switch' => 'Switch', + 'card_visacard' => 'Visa', + 'card_ach' => 'ACH', + + 'payment_type_stripe' => 'Stripe', + 'ach' => 'ACH', + 'enable_ach' => 'Activer ACH', + 'stripe_ach_help' => 'Les fonctionnalités de ACH requiert d\'être aussi activées pour Stripe.', + 'ach_disabled' => 'Another gateway is already configured for direct debit.', + + 'plaid' => 'Plaid', + 'client_id' => 'ID du client', + 'secret' => 'Secret', + 'public_key' => 'Clé publique', + 'plaid_optional' => '(optionel)', + 'plaid_environment_help' => 'Lorsque une clé de test est fournie, l’environnement de test Plaid (tartan) sera utilisé.', + 'other_providers' => 'Autres fournisseurs', + 'country_not_supported' => 'Ce pays n\'est pas supporté', + 'invalid_routing_number' => 'Le numéro de routage n\'est pas valide', + 'invalid_account_number' => 'Le numéro de compte n\'est pas valide', + 'account_number_mismatch' => 'Les numéros de compte ne correspondent pas', + 'missing_account_holder_type' => 'Veuillez sélectionner le type de compte (personnel / entreprise)', + 'missing_account_holder_name' => 'Veuillez entrer le nom du détenteur du compte', + 'routing_number' => 'Numéro de routage', + 'confirm_account_number' => 'Veuillez confirmer le numéro de compte', + 'individual_account' => 'Compte personnel', + 'company_account' => 'Compte d\'entreprise', + 'account_holder_name' => 'Nom du détenteur', + 'add_account' => 'Ajouter un compte', + 'payment_methods' => 'Méthodes de paiement', + 'complete_verification' => 'Compléter la vérification', + 'verification_amount1' => 'Montant 1', + 'verification_amount2' => 'Montant 2', + 'payment_method_verified' => 'La vérification a été complétée', + 'verification_failed' => 'La vérification a échoué', + 'remove_payment_method' => 'Retirer la méthode de paiement', + 'confirm_remove_payment_method' => 'Souhaitez-vous vraiment retirer cette méthode de paiement?', + 'remove' => 'Retirer', + 'payment_method_removed' => 'Méthode de paiement retirée', + 'bank_account_verification_help' => 'Nous avons fait deux dépôts dans votre compte avec la description "VERIFICATION". Ces dépôts prendront 1-2 jours ouvrables pour apparaître sur le relevé. Veuillez entrer les montants ci-dessous.', + 'bank_account_verification_next_steps' => 'Nous avons fait deux dépôts dans votre compte avec la description "VERIFICATION". Ces dépôts prendront 1-2 jours ouvrables pour apparaître sur votre relevé. +Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette page et cliquez sur "Compléter la vérification" à côté du compte.', + 'unknown_bank' => 'Banque inconnue', + 'ach_verification_delay_help' => 'Vous serez en mesure d\'utiliser le compte après avoir terminé la vérification. La vérification prend habituellement 1-2 jours ouvrables.', + 'add_credit_card' => 'Ajouter une carte de crédit', + 'payment_method_added' => 'Ajouter une méthode de paiement', + 'use_for_auto_bill' => 'Utiliser pour les factures automatiques', + 'used_for_auto_bill' => 'Méthode de paiement de factures automatiques', + 'payment_method_set_as_default' => 'Configurer la méthode de paiement des factures automatiques.', + 'activity_41' => 'Le paiement de :payment_amount a échoué (:payment)', + 'webhook_url' => 'URL Webhook', + 'stripe_webhook_help' => 'Vous devez :link.', + 'stripe_webhook_help_link_text' => 'ajouter cette URL comme un terminal avec Stripe', + 'payment_method_error' => 'Une erreur s\'est produite en ajoutant votre méthode de paiement. Veuillez réessayer plus tard.', + 'notification_invoice_payment_failed_subject' => 'Le paiement a échoué pour la facture :invoice', + 'notification_invoice_payment_failed' => 'Un paiement fait par le client :client pour la facture :invoice à échoué. Le paiement a été marqué comme échoué et :amount a été ajouté au solde du client.', + 'link_with_plaid' => 'Lier le compte instantanément avec Plaid', + 'link_manually' => 'Lier manuellement', + 'secured_by_plaid' => 'Sécurisé par Plaid', + 'plaid_linked_status' => 'Votre compte de banque à :bank', + 'add_payment_method' => 'Ajouter une méthode de paiement', + 'account_holder_type' => 'Type de compte du détenteur', + 'ach_authorization' => 'I authorize :company to use my bank account for future payments and, if necessary, electronically credit my account to correct erroneous debits. I understand that I may cancel this authorization at any time by removing the payment method or by contacting :email.', + 'ach_authorization_required' => 'Vous devez consentir aux transactions ACH.', + 'off' => 'Fermé', + 'opt_in' => 'Activer', + 'opt_out' => 'Désactiver', + 'always' => 'Toujours', + 'opted_out' => 'Désactivé', + 'opted_in' => 'Activé', + 'manage_auto_bill' => 'Gérer les factures automatiques', + 'enabled' => 'Activé', + 'paypal' => 'PayPal', + 'braintree_enable_paypal' => 'Activer les paiements PayPal via BrainTree', + 'braintree_paypal_disabled_help' => 'La passerelle PayPal traite les paiements PayPal', + 'braintree_paypal_help' => 'Vous devez aussi :link.', + 'braintree_paypal_help_link_text' => 'lier PayPal à votre compte BrainTree', + 'token_billing_braintree_paypal' => 'Sauvegarder les détails du paiement', + 'add_paypal_account' => 'Ajouter un compte PayPal', + + + 'no_payment_method_specified' => 'Aucune méthode de paiement spécifiée', + 'chart_type' => 'Type de graphique', + 'format' => 'Format', + 'import_ofx' => 'Importer OFX', + 'ofx_file' => 'Fichier OFX', + 'ofx_parse_failed' => 'Le traitement du fichier OFX a échoué', + + // WePay + 'wepay' => 'WePay', + 'sign_up_with_wepay' => 'S\'enregistrer avec WePay', + 'use_another_provider' => 'Utiliser un autre fournisseur', + 'company_name' => 'Nom de l\'entreprise', + 'wepay_company_name_help' => 'Ceci apparaitra sur le relevé de carte de crédit du client', + 'wepay_description_help' => 'Le but de ce compte.', + 'wepay_tos_agree' => 'J\'accepte les :link.', + 'wepay_tos_link_text' => 'Conditions d\'utilisation de WePay', + 'resend_confirmation_email' => 'Renvoyer le courriel de confirmation', + 'manage_wepay_account' => 'Gérer le compte WePay', + 'action_required' => 'Action requise', + 'finish_setup' => 'Terminer la configuration', + 'created_wepay_confirmation_required' => 'Veuillez vérifier vos courriel et confirmer votre adresse courriel avec WePay.', + 'switch_to_wepay' => 'Changer pour WePay', + 'switch' => 'Changer', + 'restore_account_gateway' => 'Restaurer la passerelle de paiement', + 'restored_account_gateway' => 'La passerelle de paiement a été restaurée', + 'united_states' => 'États-Unis', + 'canada' => 'Canada', + 'accept_debit_cards' => 'Accepter les cartes de débit', + 'debit_cards' => 'Cartes de débit', + + 'warn_start_date_changed' => 'The next invoice will be sent on the new start date.', + 'original_start_date' => 'Original start date', + 'new_start_date' => 'New start date', + 'security' => 'Security', + 'see_whats_new' => 'See what\'s new in v:version', + 'wait_for_upload' => 'Please wait for the document upload to complete.', + 'upgrade_for_permissions' => 'Upgrade to our Enterprise plan to enable permissions.', + 'enable_second_tax_rate' => 'Enable specifying a second tax rate', + 'payment_file' => 'Payment File', + 'expense_file' => 'Expense File', + 'product_file' => 'Product File', + 'import_products' => 'Import Products', + 'products_will_create' => 'products will be created.', + 'product_key' => 'Product', + 'created_products' => 'Successfully created :count product(s)', + 'export_help' => 'Use JSON if you plan to import the data into Invoice Ninja.', + 'JSON_file' => 'JSON File', + + 'view_dashboard' => 'View Dashboard', + 'client_session_expired' => 'Session Expired', + 'client_session_expired_message' => 'Your session has expired. Please click the link in your email again.', + + 'auto_bill_notification' => 'This invoice will automatically be billed to your :payment_method on file on :due_date.', + 'auto_bill_payment_method_bank_transfer' => 'bank account', + 'auto_bill_payment_method_credit_card' => 'credit card', + 'auto_bill_payment_method_paypal' => 'PayPal account', + 'auto_bill_notification_placeholder' => 'This invoice will automatically be billed to your credit card on file on the due date.', + 'payment_settings' => 'Payment Settings', + + 'on_send_date' => 'On send date', + 'on_due_date' => 'On due date', + 'auto_bill_ach_date_help' => 'ACH auto bill will always happen on the due date', + 'warn_change_auto_bill' => 'Due to NACHA rules, changes to this invoice may prevent ACH auto bill.', + + 'bank_account' => 'Bank Account', + 'payment_processed_through_wepay' => 'ACH payments will be processed using WePay.', + 'wepay_payment_tos_agree' => 'I agree to the WePay :terms and :privacy_policy.', + 'privacy_policy' => 'Privacy Policy', + 'wepay_payment_tos_agree_required' => 'You must agree to the WePay Terms of Service and Privacy Policy.', + 'payment_settings_supported_gateways' => 'These options are supported by the WePay, Stripe, and Braintree gateways.', + 'ach_email_prompt' => 'Please enter your email address:', + 'verification_pending' => 'Verification Pending', + + 'update_font_cache' => 'Please force refresh the page to update the font cache.', + 'more_options' => 'More options', + 'credit_card' => 'Credit Card', + 'bank_transfer' => 'Bank Transfer', + 'no_transaction_reference' => 'We did not recieve a payment transaction reference from the gateway.', + 'use_bank_on_file' => 'Use Bank on File', + 'auto_bill_email_message' => 'This invoice will automatically be billed to the payment method on file on the due date.', + 'bitcoin' => 'Bitcoin', + 'added_on' => 'Added :date', + 'failed_remove_payment_method' => 'Failed to remove the payment method', + 'gateway_exists' => 'This gateway already exists', + 'manual_entry' => 'Manual entry', + +); + +return $LANG; + +?> diff --git a/resources/lang/hr/auth.php b/resources/lang/hr/auth.php new file mode 100644 index 0000000000..2142a42f94 --- /dev/null +++ b/resources/lang/hr/auth.php @@ -0,0 +1,19 @@ + 'Ovi podaci ne odgovaraju našima.', + 'throttle' => 'Previše pokušaja prijave. Molim Vas pokušajte ponovno za :seconds sekundi.', + +]; diff --git a/resources/lang/hr/pagination.php b/resources/lang/hr/pagination.php new file mode 100644 index 0000000000..e0bed173da --- /dev/null +++ b/resources/lang/hr/pagination.php @@ -0,0 +1,19 @@ + '« Prethodna', + 'next' => 'Sljedeća »', + +]; diff --git a/resources/lang/hr/passwords.php b/resources/lang/hr/passwords.php new file mode 100644 index 0000000000..59f39af3fe --- /dev/null +++ b/resources/lang/hr/passwords.php @@ -0,0 +1,22 @@ + 'Lozinke moraju biti duge barem 6 znakova i moraju odgovarati potvrdi.', + 'reset' => 'Lozinka je postavljena!', + 'sent' => 'Poveznica za ponovono postavljanje lozinke je poslana!', + 'token' => 'Oznaka za ponovno postavljanje lozinke više nije važeća.', + 'user' => 'Korisnik nije pronađen.', + +]; diff --git a/resources/lang/hr/texts.php b/resources/lang/hr/texts.php new file mode 100644 index 0000000000..18170932bd --- /dev/null +++ b/resources/lang/hr/texts.php @@ -0,0 +1,1369 @@ + 'Organizacija', + 'name' => 'Ime', + 'website' => 'Web mjesto', + 'work_phone' => 'Telefon', + 'address' => 'Adresa', + 'address1' => 'Ulica', + 'address2' => 'Kat/soba', + 'city' => 'Grad', + 'state' => 'Županija', + 'postal_code' => 'Poštanski broj', + 'country_id' => 'Zemlja', + 'contacts' => 'Kontakti', + 'first_name' => 'Ime', + 'last_name' => 'Prezime', + 'phone' => 'Telefon', + 'email' => 'E-pošta', + 'additional_info' => 'Dodatne informacije', + 'payment_terms' => 'Uvjeti plaćanja', + 'currency_id' => 'Valuta', + 'size_id' => 'Veličina poduzeća', + 'industry_id' => 'Djelatnost', + 'private_notes' => 'Privatne bilješke', + 'invoice' => 'Račun', + 'client' => 'Klijent', + 'invoice_date' => 'Datum računa', + 'due_date' => 'Datum dospijeća', + 'invoice_number' => 'Broj računa', + 'invoice_number_short' => 'Račun #', + 'po_number' => 'Broj narudžbe', + 'po_number_short' => 'NN #', + 'frequency_id' => 'Koliko često', + 'discount' => 'Popust', + 'taxes' => 'Porezi', + 'tax' => 'Porez', + 'item' => 'Stavka', + 'description' => 'Opis', + 'unit_cost' => 'Jedinična cijena', + 'quantity' => 'Količina', + 'line_total' => 'Ukupno', + 'subtotal' => 'Sveukupno', + 'paid_to_date' => 'Plaćeno na vrijeme', + 'balance_due' => 'Stanje duga', + 'invoice_design_id' => 'Dizajn', + 'terms' => 'Uvjeti', + 'your_invoice' => 'Vaš račun', + 'remove_contact' => 'Ukloni kontakt', + 'add_contact' => 'Dodaj kontakt', + 'create_new_client' => 'Kreiraj novog klijenta', + 'edit_client_details' => 'Uredi detalje klijenta', + 'enable' => 'Omogući', + 'learn_more' => 'Više informacija', + 'manage_rates' => 'Upravljanje ratam', + 'note_to_client' => 'Bilješka klijentu', + 'invoice_terms' => 'Uvjeti računa', + 'save_as_default_terms' => 'Pohrani kao zadane uvjete', + 'download_pdf' => 'Preuzmi PDF', + 'pay_now' => 'Plati odmah', + 'save_invoice' => 'Pohrani račun', + 'clone_invoice' => 'Kloniraj račun', + 'archive_invoice' => 'Arhiviraj račun', + 'delete_invoice' => 'Obriši račun', + 'email_invoice' => 'Pošalji e-poštom', + 'enter_payment' => 'Unesi uplatu', + 'tax_rates' => 'Porezne stope', + 'rate' => 'Stopa', + 'settings' => 'Postavke', + 'enable_invoice_tax' => 'Omogući specificiranje poreza na računu', + 'enable_line_item_tax' => 'Omogući specifikaciju poreza na stavci', + 'dashboard' => 'Kontrolna ploča', + 'clients' => 'Klijenti', + 'invoices' => 'Računi', + 'payments' => 'Uplate', + 'credits' => 'Krediti', + 'history' => 'Povijest', + 'search' => 'Pretraga', + 'sign_up' => 'Prijava', + 'guest' => 'Gost', + 'company_details' => 'Detalji poduzeća', + 'online_payments' => 'Online uplate', + 'notifications' => 'Obavijesti e-poštom', + 'import_export' => 'Import | Export', + 'done' => 'Dovršeno', + 'save' => 'Pohrani', + 'create' => 'Kreiraj', + 'upload' => 'Otpremi', + 'import' => 'Uvoz', + 'download' => 'Preuzmi', + 'cancel' => 'Odustani', + 'close' => 'Zatvori', + 'provide_email' => 'Molim, osigurajte ispravnu adresu e-pošte', + 'powered_by' => 'Powered by', + 'no_items' => 'Nema stavki', + 'recurring_invoices' => 'Redovni računi', + 'recurring_help' => '

    Automatski šalje klijentu istovjetan račun tjedno, dvotjedno, mjesečno, kvartalno ili godišnje.

    +

    Koristite :MONTH, :QUARTER ili :YEAR za dinamičke datume. Osnovna operacije također rade, npr. :MONTH-1.

    +

    Primjeri dinamičkih varijabli računa:

    +
      +
    • "Članarina za teretanu za mjesec :MONTH" => "Članarina za teratanu za mjesec srpanj"
    • +
    • ":YEAR+1 godišnja pretplata" => "2015 godišnja pretplata"
    • +
    • "Uplata predujma za :QUARTER+1" => "Uplata predujma za Q2"
    • +
    ', + 'in_total_revenue' => 'ukupni prihod', + 'billed_client' => 'fakturirani klijent', + 'billed_clients' => 'fakturairani klijenti', + 'active_client' => 'aktivni klijent', + 'active_clients' => 'aktivni klijenti', + 'invoices_past_due' => 'Računi van valute', + 'upcoming_invoices' => 'Dolazni računi', + 'average_invoice' => 'Proječni račun', + 'archive' => 'Arhiva', + 'delete' => 'Obriši', + 'archive_client' => 'Arhiviraj klijenta', + 'delete_client' => 'Obriši klijenta', + 'archive_payment' => 'Arhiviraj uplatu', + 'delete_payment' => 'Obriši uplatu', + 'archive_credit' => 'Arhiviraj kredit', + 'delete_credit' => 'Obriši kredit', + 'show_archived_deleted' => 'Prikaži arhivirano/obrisano', + 'filter' => 'Filter', + 'new_client' => 'Novi klijent', + 'new_invoice' => 'Novi račun', + 'new_payment' => 'New Payment', + 'new_credit' => 'New Credit', + 'contact' => 'Kontakt', + 'date_created' => 'Datum kreiranja', + 'last_login' => 'Zadnja prijava', + 'balance' => 'Stanje', + 'action' => 'Akcija', + 'status' => 'Status', + 'invoice_total' => 'Račun sveukupno', + 'frequency' => 'Frekvencija', + 'start_date' => 'Početni datum', + 'end_date' => 'Završni datum', + 'transaction_reference' => 'Referenca transakcije', + 'method' => 'Metoda', + 'payment_amount' => 'Iznos uplate', + 'payment_date' => 'Datum uplate', + 'credit_amount' => 'Iznos kredita', + 'credit_balance' => 'Stanje kredita', + 'credit_date' => 'Datum kredita', + 'empty_table' => 'Nema dostupnih podataka u tablici', + 'select' => 'Odaberi', + 'edit_client' => 'Uredi klijenta', + 'edit_invoice' => 'Uredi račun', + 'create_invoice' => 'Kreiraj račun', + 'enter_credit' => 'Unesi kredit', + 'last_logged_in' => 'Zadnja prijava na', + 'details' => 'Detalji', + 'standing' => 'Stanje', + 'credit' => 'Kredit', + 'activity' => 'Aktivnost', + 'date' => 'Datum', + 'message' => 'Poruka', + 'adjustment' => 'Prilagodba', + 'are_you_sure' => 'Da li ste sigurni?', + 'payment_type_id' => 'Tip uplate', + 'amount' => 'Iznos', + 'work_email' => 'E-pošta', + 'language_id' => 'Jezik', + 'timezone_id' => 'Vremnska zona', + 'date_format_id' => 'Date Format', + 'datetime_format_id' => 'Datum/Vrijeme format', + 'users' => 'Korisnici', + 'localization' => 'Lokalizacija', + 'remove_logo' => 'Ukloni logo', + 'logo_help' => 'Podržano: JPEG, GIF i PNG', + 'payment_gateway' => 'Usmjernik naplate', + 'gateway_id' => 'Usmjernik', + 'email_notifications' => 'Obavijesti e-poštom', + 'email_sent' => 'Obavijesti me e-poštom kada je račun poslan', + 'email_viewed' => 'Obavijesti me e-poštom kada je račun pregledan', + 'email_paid' => 'Obavijest me e-poštom kada je račun plaćen', + 'site_updates' => 'Ažuriranja', + 'custom_messages' => 'Prilagođene poruke', + 'default_email_footer' => 'Postavi zadani potpis e-pošte', + 'select_file' => 'Mollim odaberite datoteku', + 'first_row_headers' => 'Koristi prvi redak kao naslovni', + 'column' => 'Kolona', + 'sample' => 'Uzorak', + 'import_to' => 'Uvezi u', + 'client_will_create' => 'klijent će biti kreiran', + 'clients_will_create' => 'klijenti će biti kreirani', + 'email_settings' => 'Postavke e-pošte', + 'client_view_styling' => 'Stil pregleda klijenta', + 'pdf_email_attachment' => 'Priloži PDF', + 'custom_css' => 'Prilagođeni CSS', + 'import_clients' => 'Uvezi podatke klijenta', + 'csv_file' => 'CSV datoteka', + 'export_clients' => 'Izvezi podatke klijenta', + 'created_client' => 'Klijent je uspješno kreiran', + 'created_clients' => 'Uspješno kreirano :count kijenata', + 'updated_settings' => 'Postavke su uspješno ažurirane', + 'removed_logo' => 'Logo je uspješno uklonjen', + 'sent_message' => 'Poruka je uspješno poslana', + 'invoice_error' => 'Molimo provjerite da odaberete klijenta i korigirate greške', + 'limit_clients' => 'Nažalost, ovime ćete preći limit od :count klijenata', + 'payment_error' => 'Došlo je do greške pri procesuiranju vaše uplate. Molimo pokušajte kasnije.', + 'registration_required' => 'Molimo prijavite se prije slanja računa e-poštom', + 'confirmation_required' => 'Molimo potvrdite svoju adresu e-pošte', + 'updated_client' => 'Uspješno ažuriranje klijenta', + 'created_client' => 'Klijent je uspješno kreiran', + 'archived_client' => 'Uspješno arhiviran klijent', + 'archived_clients' => 'Uspješno arhivirano :count klijenata', + 'deleted_client' => 'Uspješno obrisan klijent', + 'deleted_clients' => 'Uspješno obrisano :count klijenata', + 'updated_invoice' => 'Uspješno ažuriran račun', + 'created_invoice' => 'Uspješno kreiran račun', + 'cloned_invoice' => 'Uspješno kloniran račun', + 'emailed_invoice' => 'Račun uspješno poslan e-poštom', + 'and_created_client' => 'i kreiran račun', + 'archived_invoice' => 'Uspješno arhiviran račun', + 'archived_invoices' => 'Uspješno arhivirano :count računa', + 'deleted_invoice' => 'Uspješno obrisan račun', + 'deleted_invoices' => 'Uspješno obrisano :count računa', + 'created_payment' => 'Uspješno kreirana uplata', + 'created_payments' => 'Uspješno kreirano :count uplata', + 'archived_payment' => 'Uspješno arhivirana uplata', + 'archived_payments' => 'Uspješno arhivirana :count uplata', + 'deleted_payment' => 'Uspješno obrisana uplata', + 'deleted_payments' => 'Uspješno obrisano :count uplata', + 'applied_payment' => 'Uspješno primjenjena uplata', + 'created_credit' => 'Uspješno kreiran kredit', + 'archived_credit' => 'Uspješno arhiviran kredit', + 'archived_credits' => 'Uspješno arhivirano :count kredita', + 'deleted_credit' => 'Uspješno obrisan kredit', + 'deleted_credits' => 'Uspješno obrisano :count kredita', + 'imported_file' => 'Uspješno uvezena datoteka', + 'updated_vendor' => 'Uspješno ažuriran dobavljač', + 'created_vendor' => 'Uspješno kreiran dobavljač', + 'archived_vendor' => 'Uspješno arhiviran dobavljač', + 'archived_vendors' => 'Uspješno arhivirano :count dobavljača', + 'deleted_vendor' => 'Uspješno obrisan dobavljač', + 'deleted_vendors' => 'Uspješno obrisano :count dobavljača', + 'confirmation_subject' => 'Invoice Ninja odobravanje računa', + 'confirmation_header' => 'Odobrenje računa', + 'confirmation_message' => 'Molimo pristupite donjom poveznicom za odobrenje vašeg računa.', + 'invoice_subject' => 'Novi račun :invoice za :account', + 'invoice_message' => 'Za pregled vašeg računa na :amount, kliknite donju poveznicu.', + 'payment_subject' => 'Primljena uplata', + 'payment_message' => 'Hvala vam na vašoj uplati od :amount.', + 'email_salutation' => 'Poštovani/a :name,', + 'email_signature' => 'Srdačno,', + 'email_from' => 'Invoice Ninja tim', + 'invoice_link_message' => 'Za pregled računa kliknite na donju poveznicu:', + 'notification_invoice_paid_subject' => ':client je platio račun :invoice', + 'notification_invoice_sent_subject' => 'Račun :invoice je poslan :client', + 'notification_invoice_viewed_subject' => ':client je pregledao račun :invoice', + 'notification_invoice_paid' => 'Uplata u iznosu :amount je izvršena od strane :client prema računu :invoice.', + 'notification_invoice_sent' => 'Slijedećem klijentu :client je poslan e-poštom račun :invoice na iznos :amount.', + 'notification_invoice_viewed' => 'Slijedeći klijent :client je pregledao račun :invoice na iznos :amount.', + 'reset_password' => 'Možete resetirati zaporku za pristup svom računu klikom na tipku:', + 'secure_payment' => 'Sigurna uplata', + 'card_number' => 'Broj kartice', + 'expiration_month' => 'Mjesec isteka', + 'expiration_year' => 'Godina isteka', + 'cvv' => 'CVV', + 'logout' => 'Odjava', + 'sign_up_to_save' => 'Prijavite se kako bi pohranili učinjeno', + 'agree_to_terms' => 'Slažem se sa Invoice Ninja :terms', + 'terms_of_service' => 'Uvjeti korištenja usluge', + 'email_taken' => 'Ova adresa e-pošte je već registrirana', + 'working' => 'Rad u tijeku', + 'success' => 'Uspjeh', + 'success_message' => 'Uspješno ste se registrirali! Molimo kliknite na poveznicu za potvrdu računa dobivenu e-poštom kako bi verificirali svoju adresu e-pošte.', + 'erase_data' => 'Ovo će trajno obrisate vaše podatke.', + 'password' => 'Zaporka', + 'pro_plan_product' => 'Pro Plan', + 'pro_plan_success' => 'Hvala vam na odabiru Invoice Ninja Pro plana!

     
    + Slijedeći koraci

    Račun je poslan na adresu e-pošte povezanu + sa vašim korisničkim računom. Za otključavanje svih naprednih + Pro mogućnosti, molimo pratite upute za plaćanje godišnje pretplate + za Invoice Ninja Pro plan.

    + Ne možete naći račun? Trebate dodatnu pomoć? Sa zadovoljstvom ćemo pomoći + -- pošaljite nam e-poštu na contact@invoiceninja.com', + 'unsaved_changes' => 'Imate nepohranjenih promjena', + 'custom_fields' => 'Prilagođena polja', + 'company_fields' => 'Polja poduzeća', + 'client_fields' => 'Polja klijenta', + 'field_label' => 'Oznaka polja', + 'field_value' => 'Vrijednost polja', + 'edit' => 'Uredi', + 'set_name' => 'Postavite ime poduzeća', + 'view_as_recipient' => 'Pregledajte kao primatelj', + 'product_library' => 'Registar proizvoda', + 'product' => 'Proizvod', + 'products' => 'Registar proizvoda', + 'fill_products' => 'Proizvodi sa samoispunom', + 'fill_products_help' => 'Odabir proizvoda će automatski ispuniti opis i cijenu', + 'update_products' => 'Proizvidi sa autoažuriranjem', + 'update_products_help' => 'Ažuriranje računa automatski ažurirati registar proizvoda', + 'create_product' => 'Dodaj proizvod', + 'edit_product' => 'Uredi proizvod', + 'archive_product' => 'Arhiviraj proizvod', + 'updated_product' => 'Proizvod je uspješno ažuriran', + 'created_product' => 'Proizvod je uspješno kreiran', + 'archived_product' => 'Proizvod je uspješno arhiviran', + 'pro_plan_custom_fields' => ':link za omogućavanje prilagođenih polja aktivacijom Pro plana', + 'advanced_settings' => 'Napredne postavke', + 'pro_plan_advanced_settings' => ':link za omogućavanje naprednih postavki aktivacijom Pro plana', + 'invoice_design' => 'Dizajn računa', + 'specify_colors' => 'Odabir boja', + 'specify_colors_label' => 'Odaberite boje korištenje u računu', + 'chart_builder' => 'Graditelj karte', + 'ninja_email_footer' => 'Koristite :site za slanje računa klijentima i primanje uplata online besplatno!', + 'go_pro' => 'Go Pro', + 'quote' => 'Ponuda', + 'quotes' => 'Ponude', + 'quote_number' => 'Broj ponude', + 'quote_number_short' => 'Ponuda #', + 'quote_date' => 'Datum ponude', + 'quote_total' => 'Ponuda sveukupno', + 'your_quote' => 'Vaša ponuda', + 'total' => 'Sveukupno', + 'clone' => 'Kloniraj', + 'new_quote' => 'Nova ponuda', + 'create_quote' => 'Kreiraj ponudu', + 'edit_quote' => 'Uredi ponudu', + 'archive_quote' => 'Arhiviraj ponudu', + 'delete_quote' => 'Obriši ponudu', + 'save_quote' => 'Pohrani ponudu', + 'email_quote' => 'Šalji ponudu e-poštom', + 'clone_quote' => 'Kloniraj ponudu', + 'convert_to_invoice' => 'Konverzija računa', + 'view_invoice' => 'Pregled računa', + 'view_client' => 'Pregled klijenta', + 'view_quote' => 'Pregled ponude', + 'updated_quote' => 'Ponuda je uspješno ažurirana', + 'created_quote' => 'Ponuda uspješno kreirana', + 'cloned_quote' => 'Ponuda uspješno klonirana', + 'emailed_quote' => 'Ponuda uspješno poslana e-poštom', + 'archived_quote' => 'Ponuda uspješno arhivirana', + 'archived_quotes' => 'Uspješno arhivirano :count ponuda', + 'deleted_quote' => 'Ponuda uspješno obrisana', + 'deleted_quotes' => 'Uspješno obrisano :count ponuda', + 'converted_to_invoice' => 'Ponuda uspješno konvertirana u račun', + 'quote_subject' => 'Nova ponuda $quote sa :account', + 'quote_message' => 'Za pregled vaše ponude na :amount, kliknite na donju poveznicu.', + 'quote_link_message' => 'Za pregled ponude vašeg klijenta kliknite na donju poveznicu:', + 'notification_quote_sent_subject' => 'Ponuda :invoice je poslana :client', + 'notification_quote_viewed_subject' => 'Ponuda :invoice je pregledana od :client', + 'notification_quote_sent' => 'Klijentu :client je e-poštom poslana ponuda :invoice na :amount.', + 'notification_quote_viewed' => 'Klijent :client je pregledao ponudu :invoice na :amount.', + 'session_expired' => 'Vaša sjednica je istekla.', + 'invoice_fields' => 'Polja računa', + 'invoice_options' => 'Opcije računa', + 'hide_quantity' => 'Sakrij količinu', + 'hide_quantity_help' => 'Ukoliko su količine vaših stavaka uvijek 1, tada možete isključiti sa računa podatke o količini.', + 'hide_paid_to_date' => 'Sakrij datum plaćanja', + 'hide_paid_to_date_help' => 'Prikažite "Datum plaćanja" na računima, onda kada je uplata primljena.', + 'charge_taxes' => 'Naplati poreze', + 'user_management' => 'Upravljanje korisnicima', + 'add_user' => 'Dodaj korisnika', + 'send_invite' => 'Pošalji pozivnicu', + 'sent_invite' => 'Uspješno poslana pozivnica', + 'updated_user' => 'Korisnik je uspješno ažuriran', + 'invitation_message' => 'Dobili ste pozivnicu od :invitor.', + 'register_to_add_user' => 'Molimo prijavite se za dodavanje korisnika', + 'user_state' => 'Stanje', + 'edit_user' => 'Uredi korisnika', + 'delete_user' => 'Obriši korisnika', + 'active' => 'Aktivan', + 'pending' => 'Na čekanju', + 'deleted_user' => 'Korisnik je uspješno obrisan', + 'confirm_email_invoice' => 'Da li sigurno želite poslati ovaj račun e-poštom?', + 'confirm_email_quote' => 'Da li sigurno želite poslati ovu ponudu e-poštom?', + 'confirm_recurring_email_invoice' => 'Da li ste sigurni da želite poslati ovaj račun e-poštom?', + 'cancel_account' => 'Delete Account', + 'cancel_account_message' => 'Pozor: Ovo će trajno obrisati sve vaše podatke, nema povratka.', + 'go_back' => 'Idi natrag', + 'data_visualizations' => 'Vizualizacije podataka', + 'sample_data' => 'Prikaz primjernih podataka', + 'hide' => 'Sakrij', + 'new_version_available' => 'Nova verzija :releases_link je dostupna. Vi koristite v:user_version, a najnovija je v:latest_version', + 'invoice_settings' => 'Postavke računa', + 'invoice_number_prefix' => 'Prefiks broja računa', + 'invoice_number_counter' => 'Brojač računa', + 'quote_number_prefix' => 'Prefiks broja ponude', + 'quote_number_counter' => 'Brojač ponuda', + 'share_invoice_counter' => 'Dijeljeni brojač računa', + 'invoice_issued_to' => 'Račun izdan', + 'invalid_counter' => 'Za izbjegavanje mogućih konflikata molimo postavite prefiks na broju računa i ponude', + 'mark_sent' => 'Označi kao poslano', + 'gateway_help_1' => ':link za pristup na Authorize.net.', + 'gateway_help_2' => ':link za pristup na Authorize.net.', + 'gateway_help_17' => ':link za pristup vašem PayPal API potpisu.', + 'gateway_help_27' => ':link za pristup za TwoCheckout.', + 'more_designs' => 'Više dizajna', + 'more_designs_title' => 'Dodatni dizajni računa', + 'more_designs_cloud_header' => 'Nadogradite na Pro za više dizajna računa', + 'more_designs_cloud_text' => '', + 'more_designs_self_host_text' => '', + 'buy' => 'Kupi', + 'bought_designs' => 'Uspješno nadodani dizajni računa', + 'sent' => 'poslano', + 'vat_number' => 'OIB', + 'timesheets' => 'Vremenik', + 'payment_title' => 'Unesite svoju adresu računa i informacije kreditne kartice', + 'payment_cvv' => '*Ovo je 3-4 znamenkasti broj na poleđini vaše kartice', + 'payment_footer1' => '*Adresa računa mora se poklapati s adresom na kreditnoj kartici.', + 'payment_footer2' => '*Molimo kliknite "PLATI ODMAH" samo jednom - transakcija može izvoditi i do 1 minute.', + 'id_number' => 'ID broj', + 'white_label_link' => 'Bijela oznaka', + 'white_label_header' => 'Bijela oznaka', + 'bought_white_label' => 'Uspješno je omogućena licenca za bijele oznake', + 'white_labeled' => 'Označeno bijelom oznakom', + 'restore' => 'Obnovi', + 'restore_invoice' => 'Obnovi račun', + 'restore_quote' => 'Obnovi narudžbu', + 'restore_client' => 'Obnovi klijenta', + 'restore_credit' => 'Obnovi kredit', + 'restore_payment' => 'Obnovi uplatu', + 'restored_invoice' => 'Uspješno obnovljen račun', + 'restored_quote' => 'Uspješno obnovljena ponuda', + 'restored_client' => 'Uspješno obnovljen klijent', + 'restored_payment' => 'Uspješno obnovljena uplata', + 'restored_credit' => 'Uspješno obnovljen kredit', + 'reason_for_canceling' => 'Pomozite nam unaprijediti web mjesto informacijom zašto odlazite.', + 'discount_percent' => 'Postotak', + 'discount_amount' => 'Iznos', + 'invoice_history' => 'Povijest računa', + 'quote_history' => 'Povijest ponude', + 'current_version' => 'Trenutna verzija', + 'select_version' => 'Select version', + 'view_history' => 'Pregled povijesti', + 'edit_payment' => 'Uredi uplatu', + 'updated_payment' => 'Uspješno ažurirana uplata', + 'deleted' => 'Obrisano', + 'restore_user' => 'Obnovi korisnika', + 'restored_user' => 'Uspješno obnovljen korisnik', + 'show_deleted_users' => 'Prikaži obrisane korisnike', + 'email_templates' => 'Predlošci e-pošte', + 'invoice_email' => 'E-pošta računa', + 'payment_email' => 'E-pošta uplate', + 'quote_email' => 'E-pošta ponude', + 'reset_all' => 'Resetiraj sve', + 'approve' => 'Odobri', + 'token_billing_type_id' => 'Token naplata', + 'token_billing_help' => 'Omogućava vam pohranu kreditnih kartica sa vašim usmjernikom i naplatu po njima po nadolazećim datumima.', + 'token_billing_1' => 'Onemogućeno', + 'token_billing_2' => 'Opt-in - odabir je prikazan ali nije selektiran', + 'token_billing_3' => 'Opt-out - odabir je prikazan i selektiran', + 'token_billing_4' => 'Uvijek', + 'token_billing_checkbox' => 'Pohrani detalje kreditne kartice', + 'view_in_gateway' => 'View in :gateway', + 'use_card_on_file' => 'Use Card on File', + 'edit_payment_details' => 'Uredi detalje plaćanja', + 'token_billing' => 'Pohrani detalje kartice', + 'token_billing_secure' => 'The data is stored securely by :link', + 'support' => 'Podrška', + 'contact_information' => 'Kontaktne informacije', + '256_encryption' => '256-bitna enkripcija', + 'amount_due' => 'Dospjeli iznos', + 'billing_address' => 'Adresa računa', + 'billing_method' => 'Metoda naplate', + 'order_overview' => 'Pregled narudžbe', + 'match_address' => '*Adresa se mora poklapati s adresom kreditne kartice.', + 'click_once' => '*Molimo kliknite "PLATI ODMAH" samo jednom - transakcija može izvoditi i do 1 minute.', + 'invoice_footer' => 'Podnožje računa', + 'save_as_default_footer' => 'Pohrani kao zadano podnožje', + 'token_management' => 'Upravljanje tokenima', + 'tokens' => 'Tokeni', + 'add_token' => 'Dodaj token', + 'show_deleted_tokens' => 'Prikaži obrisane tokene', + 'deleted_token' => 'Uspješno obrisan token', + 'created_token' => 'Uspješno kreiran token', + 'updated_token' => 'Uspješno ažuriran token', + 'edit_token' => 'Uredi token', + 'delete_token' => 'Obriši token', + 'token' => 'Token', + 'add_gateway' => 'Dodaj usmjernik', + 'delete_gateway' => 'Obriši usmjernik', + 'edit_gateway' => 'Uredi usmjernik', + 'updated_gateway' => 'Uspješno ažuriran usmjernik', + 'created_gateway' => 'Uspješno kreiran usmjernik', + 'deleted_gateway' => 'Uspješno obrisan usmjernik', + 'pay_with_paypal' => 'PayPal', + 'pay_with_card' => 'Kreditna kartica', + 'change_password' => 'Promijeni zaporku', + 'current_password' => 'Trenutna zaporka', + 'new_password' => 'Nova zaporka', + 'confirm_password' => 'Potvrdi zaporku', + 'password_error_incorrect' => 'Trenutna zaporka nije ispravna.', + 'password_error_invalid' => 'Nova zaporka je neispravna.', + 'updated_password' => 'Uspješno ažurirana zaporka', + 'api_tokens' => 'API tokeni', + 'users_and_tokens' => 'Korisnici & tokeni', + 'account_login' => 'Korisnička prijava', + 'recover_password' => 'Obnovite vašu zaporku', + 'forgot_password' => 'Zaboravili ste zaporku?', + 'email_address' => 'Adresa e-pošte', + 'lets_go' => 'Krenimo', + 'password_recovery' => 'Obnova zaporke', + 'send_email' => 'Slanje e-pošte', + 'set_password' => 'Postava zaporke', + 'converted' => 'Konvertirano', + 'email_approved' => 'Pošalji mi e-poštu kada je ponuda odobrena', + 'notification_quote_approved_subject' => 'Quote :invoice je odobrena od strane :client', + 'notification_quote_approved' => 'Slijedeći klijent :client je odobrio ponudu :invoice iznosa :amount.', + 'resend_confirmation' => 'Ponovite potvrdnu e-poštu', + 'confirmation_resent' => 'E-pošta za potvdu je ponovo poslana', + 'gateway_help_42' => ':link za prijavu na BitPay.
    Bilješka: koristite tradicionalni API ključ, umjesto API tokena.', + 'payment_type_credit_card' => 'Kreditna kartica', + 'payment_type_paypal' => 'PayPal', + 'payment_type_bitcoin' => 'Bitcoin', + 'knowledge_base' => 'Baza znanja', + 'partial' => 'Parcijalno', + 'partial_remaining' => ':partial od :balance', + 'more_fields' => 'Više polja', + 'less_fields' => 'Manje polja', + 'client_name' => 'Ime klijenta', + 'pdf_settings' => 'PDF postavke', + 'product_settings' => 'Postavke proizvoda', + 'auto_wrap' => 'Auto formatiranje stavke', + 'duplicate_post' => 'Pozor: prethodna stranica je poslana dvaput. Drugo slanje će biti ignorirano.', + 'view_documentation' => 'Pregled dokumentacije', + 'app_title' => 'Slobodno fakturiranje otvorenim kodom.', + 'app_description' => 'Invoice Ninja je slobodno rješenje otvorenog koda za fakturiranje i upravljanje klijentima. Pomoću Invoice Ninje možete jednostavno izrađivati i slati kreativne račune sa bilo kojeg uređaja koji ima pristup Internetu. Vaši klijenti mogu ispisivati račune, preuzeti ih kao pdf datoteke i čak vam platiti online unutar istog sustava.', + 'rows' => 'redci', + 'www' => 'www', + 'logo' => 'Logo', + 'subdomain' => 'Poddomena', + 'provide_name_or_email' => 'Molimo unesite kontakt ime ili adresu e-pošte', + 'charts_and_reports' => 'Karte & Izvješća', + 'chart' => 'Karte', + 'report' => 'Izvješća', + 'group_by' => 'Grupiraj po', + 'paid' => 'Plaćeno', + 'enable_report' => 'Izvješće', + 'enable_chart' => 'Karta', + 'totals' => 'Zbrojevi', + 'run' => 'Pokreni', + 'export' => 'Izvoz', + 'documentation' => 'Dokumentacija', + 'zapier' => 'Zapier', + 'recurring' => 'Redovni', + 'last_invoice_sent' => 'Zadni račun poslan :date', + 'processed_updates' => 'Uspješno dovršeno ažuriranje', + 'tasks' => 'Zadaci', + 'new_task' => 'Novi zadatak', + 'start_time' => 'Početno vrijeme', + 'created_task' => 'Uspješno kreiran zadatak', + 'updated_task' => 'Uspješno ažuriran zadatak', + 'edit_task' => 'Uredi zadatak', + 'archive_task' => 'Arhiviraj zadatak', + 'restore_task' => 'Obnovi zadatak', + 'delete_task' => 'Obriši zadatak', + 'stop_task' => 'Završi zadatak', + 'time' => 'Vrijeme', + 'start' => 'Početak', + 'stop' => 'Završetak', + 'now' => 'Sada', + 'timer' => 'Štoperica', + 'manual' => 'Ručno', + 'date_and_time' => 'Datum & vrijeme', + 'second' => 'sekunda', + 'seconds' => 'sekunde', + 'minute' => 'minuta', + 'minutes' => 'minute', + 'hour' => 'sat', + 'hours' => 'sati', + 'task_details' => 'Detalji zadatka', + 'duration' => 'Trajanje', + 'end_time' => 'Završno vrijeme', + 'end' => 'Kraj', + 'invoiced' => 'Fakturirano', + 'logged' => 'Logirano', + 'running' => 'Pokrenuto', + 'task_error_multiple_clients' => 'Zadaci ne mogu pripadati različitim klijentima', + 'task_error_running' => 'Molimo najprije dovršite izvođenje zadatka', + 'task_error_invoiced' => 'Zadaci su več fakturirani', + 'restored_task' => 'Uspješno obnovljen zadatak', + 'archived_task' => 'Uspješno arhiviran zadatak', + 'archived_tasks' => 'Uspješno arhivirano :count zadataka', + 'deleted_task' => 'Uspješno obrisan zadatak', + 'deleted_tasks' => 'Uspješno obrisano :count zadataka', + 'create_task' => 'Kreiraj zadatak', + 'stopped_task' => 'Uspješno završen zadatak', + 'invoice_task' => 'Fakturiraj zadatak', + 'invoice_labels' => 'Oznake računa', + 'prefix' => 'Prefiks', + 'counter' => 'Brojač', + 'payment_type_dwolla' => 'Dwolla', + 'gateway_help_43' => ':link za prijavu na Dwolla', + 'partial_value' => 'Mora biti veće od nula i manje od zbroja', + 'more_actions' => 'Više akcija', + 'pro_plan_title' => 'NINJA PRO', + 'pro_plan_call_to_action' => 'Nadogradite odmah!', + 'pro_plan_feature1' => 'Kreirajte neograničeno klijenata', + 'pro_plan_feature2' => 'Pristup na 10 izvrsnih dizajna računa', + 'pro_plan_feature3' => 'Prilagođeni URL - "VašBrand.InvoiceNinja.com"', + 'pro_plan_feature4' => 'Uklonite "Created by Invoice Ninja"', + 'pro_plan_feature5' => 'Višekorisnički pristup & praćenje aktivnosti', + 'pro_plan_feature6' => 'Kreiranje ponuda & predračuna', + 'pro_plan_feature7' => 'Prilagodba naslova polja računa & numeriranje', + 'pro_plan_feature8' => 'Opcija za privitak PDFa na e-poštu klijenta', + 'resume' => 'Nastavi', + 'break_duration' => 'Prekini', + 'edit_details' => 'Uredi detalje', + 'work' => 'Rad', + 'timezone_unset' => 'Molimo :link za postavu vaše vremenske zone', + 'click_here' => 'kliknite ovdje', + 'email_receipt' => 'Pošalji e-poštom račun klijentu', + 'created_payment_emailed_client' => 'Uspješno kreirana uplata i poslana klijentu e-poštom', + 'add_company' => 'Dodaj poduzeće', + 'untitled' => 'Bez naslova', + 'new_company' => 'Novo poduzeće', + 'associated_accounts' => 'Uspješno povezani računi', + 'unlinked_account' => 'Uspješno razdvojeni računi', + 'login' => 'Prijava', + 'or' => 'ili', + 'email_error' => 'Došlo je do problema pri slanju e-pošte', + 'confirm_recurring_timing' => 'Bilješka: e-pošta je poslana na početku sata.', + 'payment_terms_help' => 'Postava zadanog datuma dospijeća', + 'unlink_account' => 'Razdvoji račune', + 'unlink' => 'Razdvoji', + 'show_address' => 'Prikaži adrese', + 'show_address_help' => 'Zahtijevaj od klijenta adresu za fakture', + 'update_address' => 'Ažuriraj adresu', + 'update_address_help' => 'Ažuriraj adresu klijenta uz osigurane detalje', + 'times' => 'Vremena', + 'set_now' => 'Postavi na sada', + 'dark_mode' => 'Tamni prikaz', + 'dark_mode_help' => 'Prikaži bijeli tekst na crnoj pozadini', + 'add_to_invoice' => 'Dodaj računu :invoice', + 'create_new_invoice' => 'Kreiraj novi račun', + 'task_errors' => 'Molimo korigirajte preklopna vremena', + 'from' => 'Šalje', + 'to' => 'Prima', + 'font_size' => 'Veličina fonta', + 'primary_color' => 'Primarna boja', + 'secondary_color' => 'Sekundarna boja', + 'customize_design' => 'Prilagodi dizajn', + 'content' => 'Sadržaj', + 'styles' => 'Stilovi', + 'defaults' => 'Zadano', + 'margins' => 'Margine', + 'header' => 'Zaglavlje', + 'footer' => 'Podnožje', + 'custom' => 'Prilagođeno', + 'invoice_to' => 'Fakturiraj na', + 'invoice_no' => 'Broj računa', + 'recent_payments' => 'Nedavne uplate', + 'outstanding' => 'Izvanredno', + 'manage_companies' => 'Upravljanje poduzećima', + 'total_revenue' => 'Ukupni prihod', + 'current_user' => 'Trenutni korisnik', + 'new_recurring_invoice' => 'Novi redovni račun', + 'recurring_invoice' => 'Redovni račun', + 'recurring_too_soon' => 'Prerano je za kreiranje novog redovnog računa, na rasporedu je za :date', + 'created_by_invoice' => 'Kreiran od :invoice', + 'primary_user' => 'Primarni korisnik', + 'help' => 'Pomoć', + 'customize_help' => '

    We use pdfmake to define the invoice designs declaratively. The pdfmake playground provide\'s a great way to see the library in action.

    +

    You can access a child property using dot notation. For example to show the client name you could use $client.name.

    +

    If you need help figuring something out post a question to our support forum with the design you\'re using.

    ', + 'invoice_due_date' => 'Datum valute', + 'quote_due_date' => 'Vrijedi do', + 'valid_until' => 'Vrijedi do', + 'reset_terms' => 'Resetiraj uvjete', + 'reset_footer' => 'Resetiraj podnožje', + 'invoices_sent' => ':count invoice sent|:count invoices sent', + 'status_draft' => 'Nacrt', + 'status_sent' => 'Poslano', + 'status_viewed' => 'Pregledano', + 'status_partial' => 'Parcijalno', + 'status_paid' => 'Plaćeno', + 'show_line_item_tax' => 'Prikaži poreze u liniji stavke', + 'iframe_url' => 'Web mjesto', + 'iframe_url_help1' => 'Kopiraj slijedeći kod na stranicu svog web mjesta.', + 'iframe_url_help2' => 'Možete testirati mogućnost klikom na \'Pogledaj kao primatelj\' za račun.', + 'auto_bill' => 'Auto račun', + 'military_time' => '24 satno vrijeme', + 'last_sent' => 'Zadnje poslano', + 'reminder_emails' => 'E-pošta podsjetnik', + 'templates_and_reminders' => 'Predlošci & podsjetnici', + 'subject' => 'Naslov', + 'body' => 'Tijelo', + 'first_reminder' => 'Prvi podsjetnik', + 'second_reminder' => 'Drugi podsjetnik', + 'third_reminder' => 'Treći podsjetnik', + 'num_days_reminder' => 'Dana nakon isteka valute', + 'reminder_subject' => 'Podsjetnik: Račun :invoice od :account', + 'reset' => 'Resetiraj', + 'invoice_not_found' => 'Traženi račun nije dostupan', + 'referral_program' => 'Referentni progam', + 'referral_code' => 'Referentni URL', + 'last_sent_on' => 'Zadnje poslano :date', + 'page_expire' => 'Ova stranica će uskoro isteći, :click_here za nastavak rada', + 'upcoming_quotes' => 'Nadolazeće ponude', + 'expired_quotes' => 'Istekle ponude', + 'sign_up_using' => 'Prijavi se koristeći', + 'invalid_credentials' => 'Ove vjerodajnice se ne odgovaraju našim zapisima', + 'show_all_options' => 'Prkaži sve opcije', + 'user_details' => 'Detalji korisnika', + 'oneclick_login' => 'Prijava jednim klikom', + 'disable' => 'Onemogući', + 'invoice_quote_number' => 'Brojevi računa i ponuda', + 'invoice_charges' => 'Troškovi računa', + 'notification_invoice_bounced' => 'Nismo mogli dostaviti račun :invoice prema :contact.', + 'notification_invoice_bounced_subject' => 'Nije moguće dostaviti :invoice', + 'notification_quote_bounced' => 'Nismo mogli dostaviti ponudu :invoice prema :contact', + 'notification_quote_bounced_subject' => 'Nije moguće dostaviti ponudu :invoice', + 'custom_invoice_link' => 'Prilagođena poveznica računa', + 'total_invoiced' => 'Ukupno fakturirano', + 'open_balance' => 'Otvoreno stanje', + 'verify_email' => 'Molimo posjetite poveznicu unutar potvrdne e-pošte računa kako bi potvrdili svoju adresu e-pošte.', + 'basic_settings' => 'Osnovne postavke', + 'pro' => 'Pro', + 'gateways' => 'Platni usmjernici', + 'next_send_on' => 'Pošalji slijedeći: :date', + 'no_longer_running' => 'Ovaj račun nije zakazan za slanje', + 'general_settings' => 'Opće postavke', + 'customize' => 'Prilagodi', + 'oneclick_login_help' => 'Spoji se na račun za prijavu bez zaporke', + 'referral_code_help' => 'Zaradite novac dijeleći našu aplikaciju online', + 'enable_with_stripe' => 'Omogući | Zahtijeva Stripe', + 'tax_settings' => 'Postavke poreza', + 'create_tax_rate' => 'Dodaj poreznu stopu', + 'updated_tax_rate' => 'Uspješno ažurirana porezna stopa', + 'created_tax_rate' => 'Uspješno kreirana porezna stopa', + 'edit_tax_rate' => 'Uredi poreznu stopu', + 'archive_tax_rate' => 'Arhiviraj poreznu stopu', + 'archived_tax_rate' => 'Uspješno arhivirana porezna stopa', + 'default_tax_rate_id' => 'Zadana porezna stopa', + 'tax_rate' => 'Porezna stopa', + 'recurring_hour' => 'Ponavljajući sat', + 'pattern' => 'Uzorak', + 'pattern_help_title' => 'Pomoć za uzorke', + 'pattern_help_1' => 'Kreirajte prilagođene brojeve računa i ponuda specifikacijom uzorka', + 'pattern_help_2' => 'Dostupne varijable:', + 'pattern_help_3' => 'Na primjer, :example bi bilo pretvoreno u :value', + 'see_options' => 'Pogledaj opcije', + 'invoice_counter' => 'Brojač računa', + 'quote_counter' => 'Brojač ponuda', + 'type' => 'Tip', + 'activity_1' => ':user kreirao klijenta :client', + 'activity_2' => ':user arhivirao klijenta :client', + 'activity_3' => ':user obrisao klijenta :client', + 'activity_4' => ':user kreirao račun :invoice', + 'activity_5' => ':user ažurirao račun :invoice', + 'activity_6' => ':user poslao e-poštom račun :invoice za :contact', + 'activity_7' => ':contact pregledao račun :invoice', + 'activity_8' => ':user arhivirao račun :invoice', + 'activity_9' => ':user obrisao račun :invoce', + 'activity_10' => ':contact upisao uplatu :payment za :invoice', + 'activity_11' => ':user ažurirao uplatu :payment', + 'activity_12' => ':user ahivirao uplatu :payment', + 'activity_13' => ':user obrisao uplatu :payment', + 'activity_14' => ':user upisao :credit kredit', + 'activity_15' => ':user ažurirao :credit kredit', + 'activity_16' => ':user arhivirao :credit kredit', + 'activity_17' => ':user obrisao :credit kredit', + 'activity_18' => ':user kreirao ponudu :quote', + 'activity_19' => ':user ažurirao ponudu :quote', + 'activity_20' => ':user poslao e-poštom ponudu :quote za :contact', + 'activity_21' => ':contact pregledao ponudu :quote', + 'activity_22' => ':user arhivirao ponudu :quote', + 'activity_23' => ':user obrisao ponudu :quote', + 'activity_24' => ':user obnovio ponudu :quote', + 'activity_25' => ':user obnovio račun :invoice', + 'activity_26' => ':user obnovio klijenta :client', + 'activity_27' => ':user obnovio uplatu :payment', + 'activity_28' => ':user obnovio :credit kredit', + 'activity_29' => ':contact odobrio ponudu :quote', + 'activity_30' => ':user kreirao :vendor', + 'activity_31' => ':user kreirao :vendor', + 'activity_32' => ':user kreirao :vendor:', + 'activity_33' => ':user kreirao :vendor', + 'activity_34' => ':user kreirao trošak :expense', + 'activity_35' => ':user kreirao :vendor', + 'activity_36' => ':user kreirao :vendor', + 'activity_37' => ':user kreirao :vendor', + 'payment' => 'Uplata', + 'system' => 'Sustav', + 'signature' => 'Potpis e-pošte', + 'default_messages' => 'Zadane poruke', + 'quote_terms' => 'Uvjeti ponude', + 'default_quote_terms' => 'Zadani uvjeti ponude', + 'default_invoice_terms' => 'Zadani uvjeti računa', + 'default_invoice_footer' => 'Zadano podnožje računa', + 'quote_footer' => 'Podnožje ponude', + 'free' => 'Slobodan', + 'quote_is_approved' => 'Ova ponuda je odobrena', + 'apply_credit' => 'Primjeni kredit', + 'system_settings' => 'Postavke sustava', + 'archive_token' => 'Arhiviraj token', + 'archived_token' => 'Uspješno arhiviran token', + 'archive_user' => 'Arhiviraj korisnika', + 'archived_user' => 'Uspješno arhiviran korisnik', + 'archive_account_gateway' => 'Arhiviraj usmjernik', + 'archived_account_gateway' => 'Uspješno arhiviran usmjernik', + 'archive_recurring_invoice' => 'Arhiviraj redoviti račun', + 'archived_recurring_invoice' => 'Uspješno arhiviran redoviti račun', + 'delete_recurring_invoice' => 'Obriši redoviti račun', + 'deleted_recurring_invoice' => 'Uspješno obrisan redoviti račun', + 'restore_recurring_invoice' => 'Obnovi redoviti račun', + 'restored_recurring_invoice' => 'Uspješno obnovljen redoviti račun', + 'archived' => 'Arhivirano', + 'untitled_account' => 'Neimenovano poduzeće', + 'before' => 'Prije', + 'after' => 'Poslije', + 'reset_terms_help' => 'Resetiraj na zadane postavke računa', + 'reset_footer_help' => 'Resetiraj na zadane postavke podnožja', + 'export_data' => 'Izvezi podatke', + 'user' => 'Korisnik', + 'country' => 'Zemlja', + 'include' => 'Uključi', + 'logo_too_large' => 'Vaš logo je :size, za bolju PDF izvedbu preporučujemo otpremu slikovne datoteke manje od 200KB', + 'import_freshbooks' => 'Uvezi iz FreshBooks', + 'import_data' => 'Uvezi podatke', + 'source' => 'Izvor', + 'csv' => 'CSV', + 'client_file' => 'Klijentska datoteka', + 'invoice_file' => 'Datoteka računa', + 'task_file' => 'Datoteka zadataka', + 'no_mapper' => 'Nema ispravnog mapiranja za datoteku', + 'invalid_csv_header' => 'Neispravno CSV zaglavlje', + 'client_portal' => 'Klijentski portal', + 'admin' => 'Administracija', + 'disabled' => 'Onemogućeno', + 'show_archived_users' => 'Prikaži arhivirane korisnike', + 'notes' => 'Bilješke', + 'invoice_will_create' => 'klijent će biti kreiran', + 'invoices_will_create' => 'računi će biti kreirani', + 'failed_to_import' => 'The following records failed to import, they either already exist or are missing required fields.', + 'publishable_key' => 'Objavljivi ključ', + 'secret_key' => 'Tajni ključ', + 'missing_publishable_key' => 'Postavite vap Stripe objavljivi ključ za poboljšani proces odjave', + 'email_design' => 'Dizajn e-pošte', + 'due_by' => 'Valuta do :date', + 'enable_email_markup' => 'Omogući markup', + 'enable_email_markup_help' => 'Olakšajte svojim klijentima plaćanje dodavanjem schema.org markupa vašoj e-pošti.', + 'template_help_title' => 'Pomoć za predloške', + 'template_help_1' => 'Dostupne varijable:', + 'email_design_id' => 'Stil e-pošte', + 'email_design_help' => 'Napravite svoju e-poštu profesionalnijom pomoću HTML postave', + 'plain' => 'Obično', + 'light' => 'Svijetlo', + 'dark' => 'Tamno', + 'industry_help' => 'Koristi se za usporedbe između prosjeka poduzeća sličnih veličina i djelatnosti.', + 'subdomain_help' => 'Prilagodite poveznicu poddomene na računu ili prikažite račun na vlastitom web mjestu.', + 'invoice_number_help' => 'Odredite prefiks ili koristite prilagođeni uzorak za dinamično postavljanje brojeva računa.', + 'quote_number_help' => 'Odredite prefiks ili koristite prilagođeni uzorak za dinamično postavljanje brojeva ponuda.', + 'custom_client_fields_helps' => 'Add a field when creating a client and display the label and value on the PDF.', + 'custom_account_fields_helps' => 'Dodajte oznaku i vrijednost na sekciju sa detaljima poduzeža na PDFu.', + 'custom_invoice_fields_helps' => 'Add a field when creating an invoice and display the label and value on the PDF.', + 'custom_invoice_charges_helps' => 'Add a field when creating an invoice and include the charge in the invoice subtotals.', + 'token_expired' => 'Validacijski token je istekao. Molimo pokušajte ponovo.', + 'invoice_link' => 'Poveznica računa', + 'button_confirmation_message' => 'Kliknite za potvrdu vaše adrese e-pošte.', + 'confirm' => 'Odobri', + 'email_preferences' => 'Postavke e-pošte', + 'created_invoices' => 'Uspješno kreirano :count računa', + 'next_invoice_number' => 'Slijedeći broj računa je :number.', + 'next_quote_number' => 'Slijedeći broj ponude je :number.', + 'days_before' => 'dana prije', + 'days_after' => 'dana poslije', + 'field_due_date' => 'datum valute', + 'field_invoice_date' => 'datum računa', + 'schedule' => 'Raspored', + 'email_designs' => 'Dizajn e-pošte', + 'assigned_when_sent' => 'Dodijeljeno pri slanju', + 'white_label_purchase_link' => 'Kupite licencu bijele oznake', + 'expense' => 'Trošak', + 'expenses' => 'Troškovi', + 'new_expense' => 'New Expense', + 'enter_expense' => 'Unesi trošak', + 'vendors' => 'Dobavljači', + 'new_vendor' => 'Novi dobavljač', + 'payment_terms_net' => 'čisto', + 'vendor' => 'Dobavljač', + 'edit_vendor' => 'Uredi dobavljača', + 'archive_vendor' => 'Arhiviraj dobavljača', + 'delete_vendor' => 'Obriši dobavljača', + 'view_vendor' => 'Pregledaj dobavljača', + 'deleted_expense' => 'Uspješno obrisan trošak', + 'archived_expense' => 'Uspješno arhiviran trošak', + 'deleted_expenses' => 'Uspješno obrisan trošak', + 'archived_expenses' => 'Uspješno arhivirani troškovi', + 'expense_amount' => 'Iznos troškova', + 'expense_balance' => 'Stanje troškova', + 'expense_date' => 'Datum troška', + 'expense_should_be_invoiced' => 'Treba li fakturirati ovaj trošak?', + 'public_notes' => 'Javne bilješke', + 'invoice_amount' => 'Iznos računa', + 'exchange_rate' => 'Tečaj', + 'yes' => 'Da', + 'no' => 'Ne', + 'should_be_invoiced' => 'Treba biti fakturiran', + 'view_expense' => 'Pregled troškova # :expense', + 'edit_expense' => 'Uredi trošak', + 'archive_expense' => 'Arhiviraj trošak', + 'delete_expense' => 'Obriši trošak', + 'view_expense_num' => 'Trošak # :expense', + 'updated_expense' => 'Uspješno ažuriran trošak', + 'created_expense' => 'Uspješno kreiran trošak', + 'enter_expense' => 'Unesi trošak', + 'view' => 'Pregled', + 'restore_expense' => 'Obnovi trošak', + 'invoice_expense' => 'Trošak računa', + 'expense_error_multiple_clients' => 'Troškovi ne mogu pripadati različitim klijentima', + 'expense_error_invoiced' => 'Trošak je već fakturiran', + 'convert_currency' => 'Konvertiraj valutu', + 'num_days' => 'Broj dana', + 'create_payment_term' => 'Kreiraj uvjete plaćanja', + 'edit_payment_terms' => 'Uredi uvjet plaćanja', + 'edit_payment_term' => 'Uredi uvjete plaćanja', + 'archive_payment_term' => 'Arhiviraj uvjet plaćanje', + 'recurring_due_dates' => 'Datumi dospjeća redovnih računa', + 'recurring_due_date_help' => '

    Automatski postavlja datume dospjeća za račune.

    +

    Računi unutar mjesečnog ili godišnjeg ciklusa postavljeni da dospijevaju na dan ili prije dana na koji su kreirani biti će dospjeli slijedeći mjesec. Računi postavljeni da dospjevaju na 29. ili 30. u mjesecu a koji nemaju taj dan biti će dospjeli zadnji dan u mjesecu.

    +

    Računi unutar tjednog ciklusa postavljeni da dospjevaju na dan u tjednu kada su kreirani dospijevati će slijedeći tjedan.

    +

    Na primjer:

    +
      +
    • Danas je 15., datum dospijeća je 1. u mjesecu. Datum dospijeća je izgledno 1. slijedećeg mjeseca.
    • +
    • Danas je 15., datum dospijeća je zadnji dan u mjesecu. Datum dospijeća je zadnji dan u ovom mjesecu. +
    • +
    • Danas je 15, datum dospjeća je 15. u mjesedu. Datum dospijeća će biti 15 dan slijedećeg mjeseca. +
    • +
    • Danas je petak, datum dospijeća je prvi slijedeći petak. Datum dospijeća je prvi slijedeći petak, a ne današnji petak. +
    • +
    ', + 'due' => 'Dospjelo', + 'next_due_on' => 'Dospijeva slijedeće :date', + 'use_client_terms' => 'Koristi uvjete klijenta', + 'day_of_month' => ':ordinal dan u mjesecu', + 'last_day_of_month' => 'Zadnji dan u mjesecu', + 'day_of_week_after' => ':ordinal :day nakon', + 'sunday' => 'Nedjelja', + 'monday' => 'Ponedjeljak', + 'tuesday' => 'Utorak', + 'wednesday' => 'Srijeda', + 'thursday' => 'Četvrtak', + 'friday' => 'Petak', + 'saturday' => 'Subota', + 'header_font_id' => 'Font zaglavlja', + 'body_font_id' => 'Font tijela', + 'color_font_help' => 'Bilješka: primarna boja i fontovi su također korišteni u klijentskom portalu i prilagođenom dizajnu e-pošte', + 'live_preview' => 'Pretpregled uživo', + 'invalid_mail_config' => 'Nije moguće poslati e-poštu, molim provjerite da li su vaše postavke e-pošte ispravne.', + 'invoice_message_button' => 'Za pregled vašeg račun iznosa :amount, kliknite na donju tipku.', + 'quote_message_button' => 'Za pregled vaše ponude iznosa :amount, kliknite donju tipku.', + 'payment_message_button' => 'Hvala vam na vašoj uplati od :amount.', + 'payment_type_direct_debit' => 'Direktni dug', + 'bank_accounts' => 'Kreditne kartice & banke', + 'add_bank_account' => 'Dodajte bankovni račun', + 'setup_account' => 'Postava računa', + 'import_expenses' => 'Uvezi troškove', + 'bank_id' => 'Bank', + 'integration_type' => 'Tip integracije', + 'updated_bank_account' => 'Uspješno ažuriran bankovni račun', + 'edit_bank_account' => 'Uredi bankovni račun', + 'archive_bank_account' => 'Arhiviraj bankovni račun', + 'archived_bank_account' => 'Uspješno arhiviran bankovni račun', + 'created_bank_account' => 'Uspješno kreiran bankovni račun', + 'validate_bank_account' => 'Provjeri bankovni račun', + 'bank_password_help' => 'Bilješka: vaša zaporka je sigurno odaslana i nikada nije pohranjivana na našim serverima.', + 'bank_password_warning' => 'Pozor: vaša zaporka je mogla biti odaslana kao običan tekst, razmotrite omogućavanje HTTPSa.', + 'username' => 'Korisničko ime', + 'account_number' => 'Broj računa', + 'account_name' => 'Ime računa', + 'bank_account_error' => 'Neuspjelo dohvaćanje detalja računa, molimo provjerite svoje ovlasti.', + 'status_approved' => 'Odobreno', + 'quote_settings' => 'Postavke ponude', + 'auto_convert_quote' => 'Auto konverzija ponude', + 'auto_convert_quote_help' => 'Automatski konvertirajte ponudu u račun nakon što je odobrena od strane klijenta.', + 'validate' => 'Validiraj', + 'info' => 'Info', + 'imported_expenses' => 'Uspješno kreirano :count_vendors dobavljača i :count_expenses troškova', + 'iframe_url_help3' => 'Bilješka: Ukoliko planirate prihvaćati kreditne kartice, snažno preporučujemo omogućavanje HTTPS na vašem web mjestu.', + 'expense_error_multiple_currencies' => 'Troškovi ne mogu imati različite valute.', + 'expense_error_mismatch_currencies' => 'Valute klijenata se ne podudaraju sa valutama troškova.', + 'trello_roadmap' => 'Trello razvojna cesta', + 'header_footer' => 'Zaglavlje/Podnožje', + 'first_page' => 'First page', + 'all_pages' => 'All pages', + 'last_page' => 'Last page', + 'all_pages_header' => 'Prikaži zaglavlje na', + 'all_pages_footer' => 'Prikaži podnožje na', + 'invoice_currency' => 'Valuta računa', + 'enable_https' => 'Snažno preporučujemo korištenje HTTPS za prihvat detalja kreditnih kartica online.', + 'quote_issued_to' => 'Ponuda napravljena za', + 'show_currency_code' => 'Kod valute', + 'trial_message' => 'Vaš račun će primiti besplatni dvotjedni probni rok za naš pro plan.', + 'trial_footer' => 'Vaš besplatni probni rok traje još :count dana, :link za trenutnu nadogradnju.', + 'trial_footer_last_day' => 'Ovo je zadnji dan vašeg probnog roka, :link za trenutnu nadogradnju.', + 'trial_call_to_action' => 'Pokreni besplatni probni rok', + 'trial_success' => 'Uspješno je omogućeno dva tjedna besplatnog probnog pro plan roka', + 'overdue' => 'Van valute', + + + 'white_label_text' => 'Purchase a ONE YEAR white label license for $: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 :link', + 'reset_password_footer' => 'If you did not request this password reset please email our support: :email', + 'limit_users' => 'Sorry, this will exceed the limit of :limit users', + 'more_designs_self_host_header' => 'Get 6 more invoice designs for just $:price', + 'old_browser' => 'Please use a newer browser', + 'white_label_custom_css' => ':link for $: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 400+ US banks.', + + 'pro_plan_remove_logo' => ':link to remove the Invoice Ninja logo by joining the Pro Plan', + 'pro_plan_remove_logo_link' => 'Click here', + 'invitation_status_sent' => 'Email Sent', + 'invitation_status_opened' => 'Email Openend', + 'invitation_status_viewed' => 'Invoice Viewed', + 'email_error_inactive_client' => 'Emails can not be sent to inactive clients', + 'email_error_inactive_contact' => 'Emails can not be sent to inactive contacts', + 'email_error_inactive_invoice' => 'Emails can not be sent to inactive invoices', + 'email_error_user_unregistered' => 'Please register your account to send emails', + 'email_error_user_unconfirmed' => 'Please confirm your account to send emails', + 'email_error_invalid_contact_email' => 'Invalid contact email', + + 'navigation' => 'Navigation', + 'list_invoices' => 'List Invoices', + 'list_clients' => 'List Clients', + 'list_quotes' => 'List Quotes', + 'list_tasks' => 'List Tasks', + 'list_expenses' => 'List Expenses', + 'list_recurring_invoices' => 'List Recurring Invoices', + 'list_payments' => 'List Payments', + 'list_credits' => 'List Credits', + 'tax_name' => 'Tax Name', + 'report_settings' => 'Report Settings', + 'search_hotkey' => 'shortcut is /', + + 'new_user' => 'New User', + 'new_product' => 'New Product', + 'new_tax_rate' => 'New Tax Rate', + 'invoiced_amount' => 'Invoiced Amount', + 'invoice_item_fields' => 'Invoice Item Fields', + 'custom_invoice_item_fields_help' => 'Add a field when creating an invoice item and display the label and value on the PDF.', + 'recurring_invoice_number' => 'Recurring Invoice Number', + 'recurring_invoice_number_prefix_help' => 'Speciy a prefix to be added to the invoice number for recurring invoices. The default value is \'R\'.', + + // Client Passwords + 'enable_portal_password'=>'Password protect invoices', + 'enable_portal_password_help'=>'Allows you to set a password for each contact. If a password is set, the contact will be required to enter a password before viewing invoices.', + 'send_portal_password'=>'Generate password automatically', + 'send_portal_password_help'=>'If no password is set, one will be generated and sent with the first invoice.', + + 'expired' => 'Expired', + 'invalid_card_number' => 'The credit card number is not valid.', + 'invalid_expiry' => 'The expiration date is not valid.', + 'invalid_cvv' => 'The CVV is not valid.', + 'cost' => 'Cost', + 'create_invoice_for_sample' => 'Note: create your first invoice to see a preview here.', + + // User Permissions + 'owner' => 'Owner', + 'administrator' => 'Administrator', + 'administrator_help' => 'Allow user to manage users, change settings and modify all records', + 'user_create_all' => 'Create clients, invoices, etc.', + 'user_view_all' => 'View all clients, invoices, etc.', + 'user_edit_all' => 'Edit all clients, invoices, etc.', + 'gateway_help_20' => ':link to sign up for Sage Pay.', + 'gateway_help_21' => ':link to sign up for Sage Pay.', + 'partial_due' => 'Partial Due', + 'restore_vendor' => 'Restore Vendor', + 'restored_vendor' => 'Successfully restored vendor', + 'restored_expense' => 'Successfully restored expense', + 'permissions' => 'Permissions', + 'create_all_help' => 'Allow user to create and modify records', + 'view_all_help' => 'Allow user to view records they didn\'t create', + 'edit_all_help' => 'Allow user to modify records they didn\'t create', + 'view_payment' => 'View Payment', + + 'january' => 'January', + 'february' => 'February', + 'march' => 'March', + 'april' => 'April', + 'may' => 'May', + 'june' => 'June', + 'july' => 'July', + 'august' => 'August', + 'september' => 'September', + 'october' => 'October', + 'november' => 'November', + 'december' => 'December', + + // Documents + 'documents_header' => 'Documents:', + 'email_documents_header' => 'Documents:', + 'email_documents_example_1' => 'Widgets Receipt.pdf', + 'email_documents_example_2' => 'Final Deliverable.zip', + 'invoice_documents' => 'Documents', + 'expense_documents' => 'Attached Documents', + 'invoice_embed_documents' => 'Embed Documents', + 'invoice_embed_documents_help' => 'Include attached images in the invoice.', + 'document_email_attachment' => 'Attach Documents', + 'download_documents' => 'Download Documents (:size)', + 'documents_from_expenses' => 'From Expenses:', + 'dropzone_default_message' => 'Drop files or click to upload', + 'dropzone_fallback_message' => 'Your browser does not support drag\'n\'drop file uploads.', + 'dropzone_fallback_text' => 'Please use the fallback form below to upload your files like in the olden days.', + 'dropzone_file_too_big' => 'File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.', + 'dropzone_invalid_file_type' => 'You can\'t upload files of this type.', + 'dropzone_response_error' => 'Server responded with {{statusCode}} code.', + 'dropzone_cancel_upload' => 'Cancel upload', + 'dropzone_cancel_upload_confirmation' => 'Are you sure you want to cancel this upload?', + 'dropzone_remove_file' => 'Remove file', + 'documents' => 'Documents', + 'document_date' => 'Document Date', + 'document_size' => 'Size', + + 'enable_client_portal' => 'Client Portal', + 'enable_client_portal_help' => 'Show/hide the client portal.', + 'enable_client_portal_dashboard' => 'Dashboard', + 'enable_client_portal_dashboard_help' => 'Show/hide the dashboard page in the client portal.', + + // Plans + 'account_management' => 'Account Management', + 'plan_status' => 'Plan Status', + + 'plan_upgrade' => 'Upgrade', + 'plan_change' => 'Change Plan', + 'pending_change_to' => 'Changes To', + 'plan_changes_to' => ':plan on :date', + 'plan_term_changes_to' => ':plan (:term) on :date', + 'cancel_plan_change' => 'Cancel Change', + 'plan' => 'Plan', + 'expires' => 'Expires', + 'renews' => 'Renews', + 'plan_expired' => ':plan Plan Expired', + 'trial_expired' => ':plan Plan Trial Ended', + 'never' => 'Never', + 'plan_free' => 'Free', + 'plan_pro' => 'Pro', + 'plan_enterprise' => 'Enterprise', + 'plan_white_label' => 'Self Hosted (White labeled)', + 'plan_free_self_hosted' => 'Self Hosted (Free)', + 'plan_trial' => 'Trial', + 'plan_term' => 'Term', + 'plan_term_monthly' => 'Monthly', + 'plan_term_yearly' => 'Yearly', + 'plan_term_month' => 'Month', + 'plan_term_year' => 'Year', + 'plan_price_monthly' => '$:price/Month', + 'plan_price_yearly' => '$:price/Year', + 'updated_plan' => 'Updated plan settings', + 'plan_paid' => 'Term Started', + 'plan_started' => 'Plan Started', + 'plan_expires' => 'Plan Expires', + + 'white_label_button' => 'White Label', + + 'pro_plan_year_description' => 'One year enrollment in the Invoice Ninja Pro Plan.', + 'pro_plan_month_description' => 'One month enrollment in the Invoice Ninja Pro Plan.', + 'enterprise_plan_product' => 'Enterprise Plan', + 'enterprise_plan_year_description' => 'One year enrollment in the Invoice Ninja Enterprise Plan.', + 'enterprise_plan_month_description' => 'One month enrollment in the Invoice Ninja Enterprise Plan.', + 'plan_credit_product' => 'Credit', + 'plan_credit_description' => 'Credit for unused time', + 'plan_pending_monthly' => 'Will switch to monthly on :date', + 'plan_refunded' => 'A refund has been issued.', + + 'live_preview' => 'Pretpregled uživo', + 'page_size' => 'Page Size', + 'live_preview_disabled' => 'Live preview has been disabled to support selected font', + 'invoice_number_padding' => 'Padding', + 'preview' => 'Preview', + 'list_vendors' => 'List Vendors', + 'add_users_not_supported' => 'Upgrade to the Enterprise plan to add additional users to your account.', + 'enterprise_plan_features' => 'The Enterprise plan adds support for multiple users and file attachments, :link to see the full list of features.', + 'return_to_app' => 'Return to app', + + + // Payment updates + 'refund_payment' => 'Refund Payment', + 'refund_max' => 'Max:', + 'refund' => 'Refund', + 'are_you_sure_refund' => 'Refund selected payments?', + 'status_pending' => 'Pending', + 'status_completed' => 'Completed', + 'status_failed' => 'Failed', + 'status_partially_refunded' => 'Partially Refunded', + 'status_partially_refunded_amount' => ':amount Refunded', + 'status_refunded' => 'Refunded', + 'status_voided' => 'Cancelled', + 'refunded_payment' => 'Refunded Payment', + 'activity_39' => ':user cancelled a :payment_amount payment (:payment)', + 'activity_40' => ':user refunded :adjustment of a :payment_amount payment (:payment)', + 'card_expiration' => 'Exp: :expires', + + 'card_creditcardother' => 'Unknown', + 'card_americanexpress' => 'American Express', + 'card_carteblanche' => 'Carte Blanche', + 'card_unionpay' => 'UnionPay', + 'card_diners' => 'Diners Club', + 'card_discover' => 'Discover', + 'card_jcb' => 'JCB', + 'card_laser' => 'Laser', + 'card_maestro' => 'Maestro', + 'card_mastercard' => 'MasterCard', + 'card_solo' => 'Solo', + 'card_switch' => 'Switch', + 'card_visacard' => 'Visa', + 'card_ach' => 'ACH', + + 'payment_type_stripe' => 'Stripe', + 'ach' => 'ACH', + 'enable_ach' => 'Enable ACH', + 'stripe_ach_help' => 'ACH support must also be enabled at Stripe.', + 'ach_disabled' => 'Another gateway is already configured for direct debit.', + + 'plaid' => 'Plaid', + 'client_id' => 'Client Id', + 'secret' => 'Secret', + 'public_key' => 'Public Key', + 'plaid_optional' => '(optional)', + 'plaid_environment_help' => 'When a Stripe test key is given, Plaid\'s development environement (tartan) will be used.', + 'other_providers' => 'Other Providers', + 'country_not_supported' => 'That country is not supported.', + 'invalid_routing_number' => 'The routing number is not valid.', + 'invalid_account_number' => 'The account number is not valid.', + 'account_number_mismatch' => 'The account numbers do not match.', + 'missing_account_holder_type' => 'Please select an individual or company account.', + 'missing_account_holder_name' => 'Please enter the account holder\'s name.', + 'routing_number' => 'Routing Number', + 'confirm_account_number' => 'Confirm Account Number', + 'individual_account' => 'Individual Account', + 'company_account' => 'Company Account', + 'account_holder_name' => 'Account Holder Name', + 'add_account' => 'Add Account', + 'payment_methods' => 'Payment Methods', + 'complete_verification' => 'Complete Verification', + 'verification_amount1' => 'Amount 1', + 'verification_amount2' => 'Amount 2', + 'payment_method_verified' => 'Verification completed successfully', + 'verification_failed' => 'Verification Failed', + 'remove_payment_method' => 'Remove Payment Method', + 'confirm_remove_payment_method' => 'Are you sure you want to remove this payment method?', + 'remove' => 'Remove', + 'payment_method_removed' => 'Removed payment method.', + 'bank_account_verification_help' => 'We have made two deposits into your account with the description "VERIFICATION". These deposits will take 1-2 business days to appear on your statement. Please enter the amounts below.', + 'bank_account_verification_next_steps' => 'We have made two deposits into your account with the description "VERIFICATION". These deposits will take 1-2 business days to appear on your statement. + Once you have the amounts, come back to this payment methods page and click "Complete Verification" next to the account.', + 'unknown_bank' => 'Unknown Bank', + 'ach_verification_delay_help' => 'You will be able to use the account after completing verification. Verification usually takes 1-2 business days.', + 'add_credit_card' => 'Add Credit Card', + 'payment_method_added' => 'Added payment method.', + 'use_for_auto_bill' => 'Use For Autobill', + 'used_for_auto_bill' => 'Autobill Payment Method', + 'payment_method_set_as_default' => 'Set Autobill payment method.', + 'activity_41' => ':payment_amount payment (:payment) failed', + 'webhook_url' => 'Webhook URL', + 'stripe_webhook_help' => 'You must :link.', + 'stripe_webhook_help_link_text' => 'add this URL as an endpoint at Stripe', + 'payment_method_error' => 'There was an error adding your payment methd. Please try again later.', + 'notification_invoice_payment_failed_subject' => 'Payment failed for Invoice :invoice', + 'notification_invoice_payment_failed' => 'A payment made by client :client towards Invoice :invoice failed. The payment has been marked as failed and :amount has been added to the client\'s balance.', + 'link_with_plaid' => 'Link Account Instantly with Plaid', + 'link_manually' => 'Link Manually', + 'secured_by_plaid' => 'Secured by Plaid', + 'plaid_linked_status' => 'Your bank account at :bank', + 'add_payment_method' => 'Add Payment Method', + 'account_holder_type' => 'Account Holder Type', + 'ach_authorization' => 'I authorize :company to use my bank account for future payments and, if necessary, electronically credit my account to correct erroneous debits. I understand that I may cancel this authorization at any time by removing the payment method or by contacting :email.', + 'ach_authorization_required' => 'You must consent to ACH transactions.', + 'off' => 'Off', + 'opt_in' => 'Opt-in', + 'opt_out' => 'Opt-out', + 'always' => 'Always', + 'opted_out' => 'Opted out', + 'opted_in' => 'Opted in', + 'manage_auto_bill' => 'Manage Auto-bill', + 'enabled' => 'Enabled', + 'paypal' => 'PayPal', + 'braintree_enable_paypal' => 'Enable PayPal payments through BrainTree', + 'braintree_paypal_disabled_help' => 'The PayPal gateway is processing PayPal payments', + 'braintree_paypal_help' => 'You must also :link.', + 'braintree_paypal_help_link_text' => 'link PayPal to your BrainTree account', + 'token_billing_braintree_paypal' => 'Save payment details', + 'add_paypal_account' => 'Add PayPal Account', + + + 'no_payment_method_specified' => 'No payment method specified', + 'chart_type' => 'Chart Type', + 'format' => 'Format', + 'import_ofx' => 'Import OFX', + 'ofx_file' => 'OFX File', + 'ofx_parse_failed' => 'Failed to parse OFX file', + + // WePay + 'wepay' => 'WePay', + 'sign_up_with_wepay' => 'Sign up with WePay', + 'use_another_provider' => 'Use another provider', + 'company_name' => 'Company Name', + 'wepay_company_name_help' => 'This will appear on client\'s credit card statements.', + 'wepay_description_help' => 'The purpose of this account.', + 'wepay_tos_agree' => 'I agree to the :link.', + 'wepay_tos_link_text' => 'WePay Terms of Service', + 'resend_confirmation_email' => 'Resend Confirmation Email', + 'manage_wepay_account' => 'Manage WePay Account', + 'action_required' => 'Action Required', + 'finish_setup' => 'Finish Setup', + 'created_wepay_confirmation_required' => 'Please check your email and confirm your email address with WePay.', + 'switch_to_wepay' => 'Switch to WePay', + 'switch' => 'Switch', + 'restore_account_gateway' => 'Restore Gateway', + 'restored_account_gateway' => 'Successfully restored gateway', + 'united_states' => 'United States', + 'canada' => 'Canada', + 'accept_debit_cards' => 'Accept Debit Cards', + 'debit_cards' => 'Debit Cards', + + 'warn_start_date_changed' => 'The next invoice will be sent on the new start date.', + 'original_start_date' => 'Original start date', + 'new_start_date' => 'New start date', + 'security' => 'Security', + 'see_whats_new' => 'See what\'s new in v:version', + 'wait_for_upload' => 'Please wait for the document upload to complete.', + 'upgrade_for_permissions' => 'Upgrade to our Enterprise plan to enable permissions.', + 'enable_second_tax_rate' => 'Enable specifying a second tax rate', + 'payment_file' => 'Payment File', + 'expense_file' => 'Expense File', + 'product_file' => 'Product File', + 'import_products' => 'Import Products', + 'products_will_create' => 'products will be created.', + 'product_key' => 'Product', + 'created_products' => 'Successfully created :count product(s)', + 'export_help' => 'Use JSON if you plan to import the data into Invoice Ninja.', + 'JSON_file' => 'JSON File', + + 'view_dashboard' => 'View Dashboard', + 'client_session_expired' => 'Session Expired', + 'client_session_expired_message' => 'Your session has expired. Please click the link in your email again.', + + 'auto_bill_notification' => 'This invoice will automatically be billed to your :payment_method on file on :due_date.', + 'auto_bill_payment_method_bank_transfer' => 'bank account', + 'auto_bill_payment_method_credit_card' => 'credit card', + 'auto_bill_payment_method_paypal' => 'PayPal account', + 'auto_bill_notification_placeholder' => 'This invoice will automatically be billed to your credit card on file on the due date.', + 'payment_settings' => 'Payment Settings', + + 'on_send_date' => 'On send date', + 'on_due_date' => 'On due date', + 'auto_bill_ach_date_help' => 'ACH auto bill will always happen on the due date', + 'warn_change_auto_bill' => 'Due to NACHA rules, changes to this invoice may prevent ACH auto bill.', + + 'bank_account' => 'Bank Account', + 'payment_processed_through_wepay' => 'ACH payments will be processed using WePay.', + 'wepay_payment_tos_agree' => 'I agree to the WePay :terms and :privacy_policy.', + 'privacy_policy' => 'Privacy Policy', + 'wepay_payment_tos_agree_required' => 'You must agree to the WePay Terms of Service and Privacy Policy.', + 'payment_settings_supported_gateways' => 'These options are supported by the WePay, Stripe, and Braintree gateways.', + 'ach_email_prompt' => 'Please enter your email address:', + 'verification_pending' => 'Verification Pending', + + 'update_font_cache' => 'Please force refresh the page to update the font cache.', + 'more_options' => 'More options', + 'credit_card' => 'Credit Card', + 'bank_transfer' => 'Bank Transfer', + 'no_transaction_reference' => 'We did not recieve a payment transaction reference from the gateway.', + 'use_bank_on_file' => 'Use Bank on File', + 'auto_bill_email_message' => 'This invoice will automatically be billed to the payment method on file on the due date.', + 'bitcoin' => 'Bitcoin', + 'added_on' => 'Added :date', + 'failed_remove_payment_method' => 'Failed to remove the payment method', + 'gateway_exists' => 'This gateway already exists', + 'manual_entry' => 'Manual entry', + +); + +return $LANG; + +?> diff --git a/resources/lang/hr/validation.php b/resources/lang/hr/validation.php new file mode 100644 index 0000000000..8b54e496b0 --- /dev/null +++ b/resources/lang/hr/validation.php @@ -0,0 +1,116 @@ + 'Polje :attribute mora biti prihvaćeno.', + 'active_url' => 'Polje :attribute nije ispravan URL.', + 'after' => 'Polje :attribute mora biti datum nakon :date.', + 'alpha' => 'Polje :attribute smije sadržavati samo slova.', + 'alpha_dash' => 'Polje :attribute smije sadržavati samo slova, brojeve i crtice.', + 'alpha_num' => 'Polje :attribute smije sadržavati samo slova i brojeve.', + 'array' => 'Polje :attribute mora biti niz.', + 'before' => 'Polje :attribute mora biti datum prije :date.', + 'between' => [ + 'numeric' => 'Polje :attribute mora biti između :min - :max.', + 'file' => 'Polje :attribute mora biti između :min - :max kilobajta.', + 'string' => 'Polje :attribute mora biti između :min - :max znakova.', + 'array' => 'Polje :attribute mora imati između :min - :max stavki.', + ], + 'boolean' => 'Polje :attribute mora biti false ili true.', + 'confirmed' => 'Potvrda polja :attribute se ne podudara.', + 'date' => 'Polje :attribute nije ispravan datum.', + 'date_format' => 'Polje :attribute ne podudara s formatom :format.', + 'different' => 'Polja :attribute i :other moraju biti različita.', + 'digits' => 'Polje :attribute mora sadržavati :digits znamenki.', + 'digits_between' => 'Polje :attribute mora imati između :min i :max znamenki.', + 'dimensions' => 'The :attribute has invalid image dimensions.', + 'distinct' => 'The :attribute field has a duplicate value.', + 'email' => 'Polje :attribute mora biti ispravna e-mail adresa.', + 'exists' => 'Odabrano polje :attribute nije ispravno.', + 'filled' => 'The :attribute field is required.', + 'image' => 'Polje :attribute mora biti slika.', + 'in' => 'Odabrano polje :attribute nije ispravno.', + 'in_array' => 'The :attribute field does not exist in :other.', + 'integer' => 'Polje :attribute mora biti broj.', + 'ip' => 'Polje :attribute mora biti ispravna IP adresa.', + 'json' => 'The :attribute must be a valid JSON string.', + 'max' => [ + 'numeric' => 'Polje :attribute mora biti manje od :max.', + 'file' => 'Polje :attribute mora biti manje od :max kilobajta.', + 'string' => 'Polje :attribute mora sadržavati manje od :max znakova.', + 'array' => 'Polje :attribute ne smije imati više od :max stavki.', + ], + 'mimes' => 'Polje :attribute mora biti datoteka tipa: :values.', + 'min' => [ + 'numeric' => 'Polje :attribute mora biti najmanje :min.', + 'file' => 'Polje :attribute mora biti najmanje :min kilobajta.', + 'string' => 'Polje :attribute mora sadržavati najmanje :min znakova.', + 'array' => 'Polje :attribute mora sadržavati najmanje :min stavki.', + ], + 'not_in' => 'Odabrano polje :attribute nije ispravno.', + 'numeric' => 'Polje :attribute mora biti broj.', + 'present' => 'The :attribute field must be present.', + 'regex' => 'Polje :attribute se ne podudara s formatom.', + 'required' => 'Polje :attribute je obavezno.', + 'required_if' => 'Polje :attribute je obavezno kada polje :other sadrži :value.', + 'required_unless' => 'The :attribute field is required unless :other is in :values.', + 'required_with' => 'Polje :attribute je obavezno kada postoji polje :values.', + 'required_with_all' => 'Polje :attribute je obavezno kada postje polja :values.', + 'required_without' => 'Polje :attribute je obavezno kada ne postoji polje :values.', + 'required_without_all' => 'Polje :attribute je obavezno kada nijedno od polja :values ne postoji.', + 'same' => 'Polja :attribute i :other se moraju podudarati.', + 'size' => [ + 'numeric' => 'Polje :attribute mora biti :size.', + 'file' => 'Polje :attribute mora biti :size kilobajta.', + 'string' => 'Polje :attribute mora biti :size znakova.', + 'array' => 'Polje :attribute mora sadržavati :size stavki.', + ], + 'string' => 'The :attribute must be a string.', + 'timezone' => 'Polje :attribute mora biti ispravna vremenska zona.', + 'unique' => 'Polje :attribute već postoji.', + 'url' => 'Polje :attribute nije ispravnog formata.', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'custom-message', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [ + // + ], + +]; diff --git a/resources/lang/it/texts.php b/resources/lang/it/texts.php index 01edae3953..0e65daa23d 100644 --- a/resources/lang/it/texts.php +++ b/resources/lang/it/texts.php @@ -1,8 +1,6 @@ - 'Organizzazione', 'name' => 'Nome', 'website' => 'Sito web', @@ -12,7 +10,7 @@ return array( 'address2' => 'Appartamento/Piano', 'city' => 'Città', 'state' => 'Stato/Provincia', - 'postal_code' => 'Codice postale', /* CAP */ + 'postal_code' => 'Codice postale', 'country_id' => 'Paese', 'contacts' => 'Contatti', 'first_name' => 'Nome', @@ -25,16 +23,14 @@ return array( 'size_id' => 'Dimensione', 'industry_id' => 'Industria', 'private_notes' => 'Note Personali', - - // invoice 'invoice' => 'Fattura', 'client' => 'Cliente', 'invoice_date' => 'Data Fattura', 'due_date' => 'Scadenza', 'invoice_number' => 'Numero Fattura', - 'invoice_number_short' => 'Fattura #', /* Fattura N° */ + 'invoice_number_short' => 'Fattura #', 'po_number' => 'Numero d\'ordine d\'acquisto', - 'po_number_short' => 'Ordine d\'acquisto #', /* Ordine d'acquisto N° */ + 'po_number_short' => 'Ordine d\'acquisto #', 'frequency_id' => 'Frequenza', 'discount' => 'Sconto', 'taxes' => 'Tasse', @@ -50,7 +46,6 @@ return array( 'invoice_design_id' => 'Stile', 'terms' => 'Condizioni', 'your_invoice' => 'Tua Fattura', - 'remove_contact' => 'Rimuovi contatto', 'add_contact' => 'Aggiungi contatto', 'create_new_client' => 'Crea nuovo cliente', @@ -60,29 +55,27 @@ return array( 'manage_rates' => 'Gestisci tassi', 'note_to_client' => 'Nota al cliente', 'invoice_terms' => 'Termini della fattura', - 'save_as_default_terms' => 'Salva termini come predefiniti', /* Imposta termini come predefiniti */ + 'save_as_default_terms' => 'Salva termini come predefiniti', 'download_pdf' => 'Scarica PDF', - 'pay_now' => 'Paga Adesso', /* Paga Ora */ + 'pay_now' => 'Paga Adesso', 'save_invoice' => 'Salva Fattura', 'clone_invoice' => 'Duplica Fattura', 'archive_invoice' => 'Archivia Fattura', 'delete_invoice' => 'Elimina Fattura', - 'email_invoice' => 'Invia Fattura', /* Spedisci Fattura */ + 'email_invoice' => 'Invia Fattura', 'enter_payment' => 'Inserisci Pagamento', - 'tax_rates' => 'Aliquote Fiscali', /* ^^Unsure^^ */ - 'rate' => 'Aliquota', /* ^^Unsure^^ */ + 'tax_rates' => 'Aliquote Fiscali', + 'rate' => 'Aliquota', 'settings' => 'Impostazioni', - 'enable_invoice_tax' => 'Abilita la specifica di aliquote fiscali', /* ^^Unsure^^ */ - 'enable_line_item_tax' => 'Abilita la specifica di aliquote di voci di bilancio', /* ^^Unsure^^ */ - - // navigation - 'dashboard' => 'Cruscotto', /* Pannello */ + 'enable_invoice_tax' => 'Abilita la specifica di aliquote fiscali', + 'enable_line_item_tax' => 'Abilita la specifica di aliquote di voci di bilancio', + 'dashboard' => 'Cruscotto', 'clients' => 'Clienti', 'invoices' => 'Fatture', 'payments' => 'Pagamenti', 'credits' => 'Crediti', - 'history' => 'Storia', /* Cronologia */ - 'search' => 'Cerca', /* Cerca */ + 'history' => 'Storia', + 'search' => 'Cerca', 'sign_up' => 'Registrati', 'guest' => 'Ospite', 'company_details' => 'Dettagli Azienda', @@ -98,10 +91,8 @@ return array( 'cancel' => 'Annulla', 'close' => 'Close', 'provide_email' => 'Per favore, fornisci un indirizzo Email valido', - 'powered_by' => 'Powered by', /* Realizzato da */ + 'powered_by' => 'Powered by', 'no_items' => 'Nessun articolo', - - // recurring invoices 'recurring_invoices' => 'Fatture ricorrenti', 'recurring_help' => '

    Invia automaticamente al cliente le stesse fatture settimanalmente, bimestralmente, mensilmente, trimestralmente o annualmente.

    Usa :MONTH, :QUARTER o :YEAR per date dinamiche. Funziona anche con la matematica di base, ad esempio :MONTH-1.

    @@ -110,19 +101,15 @@ return array(
  • "Iscrizione palestra per il mese di :MONTH" => "Iscrizione palestra per il mese di Luglio"
  • ":YEAR+1 iscrizione annuale" => "Anno d\'iscrizione 2015"
  • "Pagamento fermo a :QUARTER+1" => "Pagamento fermo al 2° trimestre"
  • - ', /* ^^Variables translated in case you'll need it for front end^^ */ - - // dashboard + ', 'in_total_revenue' => 'di fatturato', 'billed_client' => 'Cliente fatturato', 'billed_clients' => 'Clienti fatturati', 'active_client' => 'cliente attivo', - 'active_clients' => 'clienti attivi', - 'invoices_past_due' => 'Fatture Scadute', /* Insoluti */ + 'active_clients' => 'clienti attivi', + 'invoices_past_due' => 'Fatture Scadute', 'upcoming_invoices' => 'Prossime fatture', 'average_invoice' => 'Fattura media', - - // list pages 'archive' => 'Archivia', 'delete' => 'Elimina', 'archive_client' => 'Archivia cliente', @@ -158,8 +145,6 @@ return array( 'select' => 'Seleziona', 'edit_client' => 'Modifica Cliente', 'edit_invoice' => 'Modifica Fattura', - - // client view page 'create_invoice' => 'Crea Fattura', 'enter_credit' => 'Inserisci Credito', 'last_logged_in' => 'Ultimo accesso', @@ -171,12 +156,8 @@ return array( 'message' => 'Messaggio', 'adjustment' => 'Variazione', 'are_you_sure' => 'Sei sicuro?', - - // payment pages 'payment_type_id' => 'Tipo di Pagamento', 'amount' => 'Importo', - - // account/company pages 'work_email' => 'Email', 'language_id' => 'Lingua', 'timezone_id' => 'Fuso Orario', @@ -194,11 +175,7 @@ return array( 'email_paid' => 'Mandami un\'email quando una fattura è pagata', 'site_updates' => 'Aggiornamenti Sito', 'custom_messages' => 'Messaggi Personalizzati', - 'default_invoice_terms' => 'Salva termini come predefiniti', 'default_email_footer' => 'Salva firma email come predefinita', - 'import_clients' => 'Importa Dati Clienti', - 'csv_file' => 'Seleziona file CSV', - 'export_clients' => 'Esporta Dati Clienti', 'select_file' => 'Seleziona un file, per favore', 'first_row_headers' => 'Usa la prima riga come Intestazione', 'column' => 'Colonna', @@ -207,9 +184,12 @@ return array( 'client_will_create' => 'il cliente sarà creato', 'clients_will_create' => 'i clienti saranno creati', 'email_settings' => 'Email Settings', + 'client_view_styling' => 'Client View Styling', 'pdf_email_attachment' => 'Attach PDF to Emails', - - // application messages + 'custom_css' => 'Custom CSS', + 'import_clients' => 'Importa Dati Clienti', + 'csv_file' => 'Seleziona file CSV', + 'export_clients' => 'Esporta Dati Clienti', 'created_client' => 'Cliente creato con successo', 'created_clients' => ':count clienti creati con successo', 'updated_settings' => 'Impostazioni aggiornate con successo', @@ -220,14 +200,12 @@ return array( 'payment_error' => 'C\'è stato un errore durante il pagamento. Riprova più tardi, per favore.', 'registration_required' => 'Per favore, registrati per inviare una fattura', 'confirmation_required' => 'Per favore, conferma il tuo indirizzo email', - 'updated_client' => 'Cliente aggiornato con successo', 'created_client' => 'Cliente creato con successo', 'archived_client' => 'Cliente archiviato con successo', 'archived_clients' => ':count clienti archiviati con successo', 'deleted_client' => 'Cliente eliminato con successo', 'deleted_clients' => ':count clienti eliminati con successo', - 'updated_invoice' => 'Fattura aggiornata con successo', 'created_invoice' => 'Fattura creata con successo', 'cloned_invoice' => 'Fattura duplicata con successo', @@ -237,21 +215,25 @@ return array( 'archived_invoices' => ':count fatture archiviate con successo', 'deleted_invoice' => 'Fattura eliminata con successo', 'deleted_invoices' => ':count fatture eliminate con successo', - 'created_payment' => 'Pagamento creato con successo', + 'created_payments' => 'Successfully created :count payment(s)', 'archived_payment' => 'Pagamento archiviato con successo', 'archived_payments' => ':count pagamenti archiviati con successo', 'deleted_payment' => 'Pagamenti eliminati con successo', 'deleted_payments' => ':count pagamenti eliminati con successo', 'applied_payment' => 'Pagamento applicato con successo', - 'created_credit' => 'Credito creato con successo', 'archived_credit' => 'Credito archiviato con successo', 'archived_credits' => ':count crediti archiviati con successo', 'deleted_credit' => 'Credito eliminato con successo', 'deleted_credits' => ':count crediti eliminati con successo', - - // Emails + 'imported_file' => 'Successfully imported file', + 'updated_vendor' => 'Successfully updated vendor', + 'created_vendor' => 'Successfully created vendor', + 'archived_vendor' => 'Successfully archived vendor', + 'archived_vendors' => 'Successfully archived :count vendors', + 'deleted_vendor' => 'Successfully deleted vendor', + 'deleted_vendors' => 'Successfully deleted :count vendors', 'confirmation_subject' => 'Conferma Account Invoice Ninja', 'confirmation_header' => 'Conferma Account', 'confirmation_message' => 'Per favore, accedi al link qui sotto per confermare il tuo account.', @@ -262,7 +244,6 @@ return array( 'email_salutation' => 'Caro :name,', 'email_signature' => 'Distinti saluti,', 'email_from' => 'Il Team di InvoiceNinja', - 'user_email_footer' => 'Per modificare le impostazioni di notifiche via email per favore accedi a: '.SITE_URL.'/settings/notifications', 'invoice_link_message' => 'Per visualizzare la tua fattura del cliente clicca sul link qui sotto:', 'notification_invoice_paid_subject' => 'La fattura :invoice è stata pagata da :client', 'notification_invoice_sent_subject' => 'La fattura :invoice è stata inviata a :client', @@ -271,35 +252,14 @@ return array( 'notification_invoice_sent' => 'Al seguente cliente :client è stata inviata via email la fattura :invoice di :amount.', 'notification_invoice_viewed' => 'Il seguente cliente :client ha visualizzato la fattura :invoice di :amount.', 'reset_password' => 'Puoi resettare la password del tuo account cliccando sul link qui sotto:', - 'reset_password_footer' => 'Se non sei stato tu a voler resettare la password per favore invia un\'email di assistenza a: ' . CONTACT_EMAIL, - - // Payment page 'secure_payment' => 'Pagamento Sicuro', 'card_number' => 'Numero Carta', - 'expiration_month' => 'Mese di Scadenza', + 'expiration_month' => 'Mese di Scadenza', 'expiration_year' => 'Anno di Scadenza', 'cvv' => 'CVV', - - // Security alerts - 'security' => [ - 'too_many_attempts' => 'Troppi tentativi fatti. Riprova tra qualche minuto.', - 'wrong_credentials' => 'Email o password non corretti.', - 'confirmation' => 'Il tuo account è stato confermato!', - 'wrong_confirmation' => 'Codice di verifica errato.', - 'password_forgot' => 'I dati per resettare la tua password sono stati inviati alla tua email.', - 'password_reset' => 'La tua password è stata cambiata con successo.', - 'wrong_password_reset' => 'Password errata. Riprova', - ], - - // Pro Plan - 'pro_plan' => [ - 'remove_logo' => ':link per rimuovere il logo di Invoice Ninja aderendo al programma pro', - 'remove_logo_link' => 'Clicca qui', - ], - - 'logout' => 'Log Out', /* Esci */ + 'logout' => 'Log Out', 'sign_up_to_save' => 'Registrati per salvare il tuo lavoro', - 'agree_to_terms' =>'Accetto i :terms di Invoice Ninja', + 'agree_to_terms' => 'Accetto i :terms di Invoice Ninja', 'terms_of_service' => 'Condizioni di Servizio', 'email_taken' => 'Questo indirizzo email è già registrato', 'working' => 'In elaborazione', @@ -307,11 +267,8 @@ return array( 'success_message' => 'Registrazione avvenuta con successo. Per favore visita il link nell\'email di conferma per verificare il tuo indirizzo email.', 'erase_data' => 'Questo eliminerà definitivamente i tuoi dati.', 'password' => 'Password', - 'pro_plan_product' => 'Piano PRO', - 'pro_plan_description' => 'Un anno di sottoscrizione al piano PRO Invoice Ninja.', 'pro_plan_success' => 'Grazie per aver aderito! Non appena la fattura risulterà pagata il tuo piano PRO avrà inizio.', - 'unsaved_changes' => 'Ci sono dei cambiamenti non salvati', 'custom_fields' => 'Campi Personalizzabili', 'company_fields' => 'Campi Azienda', @@ -319,9 +276,8 @@ return array( 'field_label' => 'Etichetta Campo', 'field_value' => 'Valore Campo', 'edit' => 'Modifica', + 'set_name' => 'Set your company name', 'view_as_recipient' => 'Visualizza come destinatario', - - // product management 'product_library' => 'Libreria prodotti', 'product' => 'Prodotto', 'products' => 'Prodotti', @@ -336,18 +292,14 @@ return array( 'created_product' => 'Prodotto creato con successo', 'archived_product' => 'Prodotto archiviato con successo', 'pro_plan_custom_fields' => ':link to enable custom fields by joining the Pro Plan', - 'advanced_settings' => 'Impostazioni Avanzate', 'pro_plan_advanced_settings' => ':link to enable the advanced settings by joining the Pro Plan', 'invoice_design' => 'Invoice Design', 'specify_colors' => 'Specify colors', 'specify_colors_label' => 'Select the colors used in the invoice', - 'chart_builder' => 'Creatore grafico', 'ninja_email_footer' => 'Usa :site per fatturare ai tuoi clienti e venire pagato online gratis!', 'go_pro' => 'diventa Pro', - - // Quotes 'quote' => 'Preventivo', 'quotes' => 'Preventivi', 'quote_number' => 'Numero Preventivo', @@ -356,8 +308,7 @@ return array( 'quote_total' => 'Totale Preventivo', 'your_quote' => 'Il vostro Preventivo', 'total' => 'Totale', - 'clone' => 'Clona', /*Infinite verb?*/ - + 'clone' => 'Clona', 'new_quote' => 'Nuovo Preventivo', 'create_quote' => 'Crea Preventivo', 'edit_quote' => 'Modifica Preventivo', @@ -368,9 +319,8 @@ return array( 'clone_quote' => 'Clona Preventivo', 'convert_to_invoice' => 'Converti a Fattura', 'view_invoice' => 'Vedi Fattura', - 'view_quote' => 'Vedi Preventivo', 'view_client' => 'Vedi Cliente', - + 'view_quote' => 'Vedi Preventivo', 'updated_quote' => 'Preventivo aggiornato con successo', 'created_quote' => 'Preventivo creato con successo', 'cloned_quote' => 'Preventivo clonato con successo', @@ -380,24 +330,20 @@ return array( 'deleted_quote' => 'Preventivo cancellato con successo', 'deleted_quotes' => 'Sono stati cancellati :count preventivi con successo', 'converted_to_invoice' => 'Il preventivo è stato convertito a fattura con successo', - 'quote_subject' => 'Nuovo preventivo da :account', 'quote_message' => 'Per visualizzare il vostro preventivo di :amount, cliccate il collegamento sotto.', 'quote_link_message' => 'Per visualizzare il preventivo del vostro cliente cliccate il collegamento sotto:', 'notification_quote_sent_subject' => 'Il preventivo :invoice è stato inviato a :client', 'notification_quote_viewed_subject' => 'Il preventivo :invoice è stato visualizzato da :client', 'notification_quote_sent' => 'Al seguente cliente :client è stata inviato il preventivo :invoice per un importo di :amount.', - 'notification_quote_viewed' => 'Il seguente cliente :client ha visualizzato il preventivo :invoice di :amount.', - + 'notification_quote_viewed' => 'Il seguente cliente :client ha visualizzato il preventivo :invoice di :amount.', 'session_expired' => 'La vostra sessione è scaduta.', - 'invoice_fields' => 'Invoice Fields', 'invoice_options' => 'Invoice Options', '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_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.', - 'charge_taxes' => 'Charge taxes', 'user_management' => 'User Management', 'add_user' => 'Add User', @@ -412,21 +358,16 @@ return array( 'active' => 'Active', 'pending' => 'Pending', '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_quote' => 'Are you sure you want to email this quote?', 'confirm_recurring_email_invoice' => 'Are you sure you want this invoice emailed?', - 'cancel_account' => 'Cancel Account', 'cancel_account_message' => 'Warning: This will permanently erase all of your data, there is no undo.', 'go_back' => 'Go Back', - 'data_visualizations' => 'Data Visualizations', 'sample_data' => 'Sample data shown', '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', - 'invoice_settings' => 'Invoice Settings', 'invoice_number_prefix' => 'Invoice Number Prefix', 'invoice_number_counter' => 'Invoice Number Counter', @@ -435,63 +376,49 @@ return array( 'share_invoice_counter' => 'Share invoice counter', 'invoice_issued_to' => 'Invoice issued to', '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_2' => ':link to sign up for Authorize.net.', 'gateway_help_17' => ':link to get your PayPal API signature.', 'gateway_help_27' => ':link to sign up for TwoCheckout.', - 'more_designs' => 'More designs', 'more_designs_title' => 'Additional Invoice Designs', 'more_designs_cloud_header' => 'Go Pro for more invoice designs', 'more_designs_cloud_text' => '', - 'more_designs_self_host_header' => 'Get 6 more invoice designs for just $'.INVOICE_DESIGNS_PRICE, 'more_designs_self_host_text' => '', 'buy' => 'Buy', 'bought_designs' => 'Successfully added additional invoice designs', - - 'sent' => 'sent', + 'vat_number' => 'Partita IVA', 'timesheets' => 'Timesheets', - 'payment_title' => 'Inserisci il tuo indirizzo di fatturazione e i dati della tua carta di credito', 'payment_cvv' => '*This is the 3-4 digit number onthe back of your card', 'payment_footer1' => '*L\'indirizzo di fatturazione deve corrispondere all\'indirizzo associato alla carta di credito.', 'payment_footer2' => '*Please click "PAY NOW" only once - transaction may take up to 1 minute to process.', - 'vat_number' => 'Partita IVA', 'id_number' => 'ID Number', - 'white_label_link' => 'White label', 'white_label_header' => 'White Label', 'bought_white_label' => 'Successfully enabled white label license', 'white_labeled' => 'White labeled', - - 'restore' => 'Restore', 'restore_invoice' => 'Restore Invoice', 'restore_quote' => 'Restore Quote', 'restore_client' => 'Restore Client', 'restore_credit' => 'Restore Credit', 'restore_payment' => 'Restore Payment', - 'restored_invoice' => 'Successfully restored invoice', 'restored_quote' => 'Successfully restored quote', 'restored_client' => 'Successfully restored client', 'restored_payment' => 'Successfully restored payment', 'restored_credit' => 'Successfully restored credit', - 'reason_for_canceling' => 'Help us improve our site by telling us why you\'re leaving.', 'discount_percent' => 'Percent', 'discount_amount' => 'Amount', - 'invoice_history' => 'Invoice History', 'quote_history' => 'Quote History', 'current_version' => 'Current version', 'select_version' => 'Select version', 'view_history' => 'View History', - 'edit_payment' => 'Edit Payment', 'updated_payment' => 'Successfully updated payment', 'deleted' => 'Deleted', @@ -504,7 +431,6 @@ return array( 'quote_email' => 'Quote Email', 'reset_all' => 'Reset All', 'approve' => 'Approva', - '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_1' => 'Disabilitato', @@ -512,12 +438,11 @@ return array( 'token_billing_3' => 'Opt-out - checkbox is shown and selected', 'token_billing_4' => 'Sempre', 'token_billing_checkbox' => 'Salva dettagli carta di credito', - 'view_in_stripe' => 'Vedi transazione in Stripe', - 'use_card_on_file' => 'Carta di credito salvata', + 'view_in_gateway' => 'Vedi transazione in :gateway', + 'use_card_on_file' => 'Use Card on File', 'edit_payment_details' => 'Modifica dettagli pagamento', 'token_billing' => 'Salva carta di credito', - 'token_billing_secure' => 'I dati sono memorizzati su piattaforma sicura mediante :stripe_link', - + 'token_billing_secure' => 'I dati sono memorizzati su piattaforma sicura mediante :link', 'support' => 'Support', 'contact_information' => 'Informazioni di contatto', '256_encryption' => '256-Bit Encryption', @@ -527,11 +452,8 @@ return array( 'order_overview' => 'Riepilogo ordine', 'match_address' => '*L\'indirizzo deve corrispondere con quello associato alla carta di credito.', 'click_once' => '*Per favore clicca "PAGA ADESSO" solo una volta - la transazione può impiegare sino a 1 minuto per essere completata.', - - 'default_invoice_footer' => 'Set default invoice footer', 'invoice_footer' => 'Invoice footer', 'save_as_default_footer' => 'Save as default footer', - 'token_management' => 'Token Management', 'tokens' => 'Tokens', 'add_token' => 'Add Token', @@ -542,7 +464,6 @@ return array( 'edit_token' => 'Edit Token', 'delete_token' => 'Delete Token', 'token' => 'Token', - 'add_gateway' => 'Add Gateway', 'delete_gateway' => 'Delete Gateway', 'edit_gateway' => 'Edit Gateway', @@ -551,7 +472,6 @@ return array( 'deleted_gateway' => 'Successfully deleted gateway', 'pay_with_paypal' => 'PayPal', 'pay_with_card' => 'Carta di credito', - 'change_password' => 'Change password', 'current_password' => 'Current password', 'new_password' => 'New password', @@ -559,7 +479,6 @@ return array( 'password_error_incorrect' => 'The current password is incorrect.', 'password_error_invalid' => 'The new password is invalid.', 'updated_password' => 'Successfully updated password', - 'api_tokens' => 'API Tokens', 'users_and_tokens' => 'Users & Tokens', 'account_login' => 'Account Login', @@ -571,13 +490,11 @@ return array( 'send_email' => 'Send email', 'set_password' => 'Set Password', 'converted' => 'Converted', - 'email_approved' => 'Email me when a quote is approved', 'notification_quote_approved_subject' => 'Quote :invoice was approved by :client', 'notification_quote_approved' => 'The following client :client approved Quote :invoice for :amount.', 'resend_confirmation' => 'Resend confirmation email', 'confirmation_resent' => 'The confirmation email was resent', - 'gateway_help_42' => ':link to sign up for BitPay.
    Note: use a Legacy API Key, not an API token.', 'payment_type_credit_card' => 'Carta di credito', 'payment_type_paypal' => 'PayPal', @@ -585,7 +502,6 @@ return array( 'knowledge_base' => 'Knowledge Base', 'partial' => 'Partial', 'partial_remaining' => ':partial di :balance', - 'more_fields' => 'More Fields', 'less_fields' => 'Less Fields', 'client_name' => 'Client Name', @@ -596,7 +512,6 @@ return array( 'view_documentation' => 'View Documentation', '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.', - 'rows' => 'rows', 'www' => 'www', 'logo' => 'Logo', @@ -616,7 +531,6 @@ return array( 'zapier' => 'Zapier', 'recurring' => 'Ricorrenti', 'last_invoice_sent' => 'Ultima fattura inviata :date', - 'processed_updates' => 'Successfully completed update', 'tasks' => 'Task', 'new_task' => 'Nuovo Task', @@ -662,13 +576,10 @@ return array( 'invoice_labels' => 'Invoice Labels', 'prefix' => 'Prefix', 'counter' => 'Counter', - 'payment_type_dwolla' => 'Dwolla', 'gateway_help_43' => ':link to sign up for Dwolla.', 'partial_value' => 'Must be greater than zero and less than the total', 'more_actions' => 'Altre Azioni', - - 'pro_plan_title' => 'NINJA PRO', 'pro_plan_call_to_action' => 'Upgrade Now!', 'pro_plan_feature1' => 'Create Unlimited Clients', @@ -679,14 +590,12 @@ return array( 'pro_plan_feature6' => 'Create Quotes & Pro-forma Invoices', 'pro_plan_feature7' => 'Customize Invoice Field Titles & Numbering', 'pro_plan_feature8' => 'Option to Attach PDFs to Client Emails', - 'resume' => 'Riprendi', 'break_duration' => 'Interrompi', 'edit_details' => 'Modifica dettagli', 'work' => 'Work', 'timezone_unset' => 'Please :link to set your timezone', 'click_here' => 'clicca qui', - 'email_receipt' => 'Email payment receipt to the client', 'created_payment_emailed_client' => 'Successfully created payment and emailed client', 'add_company' => 'Add Company', @@ -696,10 +605,8 @@ return array( 'unlinked_account' => 'Successfully unlinked accounts', 'login' => 'Login', 'or' => 'or', - 'email_error' => 'There was a problem sending the email', 'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.', - 'old_browser' => 'Please use a newer browser', 'payment_terms_help' => 'Sets the default invoice due date', 'unlink_account' => 'Unlink Account', 'unlink' => 'Unlink', @@ -720,7 +627,6 @@ return array( 'primary_color' => 'Primary Color', 'secondary_color' => 'Secondary Color', 'customize_design' => 'Customize Design', - 'content' => 'Content', 'styles' => 'Styles', 'defaults' => 'Defaults', @@ -734,7 +640,6 @@ return array( 'outstanding' => 'Inevaso', 'manage_companies' => 'Gestisci aziende', 'total_revenue' => 'Ricavo totale', - 'current_user' => 'Current User', 'new_recurring_invoice' => 'Nuova Fattura Ricorrente', 'recurring_invoice' => 'Fattura ricorrente', @@ -743,9 +648,8 @@ return array( 'primary_user' => 'Primary User', 'help' => 'Help', 'customize_help' => '

    We use pdfmake to define the invoice designs declaratively. The pdfmake playground provide\'s a great way to see the library in action.

    -

    To access a child property using dot notation. For example to show the client name you could use $client.name.

    -

    If you need help figuring something out post a question to our support forum.

    ', - +

    You can access a child property using dot notation. For example to show the client name you could use $client.name.

    +

    If you need help figuring something out post a question to our support forum with the design you\'re using.

    ', 'invoice_due_date' => 'Scadenza fattura', 'quote_due_date' => 'Validità preventivo', 'valid_until' => 'Valido fino a', @@ -758,15 +662,12 @@ return array( 'status_partial' => 'Parziale', 'status_paid' => 'Pagato', 'show_line_item_tax' => 'Display line item taxes inline', - 'iframe_url' => 'Website', '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.', - 'auto_bill' => 'Auto Bill', 'military_time' => '24 Hour Time', 'last_sent' => 'Last Sent', - 'reminder_emails' => 'Reminder Emails', 'templates_and_reminders' => 'Templates & Reminders', 'subject' => 'Subject', @@ -778,15 +679,12 @@ return array( 'reminder_subject' => 'Reminder: Invoice :invoice from :account', 'reset' => 'Reset', 'invoice_not_found' => 'The requested invoice is not available', - 'referral_program' => 'Referral Program', 'referral_code' => 'Referral Code', 'last_sent_on' => 'Last sent on :date', - 'page_expire' => 'This page will expire soon, :click_here to keep working', 'upcoming_quotes' => 'Preventivi in scadenza', 'expired_quotes' => 'Preventivi Scaduti', - 'sign_up_using' => 'Sign up using', 'invalid_credentials' => 'Queste credenziali non corrispondono alle nostre registrazioni', 'show_all_options' => 'Mostra tutte le opzioni', @@ -795,17 +693,10 @@ return array( 'disable' => 'Disabilita', 'invoice_quote_number' => 'Numerazione Fatture e Preventivi', '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_subject' => 'Unable to deliver Invoice :invoice', 'notification_quote_bounced' => 'We were unable to deliver Quote :invoice to :contact.', 'notification_quote_bounced_subject' => 'Unable to deliver Quote :invoice', - 'custom_invoice_link' => 'Custom Invoice Link', 'total_invoiced' => 'Fatturato totale', 'open_balance' => 'Da saldare', @@ -813,14 +704,12 @@ return array( 'basic_settings' => 'Impostazioni Base', 'pro' => 'Pro', 'gateways' => 'Payment Gateways', - 'next_send_on' => 'Send Next: :date', 'no_longer_running' => 'This invoice is not scheduled to run', 'general_settings' => 'General Settings', 'customize' => 'Customize', 'oneclick_login_help' => 'Connect an account to login without a password', 'referral_code_help' => 'Earn money by sharing our app online', - 'enable_with_stripe' => 'Abilita | Richiede Stripe', 'tax_settings' => 'Tax Settings', 'create_tax_rate' => 'Add Tax Rate', @@ -841,7 +730,6 @@ return array( 'invoice_counter' => 'Invoice Counter', 'quote_counter' => 'Quote Counter', 'type' => 'Type', - 'activity_1' => ':user ha creato il cliente :client', 'activity_2' => ':user ha archiviato il cliente :client', 'activity_3' => ':user deleted client :client', @@ -871,18 +759,24 @@ return array( 'activity_27' => ':user restored payment :payment', 'activity_28' => ':user restored :credit credit', 'activity_29' => ':contact ha approvato la fattura :quote', - + 'activity_30' => ':user created :vendor', + 'activity_31' => ':user created :vendor', + 'activity_32' => ':user created :vendor', + 'activity_33' => ':user created :vendor', + 'activity_34' => ':user created expense :expense', + 'activity_35' => ':user created :vendor', + 'activity_36' => ':user created :vendor', + 'activity_37' => ':user created :vendor', 'payment' => 'Payment', 'system' => 'System', 'signature' => 'Email Signature', 'default_messages' => 'Default Messages', 'quote_terms' => 'Quote Terms', 'default_quote_terms' => 'Default Quote Terms', - 'default_invoice_terms' => 'Default Invoice Terms', - 'default_invoice_footer' => 'Default Invoice Footer', + 'default_invoice_terms' => 'Salva termini come predefiniti', + 'default_invoice_footer' => 'Set default invoice footer', 'quote_footer' => 'Quote Footer', 'free' => 'Free', - 'quote_is_approved' => 'Questo preventivo è stato approvato.', 'apply_credit' => 'Apply Credit', 'system_settings' => 'System Settings', @@ -900,7 +794,6 @@ return array( 'restored_recurring_invoice' => 'Successfully restored recurring invoice', 'archived' => 'Archived', 'untitled_account' => 'Untitled Company', - 'before' => 'Before', 'after' => 'After', 'reset_terms_help' => 'Reset to the default account terms', @@ -909,7 +802,6 @@ return array( 'user' => 'User', 'country' => 'Country', 'include' => 'Include', - '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_data' => 'Import Data', @@ -920,16 +812,6 @@ return array( 'task_file' => 'Task File', 'no_mapper' => 'No valid mapping for file', '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', 'admin' => 'Admin', 'disabled' => 'Disabled', @@ -938,11 +820,9 @@ return array( 'invoice_will_create' => 'client will be created', 'invoices_will_create' => 'invoices will be created', 'failed_to_import' => 'The following records failed to import, they either already exist or are missing required fields.', - 'publishable_key' => 'Publishable Key', 'secret_key' => 'Secret Key', 'missing_publishable_key' => 'Set your Stripe publishable key for an improved checkout process', - 'email_design' => 'Email Design', 'due_by' => 'Scadenza :date', 'enable_email_markup' => 'Enable Markup', @@ -954,7 +834,6 @@ return array( 'plain' => 'Plain', 'light' => 'Light', 'dark' => 'Dark', - '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.', 'invoice_number_help' => 'Specify a prefix or use a custom pattern to dynamically set the invoice number.', @@ -963,8 +842,6 @@ return array( '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_charges_helps' => 'Add a text input to the invoice create/edit page and include the charge in the invoice subtotals.', - 'color_help' => 'Note: the primary color is also used in the client portal and custom email designs.', - 'token_expired' => 'Validation token was expired. Please try again.', 'invoice_link' => 'Invoice Link', 'button_confirmation_message' => 'Click to confirm your email address.', @@ -973,7 +850,6 @@ return array( 'created_invoices' => 'Successfully created :count invoice(s)', 'next_invoice_number' => 'The next invoice number is :number.', 'next_quote_number' => 'The next quote number is :number.', - 'days_before' => 'days before', 'days_after' => 'days after', 'field_due_date' => 'due date', @@ -981,11 +857,7 @@ return array( 'schedule' => 'Schedule', 'email_designs' => 'Email Designs', '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', - - // Expense / vendor 'expense' => 'Spesa', 'expenses' => 'Spese', 'new_expense' => 'Inserisci Spesa', @@ -1002,8 +874,6 @@ return array( 'archived_expense' => 'Successfully archived expense', 'deleted_expenses' => 'Successfully deleted expenses', 'archived_expenses' => 'Successfully archived expenses', - - // Expenses 'expense_amount' => 'Importo Spesa', 'expense_balance' => 'Bilancio Spesa', 'expense_date' => 'Data Spesa', @@ -1025,18 +895,14 @@ return array( 'view' => 'Vedi', 'restore_expense' => 'Ripristina Spesa', 'invoice_expense' => 'Fattura Spesa', - 'expense_error_multiple_clients' =>'Le spese non possono appartenere a clienti differenti', + 'expense_error_multiple_clients' => 'Le spese non possono appartenere a clienti differenti', 'expense_error_invoiced' => 'La spesa è stata già fatturata', 'convert_currency' => 'Converti valuta', - - // Payment terms 'num_days' => 'Numero di giorni', 'create_payment_term' => 'Create Payment Term', 'edit_payment_terms' => 'Edit Payment Term', 'edit_payment_term' => 'Edit Payment Term', 'archive_payment_term' => 'Archive Payment Term', - - // recurring due dates 'recurring_due_dates' => 'Recurring Invoice Due Dates', 'recurring_due_date_help' => '

    Automatically sets a due date for the invoice.

    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.

    @@ -1064,15 +930,11 @@ return array( 'thursday' => 'Giovedì', 'friday' => 'Venerdì', 'saturday' => 'Sabato', - - // Fonts 'header_font_id' => 'Header 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.', - 'live_preview' => 'Live Preview', '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.', 'quote_message_button' => 'To view your quote for :amount, click the button below.', 'payment_message_button' => 'Thank you for your payment of :amount.', @@ -1089,7 +951,6 @@ return array( 'archived_bank_account' => 'Successfully archived bank account', 'created_bank_account' => 'Successfully created 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 400+ US banks.', '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.', 'username' => 'Username', @@ -1103,7 +964,6 @@ return array( 'validate' => 'Validate', 'info' => 'Info', '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.', '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.', @@ -1124,7 +984,28 @@ return array( 'trial_call_to_action' => 'Start Free Trial', '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.', + + + 'white_label_text' => 'Purchase a ONE YEAR white label license for $:price to remove the Invoice Ninja branding from the client portal and help support our project.', + 'user_email_footer' => 'Per modificare le impostazioni di notifiche via email per favore accedi a: :link', + 'reset_password_footer' => 'Se non sei stato tu a voler resettare la password per favore invia un\'email di assistenza a: :email', + 'limit_users' => 'Sorry, this will exceed the limit of :limit users', + 'more_designs_self_host_header' => 'Get 6 more invoice designs for just $:price', + 'old_browser' => 'Please use a newer browser', + 'white_label_custom_css' => ':link for $: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 400+ US banks.', + + 'pro_plan_remove_logo' => ':link per rimuovere il logo di Invoice Ninja aderendo al programma pro', + 'pro_plan_remove_logo_link' => 'Clicca qui', + 'invitation_status_sent' => 'Email Sent', + 'invitation_status_opened' => 'Email Openend', + 'invitation_status_viewed' => 'Invoice Viewed', + 'email_error_inactive_client' => 'Emails can not be sent to inactive clients', + 'email_error_inactive_contact' => 'Emails can not be sent to inactive contacts', + 'email_error_inactive_invoice' => 'Emails can not be sent to inactive invoices', + 'email_error_user_unregistered' => 'Please register your account to send emails', + 'email_error_user_unconfirmed' => 'Please confirm your account to send emails', + 'email_error_invalid_contact_email' => 'Invalid contact email', 'navigation' => 'Navigation', 'list_invoices' => 'List Invoices', @@ -1147,22 +1028,20 @@ return array( 'custom_invoice_item_fields_help' => 'Add a field when creating an invoice item and display the label and value on the PDF.', 'recurring_invoice_number' => 'Recurring Invoice Number', 'recurring_invoice_number_prefix_help' => 'Speciy a prefix to be added to the invoice number for recurring invoices. The default value is \'R\'.', - 'enable_client_portal' => 'Dashboard', - 'enable_client_portal_help' => 'Show/hide the dashboard page in the client portal.', // Client Passwords 'enable_portal_password'=>'Password protect invoices', 'enable_portal_password_help'=>'Allows you to set a password for each contact. If a password is set, the contact will be required to enter a password before viewing invoices.', 'send_portal_password'=>'Generate password automatically', 'send_portal_password_help'=>'If no password is set, one will be generated and sent with the first invoice.', - + 'expired' => 'Expired', 'invalid_card_number' => 'The credit card number is not valid.', 'invalid_expiry' => 'The expiration date is not valid.', 'invalid_cvv' => 'The CVV is not valid.', 'cost' => 'Cost', 'create_invoice_for_sample' => 'Note: create your first invoice to see a preview here.', - + // User Permissions 'owner' => 'Owner', 'administrator' => 'Administrator', @@ -1180,8 +1059,8 @@ return array( 'create_all_help' => 'Allow user to create and modify records', 'view_all_help' => 'Allow user to view records they didn\'t create', 'edit_all_help' => 'Allow user to modify records they didn\'t create', - 'view_payment' => 'View Payment', - + 'view_payment' => 'View Payment', + 'january' => 'Gennaio', 'february' => 'Febbraio', 'march' => 'Marzo', @@ -1207,30 +1086,28 @@ return array( 'document_email_attachment' => 'Attach Documents', 'download_documents' => 'Download Documents (:size)', 'documents_from_expenses' => 'From Expenses:', - 'dropzone' => array(// See http://www.dropzonejs.com/#config-dictDefaultMessage - 'DefaultMessage' => 'Drop files or click to upload', - 'FallbackMessage' => 'Your browser does not support drag\'n\'drop file uploads.', - 'FallbackText' => 'Please use the fallback form below to upload your files like in the olden days.', - 'FileTooBig' => 'File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.', - 'InvalidFileType' => 'You can\'t upload files of this type.', - 'ResponseError' => 'Server responded with {{statusCode}} code.', - 'CancelUpload' => 'Cancel upload', - 'CancelUploadConfirmation' => 'Are you sure you want to cancel this upload?', - 'RemoveFile' => 'Remove file', - ), + 'dropzone_default_message' => 'Drop files or click to upload', + 'dropzone_fallback_message' => 'Your browser does not support drag\'n\'drop file uploads.', + 'dropzone_fallback_text' => 'Please use the fallback form below to upload your files like in the olden days.', + 'dropzone_file_too_big' => 'File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.', + 'dropzone_invalid_file_type' => 'You can\'t upload files of this type.', + 'dropzone_response_error' => 'Server responded with {{statusCode}} code.', + 'dropzone_cancel_upload' => 'Cancel upload', + 'dropzone_cancel_upload_confirmation' => 'Are you sure you want to cancel this upload?', + 'dropzone_remove_file' => 'Remove file', 'documents' => 'Documents', 'document_date' => 'Document Date', 'document_size' => 'Size', - 'enable_client_portal' => 'Client Portal', - 'enable_client_portal_help' => 'Show/hide the client portal.', + 'enable_client_portal' => 'Dashboard', + 'enable_client_portal_help' => 'Show/hide the dashboard page in the client portal.', 'enable_client_portal_dashboard' => 'Dashboard', 'enable_client_portal_dashboard_help' => 'Show/hide the dashboard page in the client portal.', - + // Plans 'account_management' => 'Account Management', 'plan_status' => 'Plan Status', - + 'plan_upgrade' => 'Upgrade', 'plan_change' => 'Change Plan', 'pending_change_to' => 'Changes To', @@ -1260,9 +1137,9 @@ return array( 'plan_paid' => 'Term Started', 'plan_started' => 'Plan Started', 'plan_expires' => 'Plan Expires', - + 'white_label_button' => 'White Label', - + 'pro_plan_year_description' => 'One year enrollment in the Invoice Ninja Pro Plan.', 'pro_plan_month_description' => 'One month enrollment in the Invoice Ninja Pro Plan.', 'enterprise_plan_product' => 'Enterprise Plan', @@ -1280,7 +1157,207 @@ return array( 'preview' => 'Preview', 'list_vendors' => 'List Vendors', 'add_users_not_supported' => 'Upgrade to the Enterprise plan to add additional users to your account.', - 'enterprise_plan_features' => 'The Enterprise plan adds support for multiple users and file attachments.', + 'enterprise_plan_features' => 'The Enterprise plan adds support for multiple users and file attachments, :link to see the full list of features.', 'return_to_app' => 'Return to app', - + + + // Payment updates + 'refund_payment' => 'Refund Payment', + 'refund_max' => 'Max:', + 'refund' => 'Refund', + 'are_you_sure_refund' => 'Refund selected payments?', + 'status_pending' => 'Pending', + 'status_completed' => 'Completed', + 'status_failed' => 'Failed', + 'status_partially_refunded' => 'Partially Refunded', + 'status_partially_refunded_amount' => ':amount Refunded', + 'status_refunded' => 'Refunded', + 'status_voided' => 'Cancelled', + 'refunded_payment' => 'Refunded Payment', + 'activity_39' => ':user cancelled a :payment_amount payment (:payment)', + 'activity_40' => ':user refunded :adjustment of a :payment_amount payment (:payment)', + 'card_expiration' => 'Exp: :expires', + + 'card_creditcardother' => 'Unknown', + 'card_americanexpress' => 'American Express', + 'card_carteblanche' => 'Carte Blanche', + 'card_unionpay' => 'UnionPay', + 'card_diners' => 'Diners Club', + 'card_discover' => 'Discover', + 'card_jcb' => 'JCB', + 'card_laser' => 'Laser', + 'card_maestro' => 'Maestro', + 'card_mastercard' => 'MasterCard', + 'card_solo' => 'Solo', + 'card_switch' => 'Switch', + 'card_visacard' => 'Visa', + 'card_ach' => 'ACH', + + 'payment_type_stripe' => 'Stripe', + 'ach' => 'ACH', + 'enable_ach' => 'Enable ACH', + 'stripe_ach_help' => 'ACH support must also be enabled at Stripe.', + 'ach_disabled' => 'Another gateway is already configured for direct debit.', + + 'plaid' => 'Plaid', + 'client_id' => 'Client Id', + 'secret' => 'Secret', + 'public_key' => 'Public Key', + 'plaid_optional' => '(optional)', + 'plaid_environment_help' => 'When a Stripe test key is given, Plaid\'s development environement (tartan) will be used.', + 'other_providers' => 'Other Providers', + 'country_not_supported' => 'That country is not supported.', + 'invalid_routing_number' => 'The routing number is not valid.', + 'invalid_account_number' => 'The account number is not valid.', + 'account_number_mismatch' => 'The account numbers do not match.', + 'missing_account_holder_type' => 'Please select an individual or company account.', + 'missing_account_holder_name' => 'Please enter the account holder\'s name.', + 'routing_number' => 'Routing Number', + 'confirm_account_number' => 'Confirm Account Number', + 'individual_account' => 'Individual Account', + 'company_account' => 'Company Account', + 'account_holder_name' => 'Account Holder Name', + 'add_account' => 'Add Account', + 'payment_methods' => 'Payment Methods', + 'complete_verification' => 'Complete Verification', + 'verification_amount1' => 'Amount 1', + 'verification_amount2' => 'Amount 2', + 'payment_method_verified' => 'Verification completed successfully', + 'verification_failed' => 'Verification Failed', + 'remove_payment_method' => 'Remove Payment Method', + 'confirm_remove_payment_method' => 'Are you sure you want to remove this payment method?', + 'remove' => 'Remove', + 'payment_method_removed' => 'Removed payment method.', + 'bank_account_verification_help' => 'We have made two deposits into your account with the description "VERIFICATION". These deposits will take 1-2 business days to appear on your statement. Please enter the amounts below.', + 'bank_account_verification_next_steps' => 'We have made two deposits into your account with the description "VERIFICATION". These deposits will take 1-2 business days to appear on your statement. + Once you have the amounts, come back to this payment methods page and click "Complete Verification" next to the account.', + 'unknown_bank' => 'Unknown Bank', + 'ach_verification_delay_help' => 'You will be able to use the account after completing verification. Verification usually takes 1-2 business days.', + 'add_credit_card' => 'Add Credit Card', + 'payment_method_added' => 'Added payment method.', + 'use_for_auto_bill' => 'Use For Autobill', + 'used_for_auto_bill' => 'Autobill Payment Method', + 'payment_method_set_as_default' => 'Set Autobill payment method.', + 'activity_41' => ':payment_amount payment (:payment) failed', + 'webhook_url' => 'Webhook URL', + 'stripe_webhook_help' => 'You must :link.', + 'stripe_webhook_help_link_text' => 'add this URL as an endpoint at Stripe', + 'payment_method_error' => 'There was an error adding your payment methd. Please try again later.', + 'notification_invoice_payment_failed_subject' => 'Payment failed for Invoice :invoice', + 'notification_invoice_payment_failed' => 'A payment made by client :client towards Invoice :invoice failed. The payment has been marked as failed and :amount has been added to the client\'s balance.', + 'link_with_plaid' => 'Link Account Instantly with Plaid', + 'link_manually' => 'Link Manually', + 'secured_by_plaid' => 'Secured by Plaid', + 'plaid_linked_status' => 'Your bank account at :bank', + 'add_payment_method' => 'Add Payment Method', + 'account_holder_type' => 'Account Holder Type', + 'ach_authorization' => 'I authorize :company to use my bank account for future payments and, if necessary, electronically credit my account to correct erroneous debits. I understand that I may cancel this authorization at any time by removing the payment method or by contacting :email.', + 'ach_authorization_required' => 'You must consent to ACH transactions.', + 'off' => 'Off', + 'opt_in' => 'Opt-in', + 'opt_out' => 'Opt-out', + 'always' => 'Always', + 'opted_out' => 'Opted out', + 'opted_in' => 'Opted in', + 'manage_auto_bill' => 'Manage Auto-bill', + 'enabled' => 'Enabled', + 'paypal' => 'PayPal', + 'braintree_enable_paypal' => 'Enable PayPal payments through BrainTree', + 'braintree_paypal_disabled_help' => 'The PayPal gateway is processing PayPal payments', + 'braintree_paypal_help' => 'You must also :link.', + 'braintree_paypal_help_link_text' => 'link PayPal to your BrainTree account', + 'token_billing_braintree_paypal' => 'Save payment details', + 'add_paypal_account' => 'Add PayPal Account', + + + 'no_payment_method_specified' => 'No payment method specified', + 'chart_type' => 'Chart Type', + 'format' => 'Format', + 'import_ofx' => 'Import OFX', + 'ofx_file' => 'OFX File', + 'ofx_parse_failed' => 'Failed to parse OFX file', + + // WePay + 'wepay' => 'WePay', + 'sign_up_with_wepay' => 'Sign up with WePay', + 'use_another_provider' => 'Use another provider', + 'company_name' => 'Company Name', + 'wepay_company_name_help' => 'This will appear on client\'s credit card statements.', + 'wepay_description_help' => 'The purpose of this account.', + 'wepay_tos_agree' => 'I agree to the :link.', + 'wepay_tos_link_text' => 'WePay Terms of Service', + 'resend_confirmation_email' => 'Resend Confirmation Email', + 'manage_wepay_account' => 'Manage WePay Account', + 'action_required' => 'Action Required', + 'finish_setup' => 'Finish Setup', + 'created_wepay_confirmation_required' => 'Please check your email and confirm your email address with WePay.', + 'switch_to_wepay' => 'Switch to WePay', + 'switch' => 'Switch', + 'restore_account_gateway' => 'Restore Gateway', + 'restored_account_gateway' => 'Successfully restored gateway', + 'united_states' => 'United States', + 'canada' => 'Canada', + 'accept_debit_cards' => 'Accept Debit Cards', + 'debit_cards' => 'Debit Cards', + + 'warn_start_date_changed' => 'The next invoice will be sent on the new start date.', + 'original_start_date' => 'Original start date', + 'new_start_date' => 'New start date', + 'security' => 'Security', + 'see_whats_new' => 'See what\'s new in v:version', + 'wait_for_upload' => 'Please wait for the document upload to complete.', + 'upgrade_for_permissions' => 'Upgrade to our Enterprise plan to enable permissions.', + 'enable_second_tax_rate' => 'Enable specifying a second tax rate', + 'payment_file' => 'Payment File', + 'expense_file' => 'Expense File', + 'product_file' => 'Product File', + 'import_products' => 'Import Products', + 'products_will_create' => 'products will be created.', + 'product_key' => 'Product', + 'created_products' => 'Successfully created :count product(s)', + 'export_help' => 'Use JSON if you plan to import the data into Invoice Ninja.', + 'JSON_file' => 'JSON File', + + 'view_dashboard' => 'View Dashboard', + 'client_session_expired' => 'Session Expired', + 'client_session_expired_message' => 'Your session has expired. Please click the link in your email again.', + + 'auto_bill_notification' => 'This invoice will automatically be billed to your :payment_method on file on :due_date.', + 'auto_bill_payment_method_bank_transfer' => 'bank account', + 'auto_bill_payment_method_credit_card' => 'credit card', + 'auto_bill_payment_method_paypal' => 'PayPal account', + 'auto_bill_notification_placeholder' => 'This invoice will automatically be billed to your credit card on file on the due date.', + 'payment_settings' => 'Payment Settings', + + 'on_send_date' => 'On send date', + 'on_due_date' => 'On due date', + 'auto_bill_ach_date_help' => 'ACH auto bill will always happen on the due date', + 'warn_change_auto_bill' => 'Due to NACHA rules, changes to this invoice may prevent ACH auto bill.', + + 'bank_account' => 'Bank Account', + 'payment_processed_through_wepay' => 'ACH payments will be processed using WePay.', + 'wepay_payment_tos_agree' => 'I agree to the WePay :terms and :privacy_policy.', + 'privacy_policy' => 'Privacy Policy', + 'wepay_payment_tos_agree_required' => 'You must agree to the WePay Terms of Service and Privacy Policy.', + 'payment_settings_supported_gateways' => 'These options are supported by the WePay, Stripe, and Braintree gateways.', + 'ach_email_prompt' => 'Please enter your email address:', + 'verification_pending' => 'Verification Pending', + + 'update_font_cache' => 'Please force refresh the page to update the font cache.', + 'more_options' => 'More options', + 'credit_card' => 'Credit Card', + 'bank_transfer' => 'Bank Transfer', + 'no_transaction_reference' => 'We did not recieve a payment transaction reference from the gateway.', + 'use_bank_on_file' => 'Use Bank on File', + 'auto_bill_email_message' => 'This invoice will automatically be billed to the payment method on file on the due date.', + 'bitcoin' => 'Bitcoin', + 'added_on' => 'Added :date', + 'failed_remove_payment_method' => 'Failed to remove the payment method', + 'gateway_exists' => 'This gateway already exists', + 'manual_entry' => 'Manual entry', + ); + +return $LANG; + +?> diff --git a/resources/lang/ja/texts.php b/resources/lang/ja/texts.php index 3875de2435..ef8f48fd3b 100644 --- a/resources/lang/ja/texts.php +++ b/resources/lang/ja/texts.php @@ -5,8 +5,8 @@ $LANG = array( 'name' => '名前', 'website' => 'WEBサイト', 'work_phone' => '電話番号', - 'address' => "住所", - 'address1' => "番地", + 'address' => '住所', + 'address1' => '番地', 'address2' => '建物', 'city' => '市区町村', 'state' => '都道府県', @@ -268,7 +268,6 @@ $LANG = array( 'erase_data' => 'あなたのデータを完全に削除します。', 'password' => 'パスワード', 'pro_plan_product' => 'プロ・プラン', - 'pro_plan_description' => 'One year enrollment in the Invoice Ninja Pro Plan.', 'pro_plan_success' => 'Thanks for choosing Invoice Ninja\'s Pro plan!

     
    Next Steps

    A payable invoice has been sent to the email address associated with your account. To unlock all of the awesome @@ -445,11 +444,11 @@ $LANG = array( 'token_billing_3' => 'Opt-out - checkbox is shown and selected', 'token_billing_4' => 'Always', 'token_billing_checkbox' => 'Store credit card details', - 'view_in_stripe' => 'View in Stripe', - 'use_card_on_file' => 'Use card on file', + 'view_in_gateway' => 'View in :gateway', + 'use_card_on_file' => 'Use Card on File', 'edit_payment_details' => 'Edit payment 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 :link', 'support' => 'Support', 'contact_information' => 'Contact Information', '256_encryption' => '256-Bit Encryption', @@ -655,8 +654,8 @@ $LANG = array( 'primary_user' => 'プライマリ・ユーザ', 'help' => 'ヘルプ', 'customize_help' => '

    We use pdfmake to define the invoice designs declaratively. The pdfmake playground provide\'s a great way to see the library in action.

    -

    To access a child property using dot notation. For example to show the client name you could use $client.name.

    -

    If you need help figuring something out post a question to our support forum.

    ', +

    You can access a child property using dot notation. For example to show the client name you could use $client.name.

    +

    If you need help figuring something out post a question to our support forum with the design you\'re using.

    ', 'invoice_due_date' => '支払期日', 'quote_due_date' => 'Valid Until', 'valid_until' => 'Valid Until', @@ -993,40 +992,26 @@ $LANG = array( '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.', - '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 newer browser', - '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 400+ US banks.', - 'security' => [ - 'too_many_attempts' => 'Too many attempts. Try again in few minutes.', - 'wrong_credentials' => 'メールアドレスもしくはパスワードが正しくありません。', - 'confirmation' => 'アカウントが確認されました!', - 'wrong_confirmation' => '確認コードが違っています。', - 'password_forgot' => 'The information regarding password reset was sent to your email.', - 'password_reset' => 'パスワードが変更されました。', - 'wrong_password_reset' => 'パスワードが正しくありません。もう一度入力してください。', - ], - 'pro_plan' => [ - 'remove_logo' => 'プロプランに加入して、Invoice Ninjaのロゴを消す。 :link', - 'remove_logo_link' => 'こちらをクリック', - ], - 'invitation_status' => [ - 'sent' => 'メール送付済', - 'opened' => 'メール開封済', - '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', - ], + 'white_label_text' => 'Purchase a ONE YEAR white label license for $: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 :link', + 'reset_password_footer' => 'If you did not request this password reset please email our support: :email', + 'limit_users' => 'Sorry, this will exceed the limit of :limit users', + 'more_designs_self_host_header' => 'Get 6 more invoice designs for just $:price', + 'old_browser' => 'Please use a newer browser', + 'white_label_custom_css' => ':link for $: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 400+ US banks.', + + 'pro_plan_remove_logo' => 'プロプランに加入して、Invoice Ninjaのロゴを消す。 :link', + 'pro_plan_remove_logo_link' => 'こちらをクリック', + 'invitation_status_sent' => 'メール送付済', + 'invitation_status_opened' => 'メール開封済', + 'invitation_status_viewed' => '請求書閲覧済', + 'email_error_inactive_client' => 'Emails can not be sent to inactive clients', + 'email_error_inactive_contact' => 'Emails can not be sent to inactive contacts', + 'email_error_inactive_invoice' => 'Emails can not be sent to inactive invoices', + 'email_error_user_unregistered' => 'Please register your account to send emails', + 'email_error_user_unconfirmed' => 'Please confirm your account to send emails', + 'email_error_invalid_contact_email' => 'Invalid contact email', 'navigation' => 'ナビゲーション', 'list_invoices' => '請求書一覧', @@ -1049,22 +1034,20 @@ $LANG = array( 'custom_invoice_item_fields_help' => 'Add a field when creating an invoice item and display the label and value on the PDF.', 'recurring_invoice_number' => 'Recurring Invoice Number', 'recurring_invoice_number_prefix_help' => 'Speciy a prefix to be added to the invoice number for recurring invoices. The default value is \'R\'.', - 'enable_client_portal' => 'ダッシュボード', - 'enable_client_portal_help' => 'Show/hide the dashboard page in the client portal.', // Client Passwords 'enable_portal_password'=>'Password protect invoices', 'enable_portal_password_help'=>'Allows you to set a password for each contact. If a password is set, the contact will be required to enter a password before viewing invoices.', 'send_portal_password'=>'Generate password automatically', 'send_portal_password_help'=>'If no password is set, one will be generated and sent with the first invoice.', - + 'expired' => 'Expired', 'invalid_card_number' => 'The credit card number is not valid.', 'invalid_expiry' => 'The expiration date is not valid.', 'invalid_cvv' => 'The CVV is not valid.', 'cost' => 'Cost', 'create_invoice_for_sample' => 'Note: create your first invoice to see a preview here.', - + // User Permissions 'owner' => 'Owner', 'administrator' => 'Administrator', @@ -1082,8 +1065,8 @@ $LANG = array( 'create_all_help' => 'Allow user to create and modify records', 'view_all_help' => 'Allow user to view records they didn\'t create', 'edit_all_help' => 'Allow user to modify records they didn\'t create', - 'view_payment' => 'View Payment', - + 'view_payment' => 'View Payment', + 'january' => 'January', 'february' => 'February', 'march' => 'March', @@ -1109,30 +1092,28 @@ $LANG = array( 'document_email_attachment' => 'Attach Documents', 'download_documents' => 'Download Documents (:size)', 'documents_from_expenses' => 'From Expenses:', - 'dropzone' => array(// See http://www.dropzonejs.com/#config-dictDefaultMessage - 'DefaultMessage' => 'Drop files or click to upload', - 'FallbackMessage' => 'Your browser does not support drag\'n\'drop file uploads.', - 'FallbackText' => 'Please use the fallback form below to upload your files like in the olden days.', - 'FileTooBig' => 'File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.', - 'InvalidFileType' => 'You can\'t upload files of this type.', - 'ResponseError' => 'Server responded with {{statusCode}} code.', - 'CancelUpload' => 'Cancel upload', - 'CancelUploadConfirmation' => 'Are you sure you want to cancel this upload?', - 'RemoveFile' => 'Remove file', - ), + 'dropzone_default_message' => 'Drop files or click to upload', + 'dropzone_fallback_message' => 'Your browser does not support drag\'n\'drop file uploads.', + 'dropzone_fallback_text' => 'Please use the fallback form below to upload your files like in the olden days.', + 'dropzone_file_too_big' => 'File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.', + 'dropzone_invalid_file_type' => 'You can\'t upload files of this type.', + 'dropzone_response_error' => 'Server responded with {{statusCode}} code.', + 'dropzone_cancel_upload' => 'Cancel upload', + 'dropzone_cancel_upload_confirmation' => 'Are you sure you want to cancel this upload?', + 'dropzone_remove_file' => 'Remove file', 'documents' => 'Documents', 'document_date' => 'Document Date', 'document_size' => 'Size', - 'enable_client_portal' => 'Client Portal', - 'enable_client_portal_help' => 'Show/hide the client portal.', + 'enable_client_portal' => 'ダッシュボード', + 'enable_client_portal_help' => 'Show/hide the dashboard page in the client portal.', 'enable_client_portal_dashboard' => 'Dashboard', 'enable_client_portal_dashboard_help' => 'Show/hide the dashboard page in the client portal.', - + // Plans 'account_management' => 'Account Management', 'plan_status' => 'Plan Status', - + 'plan_upgrade' => 'Upgrade', 'plan_change' => 'Change Plan', 'pending_change_to' => 'Changes To', @@ -1162,9 +1143,9 @@ $LANG = array( 'plan_paid' => 'Term Started', 'plan_started' => 'Plan Started', 'plan_expires' => 'Plan Expires', - + 'white_label_button' => 'White Label', - + 'pro_plan_year_description' => 'One year enrollment in the Invoice Ninja Pro Plan.', 'pro_plan_month_description' => 'One month enrollment in the Invoice Ninja Pro Plan.', 'enterprise_plan_product' => 'Enterprise Plan', @@ -1175,19 +1156,214 @@ $LANG = array( 'plan_pending_monthly' => 'Will switch to monthly on :date', 'plan_refunded' => 'A refund has been issued.', - 'live_preview' => 'Live Preview', + 'live_preview' => 'ライブ・プレビュー', 'page_size' => 'Page Size', 'live_preview_disabled' => 'Live preview has been disabled to support selected font', 'invoice_number_padding' => 'Padding', 'preview' => 'Preview', 'list_vendors' => 'List Vendors', 'add_users_not_supported' => 'Upgrade to the Enterprise plan to add additional users to your account.', - 'enterprise_plan_features' => 'The Enterprise plan adds support for multiple users and file attachments.', + 'enterprise_plan_features' => 'The Enterprise plan adds support for multiple users and file attachments, :link to see the full list of features.', 'return_to_app' => 'Return to app', - - + + + // Payment updates + 'refund_payment' => 'Refund Payment', + 'refund_max' => 'Max:', + 'refund' => 'Refund', + 'are_you_sure_refund' => 'Refund selected payments?', + 'status_pending' => 'Pending', + 'status_completed' => 'Completed', + 'status_failed' => 'Failed', + 'status_partially_refunded' => 'Partially Refunded', + 'status_partially_refunded_amount' => ':amount Refunded', + 'status_refunded' => 'Refunded', + 'status_voided' => 'Cancelled', + 'refunded_payment' => 'Refunded Payment', + 'activity_39' => ':user cancelled a :payment_amount payment (:payment)', + 'activity_40' => ':user refunded :adjustment of a :payment_amount payment (:payment)', + 'card_expiration' => 'Exp: :expires', + + 'card_creditcardother' => 'Unknown', + 'card_americanexpress' => 'American Express', + 'card_carteblanche' => 'Carte Blanche', + 'card_unionpay' => 'UnionPay', + 'card_diners' => 'Diners Club', + 'card_discover' => 'Discover', + 'card_jcb' => 'JCB', + 'card_laser' => 'Laser', + 'card_maestro' => 'Maestro', + 'card_mastercard' => 'MasterCard', + 'card_solo' => 'Solo', + 'card_switch' => 'Switch', + 'card_visacard' => 'Visa', + 'card_ach' => 'ACH', + + 'payment_type_stripe' => 'Stripe', + 'ach' => 'ACH', + 'enable_ach' => 'Enable ACH', + 'stripe_ach_help' => 'ACH support must also be enabled at Stripe.', + 'ach_disabled' => 'Another gateway is already configured for direct debit.', + + 'plaid' => 'Plaid', + 'client_id' => 'Client Id', + 'secret' => 'Secret', + 'public_key' => 'Public Key', + 'plaid_optional' => '(optional)', + 'plaid_environment_help' => 'When a Stripe test key is given, Plaid\'s development environement (tartan) will be used.', + 'other_providers' => 'Other Providers', + 'country_not_supported' => 'That country is not supported.', + 'invalid_routing_number' => 'The routing number is not valid.', + 'invalid_account_number' => 'The account number is not valid.', + 'account_number_mismatch' => 'The account numbers do not match.', + 'missing_account_holder_type' => 'Please select an individual or company account.', + 'missing_account_holder_name' => 'Please enter the account holder\'s name.', + 'routing_number' => 'Routing Number', + 'confirm_account_number' => 'Confirm Account Number', + 'individual_account' => 'Individual Account', + 'company_account' => 'Company Account', + 'account_holder_name' => 'Account Holder Name', + 'add_account' => 'Add Account', + 'payment_methods' => 'Payment Methods', + 'complete_verification' => 'Complete Verification', + 'verification_amount1' => 'Amount 1', + 'verification_amount2' => 'Amount 2', + 'payment_method_verified' => 'Verification completed successfully', + 'verification_failed' => 'Verification Failed', + 'remove_payment_method' => 'Remove Payment Method', + 'confirm_remove_payment_method' => 'Are you sure you want to remove this payment method?', + 'remove' => 'Remove', + 'payment_method_removed' => 'Removed payment method.', + 'bank_account_verification_help' => 'We have made two deposits into your account with the description "VERIFICATION". These deposits will take 1-2 business days to appear on your statement. Please enter the amounts below.', + 'bank_account_verification_next_steps' => 'We have made two deposits into your account with the description "VERIFICATION". These deposits will take 1-2 business days to appear on your statement. + Once you have the amounts, come back to this payment methods page and click "Complete Verification" next to the account.', + 'unknown_bank' => 'Unknown Bank', + 'ach_verification_delay_help' => 'You will be able to use the account after completing verification. Verification usually takes 1-2 business days.', + 'add_credit_card' => 'Add Credit Card', + 'payment_method_added' => 'Added payment method.', + 'use_for_auto_bill' => 'Use For Autobill', + 'used_for_auto_bill' => 'Autobill Payment Method', + 'payment_method_set_as_default' => 'Set Autobill payment method.', + 'activity_41' => ':payment_amount payment (:payment) failed', + 'webhook_url' => 'Webhook URL', + 'stripe_webhook_help' => 'You must :link.', + 'stripe_webhook_help_link_text' => 'add this URL as an endpoint at Stripe', + 'payment_method_error' => 'There was an error adding your payment methd. Please try again later.', + 'notification_invoice_payment_failed_subject' => 'Payment failed for Invoice :invoice', + 'notification_invoice_payment_failed' => 'A payment made by client :client towards Invoice :invoice failed. The payment has been marked as failed and :amount has been added to the client\'s balance.', + 'link_with_plaid' => 'Link Account Instantly with Plaid', + 'link_manually' => 'Link Manually', + 'secured_by_plaid' => 'Secured by Plaid', + 'plaid_linked_status' => 'Your bank account at :bank', + 'add_payment_method' => 'Add Payment Method', + 'account_holder_type' => 'Account Holder Type', + 'ach_authorization' => 'I authorize :company to use my bank account for future payments and, if necessary, electronically credit my account to correct erroneous debits. I understand that I may cancel this authorization at any time by removing the payment method or by contacting :email.', + 'ach_authorization_required' => 'You must consent to ACH transactions.', + 'off' => 'Off', + 'opt_in' => 'Opt-in', + 'opt_out' => 'Opt-out', + 'always' => 'Always', + 'opted_out' => 'Opted out', + 'opted_in' => 'Opted in', + 'manage_auto_bill' => 'Manage Auto-bill', + 'enabled' => 'Enabled', + 'paypal' => 'PayPal', + 'braintree_enable_paypal' => 'Enable PayPal payments through BrainTree', + 'braintree_paypal_disabled_help' => 'The PayPal gateway is processing PayPal payments', + 'braintree_paypal_help' => 'You must also :link.', + 'braintree_paypal_help_link_text' => 'link PayPal to your BrainTree account', + 'token_billing_braintree_paypal' => 'Save payment details', + 'add_paypal_account' => 'Add PayPal Account', + + + 'no_payment_method_specified' => 'No payment method specified', + 'chart_type' => 'Chart Type', + 'format' => 'Format', + 'import_ofx' => 'Import OFX', + 'ofx_file' => 'OFX File', + 'ofx_parse_failed' => 'Failed to parse OFX file', + + // WePay + 'wepay' => 'WePay', + 'sign_up_with_wepay' => 'Sign up with WePay', + 'use_another_provider' => 'Use another provider', + 'company_name' => 'Company Name', + 'wepay_company_name_help' => 'This will appear on client\'s credit card statements.', + 'wepay_description_help' => 'The purpose of this account.', + 'wepay_tos_agree' => 'I agree to the :link.', + 'wepay_tos_link_text' => 'WePay Terms of Service', + 'resend_confirmation_email' => 'Resend Confirmation Email', + 'manage_wepay_account' => 'Manage WePay Account', + 'action_required' => 'Action Required', + 'finish_setup' => 'Finish Setup', + 'created_wepay_confirmation_required' => 'Please check your email and confirm your email address with WePay.', + 'switch_to_wepay' => 'Switch to WePay', + 'switch' => 'Switch', + 'restore_account_gateway' => 'Restore Gateway', + 'restored_account_gateway' => 'Successfully restored gateway', + 'united_states' => 'United States', + 'canada' => 'Canada', + 'accept_debit_cards' => 'Accept Debit Cards', + 'debit_cards' => 'Debit Cards', + + 'warn_start_date_changed' => 'The next invoice will be sent on the new start date.', + 'original_start_date' => 'Original start date', + 'new_start_date' => 'New start date', + 'security' => 'Security', + 'see_whats_new' => 'See what\'s new in v:version', + 'wait_for_upload' => 'Please wait for the document upload to complete.', + 'upgrade_for_permissions' => 'Upgrade to our Enterprise plan to enable permissions.', + 'enable_second_tax_rate' => 'Enable specifying a second tax rate', + 'payment_file' => 'Payment File', + 'expense_file' => 'Expense File', + 'product_file' => 'Product File', + 'import_products' => 'Import Products', + 'products_will_create' => 'products will be created.', + 'product_key' => 'Product', + 'created_products' => 'Successfully created :count product(s)', + 'export_help' => 'Use JSON if you plan to import the data into Invoice Ninja.', + 'JSON_file' => 'JSON File', + + 'view_dashboard' => 'View Dashboard', + 'client_session_expired' => 'Session Expired', + 'client_session_expired_message' => 'Your session has expired. Please click the link in your email again.', + + 'auto_bill_notification' => 'This invoice will automatically be billed to your :payment_method on file on :due_date.', + 'auto_bill_payment_method_bank_transfer' => 'bank account', + 'auto_bill_payment_method_credit_card' => 'credit card', + 'auto_bill_payment_method_paypal' => 'PayPal account', + 'auto_bill_notification_placeholder' => 'This invoice will automatically be billed to your credit card on file on the due date.', + 'payment_settings' => 'Payment Settings', + + 'on_send_date' => 'On send date', + 'on_due_date' => 'On due date', + 'auto_bill_ach_date_help' => 'ACH auto bill will always happen on the due date', + 'warn_change_auto_bill' => 'Due to NACHA rules, changes to this invoice may prevent ACH auto bill.', + + 'bank_account' => 'Bank Account', + 'payment_processed_through_wepay' => 'ACH payments will be processed using WePay.', + 'wepay_payment_tos_agree' => 'I agree to the WePay :terms and :privacy_policy.', + 'privacy_policy' => 'Privacy Policy', + 'wepay_payment_tos_agree_required' => 'You must agree to the WePay Terms of Service and Privacy Policy.', + 'payment_settings_supported_gateways' => 'These options are supported by the WePay, Stripe, and Braintree gateways.', + 'ach_email_prompt' => 'Please enter your email address:', + 'verification_pending' => 'Verification Pending', + + 'update_font_cache' => 'Please force refresh the page to update the font cache.', + 'more_options' => 'More options', + 'credit_card' => 'Credit Card', + 'bank_transfer' => 'Bank Transfer', + 'no_transaction_reference' => 'We did not recieve a payment transaction reference from the gateway.', + 'use_bank_on_file' => 'Use Bank on File', + 'auto_bill_email_message' => 'This invoice will automatically be billed to the payment method on file on the due date.', + 'bitcoin' => 'Bitcoin', + 'added_on' => 'Added :date', + 'failed_remove_payment_method' => 'Failed to remove the payment method', + 'gateway_exists' => 'This gateway already exists', + 'manual_entry' => 'Manual entry', + ); return $LANG; -?>. \ No newline at end of file +?> diff --git a/resources/lang/lt/texts.php b/resources/lang/lt/texts.php index 75cb494ca9..3db70f9eab 100644 --- a/resources/lang/lt/texts.php +++ b/resources/lang/lt/texts.php @@ -1,15 +1,13 @@ - 'Įmonė', - 'name' => 'Vardas', + 'name' => 'Pavadinimas', 'website' => 'Internetinis puslapis', 'work_phone' => 'Telefonas', 'address' => 'Adresas', - 'address1' => 'Gatvė', - 'address2' => 'Kabinetas', + 'address1' => 'Adresas', + 'address2' => 'Adresas2', 'city' => 'Miestas', 'state' => 'Valstija', 'postal_code' => 'Pašto kodas', @@ -19,38 +17,35 @@ return array( 'last_name' => 'Pavardė', 'phone' => 'Telefonas', 'email' => 'El. paštas', - 'additional_info' => 'Papidoma Info', - 'payment_terms' => 'Apmokėjimo sąlygos', + 'additional_info' => 'Papildoma informacija', + 'payment_terms' => 'Atsiskaitymo sąlygos', 'currency_id' => 'Valiuta', 'size_id' => 'Dydis', 'industry_id' => 'Veiklos sritis', 'private_notes' => 'Privatūs užrašai', - - // invoice 'invoice' => 'Sąkaita faktūra', 'client' => 'Klientas', 'invoice_date' => 'Išrašymo data', - 'due_date' => 'Apmokėjimo Data', + 'due_date' => 'Mokėjimo diena', 'invoice_number' => 'Serija ir Nr.', 'invoice_number_short' => 'Nr.', - 'po_number' => 'PO Numeris', - 'po_number_short' => 'PO Nr.', + 'po_number' => 'Čekio numeris', + 'po_number_short' => 'Čekio Nr.', 'frequency_id' => 'Kaip dažnai', 'discount' => 'Nuolaida', 'taxes' => 'Mokesčiai', 'tax' => 'PVM', - 'item' => 'Prekė', + 'item' => 'Prekė/Paslauga', 'description' => 'Aprašymas', 'unit_cost' => 'Vnt. kaina', 'quantity' => 'Kiekis', 'line_total' => 'Suma', 'subtotal' => 'Suma viso', 'paid_to_date' => 'Apmokėta', - 'balance_due' => 'Apmokėti', + 'balance_due' => 'Mokėti', 'invoice_design_id' => 'Dizainas', 'terms' => 'Sąlygos', 'your_invoice' => 'Tavo sąskaitos', - 'remove_contact' => 'Pašalinti kontaktą', 'add_contact' => 'Pridėti kontaktą', 'create_new_client' => 'Sukurti naują klientą', @@ -74,8 +69,6 @@ return array( 'settings' => 'Nustatymai', 'enable_invoice_tax' => 'Įjungti PVM mokesčius', 'enable_line_item_tax' => 'Įjungti PVM mokesčius sumai', - - // navigation 'dashboard' => 'Darbastalis', 'clients' => 'Klientai', 'invoices' => 'Sąskaitos', @@ -98,11 +91,9 @@ return array( 'cancel' => 'Atšaukti', 'close' => 'Uždaryti', 'provide_email' => 'Prašome pateikti galiojantį el. pašto adresą', - 'powered_by' => 'Energija teikia', + 'powered_by' => 'Sukurta', 'no_items' => 'Įrašų nėra', - - // recurring invoices - 'recurring_invoices' => 'Recurring Invoices', + 'recurring_invoices' => 'Debeto sąskaitos', 'recurring_help' => '

    Automatically send clients the same invoices weekly, bi-monthly, monthly, quarterly or annually.

    Use :MONTH, :QUARTER or :YEAR for dynamic dates. Basic math works as well, for example :MONTH-1.

    Examples of dynamic invoice variables:

    @@ -111,80 +102,70 @@ return array(
  • ":YEAR+1 yearly subscription" => "2015 Yearly Subscription"
  • "Retainer payment for :QUARTER+1" => "Retainer payment for Q2"
  • ', - - // dashboard - 'in_total_revenue' => 'in total revenue', + 'in_total_revenue' => 'iš viso pajamų', 'billed_client' => 'billed client', 'billed_clients' => 'billed clients', 'active_client' => 'active client', - 'active_clients' => 'active clients', - 'invoices_past_due' => 'Invoices Past Due', - 'upcoming_invoices' => 'Upcoming invoices', - 'average_invoice' => 'Average invoice', - - // list pages - 'archive' => 'Archive', - 'delete' => 'Delete', + 'active_clients' => 'active clients', + 'invoices_past_due' => 'Pradelsti mokėjimai', + 'upcoming_invoices' => 'Naujos sąskaitos', + 'average_invoice' => 'Sąskaitų vidurkis', + 'archive' => 'Archyvas', + 'delete' => 'Trinti', 'archive_client' => 'Archive client', - 'delete_client' => 'Delete client', + 'delete_client' => 'Trinti klientą', 'archive_payment' => 'Archive payment', - 'delete_payment' => 'Delete payment', + 'delete_payment' => 'Ištrinti mokėjimą', 'archive_credit' => 'Archive credit', 'delete_credit' => 'Delete credit', - 'show_archived_deleted' => 'Show archived/deleted', - 'filter' => 'Filter', - 'new_client' => 'New Client', - 'new_invoice' => 'New Invoice', - 'new_payment' => 'New Payment', + 'show_archived_deleted' => 'Rodyti ištrintus/suarchyvuotus', + 'filter' => 'Filtras', + 'new_client' => 'Naujas klientas', + 'new_invoice' => 'Nauja sąskaita', + 'new_payment' => 'Naujas mokėjimas', 'new_credit' => 'New Credit', - 'contact' => 'Contact', - 'date_created' => 'Date Created', - 'last_login' => 'Last Login', - 'balance' => 'Balance', - 'action' => 'Action', - 'status' => 'Status', - 'invoice_total' => 'Invoice Total', - 'frequency' => 'Frequency', - 'start_date' => 'Start Date', - 'end_date' => 'End Date', + 'contact' => 'Kontaktai', + 'date_created' => 'Sukūrimo data', + 'last_login' => 'Paskutinis prisijungimas', + 'balance' => 'Balansas', + 'action' => 'Veiksmas', + 'status' => 'Būklė', + 'invoice_total' => 'Suma', + 'frequency' => 'Periodas', + 'start_date' => 'Pradžia', + 'end_date' => 'Pabaiga', 'transaction_reference' => 'Transaction Reference', - 'method' => 'Method', - 'payment_amount' => 'Payment Amount', - 'payment_date' => 'Payment Date', + 'method' => 'Būdas', + 'payment_amount' => 'Mokėjimo suma', + 'payment_date' => 'Mokėjimo data', 'credit_amount' => 'Credit Amount', 'credit_balance' => 'Credit Balance', 'credit_date' => 'Credit Date', - 'empty_table' => 'No data available in table', - 'select' => 'Select', - 'edit_client' => 'Edit Client', - 'edit_invoice' => 'Edit Invoice', - - // client view page - 'create_invoice' => 'Create Invoice', + 'empty_table' => 'Nieko nėra', + 'select' => 'Pasirinkite', + 'edit_client' => 'Redaguoti', + 'edit_invoice' => 'Redaguoti', + 'create_invoice' => 'Sukurti sąskaitą', 'enter_credit' => 'Enter Credit', 'last_logged_in' => 'Last logged in', - 'details' => 'Details', - 'standing' => 'Standing', - 'credit' => 'Credit', - 'activity' => 'Activity', - 'date' => 'Date', - 'message' => 'Message', - 'adjustment' => 'Adjustment', - 'are_you_sure' => 'Are you sure?', - - // payment pages - 'payment_type_id' => 'Payment type', - 'amount' => 'Amount', - - // account/company pages - 'work_email' => 'Email', - 'language_id' => 'Language', + 'details' => 'Informacija', + 'standing' => 'Būklė', + 'credit' => 'Kreditas', + 'activity' => 'Įvykiai', + 'date' => 'Data', + 'message' => 'Žinutė', + 'adjustment' => 'Pritaikymas', + 'are_you_sure' => 'Ar tikrai?', + 'payment_type_id' => 'Mokėjimo tipas', + 'amount' => 'Suma', + 'work_email' => 'El. paštas', + 'language_id' => 'Kalba', 'timezone_id' => 'Timezone', 'date_format_id' => 'Date format', 'datetime_format_id' => 'Date/Time Format', - 'users' => 'Users', + 'users' => 'Klientai', 'localization' => 'Localization', - 'remove_logo' => 'Remove logo', + 'remove_logo' => 'Trinti logotipą', 'logo_help' => 'Supported: JPEG, GIF and PNG', 'payment_gateway' => 'Payment Gateway', 'gateway_id' => 'Provider', @@ -194,24 +175,23 @@ return array( 'email_paid' => 'Email me when an invoice is paid', 'site_updates' => 'Site Updates', 'custom_messages' => 'Custom Messages', - 'default_invoice_terms' => 'Set default invoice terms', 'default_email_footer' => 'Set default email signature', - 'import_clients' => 'Import Client Data', - 'csv_file' => 'Select CSV file', - 'export_clients' => 'Export Client Data', 'select_file' => 'Please select a file', 'first_row_headers' => 'Use first row as headers', 'column' => 'Column', 'sample' => 'Sample', 'import_to' => 'Import to', - 'client_will_create' => 'client will be created', - 'clients_will_create' => 'clients will be created', + 'client_will_create' => 'klientas bus sukurtas', + 'clients_will_create' => 'klientai bus sukurti', 'email_settings' => 'Email Settings', + 'client_view_styling' => 'Kliento aplinkos stilius', 'pdf_email_attachment' => 'Attach PDF to Emails', - - // application messages - 'created_client' => 'Successfully created client', - 'created_clients' => 'Successfully created :count clients', + 'custom_css' => 'Individualizuotas CSS', + 'import_clients' => 'Import Client Data', + 'csv_file' => 'Select CSV file', + 'export_clients' => 'Export Client Data', + 'created_client' => 'Klientas sukurtas', + 'created_clients' => 'Sukurta :count klientų', 'updated_settings' => 'Successfully updated settings', 'removed_logo' => 'Successfully removed logo', 'sent_message' => 'Successfully sent message', @@ -220,105 +200,81 @@ return array( 'payment_error' => 'There was an error processing your payment. Please try again later.', 'registration_required' => 'Please sign up to email an invoice', 'confirmation_required' => 'Please confirm your email address', - 'updated_client' => 'Successfully updated client', - 'created_client' => 'Successfully created client', + 'created_client' => 'Klientas sukurtas', 'archived_client' => 'Successfully archived client', 'archived_clients' => 'Successfully archived :count clients', 'deleted_client' => 'Successfully deleted client', 'deleted_clients' => 'Successfully deleted :count clients', - 'updated_invoice' => 'Successfully updated invoice', 'created_invoice' => 'Successfully created invoice', 'cloned_invoice' => 'Successfully cloned invoice', 'emailed_invoice' => 'Successfully emailed invoice', - 'and_created_client' => 'and created client', + 'and_created_client' => 'ir sukūrė klientas', 'archived_invoice' => 'Successfully archived invoice', 'archived_invoices' => 'Successfully archived :count invoices', 'deleted_invoice' => 'Successfully deleted invoice', 'deleted_invoices' => 'Successfully deleted :count invoices', - 'created_payment' => 'Successfully created payment', + 'created_payments' => 'Sukurti :count mokėjimas', 'archived_payment' => 'Successfully archived payment', 'archived_payments' => 'Successfully archived :count payments', 'deleted_payment' => 'Successfully deleted payment', 'deleted_payments' => 'Successfully deleted :count payments', 'applied_payment' => 'Successfully applied payment', - 'created_credit' => 'Successfully created credit', 'archived_credit' => 'Successfully archived credit', 'archived_credits' => 'Successfully archived :count credits', 'deleted_credit' => 'Successfully deleted credit', 'deleted_credits' => 'Successfully deleted :count credits', - - // Emails - 'confirmation_subject' => 'Invoice Ninja Account Confirmation', - 'confirmation_header' => 'Account Confirmation', - 'confirmation_message' => 'Please access the link below to confirm your account.', - 'invoice_subject' => 'New invoice :invoice from :account', - 'invoice_message' => 'To view your invoice for :amount, click the link below.', - 'payment_subject' => 'Payment Received', - 'payment_message' => 'Thank you for your payment of :amount.', - 'email_salutation' => 'Dear :name,', - 'email_signature' => 'Regards,', - 'email_from' => 'The Invoice Ninja Team', - 'user_email_footer' => 'To adjust your email notification settings please visit '.SITE_URL.'/settings/notifications', + 'imported_file' => 'Failas importuotas', + 'updated_vendor' => 'Atnaujintas tiekėjas', + 'created_vendor' => 'Sukurtas tiekėjas', + 'archived_vendor' => 'Sėkmingai suarchyvuoti tiekėjai', + 'archived_vendors' => 'Sėkmingai suarchyvuoti :count tiekėjai', + 'deleted_vendor' => 'Sėkmingai ištrintas tiekėjas', + 'deleted_vendors' => 'Ištrinta :count tiekėjų', + 'confirmation_subject' => 'Paskyros patvirtinimas', + 'confirmation_header' => 'Paskyros patvirtinimas', + 'confirmation_message' => 'Prašome paspausti nuorodą jei norite patvirtinti paskyrą.', + 'invoice_subject' => 'Nauja sąskaita :invoice nuo :account', + 'invoice_message' => 'Norėdami pamatyti sąskaitą faktūrą :amount sumai, spauskite nuorodą apačioje.', + 'payment_subject' => 'Mokėjimas gautas', + 'payment_message' => 'Dėkojame už Jūsų atliktą mokėjimą :amount.', + 'email_salutation' => 'Sveiki :name,', + 'email_signature' => 'Linkiu geros dienos,', + 'email_from' => 'Naujasdizainas.com', 'invoice_link_message' => 'To view your client invoice click the link below:', - 'notification_invoice_paid_subject' => 'Invoice :invoice was paid by :client', - 'notification_invoice_sent_subject' => 'Invoice :invoice was sent to :client', + 'notification_invoice_paid_subject' => 'Sąskaita :invoice apmokėta :client', + 'notification_invoice_sent_subject' => 'Sąskaita :invoice išsiųsta :client', 'notification_invoice_viewed_subject' => 'Invoice :invoice was viewed by :client', 'notification_invoice_paid' => 'A payment of :amount was made by client :client towards Invoice :invoice.', - '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_sent' => 'Klientui :client išsiųsta sąskaita :invoice sumai :amount.', + 'notification_invoice_viewed' => 'Klientas :client žiūrėjo sąskaitą :invoice for :amount.', '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', 'card_number' => 'Card number', - 'expiration_month' => 'Expiration month', + 'expiration_month' => 'Expiration month', 'expiration_year' => 'Expiration year', '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', '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', 'terms_of_service' => 'Terms of Service', 'email_taken' => 'The email address is already registered', 'working' => 'Working', 'success' => 'Success', 'success_message' => 'You have succesfully registered. Please visit the link in the account confirmation email to verify your email address.', 'erase_data' => 'This will permanently erase your data.', - 'password' => 'Password', - + 'password' => 'Slaptažodis', 'pro_plan_product' => '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!

     
    - Next Steps

    A payable invoice has been sent to the email - address associated with your account. To unlock all of the awesome - Pro features, please follow the instructions on the invoice to pay + Next Steps

    A payable invoice has been sent to the email + address associated with your account. To unlock all of the awesome + Pro features, please follow the instructions on the invoice to pay for a year of Pro-level invoicing.

    - 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', - 'unsaved_changes' => 'You have unsaved changes', 'custom_fields' => 'Custom fields', 'company_fields' => 'Company Fields', @@ -328,8 +284,6 @@ return array( 'edit' => 'Edit', 'set_name' => 'Set your company name', 'view_as_recipient' => 'View as recipient', - - // product management 'product_library' => 'Product Library', 'product' => 'Product', 'products' => 'Products', @@ -342,22 +296,18 @@ return array( 'archive_product' => 'Archive Product', 'updated_product' => 'Successfully updated 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', - 'advanced_settings' => 'Advanced Settings', 'pro_plan_advanced_settings' => ':link to enable the advanced settings by joining the Pro Plan', 'invoice_design' => 'Invoice Design', 'specify_colors' => 'Specify colors', 'specify_colors_label' => 'Select the colors used in the invoice', - 'chart_builder' => 'Chart Builder', 'ninja_email_footer' => 'Use :site to invoice your clients and get paid online for free!', 'go_pro' => 'Go Pro', - - // Quotes - 'quote' => 'Quote', - 'quotes' => 'Quotes', + 'quote' => 'Pasiūlymas', + 'quotes' => 'Pasiūlymai', 'quote_number' => 'Quote Number', 'quote_number_short' => 'Quote #', 'quote_date' => 'Quote Date', @@ -365,20 +315,18 @@ return array( 'your_quote' => 'Your Quote', 'total' => 'Total', 'clone' => 'Clone', - - 'new_quote' => 'New Quote', - 'create_quote' => 'Create Quote', - 'edit_quote' => 'Edit Quote', + 'new_quote' => 'Naujas pasiūlymas', + 'create_quote' => 'Sukurti pasiūlymą', + 'edit_quote' => 'Keisti pasiūlymą', 'archive_quote' => 'Archive Quote', 'delete_quote' => 'Delete Quote', 'save_quote' => 'Save Quote', 'email_quote' => 'Email Quote', 'clone_quote' => 'Clone Quote', 'convert_to_invoice' => 'Convert to Invoice', - 'view_invoice' => 'View Invoice', - 'view_client' => 'View Client', - 'view_quote' => 'View Quote', - + 'view_invoice' => 'Rodyti sąskaitą', + 'view_client' => 'Rodyti klientą', + 'view_quote' => 'Rodyti pasiūlymą', 'updated_quote' => 'Successfully updated quote', 'created_quote' => 'Successfully created quote', 'cloned_quote' => 'Successfully cloned quote', @@ -388,53 +336,44 @@ return array( 'deleted_quote' => 'Successfully deleted quote', 'deleted_quotes' => 'Successfully deleted :count quotes', 'converted_to_invoice' => 'Successfully converted quote to invoice', - - 'quote_subject' => 'New quote from :account', - 'quote_message' => 'To view your quote for :amount, click the link below.', + 'quote_subject' => 'Naujas pasiūlymas nuo :account', + 'quote_message' => 'Norėdami pažiūrėti pasiūlymą :amount sumai, paspauskite nuorodą apačioje.', 'quote_link_message' => 'To view your client quote click the link below:', - 'notification_quote_sent_subject' => 'Quote :invoice was sent to :client', + 'notification_quote_sent_subject' => 'Pasiūlymas :invoice išsiųstas :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_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.', - 'invoice_fields' => 'Invoice Fields', 'invoice_options' => 'Invoice Options', '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_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.', - 'charge_taxes' => 'Charge taxes', 'user_management' => 'User Management', - 'add_user' => 'Add User', + 'add_user' => 'Naujas narys', 'send_invite' => 'Send invitation', 'sent_invite' => 'Successfully sent invitation', 'updated_user' => 'Successfully updated user', 'invitation_message' => 'You\'ve been invited by :invitor. ', 'register_to_add_user' => 'Please sign up to add a user', - 'user_state' => 'State', + 'user_state' => 'Būklė', 'edit_user' => 'Edit User', 'delete_user' => 'Delete User', - 'active' => 'Active', - 'pending' => 'Pending', + 'active' => 'Aktyvus', + 'pending' => 'Laukia patvirtinimo', '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_quote' => 'Are you sure you want to email this quote?', 'confirm_recurring_email_invoice' => 'Are you sure you want this invoice emailed?', - 'cancel_account' => 'Cancel Account', 'cancel_account_message' => 'Warning: This will permanently erase all of your data, there is no undo.', - 'go_back' => 'Go Back', - + 'go_back' => 'Atgal', 'data_visualizations' => 'Data Visualizations', 'sample_data' => 'Sample data shown', - 'hide' => 'Hide', + 'hide' => 'Slėpti', '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_number_prefix' => 'Invoice Number Prefix', 'invoice_number_counter' => 'Invoice Number Counter', @@ -443,65 +382,51 @@ return array( 'share_invoice_counter' => 'Share invoice counter', 'invoice_issued_to' => 'Invoice issued to', '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_2' => ':link to sign up for Authorize.net.', 'gateway_help_17' => ':link to get your PayPal API signature.', 'gateway_help_27' => ':link to sign up for TwoCheckout.', - 'more_designs' => 'More designs', 'more_designs_title' => 'Additional Invoice Designs', 'more_designs_cloud_header' => 'Go Pro for more invoice designs', 'more_designs_cloud_text' => '', - 'more_designs_self_host_header' => 'Get 6 more invoice designs for just $'.INVOICE_DESIGNS_PRICE, 'more_designs_self_host_text' => '', 'buy' => 'Buy', 'bought_designs' => 'Successfully added additional invoice designs', - - - 'sent' => 'sent', - 'timesheets' => 'Timesheets', - + 'vat_number' => 'PVM kodas', + 'timesheets' => 'Laiko juosta', '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_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.', - 'vat_number' => 'Vat Number', - 'id_number' => 'ID Number', - + 'id_number' => 'Įmonės kodas', 'white_label_link' => 'White label', 'white_label_header' => 'White Label', 'bought_white_label' => 'Successfully enabled white label license', 'white_labeled' => 'White labeled', - - 'restore' => 'Restore', + 'restore' => 'Atkurti', 'restore_invoice' => 'Restore Invoice', 'restore_quote' => 'Restore Quote', 'restore_client' => 'Restore Client', 'restore_credit' => 'Restore Credit', 'restore_payment' => 'Restore Payment', - 'restored_invoice' => 'Successfully restored invoice', 'restored_quote' => 'Successfully restored quote', 'restored_client' => 'Successfully restored client', 'restored_payment' => 'Successfully restored payment', 'restored_credit' => 'Successfully restored credit', - 'reason_for_canceling' => 'Help us improve our site by telling us why you\'re leaving.', - 'discount_percent' => 'Percent', - 'discount_amount' => 'Amount', - + 'discount_percent' => 'Procentas', + 'discount_amount' => 'Suma', 'invoice_history' => 'Invoice History', 'quote_history' => 'Quote History', 'current_version' => 'Current version', 'select_version' => 'Select version', 'view_history' => 'View History', - 'edit_payment' => 'Edit Payment', - 'updated_payment' => 'Successfully updated payment', + 'updated_payment' => 'Mokėjimas atnaujintas', 'deleted' => 'Deleted', 'restore_user' => 'Restore User', 'restored_user' => 'Successfully restored user', @@ -512,7 +437,6 @@ return array( 'quote_email' => 'Quote Email', 'reset_all' => 'Reset All', 'approve' => 'Approve', - '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_1' => 'Disabled', @@ -520,12 +444,11 @@ return array( 'token_billing_3' => 'Opt-out - checkbox is shown and selected', 'token_billing_4' => 'Always', 'token_billing_checkbox' => 'Store credit card details', - 'view_in_stripe' => 'View in Stripe', - 'use_card_on_file' => 'Use card on file', + 'view_in_gateway' => 'View in :gateway', + 'use_card_on_file' => 'Use Card on File', 'edit_payment_details' => 'Edit payment 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 :link', 'support' => 'Support', 'contact_information' => 'Contact information', '256_encryption' => '256-Bit Encryption', @@ -535,11 +458,8 @@ return array( 'order_overview' => 'Order overview', '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.', - - 'default_invoice_footer' => 'Set default invoice footer', 'invoice_footer' => 'Invoice footer', 'save_as_default_footer' => 'Save as default footer', - 'token_management' => 'Token Management', 'tokens' => 'Tokens', 'add_token' => 'Add Token', @@ -550,7 +470,6 @@ return array( 'edit_token' => 'Edit Token', 'delete_token' => 'Delete Token', 'token' => 'Token', - 'add_gateway' => 'Add Gateway', 'delete_gateway' => 'Delete Gateway', 'edit_gateway' => 'Edit Gateway', @@ -559,7 +478,6 @@ return array( 'deleted_gateway' => 'Successfully deleted gateway', 'pay_with_paypal' => 'PayPal', 'pay_with_card' => 'Credit card', - 'change_password' => 'Change password', 'current_password' => 'Current password', 'new_password' => 'New password', @@ -567,25 +485,22 @@ return array( 'password_error_incorrect' => 'The current password is incorrect.', 'password_error_invalid' => 'The new password is invalid.', 'updated_password' => 'Successfully updated password', - 'api_tokens' => 'API Tokens', 'users_and_tokens' => 'Users & Tokens', - 'account_login' => 'Account Login', - 'recover_password' => 'Recover your password', - 'forgot_password' => 'Forgot your password?', - 'email_address' => 'Email address', - 'lets_go' => 'Let’s go', - 'password_recovery' => 'Password Recovery', - 'send_email' => 'Send email', - 'set_password' => 'Set Password', + 'account_login' => 'Jungtis', + 'recover_password' => 'Atkurti slaptažodį', + 'forgot_password' => 'Pamiršote slaptažodį?', + 'email_address' => 'El. pašto adresas', + 'lets_go' => 'Pradėkim', + 'password_recovery' => 'Slaptažodžio pirminimas', + 'send_email' => 'Siųsti el. laišką', + 'set_password' => 'Įrašyti slaptažodį', 'converted' => 'Converted', - 'email_approved' => 'Email me when a quote is approved', 'notification_quote_approved_subject' => 'Quote :invoice was approved by :client', 'notification_quote_approved' => 'The following client :client approved Quote :invoice for :amount.', 'resend_confirmation' => 'Resend confirmation email', 'confirmation_resent' => 'The confirmation email was resent', - 'gateway_help_42' => ':link to sign up for BitPay.
    Note: use a Legacy API Key, not an API token.', 'payment_type_credit_card' => 'Credit card', 'payment_type_paypal' => 'PayPal', @@ -593,7 +508,6 @@ return array( 'knowledge_base' => 'Knowledge Base', 'partial' => 'Partial', 'partial_remaining' => ':partial of :balance', - 'more_fields' => 'More Fields', 'less_fields' => 'Less Fields', 'client_name' => 'Client Name', @@ -604,58 +518,56 @@ return array( 'view_documentation' => 'View Documentation', '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.', - 'rows' => 'rows', 'www' => 'www', - 'logo' => 'Logo', + 'logo' => 'Logotipas', 'subdomain' => 'Subdomain', 'provide_name_or_email' => 'Please provide a contact name or email', - 'charts_and_reports' => 'Charts & Reports', - 'chart' => 'Chart', - 'report' => 'Report', - 'group_by' => 'Group by', - 'paid' => 'Paid', - 'enable_report' => 'Report', - 'enable_chart' => 'Chart', - 'totals' => 'Totals', - 'run' => 'Run', + 'charts_and_reports' => 'Diagramos ir ataskaitos', + 'chart' => 'Diagrama', + 'report' => 'Ataskaita', + 'group_by' => 'Grupuoti pagal', + 'paid' => 'Apmokėta', + 'enable_report' => 'Ataskaita', + 'enable_chart' => 'Diagrama', + 'totals' => 'Viso', + 'run' => 'Pradėti', 'export' => 'Export', 'documentation' => 'Documentation', 'zapier' => 'Zapier', - 'recurring' => 'Recurring', - 'last_invoice_sent' => 'Last invoice sent :date', - - 'processed_updates' => 'Successfully completed update', - 'tasks' => 'Tasks', - 'new_task' => 'New Task', - 'start_time' => 'Start Time', - 'created_task' => 'Successfully created task', - 'updated_task' => 'Successfully updated task', - 'edit_task' => 'Edit Task', - 'archive_task' => 'Archive Task', - 'restore_task' => 'Restore Task', - 'delete_task' => 'Delete Task', - 'stop_task' => 'Stop Task', - 'time' => 'Time', - 'start' => 'Start', - 'stop' => 'Stop', - 'now' => 'Now', - 'timer' => 'Timer', - 'manual' => 'Manual', - 'date_and_time' => 'Date & Time', - 'second' => 'second', - 'seconds' => 'seconds', - 'minute' => 'minute', - 'minutes' => 'minutes', - 'hour' => 'hour', - 'hours' => 'hours', + 'recurring' => 'Debetinės', + 'last_invoice_sent' => 'Paskutinė sąskaita išsiųsta :date', + 'processed_updates' => 'Atnaujinta', + 'tasks' => 'Darbai', + 'new_task' => 'Naujas darbas', + 'start_time' => 'Pradžia', + 'created_task' => 'Sukurtas darbas', + 'updated_task' => 'Atnaujintas darbas', + 'edit_task' => 'Keisti', + 'archive_task' => 'Archyvuoti', + 'restore_task' => 'Tęsti', + 'delete_task' => 'Trinti', + 'stop_task' => 'Stabdyti', + 'time' => 'Laikas', + 'start' => 'Pradėti', + 'stop' => 'Stabdyti', + 'now' => 'Dabar', + 'timer' => 'Chronometras', + 'manual' => 'Nurodyti', + 'date_and_time' => 'Data ir laikas', + 'second' => 'sekundė', + 'seconds' => 'sekundės', + 'minute' => 'minutė', + 'minutes' => 'minutės', + 'hour' => 'valanda', + 'hours' => 'Valandos', 'task_details' => 'Task Details', - 'duration' => 'Duration', - 'end_time' => 'End Time', - 'end' => 'End', + 'duration' => 'Trukmė', + 'end_time' => 'Pabaiga', + 'end' => 'Baigti', 'invoiced' => 'Invoiced', 'logged' => 'Logged', - 'running' => 'Running', + 'running' => 'Vykdomas', 'task_error_multiple_clients' => 'The tasks can\'t belong to different clients', 'task_error_running' => 'Please stop running tasks first', 'task_error_invoiced' => 'Tasks have already been invoiced', @@ -664,49 +576,43 @@ return array( 'archived_tasks' => 'Successfully archived :count tasks', 'deleted_task' => 'Successfully deleted task', 'deleted_tasks' => 'Successfully deleted :count tasks', - 'create_task' => 'Create Task', + 'create_task' => 'Sukurti darbą', 'stopped_task' => 'Successfully stopped task', - 'invoice_task' => 'Invoice Task', + 'invoice_task' => 'Išrašyti sąskaitą', 'invoice_labels' => 'Invoice Labels', - 'prefix' => 'Prefix', + 'prefix' => 'Priešdėlis', 'counter' => 'Counter', - 'payment_type_dwolla' => 'Dwolla', 'gateway_help_43' => ':link to sign up for Dwolla.', 'partial_value' => 'Must be greater than zero and less than the total', - 'more_actions' => 'More Actions', - + 'more_actions' => 'Kiti veiksmai', 'pro_plan_title' => 'NINJA PRO', 'pro_plan_call_to_action' => 'Upgrade Now!', 'pro_plan_feature1' => 'Create Unlimited Clients', 'pro_plan_feature2' => 'Access to 10 Beautiful Invoice Designs', 'pro_plan_feature3' => 'Custom URLs - "YourBrand.InvoiceNinja.com"', 'pro_plan_feature4' => 'Remove "Created by Invoice Ninja"', - 'pro_plan_feature5' => 'Multi-user Access & Activity Tracking', + 'pro_plan_feature5' => 'Kelių pirkėjų prieigos ir veiklos stebėjimas', 'pro_plan_feature6' => 'Create Quotes & Pro-forma Invoices', 'pro_plan_feature7' => 'Customize Invoice Field Titles & Numbering', 'pro_plan_feature8' => 'Option to Attach PDFs to Client Emails', - - 'resume' => 'Resume', - 'break_duration' => 'Break', - 'edit_details' => 'Edit Details', - 'work' => 'Work', + 'resume' => 'Tęsti', + 'break_duration' => 'Pertrauka', + 'edit_details' => 'Keisti', + 'work' => 'Darbas', 'timezone_unset' => 'Please :link to set your timezone', - 'click_here' => 'click here', - + 'click_here' => 'spausti čia', 'email_receipt' => 'Email payment receipt to the client', - 'created_payment_emailed_client' => 'Successfully created payment and emailed client', + 'created_payment_emailed_client' => 'Sukurtas mokėjimas ir išsiųstas klientui', 'add_company' => 'Add Company', 'untitled' => 'Untitled', 'new_company' => 'New Company', 'associated_accounts' => 'Successfully linked accounts', 'unlinked_account' => 'Successfully unlinked accounts', 'login' => 'Login', - 'or' => 'or', - + 'or' => 'arba', 'email_error' => 'There was a problem sending the email', 'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.', - 'old_browser' => 'Please use a newer browser', 'payment_terms_help' => 'Sets the default invoice due date', 'unlink_account' => 'Unlink Account', 'unlink' => 'Unlink', @@ -714,86 +620,77 @@ return array( 'show_address_help' => 'Require client to provide their billing address', 'update_address' => 'Update Address', 'update_address_help' => 'Update client\'s address with provided details', - 'times' => 'Times', - 'set_now' => 'Set now', + 'times' => 'Laikas', + 'set_now' => 'Dabar', 'dark_mode' => 'Dark Mode', 'dark_mode_help' => 'Show white text on black background', 'add_to_invoice' => 'Add to invoice :invoice', 'create_new_invoice' => 'Create new invoice', 'task_errors' => 'Please correct any overlapping times', - 'from' => 'From', - 'to' => 'To', + 'from' => 'Nuo', + 'to' => 'Kam', 'font_size' => 'Font Size', 'primary_color' => 'Primary Color', 'secondary_color' => 'Secondary Color', 'customize_design' => 'Customize Design', - - 'content' => 'Content', - 'styles' => 'Styles', - 'defaults' => 'Defaults', - 'margins' => 'Margins', - 'header' => 'Header', - 'footer' => 'Footer', - 'custom' => 'Custom', - 'invoice_to' => 'Invoice to', - 'invoice_no' => 'Invoice No.', - 'recent_payments' => 'Recent Payments', - 'outstanding' => 'Outstanding', - 'manage_companies' => 'Manage Companies', - 'total_revenue' => 'Total Revenue', - - 'current_user' => 'Current User', - 'new_recurring_invoice' => 'New Recurring Invoice', - 'recurring_invoice' => 'Recurring Invoice', + 'content' => 'Turinys', + 'styles' => 'Stiliai', + 'defaults' => 'Numatyti', + 'margins' => 'Tarpai', + 'header' => 'Viršus', + 'footer' => 'Apačia', + 'custom' => 'Kurti', + 'invoice_to' => 'Kam sąskaita', + 'invoice_no' => 'Sąskaitos faktūros Nr.', + 'recent_payments' => 'Naujausi mokėjimai', + 'outstanding' => 'Neapmokėta', + 'manage_companies' => 'Valdyti įmones', + 'total_revenue' => 'Iš viso pajamų', + 'current_user' => 'Dabartinis vartotojas', + 'new_recurring_invoice' => 'Nauja debeto sąskaita', + 'recurring_invoice' => 'Debeto sąskaita', 'recurring_too_soon' => 'It\'s too soon to create the next recurring invoice, it\'s scheduled for :date', - 'created_by_invoice' => 'Created by :invoice', + 'created_by_invoice' => 'Sukurta :invoice', 'primary_user' => 'Primary User', - 'help' => 'Help', + 'help' => 'Pagalba', 'customize_help' => '

    We use pdfmake to define the invoice designs declaratively. The pdfmake playground provide\'s a great way to see the library in action.

    -

    To access a child property using dot notation. For example to show the client name you could use $client.name.

    -

    If you need help figuring something out post a question to our support forum.

    ', - - 'invoice_due_date' => 'Due Date', - 'quote_due_date' => 'Valid Until', - 'valid_until' => 'Valid Until', - 'reset_terms' => 'Reset terms', +

    You can access a child property using dot notation. For example to show the client name you could use $client.name.

    +

    If you need help figuring something out post a question to our support forum with the design you\'re using.

    ', + 'invoice_due_date' => 'Terminas', + 'quote_due_date' => 'Galioja iki', + 'valid_until' => 'Galioja iki', + 'reset_terms' => 'Naujos sąlygos', 'reset_footer' => 'Reset footer', - 'invoices_sent' => ':count invoice sent|:count invoices sent', - 'status_draft' => 'Draft', - 'status_sent' => 'Sent', - 'status_viewed' => 'Viewed', - 'status_partial' => 'Partial', - 'status_paid' => 'Paid', + 'invoices_sent' => ':count sąskaita išsiųsta|:count sąskaitos išsiųstos', + 'status_draft' => 'Juodraštis', + 'status_sent' => 'Išsiųsta', + 'status_viewed' => 'Parodyta', + 'status_partial' => 'Dalinis', + 'status_paid' => 'Apmokėta', 'show_line_item_tax' => 'Display line item taxes inline', - - 'iframe_url' => 'Website', + 'iframe_url' => 'Tinklapis', '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.', - - 'auto_bill' => 'Auto Bill', - 'military_time' => '24 Hour Time', + 'auto_bill' => 'Automatinis mokėjimas', + 'military_time' => '24 val. formatas', 'last_sent' => 'Last Sent', - 'reminder_emails' => 'Reminder Emails', 'templates_and_reminders' => 'Templates & Reminders', - 'subject' => 'Subject', - 'body' => 'Body', + 'subject' => 'Tema', + 'body' => 'Žinutė', 'first_reminder' => 'First Reminder', 'second_reminder' => 'Second Reminder', 'third_reminder' => 'Third Reminder', 'num_days_reminder' => 'Days after due date', 'reminder_subject' => 'Reminder: Invoice :invoice from :account', - 'reset' => 'Reset', + 'reset' => 'Iš naujo', 'invoice_not_found' => 'The requested invoice is not available', - 'referral_program' => 'Referral Program', 'referral_code' => 'Referral Code', 'last_sent_on' => 'Last sent on :date', - 'page_expire' => 'This page will expire soon, :click_here to keep working', 'upcoming_quotes' => 'Upcoming Quotes', 'expired_quotes' => 'Expired Quotes', - 'sign_up_using' => 'Sign up using', 'invalid_credentials' => 'These credentials do not match our records', 'show_all_options' => 'Show all options', @@ -802,17 +699,10 @@ return array( 'disable' => 'Disable', 'invoice_quote_number' => 'Invoice and Quote Numbers', '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_subject' => 'Unable to deliver Invoice :invoice', 'notification_quote_bounced' => 'We were unable to deliver Quote :invoice to :contact.', 'notification_quote_bounced_subject' => 'Unable to deliver Quote :invoice', - 'custom_invoice_link' => 'Custom Invoice Link', 'total_invoiced' => 'Total Invoiced', 'open_balance' => 'Open Balance', @@ -820,14 +710,12 @@ return array( 'basic_settings' => 'Basic Settings', 'pro' => 'Pro', 'gateways' => 'Payment Gateways', - - 'next_send_on' => 'Send Next: :date', + 'next_send_on' => 'Siųsti kitą: :date', 'no_longer_running' => 'This invoice is not scheduled to run', 'general_settings' => 'General Settings', 'customize' => 'Customize', 'oneclick_login_help' => 'Connect an account to login without a password', 'referral_code_help' => 'Earn money by sharing our app online', - 'enable_with_stripe' => 'Enable | Requires Stripe', 'tax_settings' => 'Tax Settings', 'create_tax_rate' => 'Add Tax Rate', @@ -848,18 +736,17 @@ return array( 'invoice_counter' => 'Invoice Counter', 'quote_counter' => 'Quote Counter', 'type' => 'Type', - - 'activity_1' => ':user created client :client', + 'activity_1' => ':user sukūrė klientą :client', 'activity_2' => ':user archived client :client', 'activity_3' => ':user deleted client :client', - 'activity_4' => ':user created invoice :invoice', + 'activity_4' => ':user sukurta sąskaita :invoice', 'activity_5' => ':user updated invoice :invoice', - 'activity_6' => ':user emailed invoice :invoice to :contact', + 'activity_6' => ':user išsiuntė sąskaitą :invoice - :contact', 'activity_7' => ':contact viewed invoice :invoice', 'activity_8' => ':user archived invoice :invoice', 'activity_9' => ':user deleted invoice :invoice', 'activity_10' => ':contact entered payment :payment for :invoice', - 'activity_11' => ':user updated payment :payment', + 'activity_11' => ':user atnaujino mokėjimą :payment', 'activity_12' => ':user archived payment :payment', 'activity_13' => ':user deleted payment :payment', 'activity_14' => ':user entered :credit credit', @@ -878,18 +765,24 @@ return array( 'activity_27' => ':user restored payment :payment', 'activity_28' => ':user restored :credit credit', 'activity_29' => ':contact approved quote :quote', - + 'activity_30' => ':user sukurtas :vendor', + 'activity_31' => ':user sukurtas :vendor', + 'activity_32' => ':user sukurtas :vendor', + 'activity_33' => ':user sukurtas :vendor', + 'activity_34' => ':user sukurta sąskaita :expense', + 'activity_35' => ':user sukurtas :vendor', + 'activity_36' => ':user sukurtas :vendor', + 'activity_37' => ':user sukurtas :vendor', 'payment' => 'Payment', 'system' => 'System', 'signature' => 'Email Signature', 'default_messages' => 'Default Messages', 'quote_terms' => 'Quote Terms', 'default_quote_terms' => 'Default Quote Terms', - 'default_invoice_terms' => 'Default Invoice Terms', - 'default_invoice_footer' => 'Default Invoice Footer', + 'default_invoice_terms' => 'Set default invoice terms', + 'default_invoice_footer' => 'Set default invoice footer', 'quote_footer' => 'Quote Footer', 'free' => 'Free', - 'quote_is_approved' => 'This quote is approved', 'apply_credit' => 'Apply Credit', 'system_settings' => 'System Settings', @@ -907,7 +800,6 @@ return array( 'restored_recurring_invoice' => 'Successfully restored recurring invoice', 'archived' => 'Archived', 'untitled_account' => 'Untitled Company', - 'before' => 'Before', 'after' => 'After', 'reset_terms_help' => 'Reset to the default account terms', @@ -916,7 +808,6 @@ return array( 'user' => 'User', 'country' => 'Country', 'include' => 'Include', - '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_data' => 'Import Data', @@ -927,29 +818,17 @@ return array( 'task_file' => 'Task File', 'no_mapper' => 'No valid mapping for file', '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', 'admin' => 'Admin', 'disabled' => 'Disabled', 'show_archived_users' => 'Show archived users', 'notes' => 'Notes', - 'invoice_will_create' => 'client will be created', + 'invoice_will_create' => 'klientas bus sukurtas', 'invoices_will_create' => 'invoices will be created', 'failed_to_import' => 'The following records failed to import, they either already exist or are missing required fields.', - 'publishable_key' => 'Publishable Key', 'secret_key' => 'Secret Key', 'missing_publishable_key' => 'Set your Stripe publishable key for an improved checkout process', - 'email_design' => 'Email Design', 'due_by' => 'Due by :date', 'enable_email_markup' => 'Enable Markup', @@ -961,7 +840,6 @@ return array( 'plain' => 'Plain', 'light' => 'Light', 'dark' => 'Dark', - '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.', 'invoice_number_help' => 'Specify a prefix or use a custom pattern to dynamically set the invoice number.', @@ -970,57 +848,48 @@ return array( '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_charges_helps' => 'Add a text input to the invoice create/edit page and include the charge in the invoice subtotals.', - 'color_help' => 'Note: the primary color is also used in the client portal and custom email designs.', - - 'token_expired' => 'Validation token was expired. Please try again.', - 'invoice_link' => 'Invoice Link', - 'button_confirmation_message' => 'Click to confirm your email address.', - 'confirm' => 'Confirm', - 'email_preferences' => 'Email Preferences', + 'token_expired' => 'Patvirtinimo raktas negalioja. Prašau, pabandykite dar kartą.', + 'invoice_link' => 'Sąskaitos nuoroda', + 'button_confirmation_message' => 'Spustelėkite norėdami patvirtinti savo el. pašto adresą.', + 'confirm' => 'Patvirtinti', + 'email_preferences' => 'Pranešimų nustatymai', 'created_invoices' => 'Successfully created :count invoice(s)', 'next_invoice_number' => 'The next invoice number is :number.', 'next_quote_number' => 'The next quote number is :number.', - - 'days_before' => 'days before', - 'days_after' => 'days after', + 'days_before' => 'prieš dienas', + 'days_after' => 'po dienų', 'field_due_date' => 'due date', - 'field_invoice_date' => 'invoice date', - 'schedule' => 'Schedule', + 'field_invoice_date' => 'sąskaitos data', + 'schedule' => 'Grafikas', 'email_designs' => 'Email Designs', - 'assigned_when_sent' => 'Assigned when sent', - - 'white_label_custom_css' => ':link for $'.WHITE_LABEL_PRICE.' to enable custom styling and help support our project.', + 'assigned_when_sent' => 'Bus sugeneruota', 'white_label_purchase_link' => 'Purchase a white label license', - - // Expense / vendor - 'expense' => 'Expense', - 'expenses' => 'Expenses', - 'new_expense' => 'Enter Expense', - 'enter_expense' => 'Enter Expense', - 'vendors' => 'Vendors', - 'new_vendor' => 'New Vendor', + 'expense' => 'Išlaidos', + 'expenses' => 'Išlaidos', + 'new_expense' => 'Naujos išlaidos', + 'enter_expense' => 'Įveskite išlaidas', + 'vendors' => 'Tiekėjai', + 'new_vendor' => 'Naujas tiekėjas', 'payment_terms_net' => 'Net', - 'vendor' => 'Vendor', - 'edit_vendor' => 'Edit Vendor', - 'archive_vendor' => 'Archive Vendor', - 'delete_vendor' => 'Delete Vendor', - 'view_vendor' => 'View Vendor', + 'vendor' => 'Tiekėjas', + 'edit_vendor' => 'Keisti', + 'archive_vendor' => 'Archyvuoti', + 'delete_vendor' => 'Trinti', + 'view_vendor' => 'Rodyti', 'deleted_expense' => 'Successfully deleted expense', 'archived_expense' => 'Successfully archived expense', 'deleted_expenses' => 'Successfully deleted expenses', 'archived_expenses' => 'Successfully archived expenses', - - // Expenses 'expense_amount' => 'Expense Amount', 'expense_balance' => 'Expense Balance', 'expense_date' => 'Expense Date', 'expense_should_be_invoiced' => 'Should this expense be invoiced?', - 'public_notes' => 'Public Notes', - 'invoice_amount' => 'Invoice Amount', - 'exchange_rate' => 'Exchange Rate', - 'yes' => 'Yes', - 'no' => 'No', - 'should_be_invoiced' => 'Should be invoiced', + 'public_notes' => 'Viešos pastabos', + 'invoice_amount' => 'Sąskaitos suma', + 'exchange_rate' => 'Valiutos kursas', + 'yes' => 'Taip', + 'no' => 'Ne', + 'should_be_invoiced' => 'Būtina sąskaita faktūra', 'view_expense' => 'View expense # :expense', 'edit_expense' => 'Edit Expense', 'archive_expense' => 'Archive Expense', @@ -1028,22 +897,18 @@ return array( 'view_expense_num' => 'Expense # :expense', 'updated_expense' => 'Successfully updated expense', 'created_expense' => 'Successfully created expense', - 'enter_expense' => 'Enter Expense', + 'enter_expense' => 'Įveskite išlaidas', 'view' => 'View', 'restore_expense' => 'Restore Expense', 'invoice_expense' => 'Invoice Expense', - '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', - 'convert_currency' => 'Convert currency', - - // Payment terms - 'num_days' => 'Number of days', + 'convert_currency' => 'Konvertuoti valiutą', + 'num_days' => 'Dienų skaičius', 'create_payment_term' => 'Create Payment Term', 'edit_payment_terms' => 'Edit Payment Term', 'edit_payment_term' => 'Edit Payment Term', 'archive_payment_term' => 'Archive Payment Term', - - // recurring due dates 'recurring_due_dates' => 'Recurring Invoice Due Dates', 'recurring_due_date_help' => '

    Automatically sets a due date for the invoice.

    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.

    @@ -1059,27 +924,23 @@ return array( ', 'due' => 'Due', - 'next_due_on' => 'Due Next: :date', - 'use_client_terms' => 'Use client terms', + 'next_due_on' => 'Sekantis mokėjimas: :date', + 'use_client_terms' => 'Naudokite klientui terminus', 'day_of_month' => ':ordinal day of month', - 'last_day_of_month' => 'Last day of month', - 'day_of_week_after' => ':ordinal :day after', - 'sunday' => 'Sunday', - 'monday' => 'Monday', - 'tuesday' => 'Tuesday', - 'wednesday' => 'Wednesday', - 'thursday' => 'Thursday', - 'friday' => 'Friday', - 'saturday' => 'Saturday', - - // Fonts + 'last_day_of_month' => 'Paskutinė mėnesio diena', + 'day_of_week_after' => ':ordinal po :day', + 'sunday' => 'Sekmadienis', + 'monday' => 'Pirmadienis', + 'tuesday' => 'Antradienis', + 'wednesday' => 'Trečiadienis', + 'thursday' => 'Ketvirtadienis', + 'friday' => 'Penktadienis', + 'saturday' => 'Šeštadienis', 'header_font_id' => 'Header 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.', - 'live_preview' => 'Live Preview', '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.', 'quote_message_button' => 'To view your quote for :amount, click the button below.', 'payment_message_button' => 'Thank you for your payment of :amount.', @@ -1096,7 +957,6 @@ return array( 'archived_bank_account' => 'Successfully archived bank account', 'created_bank_account' => 'Successfully created 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 400+ US banks.', '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.', 'username' => 'Username', @@ -1110,7 +970,6 @@ return array( 'validate' => 'Validate', 'info' => 'Info', '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.', '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.', @@ -1121,17 +980,38 @@ return array( 'last_page' => 'last page', 'all_pages_header' => 'Show header on', 'all_pages_footer' => 'Show footer on', - 'invoice_currency' => 'Invoice Currency', + 'invoice_currency' => 'Sąskaitos valiuta', 'enable_https' => 'We strongly recommend using HTTPS to accept credit card details online.', 'quote_issued_to' => 'Quote issued to', - 'show_currency_code' => 'Currency Code', + 'show_currency_code' => 'Valiutos kodas', 'trial_message' => 'Your account will receive a free two week trial of our pro plan.', 'trial_footer' => 'Your free trial lasts :count more days, :link to upgrade now.', 'trial_footer_last_day' => 'This is the last day of your free trial, :link to upgrade now.', 'trial_call_to_action' => 'Start Free Trial', '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.', + + + 'white_label_text' => 'Purchase a ONE YEAR white label license for $: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 :link', + 'reset_password_footer' => 'If you did not request this password reset please email our support: :email', + 'limit_users' => 'Sorry, this will exceed the limit of :limit users', + 'more_designs_self_host_header' => 'Get 6 more invoice designs for just $:price', + 'old_browser' => 'Please use a newer browser', + 'white_label_custom_css' => ':link for $: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 400+ US banks.', + + 'pro_plan_remove_logo' => ':link to remove the Invoice Ninja logo by joining the Pro Plan', + 'pro_plan_remove_logo_link' => 'Click here', + 'invitation_status_sent' => 'Email Sent', + 'invitation_status_opened' => 'Email Openend', + 'invitation_status_viewed' => 'Invoice Viewed', + 'email_error_inactive_client' => 'Emails can not be sent to inactive clients', + 'email_error_inactive_contact' => 'Emails can not be sent to inactive contacts', + 'email_error_inactive_invoice' => 'Neaktyvioms sąskaitoms faktūroms el. pašto siųsti negalima', + 'email_error_user_unregistered' => 'Please register your account to send emails', + 'email_error_user_unconfirmed' => 'Please confirm your account to send emails', + 'email_error_invalid_contact_email' => 'Invalid contact email', 'navigation' => 'Navigation', 'list_invoices' => 'List Invoices', @@ -1154,32 +1034,30 @@ return array( 'custom_invoice_item_fields_help' => 'Add a field when creating an invoice item and display the label and value on the PDF.', 'recurring_invoice_number' => 'Recurring Invoice Number', 'recurring_invoice_number_prefix_help' => 'Speciy a prefix to be added to the invoice number for recurring invoices. The default value is \'R\'.', - 'enable_client_portal' => 'Dashboard', - 'enable_client_portal_help' => 'Show/hide the dashboard page in the client portal.', // Client Passwords 'enable_portal_password'=>'Password protect invoices', 'enable_portal_password_help'=>'Allows you to set a password for each contact. If a password is set, the contact will be required to enter a password before viewing invoices.', 'send_portal_password'=>'Generate password automatically', 'send_portal_password_help'=>'If no password is set, one will be generated and sent with the first invoice.', - + 'expired' => 'Expired', 'invalid_card_number' => 'The credit card number is not valid.', 'invalid_expiry' => 'The expiration date is not valid.', 'invalid_cvv' => 'The CVV is not valid.', 'cost' => 'Cost', 'create_invoice_for_sample' => 'Note: create your first invoice to see a preview here.', - + // User Permissions - 'owner' => 'Owner', - 'administrator' => 'Administrator', + 'owner' => 'Valdytojas', + 'administrator' => 'Administratorius', 'administrator_help' => 'Allow user to manage users, change settings and modify all records', 'user_create_all' => 'Create clients, invoices, etc.', 'user_view_all' => 'View all clients, invoices, etc.', 'user_edit_all' => 'Edit all clients, invoices, etc.', 'gateway_help_20' => ':link to sign up for Sage Pay.', 'gateway_help_21' => ':link to sign up for Sage Pay.', - 'partial_due' => 'Partial Due', + 'partial_due' => 'Dalinis', 'restore_vendor' => 'Restore Vendor', 'restored_vendor' => 'Successfully restored vendor', 'restored_expense' => 'Successfully restored expense', @@ -1187,57 +1065,55 @@ return array( 'create_all_help' => 'Allow user to create and modify records', 'view_all_help' => 'Allow user to view records they didn\'t create', 'edit_all_help' => 'Allow user to modify records they didn\'t create', - 'view_payment' => 'View Payment', - - 'january' => 'January', - 'february' => 'February', - 'march' => 'March', - 'april' => 'April', - 'may' => 'May', - 'june' => 'June', - 'july' => 'July', - 'august' => 'August', - 'september' => 'September', - 'october' => 'October', - 'november' => 'November', - 'december' => 'December', + 'view_payment' => 'View Payment', + + 'january' => 'Sausis', + 'february' => 'Vasaris', + 'march' => 'Kovas', + 'april' => 'Balandis', + 'may' => 'Gegužė', + 'june' => 'Birželis', + 'july' => 'Liepa', + 'august' => 'Rugpjūtis', + 'september' => 'Rugsėjis', + 'october' => 'Spalis', + 'november' => 'Lapkritis', + 'december' => 'Gruodis', // Documents - 'documents_header' => 'Documents:', - 'email_documents_header' => 'Documents:', + 'documents_header' => 'Dokumentai:', + 'email_documents_header' => 'Dokumentai:', 'email_documents_example_1' => 'Widgets Receipt.pdf', 'email_documents_example_2' => 'Final Deliverable.zip', - 'invoice_documents' => 'Documents', - 'expense_documents' => 'Attached Documents', - 'invoice_embed_documents' => 'Embed Documents', + 'invoice_documents' => 'Dokumentai', + 'expense_documents' => 'Pridėti dokumentą', + 'invoice_embed_documents' => 'Įkelti dokumentai', 'invoice_embed_documents_help' => 'Include attached images in the invoice.', 'document_email_attachment' => 'Attach Documents', 'download_documents' => 'Download Documents (:size)', - 'documents_from_expenses' => 'From Expenses:', - 'dropzone' => array(// See http://www.dropzonejs.com/#config-dictDefaultMessage - 'DefaultMessage' => 'Drop files or click to upload', - 'FallbackMessage' => 'Your browser does not support drag\'n\'drop file uploads.', - 'FallbackText' => 'Please use the fallback form below to upload your files like in the olden days.', - 'FileTooBig' => 'File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.', - 'InvalidFileType' => 'You can\'t upload files of this type.', - 'ResponseError' => 'Server responded with {{statusCode}} code.', - 'CancelUpload' => 'Cancel upload', - 'CancelUploadConfirmation' => 'Are you sure you want to cancel this upload?', - 'RemoveFile' => 'Remove file', - ), - 'documents' => 'Documents', - 'document_date' => 'Document Date', - 'document_size' => 'Size', + 'documents_from_expenses' => 'Iš išlaidų:', + 'dropzone_default_message' => 'Įkelkite dokumentus arba spustelėkite, kad įkelti', + 'dropzone_fallback_message' => 'Your browser does not support drag\'n\'drop file uploads.', + 'dropzone_fallback_text' => 'Please use the fallback form below to upload your files like in the olden days.', + 'dropzone_file_too_big' => 'File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.', + 'dropzone_invalid_file_type' => 'You can\'t upload files of this type.', + 'dropzone_response_error' => 'Server responded with {{statusCode}} code.', + 'dropzone_cancel_upload' => 'Atšaukti', + 'dropzone_cancel_upload_confirmation' => 'Are you sure you want to cancel this upload?', + 'dropzone_remove_file' => 'Trinti dokumentus', + 'documents' => 'Dokumentai', + 'document_date' => 'Dokumentų data', + 'document_size' => 'Dydis', - 'enable_client_portal' => 'Client Portal', - 'enable_client_portal_help' => 'Show/hide the client portal.', + 'enable_client_portal' => 'Dashboard', + 'enable_client_portal_help' => 'Show/hide the dashboard page in the client portal.', 'enable_client_portal_dashboard' => 'Dashboard', 'enable_client_portal_dashboard_help' => 'Show/hide the dashboard page in the client portal.', - + // Plans 'account_management' => 'Account Management', 'plan_status' => 'Plan Status', - + 'plan_upgrade' => 'Upgrade', 'plan_change' => 'Change Plan', 'pending_change_to' => 'Changes To', @@ -1267,9 +1143,9 @@ return array( 'plan_paid' => 'Term Started', 'plan_started' => 'Plan Started', 'plan_expires' => 'Plan Expires', - + 'white_label_button' => 'White Label', - + 'pro_plan_year_description' => 'One year enrollment in the Invoice Ninja Pro Plan.', 'pro_plan_month_description' => 'One month enrollment in the Invoice Ninja Pro Plan.', 'enterprise_plan_product' => 'Enterprise Plan', @@ -1287,7 +1163,207 @@ return array( 'preview' => 'Preview', 'list_vendors' => 'List Vendors', 'add_users_not_supported' => 'Upgrade to the Enterprise plan to add additional users to your account.', - 'enterprise_plan_features' => 'The Enterprise plan adds support for multiple users and file attachments.', + 'enterprise_plan_features' => 'The Enterprise plan adds support for multiple users and file attachments, :link to see the full list of features.', 'return_to_app' => 'Return to app', - -); \ No newline at end of file + + + // Payment updates + 'refund_payment' => 'Grąžinti', + 'refund_max' => 'Maks.:', + 'refund' => 'Pinigų grąžinimas', + 'are_you_sure_refund' => 'Grąžinti pinigus pasirinktam mokėjimui?', + 'status_pending' => 'Laukia', + 'status_completed' => 'Apmokėta', + 'status_failed' => 'Nepavyko', + 'status_partially_refunded' => 'Dalinis grąžinimas', + 'status_partially_refunded_amount' => ':amount grąžinta', + 'status_refunded' => 'Grąžinta', + 'status_voided' => 'Atšaukta', + 'refunded_payment' => 'Grąžinti mokėjimai', + 'activity_39' => ':user atšaukė a :payment_amount payment (:payment)', + 'activity_40' => ':user grąžino :adjustment - :payment_amount payment (:payment)', + 'card_expiration' => 'Exp: :expires', + + 'card_creditcardother' => 'Nežininomas', + 'card_americanexpress' => 'American Express', + 'card_carteblanche' => 'Carte Blanche', + 'card_unionpay' => 'UnionPay', + 'card_diners' => 'Diners Club', + 'card_discover' => 'Discover', + 'card_jcb' => 'JCB', + 'card_laser' => 'Laser', + 'card_maestro' => 'Maestro', + 'card_mastercard' => 'MasterCard', + 'card_solo' => 'Solo', + 'card_switch' => 'Switch', + 'card_visacard' => 'Visa', + 'card_ach' => 'ACH', + + 'payment_type_stripe' => 'Stripe', + 'ach' => 'ACH', + 'enable_ach' => 'Įjungti ACH', + 'stripe_ach_help' => 'ACH palaikymas taip pat turi būti įjungtas Stripe.', + 'ach_disabled' => 'Another gateway is already configured for direct debit.', + + 'plaid' => 'Plaid', + 'client_id' => 'Kliento Id', + 'secret' => 'Slaptas žodis', + 'public_key' => 'Viešas raktas', + 'plaid_optional' => '(nebūtina)', + 'plaid_environment_help' => 'When a Stripe test key is given, Plaid\'s development environement (tartan) will be used.', + 'other_providers' => 'Kiti tiekėjai', + 'country_not_supported' => 'Šiai šaliai negalima.', + 'invalid_routing_number' => 'Neteisingas identifikacijos kodas.', + 'invalid_account_number' => 'Paskyros numeris neteisingas.', + 'account_number_mismatch' => 'Ne atitinka paskyros numeris.', + 'missing_account_holder_type' => 'Prašome pasirinkti privačią arba įmonės sąskaitą.', + 'missing_account_holder_name' => 'Prašome įrašyti paskyros valdytojo vardą.', + 'routing_number' => 'Identifikacijos kodas ', + 'confirm_account_number' => 'Patvirtinkite sąskaitos numerį', + 'individual_account' => 'Asmens paskyra', + 'company_account' => 'Įmonės paskyra', + 'account_holder_name' => 'Paskyros savininko vardas', + 'add_account' => 'Nauja paskyra', + 'payment_methods' => 'Mokėjimo būdai', + 'complete_verification' => 'Užbaigti patikrą', + 'verification_amount1' => 'Suma 1', + 'verification_amount2' => 'Suma 2', + 'payment_method_verified' => 'Patikrinimas pavyko', + 'verification_failed' => 'Patikrinimas nepavyko', + 'remove_payment_method' => 'Pašalinti mokėjimo būdą', + 'confirm_remove_payment_method' => 'Ar tikrai trinti šį mokėjimo būdą?', + 'remove' => 'Trinti', + 'payment_method_removed' => 'Pašalinti mokėjimo būdai.', + 'bank_account_verification_help' => 'Mes padarėme du indėlius į Jūsų sąskaitą su aprašymu "VERIFICATION". Šie indėliai bus 1-2 darbo dienas rodomi ataskaitoje. Prašome įrašyti žemiau esančias sumas.', + 'bank_account_verification_next_steps' => 'We have made two deposits into your account with the description "VERIFICATION". These deposits will take 1-2 business days to appear on your statement. + Once you have the amounts, come back to this payment methods page and click "Complete Verification" next to the account.', + 'unknown_bank' => 'Nežinomas bankas', + 'ach_verification_delay_help' => 'Galėsite naudotis sąskaita po patikrinimo. Patikrinimas paprastai trunka 1-2 darbo dienas.', + 'add_credit_card' => 'Nauja kreditinė kortelė', + 'payment_method_added' => 'Naujas mokėjimo būdas.', + 'use_for_auto_bill' => 'Naudoti debetiniam mokėjimui', + 'used_for_auto_bill' => 'Debetinis mokėjimo būdas', + 'payment_method_set_as_default' => 'Nustatykite debetini mokėjimo būdą.', + 'activity_41' => ':payment_amount mokėjimas (:payment) nepavyko', + 'webhook_url' => 'Webhook URL', + 'stripe_webhook_help' => 'Jus privalote :link.', + 'stripe_webhook_help_link_text' => 'nurodyti ši URL Stripe', + 'payment_method_error' => 'Įvyko klaida pridedant mokėjimo būdą. Pabandykite dar kartą vėliau.', + 'notification_invoice_payment_failed_subject' => 'Mokėjimas nepavyko sąskaitai faktūrai :invoice', + 'notification_invoice_payment_failed' => 'Kliento :client atliktas mokėjimas pagal į sąskaitą faktūrą :invoice napavyko. Mokėjimas pažymėtas kaip nepavykęs ir suma :amount įkeltas į kliento balansą.', + 'link_with_plaid' => 'Priskirti sąskaitą su Plaid', + 'link_manually' => 'Nuoroda rankiniu būdu', + 'secured_by_plaid' => 'Apsaugota su Plaid', + 'plaid_linked_status' => 'Jūsų banko sąskaitą :bank', + 'add_payment_method' => 'Naujas mokėjimo būdas', + 'account_holder_type' => 'Sąskaitos savininko tipas', + 'ach_authorization' => 'I authorize :company to use my bank account for future payments and, if necessary, electronically credit my account to correct erroneous debits. I understand that I may cancel this authorization at any time by removing the payment method or by contacting :email.', + 'ach_authorization_required' => 'Turite sutikti su ACH sandoriais.', + 'off' => 'Išj.', + 'opt_in' => 'Įtraukti', + 'opt_out' => 'Pašalinti', + 'always' => 'Visada', + 'opted_out' => 'Pašalinta', + 'opted_in' => 'Įtraukta', + 'manage_auto_bill' => 'Valdyti periodinius mokėjimus', + 'enabled' => 'Įjungti', + 'paypal' => 'Paypal', + 'braintree_enable_paypal' => 'Įjungti PayPal mokėjimą su BrainTree', + 'braintree_paypal_disabled_help' => 'PayPal jungtis apdoroja PayPal mokėjimus', + 'braintree_paypal_help' => 'Jūs taip pat privalote :link.', + 'braintree_paypal_help_link_text' => 'susieti PayPal su Braintree sąskaita', + 'token_billing_braintree_paypal' => 'Išsaugoti mokėjimo duomenis', + 'add_paypal_account' => 'Nauja Paypal sąskaita', + + + 'no_payment_method_specified' => 'Nėra nurodyta mokėjimo būdo', + 'chart_type' => 'Diagramos tipas', + 'format' => 'Formatas', + 'import_ofx' => 'Importuoti OFX', + 'ofx_file' => 'OFX byla', + 'ofx_parse_failed' => 'Nepavyko nuskaityti OFX bylos', + + // WePay + 'wepay' => 'WePay', + 'sign_up_with_wepay' => 'Užsiregistruoti su WePay', + 'use_another_provider' => 'Pasirinkti kitą tiekėją', + 'company_name' => 'Įmonės pavadinimas', + 'wepay_company_name_help' => 'Tai pasirodys kliento kreditinės kortelės ataskaitose.', + 'wepay_description_help' => 'Šios sąskaitos tikslas.', + 'wepay_tos_agree' => 'Sutinku :link.', + 'wepay_tos_link_text' => 'WePay paslaugų teikimo sąlygos', + 'resend_confirmation_email' => 'Persiųsti patvirtinimo laišką', + 'manage_wepay_account' => 'Valdyti WePay paskyrą', + 'action_required' => 'Reikalingas veiksmas', + 'finish_setup' => 'Baigti nustatymus', + 'created_wepay_confirmation_required' => 'Prašome patikrinti savo el. paštą ir patvirtinkite el. pašto adresą WePay.', + 'switch_to_wepay' => 'Persijungti į WePay', + 'switch' => 'Perjungti', + 'restore_account_gateway' => 'Atkurti mokėjimo sąsają', + 'restored_account_gateway' => 'Sėkmingai atkurta sąsaja', + 'united_states' => 'JAV', + 'canada' => 'Kanada', + 'accept_debit_cards' => 'Leisti debetines korteles', + 'debit_cards' => 'Debetinė kortelė', + + 'warn_start_date_changed' => 'The next invoice will be sent on the new start date.', + 'original_start_date' => 'Original start date', + 'new_start_date' => 'New start date', + 'security' => 'Security', + 'see_whats_new' => 'See what\'s new in v:version', + 'wait_for_upload' => 'Please wait for the document upload to complete.', + 'upgrade_for_permissions' => 'Upgrade to our Enterprise plan to enable permissions.', + 'enable_second_tax_rate' => 'Enable specifying a second tax rate', + 'payment_file' => 'Payment File', + 'expense_file' => 'Expense File', + 'product_file' => 'Product File', + 'import_products' => 'Import Products', + 'products_will_create' => 'products will be created.', + 'product_key' => 'Product', + 'created_products' => 'Successfully created :count product(s)', + 'export_help' => 'Use JSON if you plan to import the data into Invoice Ninja.', + 'JSON_file' => 'JSON File', + + 'view_dashboard' => 'View Dashboard', + 'client_session_expired' => 'Session Expired', + 'client_session_expired_message' => 'Your session has expired. Please click the link in your email again.', + + 'auto_bill_notification' => 'This invoice will automatically be billed to your :payment_method on file on :due_date.', + 'auto_bill_payment_method_bank_transfer' => 'bank account', + 'auto_bill_payment_method_credit_card' => 'credit card', + 'auto_bill_payment_method_paypal' => 'PayPal account', + 'auto_bill_notification_placeholder' => 'This invoice will automatically be billed to your credit card on file on the due date.', + 'payment_settings' => 'Payment Settings', + + 'on_send_date' => 'On send date', + 'on_due_date' => 'On due date', + 'auto_bill_ach_date_help' => 'ACH auto bill will always happen on the due date', + 'warn_change_auto_bill' => 'Due to NACHA rules, changes to this invoice may prevent ACH auto bill.', + + 'bank_account' => 'Bank Account', + 'payment_processed_through_wepay' => 'ACH payments will be processed using WePay.', + 'wepay_payment_tos_agree' => 'I agree to the WePay :terms and :privacy_policy.', + 'privacy_policy' => 'Privacy Policy', + 'wepay_payment_tos_agree_required' => 'You must agree to the WePay Terms of Service and Privacy Policy.', + 'payment_settings_supported_gateways' => 'These options are supported by the WePay, Stripe, and Braintree gateways.', + 'ach_email_prompt' => 'Please enter your email address:', + 'verification_pending' => 'Verification Pending', + + 'update_font_cache' => 'Please force refresh the page to update the font cache.', + 'more_options' => 'More options', + 'credit_card' => 'Credit Card', + 'bank_transfer' => 'Bank Transfer', + 'no_transaction_reference' => 'We did not recieve a payment transaction reference from the gateway.', + 'use_bank_on_file' => 'Use Bank on File', + 'auto_bill_email_message' => 'This invoice will automatically be billed to the payment method on file on the due date.', + 'bitcoin' => 'Bitcoin', + 'added_on' => 'Added :date', + 'failed_remove_payment_method' => 'Failed to remove the payment method', + 'gateway_exists' => 'This gateway already exists', + 'manual_entry' => 'Manual entry', + +); + +return $LANG; + +?> diff --git a/resources/lang/nb_NO/texts.php b/resources/lang/nb_NO/texts.php index a06e7c60d6..ce0e88a226 100644 --- a/resources/lang/nb_NO/texts.php +++ b/resources/lang/nb_NO/texts.php @@ -1,8 +1,6 @@ - 'Organisasjon', 'name' => 'Navn', 'website' => 'Nettside', @@ -25,8 +23,6 @@ return array( 'size_id' => 'Størrelse', 'industry_id' => 'Sektor', 'private_notes' => 'Private notater', - - // invoice 'invoice' => 'Faktura', 'client' => 'Klient', 'invoice_date' => 'Faktureringsdato', @@ -50,7 +46,6 @@ return array( 'invoice_design_id' => 'Design', 'terms' => 'Vilkår', 'your_invoice' => 'Din faktura', - 'remove_contact' => 'Fjern kontakt', 'add_contact' => 'Legg til kontakt', 'create_new_client' => 'Opprett ny klient', @@ -74,8 +69,6 @@ return array( 'settings' => 'Innstillinger', 'enable_invoice_tax' => 'Aktiver for å spesifisere en faktura skatt', 'enable_line_item_tax' => 'Aktiver for å spesifisere artikkel skatt', - - // navigation 'dashboard' => 'Skrivebord', 'clients' => 'Klienter', 'invoices' => 'Fakturaer', @@ -100,8 +93,6 @@ return array( 'provide_email' => 'Vennligst oppgi en gyldig e-postadresse', 'powered_by' => 'Drevet av', 'no_items' => 'Ingen elementer', - - // recurring invoices 'recurring_invoices' => 'Gjentakende Fakturaer', 'recurring_help' => '

    Automatisk send klienter de samme fakturaene ukentlig, bi-månedlig, månedlig, kvartalsvis eller årlig.

    Bruk :MONTH, :QUARTER eller :YEAR for dynamiske datoer. Grunnleggende matematikk fungerer også, for eksempel :MONTH-1.

    @@ -111,18 +102,14 @@ return array(
  • ":YEAR+1 årlig abonnement" => "2015 årlig abonnement"
  • "Forhåndsbetaling for :QUARTER+1" => "Forhåndsbetaling for Q2"
  • ', - - // dashboard 'in_total_revenue' => 'totale inntekter', 'billed_client' => 'fakturert klient', 'billed_clients' => 'fakturerte klienter', 'active_client' => 'aktiv klient', - 'active_clients' => 'aktive klienter', + 'active_clients' => 'aktive klienter', 'invoices_past_due' => 'Forfalte Fakturaer', 'upcoming_invoices' => 'Forestående Fakturaer', 'average_invoice' => 'Gjennomsnittlige Fakturaer', - - // list pages 'archive' => 'Arkiv', 'delete' => 'Slett', 'archive_client' => 'Arkiver klient', @@ -158,8 +145,6 @@ return array( 'select' => 'Velg', 'edit_client' => 'Rediger Klient', 'edit_invoice' => 'Rediger Faktura', - - // client view page 'create_invoice' => 'Lag Faktura', 'enter_credit' => 'Oppgi Kreditt', 'last_logged_in' => 'Sist pålogget', @@ -171,12 +156,8 @@ return array( 'message' => 'Beskjed', 'adjustment' => 'Justering', 'are_you_sure' => 'Er du sikker?', - - // payment pages 'payment_type_id' => 'Betalingsmetode', 'amount' => 'Beløp', - - // account/company pages 'work_email' => 'E-post', 'language_id' => 'Språk', 'timezone_id' => 'Tidssone', @@ -195,9 +176,6 @@ return array( 'site_updates' => 'Side Oppdateringer', 'custom_messages' => 'Tilpassede Meldinger', 'default_email_footer' => 'Sett standard e-post signatur', - 'import_clients' => 'Importer Klientdata', - 'csv_file' => 'Velg CSV-fil', - 'export_clients' => 'Eksporter Klientdata', 'select_file' => 'Vennligst velg en fil', 'first_row_headers' => 'Bruk første rad som overskrifter', 'column' => 'Kolonne', @@ -206,9 +184,12 @@ return array( 'client_will_create' => 'klient vil bli opprettet', 'clients_will_create' => 'klienter vil bli opprettet', 'email_settings' => 'E-post Innstillinger', + 'client_view_styling' => 'Client View Styling', 'pdf_email_attachment' => 'Legg ved PDF', - - // application messages + 'custom_css' => 'Custom CSS', + 'import_clients' => 'Importer Klientdata', + 'csv_file' => 'Velg CSV-fil', + 'export_clients' => 'Eksporter Klientdata', 'created_client' => 'Klient opprettet suksessfullt', 'created_clients' => 'Klienter opprettet suksessfullt', 'updated_settings' => 'Innstillinger oppdatert', @@ -219,14 +200,12 @@ return array( 'payment_error' => 'Det oppstod en feil under din betaling. Vennligst prøv igjen senere.', 'registration_required' => 'Vennligst registrer deg for å sende e-postfaktura', 'confirmation_required' => 'Vennligst bekreft din e-postadresse', - 'updated_client' => 'Klient oppdatert', - 'created_client' => 'Klient lagret', + 'created_client' => 'Klient opprettet suksessfullt', 'archived_client' => 'Klient arkivert', 'archived_clients' => 'Arkiverte :count klienter', 'deleted_client' => 'Klient slettet', 'deleted_clients' => 'Slettet :count klienter', - 'updated_invoice' => 'Faktura oppdatert', 'created_invoice' => 'Faktura opprettet', 'cloned_invoice' => 'Faktura kopiert', @@ -236,21 +215,25 @@ return array( 'archived_invoices' => 'Fakturaer arkivert', 'deleted_invoice' => 'Faktura slettet', 'deleted_invoices' => 'Slettet :count fakturaer', - 'created_payment' => 'Betaling opprettet', + 'created_payments' => 'Successfully created :count payment(s)', 'archived_payment' => 'Betaling arkivert', 'archived_payments' => 'Arkiverte :count betalinger', 'deleted_payment' => 'Betaling slettet', 'deleted_payments' => 'Slettet :count betalinger', 'applied_payment' => 'Betaling lagret', - 'created_credit' => 'Kreditt opprettet', 'archived_credit' => 'Kreditt arkivert', 'archived_credits' => 'Arkiverte :count kreditter', 'deleted_credit' => 'Kreditt slettet', 'deleted_credits' => 'Slettet :count kreditter', - - // Emails + 'imported_file' => 'Successfully imported file', + 'updated_vendor' => 'Successfully updated vendor', + 'created_vendor' => 'Successfully created vendor', + 'archived_vendor' => 'Successfully archived vendor', + 'archived_vendors' => 'Successfully archived :count vendors', + 'deleted_vendor' => 'Successfully deleted vendor', + 'deleted_vendors' => 'Successfully deleted :count vendors', 'confirmation_subject' => 'Invoice Ninja Kontobekreftelse', 'confirmation_header' => 'Kontobekreftelse', 'confirmation_message' => 'Vennligst åpne lenken nedenfor for å bekrefte kontoen din.', @@ -261,45 +244,22 @@ return array( 'email_salutation' => 'Kjære :name,', 'email_signature' => 'Med vennlig hilsen,', 'email_from' => 'Invoice Ninja Gjengen', - 'user_email_footer' => 'For å justere varslingsinnstillingene vennligst besøk '.SITE_URL.'/settings/notifications', 'invoice_link_message' => 'Hvis du vil se din klientfaktura klikk på lenken under:', 'notification_invoice_paid_subject' => 'Faktura :invoice betalt av :client', 'notification_invoice_sent_subject' => 'Faktura :invoice sendt til :client', 'notification_invoice_viewed_subject' => 'Faktura :invoice sett av :client', 'notification_invoice_paid' => 'En betaling pålydende :amount ble gjort av :client for faktura :invoice.', 'notification_invoice_sent' => 'E-post har blitt sendt til :client - Faktura :invoice pålydende :amount.', - 'notification_invoice_viewed' => ':client har nå sett faktura :invoice pålydende :amount.', + 'notification_invoice_viewed' => ':client har nå sett faktura :invoice pålydende :amount.', 'reset_password' => 'Du kan nullstille ditt passord ved å besøke følgende lenke:', - 'reset_password_footer' => 'Hvis du ikke ba om å få nullstillt ditt passord, vennligst kontakt kundeservice: ' . CONTACT_EMAIL, - - - // Payment page 'secure_payment' => 'Sikker betaling', 'card_number' => 'Kortnummer', 'expiration_month' => 'Utløpsdato', 'expiration_year' => 'Utløpsår', 'cvv' => 'CVV', - - // Security alerts - 'security' => [ - 'too_many_attempts' => 'For mange forsøk. Prøv igjen om noen få minutter.', - 'wrong_credentials' => 'Feil e-post eller passord.', - 'confirmation' => 'Din konto har blitt bekreftet!', - 'wrong_confirmation' => 'Feil bekreftelseskode.', - 'password_forgot' => 'Informasjonen om tilbakestilling av passord ble sendt til e-postadressen.', - 'password_reset' => 'Passordet ditt er endret.', - 'wrong_password_reset' => 'Ugyldig passord. Prøv på nytt', - ], - - // Pro Plan - 'pro_plan' => [ - 'remove_logo' => ':link for å fjerne Invoice Ninja-logoen, oppgrader til en Pro Plan', - 'remove_logo_link' => 'Klikk her', - ], - 'logout' => 'Logg ut', 'sign_up_to_save' => 'Registrer deg for å lagre arbeidet ditt', - 'agree_to_terms' =>'Jeg godtar Invoice Ninja :terms', + 'agree_to_terms' => 'Jeg godtar Invoice Ninja :terms', 'terms_of_service' => 'vilkår for bruk', 'email_taken' => 'Epost-adressen er allerede registrert', 'working' => 'Jobber', @@ -307,17 +267,14 @@ return array( 'success_message' => 'Du har nå blitt registrert. Vennligst gå inn på lenken som du har mottatt i e-postbekreftelsen for å bekrefte e-postadressen.', 'erase_data' => 'Dette vil permanent slette alle dine data.', 'password' => 'Passord', - 'pro_plan_product' => 'Pro Plan', - 'pro_plan_description' => 'Ett års innmelding i Invoice Ninja Pro Plan.', 'pro_plan_success' => 'Takk for at du valgte Invoice Ninja\'s Pro plan!

     
    - Neste steg

    en betalbar faktura er sendt til e-postadressen - som er tilknyttet kontoen din. For å låse opp alle de utrolige - Pro-funksjonene, kan du følge instruksjonene på fakturaen til å + Neste steg

    en betalbar faktura er sendt til e-postadressen + som er tilknyttet kontoen din. For å låse opp alle de utrolige + Pro-funksjonene, kan du følge instruksjonene på fakturaen til å betale for et år med Pro-nivå funksjoner.

    - Finner du ikke fakturaen? Trenger du mer hjelp? Vi hjelper deg gjerne om det skulle være noe + Finner du ikke fakturaen? Trenger du mer hjelp? Vi hjelper deg gjerne om det skulle være noe -- kontakt oss på contact@invoiceninja.com', - 'unsaved_changes' => 'Du har ulagrede endringer', 'custom_fields' => 'Egendefinerte felt', 'company_fields' => 'Selskapets felt', @@ -327,8 +284,6 @@ return array( 'edit' => 'Endre', 'set_name' => 'Sett ditt firmanavn', 'view_as_recipient' => 'Vis som mottaker', - - // product management 'product_library' => 'Produktbibliotek', 'product' => 'Produkt', 'products' => 'Produkter', @@ -341,20 +296,16 @@ return array( 'archive_product' => 'Arkiver produkt', 'updated_product' => 'Produkt oppdatert', 'created_product' => 'Produkt lagret', - 'archived_product' => 'Produkt arkivert', + 'archived_product' => 'Produkt arkivert', 'pro_plan_custom_fields' => ':link for å aktivere egendefinerte felt ved å delta i Pro Plan', - 'advanced_settings' => 'Avanserte innstillinger', 'pro_plan_advanced_settings' => ':link for å aktivere avanserte innstillinger ved å delta i en Pro Plan', 'invoice_design' => 'Fakturadesign', 'specify_colors' => 'Egendefinerte farger', 'specify_colors_label' => 'Velg farger som brukes i fakturaen', - 'chart_builder' => 'Diagram bygger', 'ninja_email_footer' => 'Bruk :site til å fakturere kundene dine og få betalt på nettet - gratis!', 'go_pro' => 'Velg Pro', - - // Quotes 'quote' => 'Pristilbud', 'quotes' => 'Pristilbud', 'quote_number' => 'Tilbud nummer', @@ -364,7 +315,6 @@ return array( 'your_quote' => 'Ditt tilbud', 'total' => 'Totalt', 'clone' => 'Kopier', - 'new_quote' => 'Nytt tilbud', 'create_quote' => 'Lag tilbud', 'edit_quote' => 'Endre tilbud', @@ -377,7 +327,6 @@ return array( 'view_invoice' => 'Se faktura', 'view_client' => 'Vis klient', 'view_quote' => 'Se tilbud', - 'updated_quote' => 'Tilbud oppdatert', 'created_quote' => 'Tilbud opprettet', 'cloned_quote' => 'Tilbud kopiert', @@ -387,24 +336,20 @@ return array( 'deleted_quote' => 'Tilbud slettet', 'deleted_quotes' => 'Slettet :count tilbud', 'converted_to_invoice' => 'Tilbud konvertert til faktura', - 'quote_subject' => 'Nytt tilbud fra :account', 'quote_message' => 'For å se ditt tilbud pålydende :amount, klikk lenken nedenfor.', 'quote_link_message' => 'Hvis du vil se din klients tilbud, klikk på lenken under:', 'notification_quote_sent_subject' => 'Tilbud :invoice sendt til :client', 'notification_quote_viewed_subject' => 'Tilbudet :invoice er nå sett av :client', 'notification_quote_sent' => 'Følgende klient :client ble sendt tilbudsfaktura :invoice pålydende :amount.', - 'notification_quote_viewed' => 'Følgende klient :client har nå sett tilbudsfakturaen :invoice pålydende :amount.', - + 'notification_quote_viewed' => 'Følgende klient :client har nå sett tilbudsfakturaen :invoice pålydende :amount.', 'session_expired' => 'Økten er utløpt.', - 'invoice_fields' => 'Faktura felt', 'invoice_options' => 'Faktura alternativer', 'hide_quantity' => 'Skjul antall', 'hide_quantity_help' => 'Hvis du alltid har 1 (en) av hvert element på fakturaen, kan du velge dette alternativet for å ikke vise antall på fakturaen.', 'hide_paid_to_date' => 'Skjul delbetalinger', 'hide_paid_to_date_help' => 'Bare vis delbetalinger om det har forekommet en delbetaling.', - 'charge_taxes' => 'Inkluder skatt', 'user_management' => 'Brukerhåndtering', 'add_user' => 'Legg til bruker', @@ -419,21 +364,16 @@ return array( 'active' => 'Aktiv', 'pending' => 'Avventer', 'deleted_user' => 'Bruker slettet', - 'limit_users' => 'Dessverre, vil dette overstige grensen på ' . MAX_NUM_USERS . ' brukere', - 'confirm_email_invoice' => 'Er du sikker på at du ønsker å e-poste denne fakturaen?', 'confirm_email_quote' => 'Er du sikker på at du ønsker å e-poste dette tilbudet?', 'confirm_recurring_email_invoice' => 'Er du sikker på at du ønsker denne fakturaen e-postet?', - 'cancel_account' => 'Kanseler Konto', 'cancel_account_message' => 'Advarsel: Dette vil slette alle dine data og kan ikke angres.', 'go_back' => 'Gå Tilbake', - 'data_visualizations' => 'Data Visualiseringer', 'sample_data' => 'Eksempel data vist', 'hide' => 'Skjul', 'new_version_available' => 'En ny versjon av :releases_link er tilgjengelig. Du kjører v:user_version, siste versjon er v:latest_version', - 'invoice_settings' => 'Faktura Innstillinger', 'invoice_number_prefix' => 'Faktura Nummer Prefiks', 'invoice_number_counter' => 'Faktura Nummer Teller', @@ -443,59 +383,48 @@ return array( 'invoice_issued_to' => 'Faktura utgitt til', 'invalid_counter' => 'For å forhindre en mulig konflikt, sett et faktura eller tilbuds nummmer prefiks', 'mark_sent' => 'Merk som Sendt', - 'gateway_help_1' => ':link for å lage en konto for Authorize.net.', 'gateway_help_2' => ':link for å lage en konto for Authorize.net.', 'gateway_help_17' => ':link for å få din PayPal API signatur.', 'gateway_help_27' => ':link for å lage en konto for TwoCheckout.', - 'more_designs' => 'Flere design', 'more_designs_title' => 'Flere Faktura Design', 'more_designs_cloud_header' => 'Gå Pro for flere faktura design', 'more_designs_cloud_text' => '', - 'more_designs_self_host_header' => 'Få 6 flere design for bare $'.INVOICE_DESIGNS_PRICE, 'more_designs_self_host_text' => '', 'buy' => 'Kjøp', 'bought_designs' => 'Det ble suksessfullt lagt til flere design', 'sent' => 'sendt', - 'vat_number' => 'MVA Nummer', 'timesheets' => 'Tidsskjemaer', - 'payment_title' => 'Oppgi Din Faktura Adresse og Betalingskort informasjon', 'payment_cvv' => '*Dette er de 3-4 tallene på baksiden av ditt kort', 'payment_footer1' => '*Faktura adressen må være lik adressen assosiert med betalingskortet.', 'payment_footer2' => '*Vennligst klikk "BETAL NÅ" kun en gang - transaksjonen kan ta opp til 1 minutt å prosessere.', - 'id_number' => 'ID Nummer', 'white_label_link' => 'Reklamefri', 'white_label_header' => 'Reklamefri', 'bought_white_label' => 'Du har suksessfullt aktivert din reklamefrie lisens.', 'white_labeled' => 'Reklamefrie', - 'restore' => 'Gjenopprette', 'restore_invoice' => 'Gjenopprette Faktura', 'restore_quote' => 'Gjenopprette Tilbud', 'restore_client' => 'Gjenopprette Klient', 'restore_credit' => 'Gjenopprette Kreditt', 'restore_payment' => 'Gjenopprette Betaling', - 'restored_invoice' => 'Suksessfullt gjenopprettet faktura', 'restored_quote' => 'Suksessfullt gjenopprettet tilbud', 'restored_client' => 'Suksessfullt gjenopprettet klient', 'restored_payment' => 'Suksessfullt gjenopprettet betaling', 'restored_credit' => 'Suksessfullt gjenopprettet kreditt', - 'reason_for_canceling' => 'Hjelp oss å forbedre vår side ved å fortelle oss hvorfor du forlater oss.', 'discount_percent' => 'Prosent', 'discount_amount' => 'Beløp', - 'invoice_history' => 'Faktura Historikk', 'quote_history' => 'Tilbuds Historikk', 'current_version' => 'Nåværende versjon', 'select_version' => 'Velg versjon', 'view_history' => 'Vis Historikk', - 'edit_payment' => 'Rediger Betaling', 'updated_payment' => 'Suksessfullt oppdatert betaling', 'deleted' => 'Slettet', @@ -508,7 +437,6 @@ return array( 'quote_email' => 'Tilbuds E-post', 'reset_all' => 'Tilbakebestill Alt', 'approve' => 'Godkjenn', - 'token_billing_type_id' => 'Token Fakturering', 'token_billing_help' => 'Tillater deg å lagre betalingskort gjennom din betalingsleverandør og belaste dem på et senere tidspunkt.', 'token_billing_1' => 'Deaktivert', @@ -516,12 +444,11 @@ return array( 'token_billing_3' => 'Aktivert - valgboks er vist og valgt', 'token_billing_4' => 'Alltid', 'token_billing_checkbox' => 'Lagre bankkort detaljer', - 'view_in_stripe' => 'Vis i Stripe', - 'use_card_on_file' => 'Bruk lagret kort', + 'view_in_gateway' => 'Vis i :gateway', + 'use_card_on_file' => 'Use Card on File', 'edit_payment_details' => 'Rediger betalings detaljer', 'token_billing' => 'Lagre kort detaljer', - 'token_billing_secure' => 'Dataene er trygt lagret av :stripe_link', - + 'token_billing_secure' => 'Dataene er trygt lagret av :link', 'support' => 'Brukerstøtte', 'contact_information' => 'Kontaktinformasjon', '256_encryption' => '256-Bit Kryptering', @@ -531,10 +458,8 @@ return array( 'order_overview' => 'Bestillings oversikt', 'match_address' => '*Adressen må være lik adressen med assosiert betalingskort', 'click_once' => '*Vennligst klikk "BETAL NÅ" kun en gang - transaksjonen kan ta opp til 1 minutt å prosessere.', - 'invoice_footer' => 'Faktura Bunntekst', 'save_as_default_footer' => 'Lagre som standard bunntekst', - 'token_management' => 'Token Organisering', 'tokens' => 'Tokens', 'add_token' => 'Legg til Token', @@ -545,7 +470,6 @@ return array( 'edit_token' => 'Rediger Token', 'delete_token' => 'Slett Token', 'token' => 'Token', - 'add_gateway' => 'Legg til Tilbyder', 'delete_gateway' => 'Slett Tilbyder', 'edit_gateway' => 'Rediger Tilbyder', @@ -554,7 +478,6 @@ return array( 'deleted_gateway' => 'Suksessfullt slettet tilbyder', 'pay_with_paypal' => 'PayPal', 'pay_with_card' => 'Betalingskort', - 'change_password' => 'Skift passord', 'current_password' => 'Nåværende passord', 'new_password' => 'Nytt passord', @@ -562,7 +485,6 @@ return array( 'password_error_incorrect' => 'Nåværende passord er ikke riktig.', 'password_error_invalid' => 'Det nye passordet er ikke godkjent.', 'updated_password' => 'Suksessfullt oppdatert passord', - 'api_tokens' => 'API Tokens', 'users_and_tokens' => 'Brukere & Tokens', 'account_login' => 'Kontoinnlogging', @@ -570,18 +492,15 @@ return array( 'forgot_password' => 'Glemt ditt passord?', 'email_address' => 'E-post adresse', 'lets_go' => 'La oss fortsette', - //'lets_go' => 'Login', 'password_recovery' => 'Passord gjenoppretting', 'send_email' => 'Send e-post', 'set_password' => 'Sett Passord', 'converted' => 'Konvertert', - 'email_approved' => 'Send meg en e-post når tilbudet er godkjent', 'notification_quote_approved_subject' => 'Tilbud :invoice ble godkjent av :client', 'notification_quote_approved' => 'Følgende klient :client godkjente Tilbud :invoice pålydende :amount.', 'resend_confirmation' => 'Send bekreftelses e-post på nytt', 'confirmation_resent' => 'E-postbekreftelsen ble sendt på nytt', - 'gateway_help_42' => ':link for å lage en konto hos BitPay.
    Info: bruk en Legacy API Nøkkel, ikke en API token.', 'payment_type_credit_card' => 'Bankkort', 'payment_type_paypal' => 'PayPal', @@ -589,7 +508,6 @@ return array( 'knowledge_base' => 'Kunnskapsbase', 'partial' => 'Delvis', 'partial_remaining' => ':delvis av :balance', - 'more_fields' => 'Flere Felt', 'less_fields' => 'Mindre Felt', 'client_name' => 'Klient Navn', @@ -600,7 +518,6 @@ return array( 'view_documentation' => 'Vis Dokumentasjon', 'app_title' => 'Gratis Åpen Kildekode Internett Fakturering', 'app_description' => 'Invoice Ninja er en gratis, åpen kildekode løsning for fakturaer og fakturering av kunder. Med Invoice Ninja, kan du enkelt bygge og sende vakre fakturaer fra alle enheter som har tilgang til nettet. Dine kunder kan skrive ut fakturaer, laste dem ned som pdf-filer og selv betale deg på internett fra systemet.', - 'rows' => 'rader', 'www' => 'www', 'logo' => 'Logo', @@ -620,7 +537,6 @@ return array( 'zapier' => 'Zapier', 'recurring' => 'Gjentakende', 'last_invoice_sent' => 'Siste faktura sendt :date', - 'processed_updates' => 'Suksessfullt fullført oppdatering', 'tasks' => 'Oppgaver', 'new_task' => 'Ny Oppgave', @@ -666,12 +582,10 @@ return array( 'invoice_labels' => 'Fakturerings Etiketter', 'prefix' => 'Prefiks', 'counter' => 'Teller', - 'payment_type_dwolla' => 'Dwolla', 'gateway_help_43' => ':link for å lage en konto hos Dwolla.
    Info: fjern bindestreker fra Destinasjons/Dwolla IDen', 'partial_value' => 'Må være større enn null og mindre enn totalen', 'more_actions' => 'Flere Valg', - 'pro_plan_title' => 'NINJA PRO', 'pro_plan_call_to_action' => 'Oppgrader Nå!', 'pro_plan_feature1' => 'Lag Ubegrensede Klienter', @@ -682,14 +596,12 @@ return array( 'pro_plan_feature6' => 'Lag Tilbud & Proforma Fakturaer', 'pro_plan_feature7' => 'Modifiser Faktura Felt Titler & Nummerering', 'pro_plan_feature8' => 'Mulighet til å Legge ved PDFer til Klient E-poster', - 'resume' => 'Gjenoppta', 'break_duration' => 'Pause', 'edit_details' => 'Rediger Detaljer', 'work' => 'Arbeid', 'timezone_unset' => 'Vennligst :link for å sette din tidssone', 'click_here' => 'klikk her', - 'email_receipt' => 'E-post betalingskvittering til klienten', 'created_payment_emailed_client' => 'Suksessfullt opprettet en betaling og e-postet klient', 'add_company' => 'Legg til Selskap', @@ -699,10 +611,8 @@ return array( 'unlinked_account' => 'Suksessfullt frakoblet kontoer', 'login' => 'Logg inn', 'or' => 'eller', - 'email_error' => 'Det oppstod et problem med utsending av e-posten', 'confirm_recurring_timing' => 'Info: e-poster er sendt på starten av en time.', - 'old_browser' => 'Vennligst bruk en nyere nettleser', 'payment_terms_help' => 'Setter standard faktura dato', 'unlink_account' => 'Frakoble Konto', 'unlink' => 'Frakoble', @@ -723,7 +633,6 @@ return array( 'primary_color' => 'Primærfarge', 'secondary_color' => 'Sekundær farge', 'customize_design' => 'Modifiser Design', - 'content' => 'Innhold', 'styles' => 'Stiler', 'defaults' => 'Standarder', @@ -737,7 +646,6 @@ return array( 'outstanding' => 'Utestående', 'manage_companies' => 'Administrer Selskaper', 'total_revenue' => 'Sum Omsetning', - 'current_user' => 'Nåværende Bruker', 'new_recurring_invoice' => 'Ny Gjentakende Faktura', 'recurring_invoice' => 'Gjentakende Faktura', @@ -745,10 +653,9 @@ return array( 'created_by_invoice' => 'Laget av :invoice', 'primary_user' => 'Hovedbruker', 'help' => 'Hjelp', - 'customize_help' => '

    Vi bruker pdfmake for å definere faktura designene deklarativt. Pdfmake playground gir en flott måte å se biblioteket i aksjon.

    -

    For å få tilgang til et underelementet ved bruk av prikk notasjon. For eksempel for å vise klientens navn, kan du bruke $client.name.

    -

    Om du trenger hjelp til å finne ut noe, poster et spørsmål til vårt brukerforum.

    ', - + 'customize_help' => '

    We use pdfmake to define the invoice designs declaratively. The pdfmake playground provide\'s a great way to see the library in action.

    +

    You can access a child property using dot notation. For example to show the client name you could use $client.name.

    +

    If you need help figuring something out post a question to our support forum with the design you\'re using.

    ', 'invoice_due_date' => 'Tidsfrist', 'quote_due_date' => 'Gyldig til', 'valid_until' => 'Gyldig til', @@ -761,15 +668,12 @@ return array( 'status_partial' => 'Delvis', 'status_paid' => 'Betalt', 'show_line_item_tax' => 'Vis linje element skatter på linje', - 'iframe_url' => 'Nettside', 'iframe_url_help1' => 'Kopier følgende kode til en side på din nettside.', 'iframe_url_help2' => 'Du kan teste funksjonen ved å klikke \'Vis som mottager\' for en faktura.', - 'auto_bill' => 'Auto Fakturer', 'military_time' => '24 Timers Tid', 'last_sent' => 'Sist Sendt', - 'reminder_emails' => 'Påminnelses E-poster', 'templates_and_reminders' => 'Design & Påminnelser', 'subject' => 'Emne', @@ -781,15 +685,12 @@ return array( 'reminder_subject' => 'Påminnelse: Faktura :invoice fra :account', 'reset' => 'Nullstill', 'invoice_not_found' => 'Ønsket faktura er ikke tilgjengelig', - 'referral_program' => 'Henvisningsprogram', 'referral_code' => 'Henvisnings Kode', 'last_sent_on' => 'Sendt Sist: :date', - 'page_expire' => 'Denne siden vil utløpe snart, :click_here for å fortsette å arbeide', 'upcoming_quotes' => 'Oppkommende Tilbud', 'expired_quotes' => 'Utløpte Tilbud', - 'sign_up_using' => 'Meld deg på ved å bruke', 'invalid_credentials' => 'Disse kredentialene samsvarer ikke med våre opplysninger', 'show_all_options' => 'Vis alle alternativene', @@ -798,18 +699,10 @@ return array( 'disable' => 'Deaktiver', 'invoice_quote_number' => 'Faktura og Tilbuds Nummer', 'invoice_charges' => 'Faktura Kostnader', - - 'invitation_status' => [ - 'sent' => 'E-post Sendt', - 'opened' => 'E-post Åpnet', - 'viewed' => 'Faktura Vist', - ], - 'notification_invoice_bounced' => 'Vi klarte ikke å levere Faktura :invoice til :contact.', 'notification_invoice_bounced_subject' => 'Klarte ikke å levere Faktura :invoice', 'notification_quote_bounced' => 'Vi klarte ikke å levere Tilbud :invoice til :contact.', 'notification_quote_bounced_subject' => 'Klarte ikke å levere Tilbud :invoice', - 'custom_invoice_link' => 'Tilpasset Faktura Lenke', 'total_invoiced' => 'Totalt Fakturert', 'open_balance' => 'Åpen Balanse', @@ -817,15 +710,12 @@ return array( 'basic_settings' => 'Grunnleggende Innstillinger', 'pro' => 'Pro', 'gateways' => 'Betalings Tilbydere', - 'next_send_on' => 'Send Neste: :date', 'no_longer_running' => 'Denne fakturaen er ikke planlagt for kjøring', 'general_settings' => 'Systeminnstillinger', 'customize' => 'Tilpass', - 'oneclick_login_help' => 'Koble til en konto for å logge inn uten et passord', 'referral_code_help' => 'Tjen penger ved å dele appen vår på internett', - 'enable_with_stripe' => 'Aktiver | Krever Stripe', 'tax_settings' => 'Skatteinnstillinger', 'create_tax_rate' => 'Legg Til Skattesats', @@ -846,7 +736,6 @@ return array( 'invoice_counter' => 'Faktura Teller', 'quote_counter' => 'Tilbuds Teller', 'type' => 'Type', - 'activity_1' => ':user opprettet klient :client', 'activity_2' => ':user arkiverte klient :client', 'activity_3' => ':user slettet klient :client', @@ -876,7 +765,14 @@ return array( 'activity_27' => ':user gjenopprettet betaling :payment', 'activity_28' => ':user gjenopprettet :credit kreditt', 'activity_29' => ':contact godkjente tilbud :quote', - + 'activity_30' => ':user created :vendor', + 'activity_31' => ':user created :vendor', + 'activity_32' => ':user created :vendor', + 'activity_33' => ':user created :vendor', + 'activity_34' => ':user created expense :expense', + 'activity_35' => ':user created :vendor', + 'activity_36' => ':user created :vendor', + 'activity_37' => ':user created :vendor', 'payment' => 'Betaling', 'system' => 'System', 'signature' => 'E-post Signatur', @@ -887,7 +783,6 @@ return array( 'default_invoice_footer' => 'Standard Faktura Bunntekst', 'quote_footer' => 'Tilbud Bunntekst', 'free' => 'Gratis', - 'quote_is_approved' => 'Dette tilbudet er godkjent', 'apply_credit' => 'Bruk Kreditt', 'system_settings' => 'Systeminnstillinger', @@ -905,7 +800,6 @@ return array( 'restored_recurring_invoice' => 'Suksessfullt gjenopprettet gjentakende faktura', 'archived' => 'Arkivert', 'untitled_account' => 'Selskap Uten Navn', - 'before' => 'Before', 'after' => 'After', 'reset_terms_help' => 'Reset to the default account terms', @@ -914,7 +808,6 @@ return array( 'user' => 'User', 'country' => 'Country', 'include' => 'Include', - '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_data' => 'Import Data', @@ -925,16 +818,6 @@ return array( 'task_file' => 'Task File', 'no_mapper' => 'No valid mapping for file', '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', 'admin' => 'Admin', 'disabled' => 'Disabled', @@ -943,11 +826,9 @@ return array( 'invoice_will_create' => 'client will be created', 'invoices_will_create' => 'invoices will be created', 'failed_to_import' => 'The following records failed to import, they either already exist or are missing required fields.', - 'publishable_key' => 'Publishable Key', 'secret_key' => 'Secret Key', 'missing_publishable_key' => 'Set your Stripe publishable key for an improved checkout process', - 'email_design' => 'Email Design', 'due_by' => 'Due by :date', 'enable_email_markup' => 'Enable Markup', @@ -959,7 +840,6 @@ return array( 'plain' => 'Plain', 'light' => 'Light', 'dark' => 'Dark', - '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.', 'invoice_number_help' => 'Specify a prefix or use a custom pattern to dynamically set the invoice number.', @@ -968,8 +848,6 @@ return array( '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_charges_helps' => 'Add a text input to the invoice create/edit page and include the charge in the invoice subtotals.', - 'color_help' => 'Note: the primary color is also used in the client portal and custom email designs.', - 'token_expired' => 'Validation token was expired. Please try again.', 'invoice_link' => 'Invoice Link', 'button_confirmation_message' => 'Click to confirm your email address.', @@ -978,7 +856,6 @@ return array( 'created_invoices' => 'Successfully created :count invoice(s)', 'next_invoice_number' => 'The next invoice number is :number.', 'next_quote_number' => 'The next quote number is :number.', - 'days_before' => 'days before', 'days_after' => 'days after', 'field_due_date' => 'due date', @@ -986,11 +863,7 @@ return array( 'schedule' => 'Schedule', 'email_designs' => 'Email Designs', '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', - - // Expense / vendor 'expense' => 'Expense', 'expenses' => 'Expenses', 'new_expense' => 'Enter Expense', @@ -1007,8 +880,6 @@ return array( 'archived_expense' => 'Successfully archived expense', 'deleted_expenses' => 'Successfully deleted expenses', 'archived_expenses' => 'Successfully archived expenses', - - // Expenses 'expense_amount' => 'Expense Amount', 'expense_balance' => 'Expense Balance', 'expense_date' => 'Expense Date', @@ -1030,18 +901,14 @@ return array( 'view' => 'View', 'restore_expense' => 'Restore Expense', 'invoice_expense' => 'Invoice Expense', - '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', 'convert_currency' => 'Convert currency', - - // Payment terms 'num_days' => 'Number of days', 'create_payment_term' => 'Create Payment Term', 'edit_payment_terms' => 'Edit Payment Term', 'edit_payment_term' => 'Edit Payment Term', 'archive_payment_term' => 'Archive Payment Term', - - // recurring due dates 'recurring_due_dates' => 'Recurring Invoice Due Dates', 'recurring_due_date_help' => '

    Automatically sets a due date for the invoice.

    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.

    @@ -1069,15 +936,11 @@ return array( 'thursday' => 'Thursday', 'friday' => 'Friday', 'saturday' => 'Saturday', - - // Fonts 'header_font_id' => 'Header 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.', - 'live_preview' => 'Live Preview', '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.', 'quote_message_button' => 'To view your quote for :amount, click the button below.', 'payment_message_button' => 'Thank you for your payment of :amount.', @@ -1094,7 +957,6 @@ return array( 'archived_bank_account' => 'Successfully archived bank account', 'created_bank_account' => 'Successfully created 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 400+ US banks.', '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.', 'username' => 'Username', @@ -1108,7 +970,6 @@ return array( 'validate' => 'Validate', 'info' => 'Info', '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.', '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.', @@ -1129,7 +990,28 @@ return array( 'trial_call_to_action' => 'Start Free Trial', '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.', + + + 'white_label_text' => 'Purchase a ONE YEAR white label license for $:price to remove the Invoice Ninja branding from the client portal and help support our project.', + 'user_email_footer' => 'For å justere varslingsinnstillingene vennligst besøk :link', + 'reset_password_footer' => 'Hvis du ikke ba om å få nullstillt ditt passord, vennligst kontakt kundeservice: :email', + 'limit_users' => 'Dessverre, vil dette overstige grensen på :limit brukere', + 'more_designs_self_host_header' => 'Få 6 flere design for bare $:price', + 'old_browser' => 'Vennligst bruk en nyere nettleser', + 'white_label_custom_css' => ':link for $: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 400+ US banks.', + + 'pro_plan_remove_logo' => ':link for å fjerne Invoice Ninja-logoen, oppgrader til en Pro Plan', + 'pro_plan_remove_logo_link' => 'Klikk her', + 'invitation_status_sent' => 'E-post Sendt', + 'invitation_status_opened' => 'E-post Åpnet', + 'invitation_status_viewed' => 'Faktura Vist', + 'email_error_inactive_client' => 'Emails can not be sent to inactive clients', + 'email_error_inactive_contact' => 'Emails can not be sent to inactive contacts', + 'email_error_inactive_invoice' => 'Emails can not be sent to inactive invoices', + 'email_error_user_unregistered' => 'Please register your account to send emails', + 'email_error_user_unconfirmed' => 'Please confirm your account to send emails', + 'email_error_invalid_contact_email' => 'Invalid contact email', 'navigation' => 'Navigation', 'list_invoices' => 'List Invoices', @@ -1152,22 +1034,20 @@ return array( 'custom_invoice_item_fields_help' => 'Add a field when creating an invoice item and display the label and value on the PDF.', 'recurring_invoice_number' => 'Recurring Invoice Number', 'recurring_invoice_number_prefix_help' => 'Speciy a prefix to be added to the invoice number for recurring invoices. The default value is \'R\'.', - 'enable_client_portal' => 'Dashboard', - 'enable_client_portal_help' => 'Show/hide the dashboard page in the client portal.', // Client Passwords 'enable_portal_password'=>'Password protect invoices', 'enable_portal_password_help'=>'Allows you to set a password for each contact. If a password is set, the contact will be required to enter a password before viewing invoices.', 'send_portal_password'=>'Generate password automatically', 'send_portal_password_help'=>'If no password is set, one will be generated and sent with the first invoice.', - + 'expired' => 'Expired', 'invalid_card_number' => 'The credit card number is not valid.', 'invalid_expiry' => 'The expiration date is not valid.', 'invalid_cvv' => 'The CVV is not valid.', 'cost' => 'Cost', 'create_invoice_for_sample' => 'Note: create your first invoice to see a preview here.', - + // User Permissions 'owner' => 'Owner', 'administrator' => 'Administrator', @@ -1185,8 +1065,8 @@ return array( 'create_all_help' => 'Allow user to create and modify records', 'view_all_help' => 'Allow user to view records they didn\'t create', 'edit_all_help' => 'Allow user to modify records they didn\'t create', - 'view_payment' => 'View Payment', - + 'view_payment' => 'View Payment', + 'january' => 'January', 'february' => 'February', 'march' => 'March', @@ -1212,30 +1092,28 @@ return array( 'document_email_attachment' => 'Attach Documents', 'download_documents' => 'Download Documents (:size)', 'documents_from_expenses' => 'From Expenses:', - 'dropzone' => array(// See http://www.dropzonejs.com/#config-dictDefaultMessage - 'DefaultMessage' => 'Drop files or click to upload', - 'FallbackMessage' => 'Your browser does not support drag\'n\'drop file uploads.', - 'FallbackText' => 'Please use the fallback form below to upload your files like in the olden days.', - 'FileTooBig' => 'File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.', - 'InvalidFileType' => 'You can\'t upload files of this type.', - 'ResponseError' => 'Server responded with {{statusCode}} code.', - 'CancelUpload' => 'Cancel upload', - 'CancelUploadConfirmation' => 'Are you sure you want to cancel this upload?', - 'RemoveFile' => 'Remove file', - ), + 'dropzone_default_message' => 'Drop files or click to upload', + 'dropzone_fallback_message' => 'Your browser does not support drag\'n\'drop file uploads.', + 'dropzone_fallback_text' => 'Please use the fallback form below to upload your files like in the olden days.', + 'dropzone_file_too_big' => 'File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.', + 'dropzone_invalid_file_type' => 'You can\'t upload files of this type.', + 'dropzone_response_error' => 'Server responded with {{statusCode}} code.', + 'dropzone_cancel_upload' => 'Cancel upload', + 'dropzone_cancel_upload_confirmation' => 'Are you sure you want to cancel this upload?', + 'dropzone_remove_file' => 'Remove file', 'documents' => 'Documents', 'document_date' => 'Document Date', 'document_size' => 'Size', - 'enable_client_portal' => 'Client Portal', - 'enable_client_portal_help' => 'Show/hide the client portal.', + 'enable_client_portal' => 'Dashboard', + 'enable_client_portal_help' => 'Show/hide the dashboard page in the client portal.', 'enable_client_portal_dashboard' => 'Dashboard', 'enable_client_portal_dashboard_help' => 'Show/hide the dashboard page in the client portal.', - + // Plans 'account_management' => 'Account Management', 'plan_status' => 'Plan Status', - + 'plan_upgrade' => 'Upgrade', 'plan_change' => 'Change Plan', 'pending_change_to' => 'Changes To', @@ -1265,9 +1143,9 @@ return array( 'plan_paid' => 'Term Started', 'plan_started' => 'Plan Started', 'plan_expires' => 'Plan Expires', - + 'white_label_button' => 'White Label', - + 'pro_plan_year_description' => 'One year enrollment in the Invoice Ninja Pro Plan.', 'pro_plan_month_description' => 'One month enrollment in the Invoice Ninja Pro Plan.', 'enterprise_plan_product' => 'Enterprise Plan', @@ -1285,7 +1163,207 @@ return array( 'preview' => 'Preview', 'list_vendors' => 'List Vendors', 'add_users_not_supported' => 'Upgrade to the Enterprise plan to add additional users to your account.', - 'enterprise_plan_features' => 'The Enterprise plan adds support for multiple users and file attachments.', + 'enterprise_plan_features' => 'The Enterprise plan adds support for multiple users and file attachments, :link to see the full list of features.', 'return_to_app' => 'Return to app', - -); \ No newline at end of file + + + // Payment updates + 'refund_payment' => 'Refund Payment', + 'refund_max' => 'Max:', + 'refund' => 'Refund', + 'are_you_sure_refund' => 'Refund selected payments?', + 'status_pending' => 'Pending', + 'status_completed' => 'Completed', + 'status_failed' => 'Failed', + 'status_partially_refunded' => 'Partially Refunded', + 'status_partially_refunded_amount' => ':amount Refunded', + 'status_refunded' => 'Refunded', + 'status_voided' => 'Cancelled', + 'refunded_payment' => 'Refunded Payment', + 'activity_39' => ':user cancelled a :payment_amount payment (:payment)', + 'activity_40' => ':user refunded :adjustment of a :payment_amount payment (:payment)', + 'card_expiration' => 'Exp: :expires', + + 'card_creditcardother' => 'Unknown', + 'card_americanexpress' => 'American Express', + 'card_carteblanche' => 'Carte Blanche', + 'card_unionpay' => 'UnionPay', + 'card_diners' => 'Diners Club', + 'card_discover' => 'Discover', + 'card_jcb' => 'JCB', + 'card_laser' => 'Laser', + 'card_maestro' => 'Maestro', + 'card_mastercard' => 'MasterCard', + 'card_solo' => 'Solo', + 'card_switch' => 'Switch', + 'card_visacard' => 'Visa', + 'card_ach' => 'ACH', + + 'payment_type_stripe' => 'Stripe', + 'ach' => 'ACH', + 'enable_ach' => 'Enable ACH', + 'stripe_ach_help' => 'ACH support must also be enabled at Stripe.', + 'ach_disabled' => 'Another gateway is already configured for direct debit.', + + 'plaid' => 'Plaid', + 'client_id' => 'Client Id', + 'secret' => 'Secret', + 'public_key' => 'Public Key', + 'plaid_optional' => '(optional)', + 'plaid_environment_help' => 'When a Stripe test key is given, Plaid\'s development environement (tartan) will be used.', + 'other_providers' => 'Other Providers', + 'country_not_supported' => 'That country is not supported.', + 'invalid_routing_number' => 'The routing number is not valid.', + 'invalid_account_number' => 'The account number is not valid.', + 'account_number_mismatch' => 'The account numbers do not match.', + 'missing_account_holder_type' => 'Please select an individual or company account.', + 'missing_account_holder_name' => 'Please enter the account holder\'s name.', + 'routing_number' => 'Routing Number', + 'confirm_account_number' => 'Confirm Account Number', + 'individual_account' => 'Individual Account', + 'company_account' => 'Company Account', + 'account_holder_name' => 'Account Holder Name', + 'add_account' => 'Add Account', + 'payment_methods' => 'Payment Methods', + 'complete_verification' => 'Complete Verification', + 'verification_amount1' => 'Amount 1', + 'verification_amount2' => 'Amount 2', + 'payment_method_verified' => 'Verification completed successfully', + 'verification_failed' => 'Verification Failed', + 'remove_payment_method' => 'Remove Payment Method', + 'confirm_remove_payment_method' => 'Are you sure you want to remove this payment method?', + 'remove' => 'Remove', + 'payment_method_removed' => 'Removed payment method.', + 'bank_account_verification_help' => 'We have made two deposits into your account with the description "VERIFICATION". These deposits will take 1-2 business days to appear on your statement. Please enter the amounts below.', + 'bank_account_verification_next_steps' => 'We have made two deposits into your account with the description "VERIFICATION". These deposits will take 1-2 business days to appear on your statement. + Once you have the amounts, come back to this payment methods page and click "Complete Verification" next to the account.', + 'unknown_bank' => 'Unknown Bank', + 'ach_verification_delay_help' => 'You will be able to use the account after completing verification. Verification usually takes 1-2 business days.', + 'add_credit_card' => 'Add Credit Card', + 'payment_method_added' => 'Added payment method.', + 'use_for_auto_bill' => 'Use For Autobill', + 'used_for_auto_bill' => 'Autobill Payment Method', + 'payment_method_set_as_default' => 'Set Autobill payment method.', + 'activity_41' => ':payment_amount payment (:payment) failed', + 'webhook_url' => 'Webhook URL', + 'stripe_webhook_help' => 'You must :link.', + 'stripe_webhook_help_link_text' => 'add this URL as an endpoint at Stripe', + 'payment_method_error' => 'There was an error adding your payment methd. Please try again later.', + 'notification_invoice_payment_failed_subject' => 'Payment failed for Invoice :invoice', + 'notification_invoice_payment_failed' => 'A payment made by client :client towards Invoice :invoice failed. The payment has been marked as failed and :amount has been added to the client\'s balance.', + 'link_with_plaid' => 'Link Account Instantly with Plaid', + 'link_manually' => 'Link Manually', + 'secured_by_plaid' => 'Secured by Plaid', + 'plaid_linked_status' => 'Your bank account at :bank', + 'add_payment_method' => 'Add Payment Method', + 'account_holder_type' => 'Account Holder Type', + 'ach_authorization' => 'I authorize :company to use my bank account for future payments and, if necessary, electronically credit my account to correct erroneous debits. I understand that I may cancel this authorization at any time by removing the payment method or by contacting :email.', + 'ach_authorization_required' => 'You must consent to ACH transactions.', + 'off' => 'Off', + 'opt_in' => 'Opt-in', + 'opt_out' => 'Opt-out', + 'always' => 'Always', + 'opted_out' => 'Opted out', + 'opted_in' => 'Opted in', + 'manage_auto_bill' => 'Manage Auto-bill', + 'enabled' => 'Enabled', + 'paypal' => 'PayPal', + 'braintree_enable_paypal' => 'Enable PayPal payments through BrainTree', + 'braintree_paypal_disabled_help' => 'The PayPal gateway is processing PayPal payments', + 'braintree_paypal_help' => 'You must also :link.', + 'braintree_paypal_help_link_text' => 'link PayPal to your BrainTree account', + 'token_billing_braintree_paypal' => 'Save payment details', + 'add_paypal_account' => 'Add PayPal Account', + + + 'no_payment_method_specified' => 'No payment method specified', + 'chart_type' => 'Chart Type', + 'format' => 'Format', + 'import_ofx' => 'Import OFX', + 'ofx_file' => 'OFX File', + 'ofx_parse_failed' => 'Failed to parse OFX file', + + // WePay + 'wepay' => 'WePay', + 'sign_up_with_wepay' => 'Sign up with WePay', + 'use_another_provider' => 'Use another provider', + 'company_name' => 'Company Name', + 'wepay_company_name_help' => 'This will appear on client\'s credit card statements.', + 'wepay_description_help' => 'The purpose of this account.', + 'wepay_tos_agree' => 'I agree to the :link.', + 'wepay_tos_link_text' => 'WePay Terms of Service', + 'resend_confirmation_email' => 'Resend Confirmation Email', + 'manage_wepay_account' => 'Manage WePay Account', + 'action_required' => 'Action Required', + 'finish_setup' => 'Finish Setup', + 'created_wepay_confirmation_required' => 'Please check your email and confirm your email address with WePay.', + 'switch_to_wepay' => 'Switch to WePay', + 'switch' => 'Switch', + 'restore_account_gateway' => 'Restore Gateway', + 'restored_account_gateway' => 'Successfully restored gateway', + 'united_states' => 'United States', + 'canada' => 'Canada', + 'accept_debit_cards' => 'Accept Debit Cards', + 'debit_cards' => 'Debit Cards', + + 'warn_start_date_changed' => 'The next invoice will be sent on the new start date.', + 'original_start_date' => 'Original start date', + 'new_start_date' => 'New start date', + 'security' => 'Security', + 'see_whats_new' => 'See what\'s new in v:version', + 'wait_for_upload' => 'Please wait for the document upload to complete.', + 'upgrade_for_permissions' => 'Upgrade to our Enterprise plan to enable permissions.', + 'enable_second_tax_rate' => 'Enable specifying a second tax rate', + 'payment_file' => 'Payment File', + 'expense_file' => 'Expense File', + 'product_file' => 'Product File', + 'import_products' => 'Import Products', + 'products_will_create' => 'products will be created.', + 'product_key' => 'Product', + 'created_products' => 'Successfully created :count product(s)', + 'export_help' => 'Use JSON if you plan to import the data into Invoice Ninja.', + 'JSON_file' => 'JSON File', + + 'view_dashboard' => 'View Dashboard', + 'client_session_expired' => 'Session Expired', + 'client_session_expired_message' => 'Your session has expired. Please click the link in your email again.', + + 'auto_bill_notification' => 'This invoice will automatically be billed to your :payment_method on file on :due_date.', + 'auto_bill_payment_method_bank_transfer' => 'bank account', + 'auto_bill_payment_method_credit_card' => 'credit card', + 'auto_bill_payment_method_paypal' => 'PayPal account', + 'auto_bill_notification_placeholder' => 'This invoice will automatically be billed to your credit card on file on the due date.', + 'payment_settings' => 'Payment Settings', + + 'on_send_date' => 'On send date', + 'on_due_date' => 'On due date', + 'auto_bill_ach_date_help' => 'ACH auto bill will always happen on the due date', + 'warn_change_auto_bill' => 'Due to NACHA rules, changes to this invoice may prevent ACH auto bill.', + + 'bank_account' => 'Bank Account', + 'payment_processed_through_wepay' => 'ACH payments will be processed using WePay.', + 'wepay_payment_tos_agree' => 'I agree to the WePay :terms and :privacy_policy.', + 'privacy_policy' => 'Privacy Policy', + 'wepay_payment_tos_agree_required' => 'You must agree to the WePay Terms of Service and Privacy Policy.', + 'payment_settings_supported_gateways' => 'These options are supported by the WePay, Stripe, and Braintree gateways.', + 'ach_email_prompt' => 'Please enter your email address:', + 'verification_pending' => 'Verification Pending', + + 'update_font_cache' => 'Please force refresh the page to update the font cache.', + 'more_options' => 'More options', + 'credit_card' => 'Credit Card', + 'bank_transfer' => 'Bank Transfer', + 'no_transaction_reference' => 'We did not recieve a payment transaction reference from the gateway.', + 'use_bank_on_file' => 'Use Bank on File', + 'auto_bill_email_message' => 'This invoice will automatically be billed to the payment method on file on the due date.', + 'bitcoin' => 'Bitcoin', + 'added_on' => 'Added :date', + 'failed_remove_payment_method' => 'Failed to remove the payment method', + 'gateway_exists' => 'This gateway already exists', + 'manual_entry' => 'Manual entry', + +); + +return $LANG; + +?> diff --git a/resources/lang/nl/texts.php b/resources/lang/nl/texts.php index 6d19485ff8..5d6e89e771 100644 --- a/resources/lang/nl/texts.php +++ b/resources/lang/nl/texts.php @@ -1,8 +1,6 @@ 'Organisatie', 'name' => 'Naam', 'website' => 'Website', @@ -25,8 +23,6 @@ return array( 'size_id' => 'Grootte', 'industry_id' => 'Industrie', 'private_notes' => 'Notitie (privé)', - - // invoice 'invoice' => 'Factuur', 'client' => 'Klant', 'invoice_date' => 'Factuurdatum', @@ -50,7 +46,6 @@ return array( 'invoice_design_id' => 'Ontwerp', 'terms' => 'Voorwaarden', 'your_invoice' => 'Jouw factuur', - 'remove_contact' => 'Verwijder contact', 'add_contact' => 'Contact toevoegen', 'create_new_client' => 'Maak nieuwe klant', @@ -69,13 +64,11 @@ return array( 'delete_invoice' => 'Verwijder factuur', 'email_invoice' => 'E-mail factuur', 'enter_payment' => 'Betaling invoeren', - 'tax_rates' => 'BTW-tarief', + 'tax_rates' => 'BTW-tarieven', 'rate' => 'Tarief', 'settings' => 'Instellingen', 'enable_invoice_tax' => 'Activeer instelling van BTW op volledige factuur', 'enable_line_item_tax' => 'Activeer instelling van BTW per lijn', - - // navigation 'dashboard' => 'Dashboard', 'clients' => 'Klanten', 'invoices' => 'Facturen', @@ -96,11 +89,10 @@ return array( 'import' => 'Importeer', 'download' => 'Downloaden', 'cancel' => 'Annuleren', + 'close' => 'Sluiten', 'provide_email' => 'Geef een geldig e-mailadres aub.', 'powered_by' => 'Factuur gemaakt via', 'no_items' => 'Geen artikelen', - - // recurring invoices 'recurring_invoices' => 'Terugkerende facturen', 'recurring_help' => '

    Zend klanten automatisch wekelijks, twee keer per maand, maandelijks, per kwartaal of jaarlijks dezelfde facturen.

    Gebruik :MONTH, :QUARTER of :YEAR voor dynamische datums. Eenvoudige wiskunde werkt ook, bijvoorbeeld :MONTH-1.

    @@ -110,8 +102,6 @@ return array(
  • "Jaarlijks abonnement :YEAR+1" => "Jaarlijks abonnement 2015"
  • "Betaling voor :QUARTER+1" => "Betaling voor Q2"
  • ', - - // dashboard 'in_total_revenue' => 'in totale opbrengst', 'billed_client' => 'Gefactureerde klant', 'billed_clients' => 'Gefactureerde klanten', @@ -120,8 +110,6 @@ return array( 'invoices_past_due' => 'Vervallen facturen', 'upcoming_invoices' => 'Aankomende facturen', 'average_invoice' => 'Gemiddelde factuur', - - // list pages 'archive' => 'Archiveer', 'delete' => 'Verwijder', 'archive_client' => 'Archiveer klant', @@ -157,8 +145,6 @@ return array( 'select' => 'Selecteer', 'edit_client' => 'Klant aanpassen', 'edit_invoice' => 'Factuur aanpassen', - - // client view page 'create_invoice' => 'Factuur aanmaken', 'enter_credit' => 'Kredietnota ingeven', 'last_logged_in' => 'Laatste login', @@ -170,12 +156,8 @@ return array( 'message' => 'Bericht', 'adjustment' => 'Aanpassing', 'are_you_sure' => 'Weet u het zeker?', - - // payment pages 'payment_type_id' => 'Betalingstype', 'amount' => 'Bedrag', - - // account/company pages 'work_email' => 'E-mailadres', 'language_id' => 'Taal', 'timezone_id' => 'Tijdszone', @@ -193,11 +175,7 @@ return array( 'email_paid' => 'E-mail mij wanneer een factuur is betaald', 'site_updates' => 'Site Aanpassingen', 'custom_messages' => 'Aangepaste berichten', - 'default_invoice_terms' => 'Stel standaard factuurvoorwaarden in', 'default_email_footer' => 'Stel standaard e-mailhandtekening in', - 'import_clients' => 'Importeer Klant Gegevens', - 'csv_file' => 'Selecteer CSV bestand', - 'export_clients' => 'Exporteer Klant Gegevens', 'select_file' => 'Selecteer een bestand', 'first_row_headers' => 'Gebruik eerste rij als koppen', 'column' => 'Kolom', @@ -206,9 +184,12 @@ return array( 'client_will_create' => 'klant zal aangemaakt worden', 'clients_will_create' => 'klanten zullen aangemaakt worden', 'email_settings' => 'E-mailinstellingen', + 'client_view_styling' => 'Opmaak klantenportaal', 'pdf_email_attachment' => 'PDF als bijlage toevoegen in e-mailberichten', - - // application messages + 'custom_css' => 'Aangepaste CSS', + 'import_clients' => 'Importeer Klant Gegevens', + 'csv_file' => 'Selecteer CSV bestand', + 'export_clients' => 'Exporteer Klant Gegevens', 'created_client' => 'Klant succesvol aangemaakt', 'created_clients' => ':count klanten succesvol aangemaakt', 'updated_settings' => 'Instellingen succesvol aangepast', @@ -219,14 +200,12 @@ return array( 'payment_error' => 'Er was een fout bij het verwerken van uw betaling. Probeer later alstublieft opnieuw.', 'registration_required' => 'Meld u aan om een factuur te mailen', 'confirmation_required' => 'Bevestig uw e-mailadres alstublieft', - 'updated_client' => 'Klant succesvol aangepast', 'created_client' => 'Klant succesvol aangemaakt', 'archived_client' => 'Klant succesvol gearchiveerd', 'archived_clients' => ':count klanten succesvol gearchiveerd', 'deleted_client' => 'Klant succesvol verwijderd', 'deleted_clients' => ':count klanten succesvol verwijderd', - 'updated_invoice' => 'Factuur succesvol aangepast', 'created_invoice' => 'Factuur succesvol aangemaakt', 'cloned_invoice' => 'Factuur succesvol gekopieerd', @@ -236,21 +215,25 @@ return array( 'archived_invoices' => ':count facturen succesvol gearchiveerd', 'deleted_invoice' => 'Factuur succesvol verwijderd', 'deleted_invoices' => ':count facturen succesvol verwijderd', - 'created_payment' => 'Betaling succesvol aangemaakt', + 'created_payments' => 'Succesvol :count betaling(en) aangemaakt', 'archived_payment' => 'Betaling succesvol gearchiveerd', 'archived_payments' => ':count betalingen succesvol gearchiveerd', 'deleted_payment' => 'Betaling succesvol verwijderd', 'deleted_payments' => ':count betalingen succesvol verwijderd', 'applied_payment' => 'Betaling succesvol toegepast', - 'created_credit' => 'Kredietnota succesvol aangemaakt', 'archived_credit' => 'Kredietnota succesvol gearchiveerd', 'archived_credits' => ':count kredietnota\'s succesvol gearchiveerd', 'deleted_credit' => 'Kredietnota succesvol verwijderd', 'deleted_credits' => ':count kredietnota\'s succesvol verwijderd', - - // E-mails + 'imported_file' => 'Bestand succesvol geïmporteerd', + 'updated_vendor' => 'Leverancier succesvol bijgewerkt', + 'created_vendor' => 'Leverancier succesvol aangemaakt', + 'archived_vendor' => 'Leverancier succesvol gearchiveerd', + 'archived_vendors' => 'Succesvol :count leveranciers gearchiveerd', + 'deleted_vendor' => 'Leverancier succesvol verwijderd', + 'deleted_vendors' => 'Succesvol :count leveranciers verwijderd', 'confirmation_subject' => 'InvoiceNinja Accountbevestiging', 'confirmation_header' => 'Bevestiging Account', 'confirmation_message' => 'Klik op onderstaande link om uw account te bevestigen.', @@ -261,41 +244,19 @@ return array( 'email_salutation' => 'Beste :name,', 'email_signature' => 'Met vriendelijke groeten,', 'email_from' => 'Het InvoiceNinja Team', - 'user_email_footer' => 'Ga alstublieft naar '.SITE_URL.'/settings/notifications om uw e-mail notificatie instellingen aan te passen', - 'invoice_link_message' => 'Klik op volgende link om de Factuur van uw klant te bekijken:', + 'invoice_link_message' => 'Klik op volgende link om de factuur van uw klant te bekijken:', 'notification_invoice_paid_subject' => 'Factuur :invoice is betaald door :client', - 'notification_invoice_sent_subject' => 'Factuur :invoice is gezonden door :client', + 'notification_invoice_sent_subject' => 'Factuur :invoice is verstuurd naar :client', 'notification_invoice_viewed_subject' => 'Factuur :invoice is bekeken door :client', 'notification_invoice_paid' => 'Een betaling voor :amount is gemaakt door klant :client voor Factuur :invoice.', - 'notification_invoice_sent' => 'De volgende klant :client heeft Factuur :invoice voor :amount gemaild gekregen.', - 'notification_invoice_viewed' => 'De volgende klant :client heeft Factuur :invoice voor :amount bekeken.', + 'notification_invoice_sent' => 'Factuur :invoice ter waarde van :amount is per e-mail naar :client verstuurd.', + 'notification_invoice_viewed' => ':client heeft factuur :invoice ter waarde van :amount bekeken.', 'reset_password' => 'U kunt het wachtwoord van uw account resetten door op de volgende link te klikken:', - 'reset_password_footer' => 'Neem a.u.b. contact op met onze helpdesk indien u deze wachtwoordreset niet heeft aangevraagd. Het e-mailadres van de helpdesk is '.CONTACT_EMAIL, - - // Payment page 'secure_payment' => 'Veilige betaling', 'card_number' => 'Kaartnummer', 'expiration_month' => 'Verval maand', 'expiration_year' => 'Verval jaar', 'cvv' => 'CVV', - - // Security alerts - 'security' => [ - 'too_many_attempts' => 'Te veel pogingen. Probeer opnieuw binnen enkele minuten.', - 'wrong_credentials' => 'Verkeerd e-mailadres of wachtwoord.', - 'confirmation' => 'Uw account is bevestigd!', - 'wrong_confirmation' => 'Verkeerde bevestigingscode.', - 'password_forgot' => 'De informatie over uw wachtwoordreset is verzonden naar uw e-mailadres.', - 'password_reset' => 'Uw wachtwoord is succesvol aangepast.', - 'wrong_password_reset' => 'Ongeldig wachtwoord. Probeer opnieuw', - ], - - // Pro Plan - 'pro_plan' => [ - 'remove_logo' => ':link om het InvoiceNinja logo te verwijderen door het pro plan te nemen', - 'remove_logo_link' => 'Klik hier', - ], - 'logout' => 'Afmelden', 'sign_up_to_save' => 'Registreer u om uw werk op te slaan', 'agree_to_terms' => 'Ik accepteer de InvoiceNinja :terms', @@ -306,13 +267,8 @@ return array( 'success_message' => 'U bent succesvol geregistreerd. Ga alstublieft naar de link in de bevestigingsmail om uw e-mailadres te verifiëren.', 'erase_data' => 'Dit zal uw data permanent verwijderen.', 'password' => 'Wachtwoord', - 'invoice_subject' => 'Nieuwe factuur :invoice van :account', - 'close' => 'Sluiten', - 'pro_plan_product' => 'Pro Plan', - 'pro_plan_description' => 'Eén jaar abbonnement op het InvoiceNinja Pro Plan.', 'pro_plan_success' => 'Bedankt voor het aanmelden! Zodra uw factuur betaald is zal uw Pro Plan lidmaatschap beginnen.', - 'unsaved_changes' => 'U hebt niet opgeslagen wijzigingen', 'custom_fields' => 'Aangepaste velden', 'company_fields' => 'Velden Bedrijf', @@ -320,10 +276,8 @@ return array( 'field_label' => 'Label Veld', 'field_value' => 'Waarde Veld', 'edit' => 'Bewerk', - 'view_invoice' => 'Bekijk factuur', + 'set_name' => 'Bedrijfsnaam instellen', 'view_as_recipient' => 'Bekijk als ontvanger', - - // product management 'product_library' => 'Productbibliotheek', 'product' => 'Product', 'products' => 'Producten', @@ -338,18 +292,14 @@ return array( 'created_product' => 'Product Succesvol aangemaakt', 'archived_product' => 'Product Succesvol gearchiveerd', 'pro_plan_custom_fields' => ':link om aangepaste velden in te schakelen door het Pro Plan te nemen', - 'advanced_settings' => 'Geavanceerde instellingen', 'pro_plan_advanced_settings' => ':link om de geavanceerde instellingen te activeren door het Pro Plan te nemen', 'invoice_design' => 'Factuurontwerp', 'specify_colors' => 'Kies kleuren', 'specify_colors_label' => 'Kies de kleuren die in de factuur gebruikt worden', - 'chart_builder' => 'Grafiekbouwer', 'ninja_email_footer' => 'Gebruik :site om uw klanten gratis te factureren en betalingen te ontvangen!', 'go_pro' => 'Go Pro', - - // Quotes 'quote' => 'Offerte', 'quotes' => 'Offertes', 'quote_number' => 'Offertenummer', @@ -359,7 +309,6 @@ return array( 'your_quote' => 'Uw Offerte', 'total' => 'Totaal', 'clone' => 'Kloon', - 'new_quote' => 'Nieuwe offerte', 'create_quote' => 'Maak offerte aan', 'edit_quote' => 'Bewerk offecte', @@ -370,9 +319,8 @@ return array( 'clone_quote' => 'Kloon offerte', 'convert_to_invoice' => 'Zet om naar factuur', 'view_invoice' => 'Bekijk factuur', - 'view_quote' => 'Bekijk offerte', 'view_client' => 'Bekijk klant', - + 'view_quote' => 'Bekijk offerte', 'updated_quote' => 'Offerte succesvol bijgewerkt', 'created_quote' => 'Offerte succesvol aangemaakt', 'cloned_quote' => 'Offerte succesvol gekopieerd', @@ -382,25 +330,20 @@ return array( 'deleted_quote' => 'Offerte succesvol verwijderd', 'deleted_quotes' => ':count offertes succesvol verwijderd', 'converted_to_invoice' => 'Offerte succesvol omgezet naar factuur', - 'quote_subject' => 'Nieuwe offerte van :account', 'quote_message' => 'Om uw offerte voor :amount te bekijken, klik op de link hieronder.', 'quote_link_message' => 'Klik op de link hieronder om de offerte te bekijken:', 'notification_quote_sent_subject' => 'Offerte :invoice is verstuurd naar :client', 'notification_quote_viewed_subject' => 'Offerte :invoice is bekeken door :client', - 'notification_quote_sent' => 'Klant :client heeft offerte :invoice voor :amount per email ontvangen.', + 'notification_quote_sent' => 'Offerte :invoice ter waarde van :amount is per e-mail naar :client verstuurd.', 'notification_quote_viewed' => 'Klant :client heeft offerte :invoice voor :amount bekeken.', - 'auto_convert_quote' => 'Offerte automatisch omzetten in factuur als deze goed gekeurd wordt', - 'session_expired' => 'Uw sessie is verlopen.', - 'invoice_fields' => 'Factuurvelden', 'invoice_options' => 'Factuuropties', 'hide_quantity' => 'Verberg aantallen', 'hide_quantity_help' => 'Als de artikel-aantallen altijd 1 zijn, kunt u uw facturen netter maken door dit veld te verbergen.', 'hide_paid_to_date' => 'Verberg "Reeds betaald"', 'hide_paid_to_date_help' => 'Toon alleen het "Reeds betaald" gebied op je facturen als er een betaling gemaakt is.', - 'charge_taxes' => 'BTW berekenen', 'user_management' => 'Gebruikersbeheer', 'add_user' => 'Nieuwe gebruiker', @@ -415,21 +358,16 @@ return array( 'active' => 'Actief', 'pending' => 'In afwachting', 'deleted_user' => 'Gebruiker succesvol verwijderd', - 'limit_users' => 'Sorry, dit zou de limiet van '.MAX_NUM_USERS.' gebruikers overschrijden', - 'confirm_email_invoice' => 'Weet u zeker dat u deze factuur wilt e-mailen?', 'confirm_email_quote' => 'Weet u zeker dat u deze offerte wilt e-mailen?', 'confirm_recurring_email_invoice' => 'Terugkeren (herhalen) staat aan, weet u zeker dat u deze factuur wilt e-mailen?', - 'cancel_account' => 'Account opzeggen', 'cancel_account_message' => 'Waarschuwing: Dit zal al uw data verwijderen. Er is geen manier om dit ongedaan te maken', 'go_back' => 'Ga Terug', - 'data_visualizations' => 'Datavisualisaties', 'sample_data' => 'Voorbeelddata getoond', 'hide' => 'Verberg', 'new_version_available' => 'Een nieuwe versie van :releases_link is beschikbaar. U gebruikt nu v:user_version, de laatste versie is v:latest_version', - 'invoice_settings' => 'Factuurinstellingen', 'invoice_number_prefix' => 'Factuurnummer voorvoegsel', 'invoice_number_counter' => 'Factuurnummer teller', @@ -439,59 +377,48 @@ return array( 'invoice_issued_to' => 'Factuur uitgegeven aan', 'invalid_counter' => 'Stel een factuurnummervoorvoegsel of offertenummervoorvoegsel in om een mogelijk conflict te voorkomen.', 'mark_sent' => 'Markeer als verzonden', - 'gateway_help_1' => ':link om in te schrijven voor Authorize.net.', 'gateway_help_2' => ':link om in te schrijven voor Authorize.net.', 'gateway_help_17' => ':link om uw PayPal API signature te krijgen.', 'gateway_help_27' => ':link om in te schrijven voor TwoCheckout.', - 'more_designs' => 'Meer ontwerpen', 'more_designs_title' => 'Aanvullende factuurontwerpen', 'more_designs_cloud_header' => 'Neem Pro Plan voor meer factuurontwerpen', 'more_designs_cloud_text' => '', - 'more_designs_self_host_header' => 'Krijg 6 extra factuurontwerpen voor maar $'.INVOICE_DESIGNS_PRICE, 'more_designs_self_host_text' => '', 'buy' => 'Koop', 'bought_designs' => 'Aanvullende factuurontwerpen succesvol toegevoegd', - 'sent' => 'verzonden', + 'vat_number' => 'BTW-nummer', 'timesheets' => 'Timesheets', - 'payment_title' => 'Geef uw betalingsadres en creditcardgegevens op', 'payment_cvv' => '*Dit is de code van 3 of 4 tekens op de achterkant van uw kaart', 'payment_footer1' => '*Betalingsadres moet overeenkomen met het adres dat aan uw kaart gekoppeld is.', 'payment_footer2' => '*Klik alstublieft slechts één keer op "PAY NOW" - verwerking kan tot 1 minuut duren.', - 'vat_number' => 'BTW-nummer', 'id_number' => 'Identificatienummer', - 'white_label_link' => 'White label', 'white_label_header' => 'White label', 'bought_white_label' => 'White label licentie succesvol geactiveerd', 'white_labeled' => 'White labeled', - 'restore' => 'Herstel', 'restore_invoice' => 'Herstel factuur', 'restore_quote' => 'Herstel offerte', 'restore_client' => 'Herstel klant', 'restore_credit' => 'Herstel kredietnota', 'restore_payment' => 'Herstel betaling', - 'restored_invoice' => 'Factuur succesvol hersteld', 'restored_quote' => 'Offerte succesvol hersteld', 'restored_client' => 'Klant succesvol hersteld', 'restored_payment' => 'Betaling succesvol hersteld', 'restored_credit' => 'Kredietnota succesvol hersteld', - 'reason_for_canceling' => 'Help ons om onze site te verbeteren door ons te vertellen waarom u weggaat.', 'discount_percent' => 'Percentage', 'discount_amount' => 'Bedrag', - 'invoice_history' => 'Factuurgeschiedenis', 'quote_history' => 'Offertegeschiedenis', 'current_version' => 'Huidige versie', 'select_version' => 'Selecteer versie', 'view_history' => 'Bekijk geschiedenis', - 'edit_payment' => 'Bewerk betaling', 'updated_payment' => 'Betaling succesvol bijgewerkt', 'deleted' => 'Verwijderd', @@ -504,7 +431,6 @@ return array( 'quote_email' => 'Offerte-e-mail', 'reset_all' => 'Reset alles', 'approve' => 'Goedkeuren', - 'token_billing_type_id' => 'Betalingstoken', 'token_billing_help' => 'Stelt u in staat om creditcard gegevens bij uw gateway op te slaan en ze later te gebruiken.', 'token_billing_1' => 'Inactief', @@ -512,12 +438,11 @@ return array( 'token_billing_3' => 'Opt-out - checkbox is getoond en geselecteerd', 'token_billing_4' => 'Altijd', 'token_billing_checkbox' => 'Sla carditcard gegevens op', - 'view_in_stripe' => 'In Stripe bekijken', - 'use_card_on_file' => 'Gebruik opgeslagen kaart', + 'view_in_gateway' => 'In :gateway bekijken', + 'use_card_on_file' => 'Use Card on File', 'edit_payment_details' => 'Betalingsdetails aanpassen', 'token_billing' => 'Kaartgegevens opslaan', - 'token_billing_secure' => 'Kaartgegevens worden veilig opgeslagen door :stripe_link', - + 'token_billing_secure' => 'Kaartgegevens worden veilig opgeslagen door :link', 'support' => 'Ondersteuning', 'contact_information' => 'Contact informatie', '256_encryption' => '256-bit versleuteling', @@ -527,11 +452,8 @@ return array( 'order_overview' => 'Orderoverzicht', 'match_address' => '*Adres moet overeenkomen met adres van creditcard.', 'click_once' => '*Klik alstublieft maar één keer; het kan een minuut duren om de betaling te verwerken.', - - 'default_invoice_footer' => 'Stel standaard factuurfooter in', 'invoice_footer' => 'Factuurfooter', 'save_as_default_footer' => 'Bewaar als standaardfooter', - 'token_management' => 'Tokenbeheer', 'tokens' => 'Tokens', 'add_token' => 'Voeg token toe', @@ -542,7 +464,6 @@ return array( 'edit_token' => 'Bewerk token', 'delete_token' => 'Verwijder token', 'token' => 'Token', - 'add_gateway' => 'Gateway toevoegen', 'delete_gateway' => 'Gateway verwijderen', 'edit_gateway' => 'Gateway aanpassen', @@ -551,7 +472,6 @@ return array( 'deleted_gateway' => 'Gateway succesvol verwijderd', 'pay_with_paypal' => 'PayPal', 'pay_with_card' => 'Creditcard', - 'change_password' => 'Verander wachtwoord', 'current_password' => 'Huidig wachtwoord', 'new_password' => 'Nieuw wachtwoord', @@ -559,7 +479,6 @@ return array( 'password_error_incorrect' => 'Het huidige wachtwoord is niet juist.', 'password_error_invalid' => 'Het nieuwe wachtwoord is ongeldig.', 'updated_password' => 'Wachtwoord succesvol aangepast', - 'api_tokens' => 'API Tokens', 'users_and_tokens' => 'Gebruikers en tokens', 'account_login' => 'Accountlogin', @@ -571,13 +490,11 @@ return array( 'send_email' => 'Verstuur email', 'set_password' => 'Stel wachtwoord in', 'converted' => 'Omgezet', - 'email_approved' => 'Email mij wanneer een offerte is goedgekeurd', 'notification_quote_approved_subject' => 'Offerte :invoice is goedgekeurd door :client', 'notification_quote_approved' => ':client heeft offerte :invoice goedgekeurd voor :amount.', 'resend_confirmation' => 'Verstuurd bevestingsmail opnieuw', 'confirmation_resent' => 'De bevestigingsmail is opnieuw verstuurd', - 'gateway_help_42' => ':link om te registreren voor BitPay.
    Opmerking: gebruik een Legacy API Key, niet een API token.', 'payment_type_credit_card' => 'Creditcard', 'payment_type_paypal' => 'PayPal', @@ -585,7 +502,6 @@ return array( 'knowledge_base' => 'Kennisbank', 'partial' => 'Gedeeld', 'partial_remaining' => ':partial / :balance', - 'more_fields' => 'Meer velden', 'less_fields' => 'Minder velden', 'client_name' => 'Klantnaam', @@ -596,7 +512,6 @@ return array( 'view_documentation' => 'Bekijk documentatie', 'app_title' => 'Gratis Open-Source Online Facturatie', 'app_description' => 'Invoice Ninja is een gratis, open-source oplossing voor het maken en versturen van facturen aan klanten. Met Invoice Ninja, kun je gemakkelijk mooie facturen maken en verzenden vanaf elk apparaat met internettoegang. Je klanten kunnen je facturen afdrukken, downloaden als pdf bestand en je zelfs online betalen vanuit het systeem.', - 'rows' => 'rijen', 'www' => 'www', 'logo' => 'Logo', @@ -616,7 +531,6 @@ return array( 'zapier' => 'Zapier', 'recurring' => 'Terugkerend', 'last_invoice_sent' => 'Laatste factuur verzonden :date', - 'processed_updates' => 'Update succesvol uitgevoerd', 'tasks' => 'Taken', 'new_task' => 'Nieuwe taak', @@ -662,12 +576,10 @@ return array( 'invoice_labels' => 'Factuurlabels', 'prefix' => 'Voorvoegsel', 'counter' => 'Teller', - 'payment_type_dwolla' => 'Dwolla', 'gateway_help_43' => ':link om in te schrijven voor Dwolla.', 'partial_value' => 'Moet groter zijn dan nul en minder dan het totaal', 'more_actions' => 'Meer acties', - 'pro_plan_title' => 'NINJA PRO', 'pro_plan_call_to_action' => 'Nu upgraden!', 'pro_plan_feature1' => 'Ongelimiteerd klanten aanmaken', @@ -678,14 +590,12 @@ return array( 'pro_plan_feature6' => 'Maak offertes & Pro-forma facturen aan', 'pro_plan_feature7' => 'Pas factuur veld titels & nummering aan', 'pro_plan_feature8' => 'Optie om PDFs toe te voegen aan de emails naar klanten', - 'resume' => 'Doorgaan', 'break_duration' => 'Pauze', 'edit_details' => 'Details aanpassen', 'work' => 'Werk', 'timezone_unset' => ':link om uw tijdszone aan te passen', 'click_here' => 'Klik hier', - 'email_receipt' => 'Mail betalingsbewijs naar de klant', 'created_payment_emailed_client' => 'Betaling succesvol toegevoegd en gemaild naar de klant', 'add_company' => 'Bedrijf toevoegen', @@ -695,10 +605,8 @@ return array( 'unlinked_account' => 'Accounts succesvol losgekoppeld', 'login' => 'Login', 'or' => 'of', - 'email_error' => 'Er was een probleem met versturen van de e-mail', 'confirm_recurring_timing' => 'Opmerking: e-mails worden aan het begin van het uur verzonden.', - 'old_browser' => 'Gebruik a.u.b. een moderne browser', 'payment_terms_help' => 'Stel de standaard factuurvervaldatum in', 'unlink_account' => 'Koppel account los', 'unlink' => 'Koppel los', @@ -719,7 +627,6 @@ return array( 'primary_color' => 'Primaire kleur', 'secondary_color' => 'Secundaire kleur', 'customize_design' => 'Pas ontwerp aan', - 'content' => 'Inhoud', 'styles' => 'Stijlen', 'defaults' => 'Standaardwaarden', @@ -733,17 +640,16 @@ return array( 'outstanding' => 'Uitstaand', 'manage_companies' => 'Beheer bedrijven', 'total_revenue' => 'Totale opbrengst', - 'current_user' => 'Huidige gebruiker', 'new_recurring_invoice' => 'Nieuwe terugkerende factuur', 'recurring_invoice' => 'Terugkerende factuur', + 'recurring_too_soon' => 'Het is te vroeg om de volgende terugkerende factuur aan te maken, dit is gepland voor :date', 'created_by_invoice' => 'Aangemaakt door :invoice', 'primary_user' => 'Primaire gebruiker', 'help' => 'Help', - 'customize_help' => '

    We gebruiken pdfmake om de factuurontwerpen declaratief te definieren. De pdfmake playground is een interessante manier om de library in actie te zien.

    -

    Gebruik puntnotatie om een "dochter eigenschap" te gebruiken. Bijvoorbeeld: om de naam van een klant te tonen gebruik je $client.name.

    -

    Als je ergens hulp bij nodig hebt, stel dan een vraag op ons support forum.

    ', - + 'customize_help' => '

    We use pdfmake to define the invoice designs declaratively. The pdfmake playground provide\'s a great way to see the library in action.

    +

    You can access a child property using dot notation. For example to show the client name you could use $client.name.

    +

    If you need help figuring something out post a question to our support forum with the design you\'re using.

    ', 'invoice_due_date' => 'Vervaldatum', 'quote_due_date' => 'Geldig tot', 'valid_until' => 'Geldig tot', @@ -753,19 +659,15 @@ return array( 'status_draft' => 'Concept', 'status_sent' => 'Verstuurd', 'status_viewed' => 'Bekeken', - 'status_approved' => 'Goedgekeurd', 'status_partial' => 'Gedeeltelijk', 'status_paid' => 'Betaald', 'show_line_item_tax' => 'BTW-tarieven per regel tonen', - 'iframe_url' => 'Website', 'iframe_url_help1' => 'Kopieer de volgende code naar een pagina op uw site.', 'iframe_url_help2' => 'U kunt de functionaliteit testen door te klikken op \'Bekijk als ontvanger\' bij een factuur.', - 'auto_bill' => 'Automatische incasso', 'military_time' => '24-uurs klok', 'last_sent' => 'Laatst verstuurd', - 'reminder_emails' => 'Herinnerings-e-mails', 'templates_and_reminders' => 'Sjablonen en herinneringen', 'subject' => 'Onderwerp', @@ -777,15 +679,12 @@ return array( 'reminder_subject' => 'Herinnering: Factuur :invoice van :account', 'reset' => 'Reset', 'invoice_not_found' => 'De opgevraagde factuur is niet beschikbaar', - 'referral_program' => 'Referral Program', 'referral_code' => 'Referral Code', 'last_sent_on' => 'Laatst verstuurd op :date', - 'page_expire' => 'Deze pagina verloopt binnenkort, :click_here om verder te kunnen werken', 'upcoming_quotes' => 'Eersvolgende offertes', 'expired_quotes' => 'Verlopen offertes', - 'sign_up_using' => 'Meld u aan met', 'invalid_credentials' => 'Deze inloggegevens zijn niet bij ons bekend', 'show_all_options' => 'Alle opties tonen', @@ -794,17 +693,10 @@ return array( 'disable' => 'Uitzetten', 'invoice_quote_number' => 'Factuur- en offertenummers', 'invoice_charges' => 'Facturatiekosten', - - 'invitation_status' => [ - 'sent' => 'E-mail verstuurd', - 'opened' => 'E-mail geopend', - 'viewed' => 'Factuur bekeken', - ], 'notification_invoice_bounced' => 'We konden factuur :invoice niet afleveren bij :contact.', 'notification_invoice_bounced_subject' => 'Factuur :invoice kon niet worden afgeleverd', 'notification_quote_bounced' => 'We konden offerte :invoice niet afleveren bij :contact.', 'notification_quote_bounced_subject' => 'Offerte :invoice kon niet worden afgeleverd', - 'custom_invoice_link' => 'Eigen factuurlink', 'total_invoiced' => 'Totaal gefactureerd', 'open_balance' => 'Openstaand bedrag', @@ -812,15 +704,12 @@ return array( 'basic_settings' => 'Basisinstellingen', 'pro' => 'Pro', 'gateways' => 'Betalingsverwerkers', - 'recurring_too_soon' => 'Het is te vroeg om de volgende terugkerende factuur aan te maken, dit is gepland voor :date', - 'next_send_on' => 'Verstuur volgende: :date', 'no_longer_running' => 'Deze factuur is niet ingepland', 'general_settings' => 'Algemene instellingen', 'customize' => 'Aanpassen', 'oneclick_login_help' => 'Verbind een account om zonder wachtwoord in te kunnen loggen', 'referral_code_help' => 'Verdien geld door onze applicatie online te delen', - 'enable_with_stripe' => 'Aanzetten | Vereist Stripe', 'tax_settings' => 'BTW-instellingen', 'create_tax_rate' => 'Voeg een tarief toe', @@ -841,7 +730,6 @@ return array( 'invoice_counter' => 'Factuurteller', 'quote_counter' => 'Offerteteller', 'type' => 'Type', - 'activity_1' => ':user heeft klant :client aangemaakt', 'activity_2' => ':user heeft klant :client gearchiveerd', 'activity_3' => ':user heeft klant :client verwijderd', @@ -871,18 +759,24 @@ return array( 'activity_27' => ':user heeft betaling :payment hersteld', 'activity_28' => ':user heeft :credit krediet hersteld', 'activity_29' => ':contact heeft offerte :quote goedgekeurd', - + 'activity_30' => ':user heeft leverancier :vendor aangemaakt', + 'activity_31' => ':user heeft leverancier :vendor aangemaakt', + 'activity_32' => ':user heeft leverancier :vendor aangemaakt', + 'activity_33' => ':user heeft leverancier :vendor aangemaakt', + 'activity_34' => ':user heeft uitgave :expense aangemaakt', + 'activity_35' => ':user heeft leverancier :vendor aangemaakt', + 'activity_36' => ':user heeft leverancier :vendor aangemaakt', + 'activity_37' => ':user heeft leverancier :vendor aangemaakt', 'payment' => 'Betaling', 'system' => 'Systeem', 'signature' => 'E-mailhandtekening', 'default_messages' => 'Standaardberichten', 'quote_terms' => 'Offertevoorwaarden', 'default_quote_terms' => 'Standaard offertevoorwaarden', - 'default_invoice_terms' => 'Standaard factuurvoorwaarden', - 'default_invoice_footer' => 'Standaard factuurfooter', + 'default_invoice_terms' => 'Stel standaard factuurvoorwaarden in', + 'default_invoice_footer' => 'Stel standaard factuurfooter in', 'quote_footer' => 'Offertefooter', 'free' => 'Gratis', - 'quote_is_approved' => 'Deze offerte is geaccordeerd', 'apply_credit' => 'Krediet gebruiken', 'system_settings' => 'Systeeminstellingen', @@ -900,7 +794,6 @@ return array( 'restored_recurring_invoice' => 'Terugkerende factuur succesvol hersteld', 'archived' => 'Gearchiveerd', 'untitled_account' => 'Naamloos bedrijf', - 'before' => 'Voor', 'after' => 'Na', 'reset_terms_help' => 'Herstel de standaardvoorwaarden', @@ -909,7 +802,6 @@ return array( 'user' => 'Gebruiker', 'country' => 'Land', 'include' => 'Voeg in', - 'logo_too_large' => 'Je logo is :size groot, voor betere PDF prestaties raden we je aan om een afbeelding kleiner dan 200KB te uploaden.', 'import_freshbooks' => 'Importeren van FreshBooks', 'import_data' => 'Importeer data', @@ -920,16 +812,6 @@ return array( 'task_file' => 'Urenbestand', 'no_mapper' => 'Geen geldige mapping voor bestand', 'invalid_csv_header' => 'Ongeldige CSV kop', - - 'email_errors' => [ - 'inactive_client' => 'E-mails kunnen niet worden verstuurd naar inactieve klanten', - 'inactive_contact' => 'E-mails kunnen niet worden verstuurd naar inactieve contactpersonen', - 'inactive_invoice' => 'E-mails kunnen niet worden verstuurd naar inactieve facturen', - 'user_unregistered' => 'Registreer een account om e-mails te kunnen versturen', - 'user_unconfirmed' => 'Bevestig uw account om e-mails te kunnen versturen', - 'invalid_contact_email' => 'Ongeldig e-mailadres van contactpersoon', - ], - 'client_portal' => 'Klantenportaal', 'admin' => 'Admin', 'disabled' => 'Uitgeschakeld', @@ -938,11 +820,9 @@ return array( 'invoice_will_create' => 'klant zal worden aangemaakt', 'invoices_will_create' => 'factuur zal worden aangemaakt', 'failed_to_import' => 'De volgende regels konden niet worden geïmporteerd, ze bestaan al of missen verplichte velden.', - 'publishable_key' => 'Publishable Key', 'secret_key' => 'Secret Key', 'missing_publishable_key' => 'Set your Stripe publishable key for an improved checkout process', - 'email_design' => 'E-mail Ontwerp', 'due_by' => 'Vervaldatum :date', 'enable_email_markup' => 'Opmaak inschakelen', @@ -954,7 +834,6 @@ return array( 'plain' => 'Platte tekst', 'light' => 'Licht', 'dark' => 'Donker', - 'industry_help' => 'Wordt gebruikt om een vergelijking te kunnen maken met de gemiddelden van andere bedrijven uit dezelfde sector en van dezelfde grootte.', 'subdomain_help' => 'Pas het factuur link subdomein aan of toon de factuur op uw eigen website.', 'invoice_number_help' => 'Kies een voorvoegsel of gebruik een patroon om het factuurnummer dynamisch te genereren.', @@ -963,17 +842,14 @@ return array( 'custom_account_fields_helps' => 'Plaatst een tekstveld op de bedrijven aanmaak-/bewerkpagina en toont het gekozen label op de PDF.', 'custom_invoice_fields_helps' => 'Plaatst een tekstveld op de factuur aanmaak-/bewerkpagina en toont het gekozen label op de PDF.', 'custom_invoice_charges_helps' => 'Plaatst een tekstveld op de factuur aanmaak-/bewerkpagina en verwerkt de facturatiekosten in het subtotaal.', - 'color_help' => 'Opmerking: de primaire kleur wordt ook gebruikt in het klantenportaal en in aangepaste e-mailontwerpen.', - 'token_expired' => 'De validatie token is verlopen. Probeer het opnieuw.', 'invoice_link' => 'Factuur Link', 'button_confirmation_message' => 'Klik om uw e-mailadres te bevestigen.', 'confirm' => 'Bevestigen', 'email_preferences' => 'E-mailvoorkeuren', - 'created_invoices' => ':count facturen succesvol aangemaakt', //TODO: Implement pluralization? + 'created_invoices' => ':count facturen succesvol aangemaakt', 'next_invoice_number' => 'Het volgende factuurnummer is :number.', 'next_quote_number' => 'Het volgende offertenummer is :number.', - 'days_before' => 'dagen voor', 'days_after' => 'dagen na', 'field_due_date' => 'vervaldatum', @@ -981,29 +857,23 @@ return array( 'schedule' => 'Schema', 'email_designs' => 'E-mail Ontwerpen', 'assigned_when_sent' => 'Toegwezen zodra verzonden', - - 'white_label_custom_css' => ':link voor $'.WHITE_LABEL_PRICE.' om eigen opmaak te gebruiken en ons project te ondersteunen.', 'white_label_purchase_link' => 'Koop een whitelabel licentie', - - // Expense / vendor 'expense' => 'Uitgave', 'expenses' => 'Uitgaven', 'new_expense' => 'Nieuwe uitgave', 'enter_expense' => 'Uitgave invoeren', - 'vendors' => 'Verkopers', - 'new_vendor' => 'Nieuwe verkoper', + 'vendors' => 'Leveranciers', + 'new_vendor' => 'Nieuwe leverancier', 'payment_terms_net' => 'Betaaltermijn', - 'vendor' => 'Verkoper', - 'edit_vendor' => 'Bewerk verkoper', - 'archive_vendor' => 'Archiveer verkoper', - 'delete_vendor' => 'Verwijder verkoper', - 'view_vendor' => 'Bekijk verkoper', + 'vendor' => 'Leverancier', + 'edit_vendor' => 'Bewerk leverancier', + 'archive_vendor' => 'Archiveer leverancier', + 'delete_vendor' => 'Verwijder leverancier', + 'view_vendor' => 'Bekijk leverancier', 'deleted_expense' => 'Uitgave succesvol verwijderd', 'archived_expense' => 'Uitgave succesvol gearchiveerd', 'deleted_expenses' => 'Uitgaven succesvol verwijderd', 'archived_expenses' => 'Uitgaven succesvol gearchiveerd', - - // Expenses 'expense_amount' => 'Uitgave bedrag', 'expense_balance' => 'Uitgave saldo', 'expense_date' => 'Uitgave datum', @@ -1028,15 +898,11 @@ return array( 'expense_error_multiple_clients' => 'De uitgaven kunnen niet bij verschillende klanten horen', 'expense_error_invoiced' => 'Uitgave is al gefactureerd', 'convert_currency' => 'Valuta omrekenen', - - // Payment terms 'num_days' => 'Aantal dagen', 'create_payment_term' => 'Betalingstermijn aanmaken', 'edit_payment_terms' => 'Bewerk betalingstermijnen', 'edit_payment_term' => 'Bewerk betalingstermijn', 'archive_payment_term' => 'Archiveer betalingstermijn', - - // recurring due dates 'recurring_due_dates' => 'Vervaldatums van terugkerende facturen', 'recurring_due_date_help' => '

    Stelt automatisch een vervaldatum in voor de factuur.

    Facturen die maandelijks of jaarlijks terugkeren en ingesteld zijn om te vervallen op of voor de datum waarop ze gemaakt zijn zullen de volgende maand vervallen. Facturen die ingesteld zijn te vervallen op de 29e of 30e van een maand die deze dag niet heeft zullen vervallen op de laatste dag van die maand.

    @@ -1061,15 +927,11 @@ return array( 'thursday' => 'Donderdag', 'friday' => 'Vrijdag', 'saturday' => 'Zaterdag', - - // Fonts 'header_font_id' => 'Header lettertype', 'body_font_id' => 'Body lettertype', 'color_font_help' => 'Opmerking: de primaire kleuren en lettertypen wordt ook gebruikt in het klantenportaal en in aangepaste e-mailontwerpen.', - 'live_preview' => 'Live Voorbeeld', 'invalid_mail_config' => 'Kon de e-mail niet verzenden, controleer of de e-mailinstellingen kloppen.', - 'invoice_message_button' => 'Klik op de onderstaande link om uw factuur van :amount te bekijken.', 'quote_message_button' => 'Klik op de onderstaande link om uw offerte van :amount te bekijken.', 'payment_message_button' => 'Bedankt voor uw betaling van :amount.', @@ -1086,7 +948,6 @@ return array( 'archived_bank_account' => 'Bankrekening succesvol gearchiveerd', 'created_bank_account' => 'Bankrekening succesvol toegevoegd', 'validate_bank_account' => 'Bankrekening valideren', - 'bank_accounts_help' => 'Koppel een bankrekening om automatisch uitgaven en leveranciers te importeren. Ondersteund American Express en 400+ banken uit de VS.', 'bank_password_help' => 'Opmerking: uw wachtwoord wordt beveiligd verstuurd en wordt nooit op onze servers opgeslagen.', 'bank_password_warning' => 'Waarschuwing: uw wachtwoord wordt mogelijk als leesbare tekst verzonden, overweeg HTTPS in te schakelen.', 'username' => 'Gebruikersnaam', @@ -1095,12 +956,11 @@ return array( 'bank_account_error' => 'Het ophalen van rekeninggegevens is mislukt, controleer uw inloggegevens.', 'status_approved' => 'Goedgekeurd', 'quote_settings' => 'Offerte instellingen', - 'auto_convert_quote' => 'Offerte automatisch omzetten', + 'auto_convert_quote' => 'Offerte automatisch omzetten in factuur als deze goed gekeurd wordt', 'auto_convert_quote_help' => 'Zet een offerte automatisch om in een factuur zodra deze door een klant wordt goedgekeurd.', 'validate' => 'Valideren', 'info' => 'Informatie', 'imported_expenses' => 'Er zijn succesvol :count_vendors leverancier(s) en :count_expenses uitgaven aangemaakt.', - 'iframe_url_help3' => 'Opmerking: als u van plan bent om creditcard betalingen te accepteren raden wij u dringend aan om HTTPS in te schakelen op uw website.', 'expense_error_multiple_currencies' => 'De uitgaven kunnen geen verschillende munteenheden hebben.', 'expense_error_mismatch_currencies' => 'De munteenheid van de klant komt niet overeen met de munteenheid van de uitgave.', @@ -1121,7 +981,28 @@ return array( 'trial_call_to_action' => 'Start gratis probeerversie', 'trial_success' => 'De gratis twee weken durende probeerversie van het pro plan is succesvol geactiveerd.', 'overdue' => 'Verlopen', - 'white_label_text' => 'Koop een één jaar geldige white label licentie van $'.WHITE_LABEL_PRICE.' om de Invoice Ninja logo\'s in het klantenportaal te verbergen en ons project te ondersteunen.', + + + 'white_label_text' => 'Koop een één jaar geldige white label licentie van $:price om de Invoice Ninja logo\'s in het klantenportaal te verbergen en ons project te ondersteunen.', + 'user_email_footer' => 'Ga alstublieft naar :link om uw e-mail notificatie instellingen aan te passen', + 'reset_password_footer' => 'Neem a.u.b. contact op met onze helpdesk indien u deze wachtwoordreset niet heeft aangevraagd. Het e-mailadres van de helpdesk is :email', + 'limit_users' => 'Sorry, dit zou de limiet van :limit gebruikers overschrijden', + 'more_designs_self_host_header' => 'Krijg 6 extra factuurontwerpen voor maar $:price', + 'old_browser' => 'Gebruik a.u.b. een moderne browser', + 'white_label_custom_css' => ':link voor $:price om eigen opmaak te gebruiken en ons project te ondersteunen.', + 'bank_accounts_help' => 'Koppel een bankrekening om automatisch uitgaven en leveranciers te importeren. Ondersteund American Express en 400+ banken uit de VS.', + + 'pro_plan_remove_logo' => ':link om het InvoiceNinja logo te verwijderen door het pro plan te nemen', + 'pro_plan_remove_logo_link' => 'Klik hier', + 'invitation_status_sent' => 'E-mail verstuurd', + 'invitation_status_opened' => 'E-mail geopend', + 'invitation_status_viewed' => 'Factuur bekeken', + 'email_error_inactive_client' => 'E-mails kunnen niet worden verstuurd naar inactieve klanten', + 'email_error_inactive_contact' => 'E-mails kunnen niet worden verstuurd naar inactieve contactpersonen', + 'email_error_inactive_invoice' => 'E-mails kunnen niet worden verstuurd naar inactieve facturen', + 'email_error_user_unregistered' => 'Registreer een account om e-mails te kunnen versturen', + 'email_error_user_unconfirmed' => 'Bevestig uw account om e-mails te kunnen versturen', + 'email_error_invalid_contact_email' => 'Ongeldig e-mailadres van contactpersoon', 'navigation' => 'Navigatie', 'list_invoices' => 'Toon Facturen', @@ -1144,22 +1025,20 @@ return array( 'custom_invoice_item_fields_help' => 'Voeg een veld toe bij het aanmaken van een factuurregel en toon het label met de waarde op de PDF.', 'recurring_invoice_number' => 'Nummer terugkerende factuur', 'recurring_invoice_number_prefix_help' => 'Kies een voorvoegsel voor het factuurnummer van terugkerende facturen. De standaard is: \'R\'.', - 'enable_client_portal' => 'Dashboard', - 'enable_client_portal_help' => 'Toon/verberg de dashboard pagina in het klantenportaal.', // Client Passwords 'enable_portal_password'=>'Facturen beveiligen met een wachtwoord', 'enable_portal_password_help'=>'Geeft u de mogelijkheid om een wachtwoord in te stellen voor elke contactpersoon. Als er een wachtwoord is ingesteld moet de contactpersoon het wachtwoord invoeren voordat deze facturen kan bekijken.', 'send_portal_password'=>'Wachtwoord automatisch genereren', 'send_portal_password_help'=>'Als er geen wachtwoord is ingesteld zal deze automatisch worden gegenereerd en verzonden bij de eerste factuur.', - + 'expired' => 'Verlopen', 'invalid_card_number' => 'Het creditcardnummer is niet geldig.', 'invalid_expiry' => 'De verloopdatum is niet geldig.', 'invalid_cvv' => 'Het CVV-nummer is niet geldig.', 'cost' => 'Kosten', 'create_invoice_for_sample' => 'Opmerking: maak uw eerste factuur om hier een voorbeeld te zien.', - + // User Permissions 'owner' => 'Eigenaar', 'administrator' => 'Beheerder', @@ -1178,7 +1057,7 @@ return array( 'view_all_help' => 'Gebruiker toestemming geven om regels te bekijken die hij niet heeft gemaakt', 'edit_all_help' => 'Gebruiker toestemming geven om regels te bewerken die hij niet heeft gemaakt', 'view_payment' => 'Betaling bekijken', - + 'january' => 'januari', 'february' => 'februari', 'march' => 'maart', @@ -1193,91 +1072,289 @@ return array( 'december' => 'december', // Documents - 'documents_header' => 'Documents:', - 'email_documents_header' => 'Documents:', - 'email_documents_example_1' => 'Widgets Receipt.pdf', - 'email_documents_example_2' => 'Final Deliverable.zip', - 'invoice_documents' => 'Documents', - 'expense_documents' => 'Attached Documents', - 'invoice_embed_documents' => 'Embed Documents', - 'invoice_embed_documents_help' => 'Include attached images in the invoice.', - 'document_email_attachment' => 'Attach Documents', - 'download_documents' => 'Download Documents (:size)', - 'documents_from_expenses' => 'From Expenses:', - 'dropzone' => array(// See http://www.dropzonejs.com/#config-dictDefaultMessage - 'DefaultMessage' => 'Drop files or click to upload', - 'FallbackMessage' => 'Your browser does not support drag\'n\'drop file uploads.', - 'FallbackText' => 'Please use the fallback form below to upload your files like in the olden days.', - 'FileTooBig' => 'File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.', - 'InvalidFileType' => 'You can\'t upload files of this type.', - 'ResponseError' => 'Server responded with {{statusCode}} code.', - 'CancelUpload' => 'Cancel upload', - 'CancelUploadConfirmation' => 'Are you sure you want to cancel this upload?', - 'RemoveFile' => 'Remove file', - ), - 'documents' => 'Documents', - 'document_date' => 'Document Date', - 'document_size' => 'Size', + 'documents_header' => 'Documenten:', + 'email_documents_header' => 'Documenten:', + 'email_documents_example_1' => 'Widgets Kwitantie.pdf', + 'email_documents_example_2' => 'Definitieve Levering.zip', + 'invoice_documents' => 'Documenten', + 'expense_documents' => 'Bijgevoegde documenten', + 'invoice_embed_documents' => 'Documenten invoegen', + 'invoice_embed_documents_help' => 'Bijgevoegde afbeeldingen weergeven in de factuur.', + 'document_email_attachment' => 'Documenten bijvoegen', + 'download_documents' => 'Documenten downloaden (:size)', + 'documents_from_expenses' => 'Van uitgaven:', + 'dropzone_default_message' => 'Sleep bestanden hierheen of klik om te uploaden', + 'dropzone_fallback_message' => 'Je browser ondersteunt het slepen van bestanden niet.', + 'dropzone_fallback_text' => 'Gebruik de onderstaande optie om je bestanden te uploaden.', + 'dropzone_file_too_big' => 'Het bestand is te groot ({{filesize}}MiB). Maximale grootte: {{maxFilesize}}MiB.', + 'dropzone_invalid_file_type' => 'Je kan geen bestanden van dit type uploaden.', + 'dropzone_response_error' => 'De server gaf foutcode {{statusCode}} terug.', + 'dropzone_cancel_upload' => 'Upload annuleren', + 'dropzone_cancel_upload_confirmation' => 'Weet je zeker dat je deze upload wilt annuleren?', + 'dropzone_remove_file' => 'Bestand verwijderen', + 'documents' => 'Documenten', + 'document_date' => 'Documentdatum', + 'document_size' => 'Grootte', - 'enable_client_portal' => 'Client Portal', - 'enable_client_portal_help' => 'Show/hide the client portal.', + 'enable_client_portal' => 'Dashboard', + 'enable_client_portal_help' => 'Toon/verberg het klantenportaal.', 'enable_client_portal_dashboard' => 'Dashboard', - 'enable_client_portal_dashboard_help' => 'Show/hide the dashboard page in the client portal.', - - // Plans - 'account_management' => 'Account Management', - 'plan_status' => 'Plan Status', - - 'plan_upgrade' => 'Upgrade', - 'plan_change' => 'Change Plan', - 'pending_change_to' => 'Changes To', - 'plan_changes_to' => ':plan on :date', - 'plan_term_changes_to' => ':plan (:term) on :date', - 'cancel_plan_change' => 'Cancel Change', - 'plan' => 'Plan', - 'expires' => 'Expires', - 'renews' => 'Renews', - 'plan_expired' => ':plan Plan Expired', - 'trial_expired' => ':plan Plan Trial Ended', - 'never' => 'Never', - 'plan_free' => 'Free', - 'plan_pro' => 'Pro', - 'plan_enterprise' => 'Enterprise', - 'plan_white_label' => 'Self Hosted (White labeled)', - 'plan_free_self_hosted' => 'Self Hosted (Free)', - 'plan_trial' => 'Trial', - 'plan_term' => 'Term', - 'plan_term_monthly' => 'Monthly', - 'plan_term_yearly' => 'Yearly', - 'plan_term_month' => 'Month', - 'plan_term_year' => 'Year', - 'plan_price_monthly' => '$:price/Month', - 'plan_price_yearly' => '$:price/Year', - 'updated_plan' => 'Updated plan settings', - 'plan_paid' => 'Term Started', - 'plan_started' => 'Plan Started', - 'plan_expires' => 'Plan Expires', - - 'white_label_button' => 'White Label', - - 'pro_plan_year_description' => 'One year enrollment in the Invoice Ninja Pro Plan.', - 'pro_plan_month_description' => 'One month enrollment in the Invoice Ninja Pro Plan.', - 'enterprise_plan_product' => 'Enterprise Plan', - 'enterprise_plan_year_description' => 'One year enrollment in the Invoice Ninja Enterprise Plan.', - 'enterprise_plan_month_description' => 'One month enrollment in the Invoice Ninja Enterprise Plan.', - 'plan_credit_product' => 'Credit', - 'plan_credit_description' => 'Credit for unused time', - 'plan_pending_monthly' => 'Will switch to monthly on :date', - 'plan_refunded' => 'A refund has been issued.', + 'enable_client_portal_dashboard_help' => 'Toon/verberg de dashboard pagina in het klantenportaal.', - 'live_preview' => 'Live Preview', - 'page_size' => 'Page Size', - 'live_preview_disabled' => 'Live preview has been disabled to support selected font', - 'invoice_number_padding' => 'Padding', - 'preview' => 'Preview', - 'list_vendors' => 'List Vendors', - 'add_users_not_supported' => 'Upgrade to the Enterprise plan to add additional users to your account.', - 'enterprise_plan_features' => 'The Enterprise plan adds support for multiple users and file attachments.', - 'return_to_app' => 'Return to app', - -); \ No newline at end of file + // Plans + 'account_management' => 'Accountbeheer', + 'plan_status' => 'Status abonnement', + + 'plan_upgrade' => 'Upgraden', + 'plan_change' => 'Abonnement wijzigen', + 'pending_change_to' => 'Veranderd naar', + 'plan_changes_to' => ':plan op :date', + 'plan_term_changes_to' => ':plan (:term) op :date', + 'cancel_plan_change' => 'Wijziging annuleren', + 'plan' => 'Abonnement', + 'expires' => 'Verloopt', + 'renews' => 'Verlengt', + 'plan_expired' => ':plan abonnement verlopen', + 'trial_expired' => ':plan proefabonnement afgelopen', + 'never' => 'Nooit', + 'plan_free' => 'Gratis', + 'plan_pro' => 'Pro', + 'plan_enterprise' => 'Zakelijk', + 'plan_white_label' => 'Zelf gehost (White label)', + 'plan_free_self_hosted' => 'Zelf gehost (Gratis)', + 'plan_trial' => 'Proefabonnement', + 'plan_term' => 'Duur', + 'plan_term_monthly' => 'Maandelijks', + 'plan_term_yearly' => 'Jaarlijks', + 'plan_term_month' => 'Maand', + 'plan_term_year' => 'Jaar', + 'plan_price_monthly' => '$:price/maand', + 'plan_price_yearly' => '$:price/jaar', + 'updated_plan' => 'Bijgewerkte abonnement instellingen', + 'plan_paid' => 'Termijn gestart', + 'plan_started' => 'Abonnement gestart', + 'plan_expires' => 'Abonnement verloopt', + + 'white_label_button' => 'White Label', + + 'pro_plan_year_description' => 'Jaarabonnement op Invoice Ninja Pro.', + 'pro_plan_month_description' => 'Maandabonnement op Invoice Ninja Pro.', + 'enterprise_plan_product' => 'Zakelijk abonnement', + 'enterprise_plan_year_description' => 'Jaarabonnement op Invoice Ninja zakelijk.', + 'enterprise_plan_month_description' => 'Maandabonnement op Invoice Ninja zakelijk.', + 'plan_credit_product' => 'Krediet', + 'plan_credit_description' => 'Krediet voor ongebruikte tijd', + 'plan_pending_monthly' => 'Zal omgezet wordt in maandelijks op :date', + 'plan_refunded' => 'Een terugbetaling is toegekend.', + + 'live_preview' => 'Live Voorbeeld', + 'page_size' => 'Paginagrootte', + 'live_preview_disabled' => 'Live voorbeeld weergave is uitgeschakeld om het geselecteerde lettertype te ondersteunen.', + 'invoice_number_padding' => 'Marge', + 'preview' => 'Voorbeeld', + 'list_vendors' => 'Toon leveranciers', + 'add_users_not_supported' => 'Upgrade naar het zakelijke abonnement om extra gebruikers toe te voegen aan uw account.', + 'enterprise_plan_features' => 'The Enterprise plan adds support for multiple users and file attachments, :link to see the full list of features.', + 'return_to_app' => 'Terug naar app', + + + // Payment updates + 'refund_payment' => 'Terugbetalen', + 'refund_max' => 'Max:', + 'refund' => 'Terugbetaling', + 'are_you_sure_refund' => 'Geselecteerde betalingen terugbetalen?', + 'status_pending' => 'In afwachting', + 'status_completed' => 'Voltooid', + 'status_failed' => 'Mislukt', + 'status_partially_refunded' => 'Deels terugbetaald', + 'status_partially_refunded_amount' => ':amount terugbetaald', + 'status_refunded' => 'Gecrediteerd', + 'status_voided' => 'Geannuleerd', + 'refunded_payment' => 'Gecrediteerde betaling', + 'activity_39' => ':user heeft een betaling van :payment_amount geannuleerd (:payment)', + 'activity_40' => ':user heeft een bedrag van :adjustment gecrediteerd op :payment_amount (:payment)', + 'card_expiration' => 'Verloopt:', + + 'card_creditcardother' => 'Onbekend', + 'card_americanexpress' => 'American Express', + 'card_carteblanche' => 'Carte Blanche', + 'card_unionpay' => 'UnionPay', + 'card_diners' => 'Diners Club', + 'card_discover' => 'Discover', + 'card_jcb' => 'JCB', + 'card_laser' => 'Laser', + 'card_maestro' => 'Maestro', + 'card_mastercard' => 'MasterCard', + 'card_solo' => 'Solo', + 'card_switch' => 'Switch', + 'card_visacard' => 'Visa', + 'card_ach' => 'ACH', + + 'payment_type_stripe' => 'Stripe', + 'ach' => 'ACH', + 'enable_ach' => 'ACH inschakelen', + 'stripe_ach_help' => 'ACH ondersteuning moet ook ingeschakeld worden bij Stripe.', + 'ach_disabled' => 'Another gateway is already configured for direct debit.', + + 'plaid' => 'Plaid', + 'client_id' => 'Klantnummer', + 'secret' => 'Secret', + 'public_key' => 'Public Key', + 'plaid_optional' => '(optioneel)', + 'plaid_environment_help' => 'Als er een Stripe test key is ingevoerd zal Plaid\'s ontwikkelomgeving (tartan) gebruikt worden.', + 'other_providers' => 'Andere leveranciers', + 'country_not_supported' => 'Dat land wordt niet ondersteund.', + 'invalid_routing_number' => 'Het banknummer is niet juist.', + 'invalid_account_number' => 'Het rekeningnummer is niet juist.', + 'account_number_mismatch' => 'De rekeningnummers komen niet overeen.', + 'missing_account_holder_type' => 'Kies alstublieft een persoonlijke rekening of een bedrijfsrekening.', + 'missing_account_holder_name' => 'Voer alstublieft de rekeninghouder in.', + 'routing_number' => 'Banknummer', + 'confirm_account_number' => 'Bevestig rekeningnummer', + 'individual_account' => 'Persoonlijke rekening', + 'company_account' => 'Bedrijfsrekening', + 'account_holder_name' => 'Rekeninghouder', + 'add_account' => 'Rekening toevoegen', + 'payment_methods' => 'Betalingsmethode', + 'complete_verification' => 'Verificatie voltooien', + 'verification_amount1' => 'Bedrag 1', + 'verification_amount2' => 'Bedrag 2', + 'payment_method_verified' => 'Verificatie succesvol voltooid', + 'verification_failed' => 'Verificatie mislukt', + 'remove_payment_method' => 'Betalingsmethode verwijderen', + 'confirm_remove_payment_method' => 'Weet u zeker dat u deze betalingsmethode wilt verwijderen?', + 'remove' => 'Verwijderen', + 'payment_method_removed' => 'Betalingsmethode verwijderd.', + 'bank_account_verification_help' => 'We hebben twee bedragen met de omschrijving "VERIFICATION" overgeboekt naar uw rekening. Het duurt 1 à 2 werkdagen voordat deze overschrijvingen zichtbaar zijn op uw afschriften. Voer de bedragen hieronder in.', + 'bank_account_verification_next_steps' => 'We hebben twee bedragen met de omschrijving "VERIFICATION" overgeboekt naar uw rekening. Het duurt 1 à 2 werkdagen voordat deze overschrijvingen zichtbaar zijn op uw afschriften. +Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen en klik op "Verificatie voltooien" direct naast de rekening.', + 'unknown_bank' => 'Onbekende bank', + 'ach_verification_delay_help' => 'U kunt de rekening gebruiken na het voltooien van de verificatie. Verificatie duurt doorgaans 1 à 2 werkdagen.', + 'add_credit_card' => 'Creditcard toevoegen', + 'payment_method_added' => 'Betalingsmethode toegevoegd.', + 'use_for_auto_bill' => 'Gebruiken voor Autobill', + 'used_for_auto_bill' => 'Autobill betalingsmethode', + 'payment_method_set_as_default' => 'Autobill betalingsmethode instellen.', + 'activity_41' => 'Betaling van :payment_amount mislukt (:payment)', + 'webhook_url' => 'Webhook URL', + 'stripe_webhook_help' => 'U moet :link.', + 'stripe_webhook_help_link_text' => 'deze URL toevoegen als een endpoint in Stripe', + 'payment_method_error' => 'Er is een fout opgetreden bij het toevoegen van de betalingsmethode. Probeer het later opnieuw.', + 'notification_invoice_payment_failed_subject' => 'Betaling mislukt voor factuur :invoice', + 'notification_invoice_payment_failed' => 'Een betaling van :client voor factuur :invoice is mislukt. De betaling is gemarkeerd als mislukt en het :amount is toegevoegd aan het krediet van de klant.', + 'link_with_plaid' => 'Rekening direct koppelen met Plaid', + 'link_manually' => 'Handmatig koppelen', + 'secured_by_plaid' => 'Beveiligd met Plaid', + 'plaid_linked_status' => 'Uw bankrekening bij :bank', + 'add_payment_method' => 'Betalingsmethode toevoegen', + 'account_holder_type' => 'Type rekeninghouder', + 'ach_authorization' => 'I authorize :company to use my bank account for future payments and, if necessary, electronically credit my account to correct erroneous debits. I understand that I may cancel this authorization at any time by removing the payment method or by contacting :email.', + 'ach_authorization_required' => 'U moet toestemming geven voor ACH overschrijvingen.', + 'off' => 'Uit', + 'opt_in' => 'Meedoen', + 'opt_out' => 'Terugtrekken', + 'always' => 'Altijd', + 'opted_out' => 'Teruggetrokken', + 'opted_in' => 'Meegedaan', + 'manage_auto_bill' => 'Beheer Autobill', + 'enabled' => 'Ingeschakeld', + 'paypal' => 'PayPal', + 'braintree_enable_paypal' => 'PayPal betalingen via BrainTree inschakelen', + 'braintree_paypal_disabled_help' => 'De PayPal gateway verwerkt PayPal betalingen', + 'braintree_paypal_help' => 'U moet ook :link.', + 'braintree_paypal_help_link_text' => 'PayPal koppelen aan uw BrainTree account', + 'token_billing_braintree_paypal' => 'Betalingsgegevens opslaan', + 'add_paypal_account' => 'PayPal rekening toevoegen', + + + 'no_payment_method_specified' => 'Geen betalingsmethode gespecificeerd', + 'chart_type' => 'Grafiektype', + 'format' => 'Formaat', + 'import_ofx' => 'OFX importeren', + 'ofx_file' => 'OFX-bestand', + 'ofx_parse_failed' => 'OFX-bestand kon niet worden verwerkt', + + // WePay + 'wepay' => 'WePay', + 'sign_up_with_wepay' => 'Aanmelden met WePay', + 'use_another_provider' => 'Gebruik een andere leverancier', + 'company_name' => 'Bedrijfsnaam', + 'wepay_company_name_help' => 'Dit wordt zichtbaar op de creditcard afschriften van de klant.', + 'wepay_description_help' => 'De reden van deze account.', + 'wepay_tos_agree' => 'Ik ga akkoord met de :link.', + 'wepay_tos_link_text' => 'WePay servicevoorwaarden', + 'resend_confirmation_email' => 'Bevestigings-e-mail opnieuw versturen', + 'manage_wepay_account' => 'WePay account beheren', + 'action_required' => 'Actie vereist', + 'finish_setup' => 'Installatie voltooien', + 'created_wepay_confirmation_required' => 'Controleer uw e-mail en bevestig uw e-mailadres met WePay.', + 'switch_to_wepay' => 'Overschakelen naar WePay', + 'switch' => 'Overschakelen', + 'restore_account_gateway' => 'Gateway herstellen', + 'restored_account_gateway' => 'Gateway succesvol hersteld', + 'united_states' => 'Verenigde Staten', + 'canada' => 'Canada', + 'accept_debit_cards' => 'Accepteer betaalkaart', + 'debit_cards' => 'Betaalkaarten', + + 'warn_start_date_changed' => 'The next invoice will be sent on the new start date.', + 'original_start_date' => 'Original start date', + 'new_start_date' => 'New start date', + 'security' => 'Security', + 'see_whats_new' => 'See what\'s new in v:version', + 'wait_for_upload' => 'Please wait for the document upload to complete.', + 'upgrade_for_permissions' => 'Upgrade to our Enterprise plan to enable permissions.', + 'enable_second_tax_rate' => 'Enable specifying a second tax rate', + 'payment_file' => 'Payment File', + 'expense_file' => 'Expense File', + 'product_file' => 'Product File', + 'import_products' => 'Import Products', + 'products_will_create' => 'products will be created.', + 'product_key' => 'Product', + 'created_products' => 'Successfully created :count product(s)', + 'export_help' => 'Use JSON if you plan to import the data into Invoice Ninja.', + 'JSON_file' => 'JSON File', + + 'view_dashboard' => 'View Dashboard', + 'client_session_expired' => 'Session Expired', + 'client_session_expired_message' => 'Your session has expired. Please click the link in your email again.', + + 'auto_bill_notification' => 'This invoice will automatically be billed to your :payment_method on file on :due_date.', + 'auto_bill_payment_method_bank_transfer' => 'bank account', + 'auto_bill_payment_method_credit_card' => 'credit card', + 'auto_bill_payment_method_paypal' => 'PayPal account', + 'auto_bill_notification_placeholder' => 'This invoice will automatically be billed to your credit card on file on the due date.', + 'payment_settings' => 'Payment Settings', + + 'on_send_date' => 'On send date', + 'on_due_date' => 'On due date', + 'auto_bill_ach_date_help' => 'ACH auto bill will always happen on the due date', + 'warn_change_auto_bill' => 'Due to NACHA rules, changes to this invoice may prevent ACH auto bill.', + + 'bank_account' => 'Bank Account', + 'payment_processed_through_wepay' => 'ACH payments will be processed using WePay.', + 'wepay_payment_tos_agree' => 'I agree to the WePay :terms and :privacy_policy.', + 'privacy_policy' => 'Privacy Policy', + 'wepay_payment_tos_agree_required' => 'You must agree to the WePay Terms of Service and Privacy Policy.', + 'payment_settings_supported_gateways' => 'These options are supported by the WePay, Stripe, and Braintree gateways.', + 'ach_email_prompt' => 'Please enter your email address:', + 'verification_pending' => 'Verification Pending', + + 'update_font_cache' => 'Please force refresh the page to update the font cache.', + 'more_options' => 'More options', + 'credit_card' => 'Credit Card', + 'bank_transfer' => 'Bank Transfer', + 'no_transaction_reference' => 'We did not recieve a payment transaction reference from the gateway.', + 'use_bank_on_file' => 'Use Bank on File', + 'auto_bill_email_message' => 'This invoice will automatically be billed to the payment method on file on the due date.', + 'bitcoin' => 'Bitcoin', + 'added_on' => 'Added :date', + 'failed_remove_payment_method' => 'Failed to remove the payment method', + 'gateway_exists' => 'This gateway already exists', + 'manual_entry' => 'Manual entry', + +); + +return $LANG; + +?> diff --git a/resources/lang/pl/texts.php b/resources/lang/pl/texts.php index 9b91d00cfd..97eb20ac77 100644 --- a/resources/lang/pl/texts.php +++ b/resources/lang/pl/texts.php @@ -39,11 +39,11 @@ $LANG = array( 'description' => 'Opis', 'unit_cost' => 'Cena jednostkowa', 'quantity' => 'Ilość', - 'line_total' => 'Wartość całkowita', + 'line_total' => 'Suma', 'subtotal' => 'Suma częściowa', 'paid_to_date' => 'Wypłacono do tej pory', 'balance_due' => 'Balance Due', - 'invoice_design_id' => 'Szablon', + 'invoice_design_id' => 'Motyw', 'terms' => 'Warunki', 'your_invoice' => 'Twoja faktura', 'remove_contact' => 'Usuń kontakt', @@ -185,69 +185,69 @@ $LANG = array( 'clients_will_create' => 'klienci będą utworzeni', 'email_settings' => 'Ustawienia e-mail', 'client_view_styling' => 'Client View Styling', - 'pdf_email_attachment' => 'Attach PDFs', + 'pdf_email_attachment' => 'Dodaj PDF', 'custom_css' => 'Custom CSS', - 'import_clients' => 'Import Client Data', - 'csv_file' => 'CSV file', - 'export_clients' => 'Export Client Data', - 'created_client' => 'Successfully created client', + 'import_clients' => 'Importuj dane klienta', + 'csv_file' => 'Plik CSV', + 'export_clients' => 'Eksportuj dane klienta', + 'created_client' => 'Klient został utworzony', 'created_clients' => 'Successfully created :count client(s)', - 'updated_settings' => 'Successfully updated settings', - 'removed_logo' => 'Successfully removed logo', - 'sent_message' => 'Successfully sent message', - 'invoice_error' => 'Please make sure to select a client and correct any errors', + 'updated_settings' => 'Ustawienia zostały zaktualizowane', + 'removed_logo' => 'Logo zostało usunięte', + 'sent_message' => 'Wiadomość została wysłana', + 'invoice_error' => 'Pamiętaj aby wybrać klienta i poprawidź błędy', 'limit_clients' => 'Sorry, this will exceed the limit of :count clients', 'payment_error' => 'There was an error processing your payment. Please try again later.', 'registration_required' => 'Please sign up to email an invoice', - 'confirmation_required' => 'Please confirm your email address', - 'updated_client' => 'Successfully updated client', - 'created_client' => 'Successfully created client', - 'archived_client' => 'Successfully archived client', - 'archived_clients' => 'Successfully archived :count clients', - 'deleted_client' => 'Successfully deleted client', - 'deleted_clients' => 'Successfully deleted :count clients', - 'updated_invoice' => 'Successfully updated invoice', - 'created_invoice' => 'Successfully created invoice', - 'cloned_invoice' => 'Successfully cloned invoice', - 'emailed_invoice' => 'Successfully emailed invoice', - 'and_created_client' => 'and created client', - 'archived_invoice' => 'Successfully archived invoice', - 'archived_invoices' => 'Successfully archived :count invoices', - 'deleted_invoice' => 'Successfully deleted invoice', - 'deleted_invoices' => 'Successfully deleted :count invoices', - 'created_payment' => 'Successfully created payment', - 'created_payments' => 'Successfully created :count payment(s)', - 'archived_payment' => 'Successfully archived payment', - 'archived_payments' => 'Successfully archived :count payments', - 'deleted_payment' => 'Successfully deleted payment', - 'deleted_payments' => 'Successfully deleted :count payments', - 'applied_payment' => 'Successfully applied payment', - 'created_credit' => 'Successfully created credit', - 'archived_credit' => 'Successfully archived credit', - 'archived_credits' => 'Successfully archived :count credits', - 'deleted_credit' => 'Successfully deleted credit', - 'deleted_credits' => 'Successfully deleted :count credits', - 'imported_file' => 'Successfully imported file', - 'updated_vendor' => 'Successfully updated vendor', - 'created_vendor' => 'Successfully created vendor', - 'archived_vendor' => 'Successfully archived vendor', - 'archived_vendors' => 'Successfully archived :count vendors', - 'deleted_vendor' => 'Successfully deleted vendor', - 'deleted_vendors' => 'Successfully deleted :count vendors', - 'confirmation_subject' => 'Invoice Ninja Account Confirmation', - 'confirmation_header' => 'Account Confirmation', + 'confirmation_required' => 'Proszę potwierdzić adres email', + 'updated_client' => 'Klient został zaktualizowany', + 'created_client' => 'Klient został utworzony', + 'archived_client' => 'Klient został zarchiwizowany', + 'archived_clients' => 'Zarchiwizowano :count klientów', + 'deleted_client' => 'Klient został usunięty', + 'deleted_clients' => 'Usunięto :count klientów', + 'updated_invoice' => 'Faktura została zaktualizowana', + 'created_invoice' => 'Faktura została utworzona', + 'cloned_invoice' => 'Faktura została sklonowana', + 'emailed_invoice' => 'Faktura została wysłana', + 'and_created_client' => 'i utworzono klienta', + 'archived_invoice' => 'Faktura została zarchiwizowana', + 'archived_invoices' => 'Zarchiwizowano :count faktury', + 'deleted_invoice' => 'Faktura została usunięta', + 'deleted_invoices' => 'Usunięto :count faktury', + 'created_payment' => 'Płatność została utworzona', + 'created_payments' => 'Utworzono :count płatność/płatności', + 'archived_payment' => 'Płatność zostałą zarchiwizowana', + 'archived_payments' => 'Zarchiwizowano :count płatności', + 'deleted_payment' => 'Płatność została usunięta', + 'deleted_payments' => 'Usunięto :count płatności', + 'applied_payment' => 'Zastosowano płatność', + 'created_credit' => 'Kredyt został utworzony', + 'archived_credit' => 'Kredyt zarchiwizowano', + 'archived_credits' => 'Zarchiwizowano :count kredyty', + 'deleted_credit' => 'Kredyt został usunięty', + 'deleted_credits' => 'Usunięto :count kredyty', + 'imported_file' => 'Plik został zaimportowany', + 'updated_vendor' => 'Zaktualizowano sprzedawcę', + 'created_vendor' => 'Sprzedawca został utworzony', + 'archived_vendor' => 'Sprzedawca został zarchiwizowany', + 'archived_vendors' => 'Zarchiwizowano :count sprzedawców', + 'deleted_vendor' => 'Sprzedawca usunięty', + 'deleted_vendors' => 'Usunięto :count sprzedawców', + 'confirmation_subject' => 'Potwierdzenie konta Invoice Ninja', + 'confirmation_header' => 'Potwierdzenie konta', 'confirmation_message' => 'Please access the link below to confirm your account.', - 'invoice_subject' => 'New invoice :invoice from :account', - 'invoice_message' => 'To view your invoice for :amount, click the link below.', - 'payment_subject' => 'Payment Received', + 'invoice_subject' => 'Nowa faktura :invoice z :account', + 'invoice_message' => 'Aby wyświetlić fakturę za :amount, kliknij link poniżej.', + 'payment_subject' => 'Otrzymano płatność', 'payment_message' => 'Thank you for your payment of :amount.', 'email_salutation' => 'Drogi :name,', 'email_signature' => 'Pozdrowienia,', 'email_from' => 'Zespół The Invoice Ninja', - 'invoice_link_message' => 'To view the invoice click the link below:', - 'notification_invoice_paid_subject' => 'Invoice :invoice was paid by :client', - 'notification_invoice_sent_subject' => 'Invoice :invoice was sent to :client', - 'notification_invoice_viewed_subject' => 'Invoice :invoice was viewed by :client', + 'invoice_link_message' => 'Aby wyświetlić fakturę kliknij link poniżej:', + 'notification_invoice_paid_subject' => 'Faktura :invoice zapłacona przez :client', + 'notification_invoice_sent_subject' => 'Faktura :invoice wysłana do :client', + 'notification_invoice_viewed_subject' => 'Faktura :invoice wyświetlona przez :client', 'notification_invoice_paid' => 'A payment of :amount was made by client :client towards Invoice :invoice.', '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.', @@ -260,14 +260,14 @@ $LANG = array( 'logout' => 'Wyloguj się', 'sign_up_to_save' => 'Sign up to save your work', 'agree_to_terms' => 'I agree to the Invoice Ninja :terms', - 'terms_of_service' => 'Terms of Service', - 'email_taken' => 'The email address is already registered', - 'working' => 'Working', - 'success' => 'Success', + 'terms_of_service' => 'Warunki korzystania z Serwisu', + 'email_taken' => 'Podany adres email już istnieje', + 'working' => 'Pracuję', + 'success' => 'Sukces', '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.', 'password' => 'Hasło', - 'pro_plan_product' => 'Pro Plan', + 'pro_plan_product' => 'Plan Pro', 'pro_plan_success' => 'Thanks for choosing Invoice Ninja\'s Pro plan!

     
    Next Steps

    A payable invoice has been sent to the email address associated with your account. To unlock all of the awesome @@ -282,30 +282,30 @@ $LANG = array( 'field_label' => 'Field Label', 'field_value' => 'Field Value', 'edit' => 'Edytuj', - 'set_name' => 'Set your company name', - 'view_as_recipient' => 'View as recipient', - 'product_library' => 'Product Library', + 'set_name' => 'Ustaw nazwę firmy', + 'view_as_recipient' => 'Wyświetl jako odbiorca', + 'product_library' => 'Biblioteka produktów', 'product' => 'Produkt', 'products' => 'Produkty', - 'fill_products' => 'Auto-fill products', + 'fill_products' => 'Automatycznie uzupełniaj produkty', 'fill_products_help' => 'Selecting a product will automatically fill in the description and cost', - 'update_products' => 'Auto-update products', + 'update_products' => 'Automatycznie aktualizuj produkty', 'update_products_help' => 'Updating an invoice will automatically update the product library', - 'create_product' => 'Add Product', - 'edit_product' => 'Edit Product', - 'archive_product' => 'Archive Product', - 'updated_product' => 'Successfully updated product', - 'created_product' => 'Successfully created product', - 'archived_product' => 'Successfully archived product', + 'create_product' => 'Dodaj produkt', + 'edit_product' => 'Edytuj produkt', + 'archive_product' => 'Zarchiwizuj produkt', + 'updated_product' => 'Produkt został zaktualizowany', + 'created_product' => 'Produkt został utworzony', + 'archived_product' => 'Produkt został zarchiwizowany', 'pro_plan_custom_fields' => ':link to enable custom fields by joining the Pro Plan', - 'advanced_settings' => 'Advanced Settings', + 'advanced_settings' => 'Ustawienia zaawansowane', 'pro_plan_advanced_settings' => ':link to enable the advanced settings by joining the Pro Plan', - 'invoice_design' => 'Invoice Design', - 'specify_colors' => 'Specify colors', - 'specify_colors_label' => 'Select the colors used in the invoice', + 'invoice_design' => 'Motyw faktury', + 'specify_colors' => 'Wybierz kolory', + 'specify_colors_label' => 'Dopasuj kolory użyte w fakturze', 'chart_builder' => 'Chart Builder', 'ninja_email_footer' => 'Use :site to invoice your clients and get paid online for free!', - 'go_pro' => 'Go Pro', + 'go_pro' => 'Wybierz Pro', 'quote' => 'Oferta', 'quotes' => 'Oferty', 'quote_number' => 'Numer oferty', @@ -314,7 +314,7 @@ $LANG = array( 'quote_total' => 'Suma oferty', 'your_quote' => 'Twoja oferta', 'total' => 'Suma', - 'clone' => 'Clone', + 'clone' => 'Klonuj', 'new_quote' => 'Nowa oferta', 'create_quote' => 'Stwórz ofertę', 'edit_quote' => 'Edytuj ofertę', @@ -327,81 +327,81 @@ $LANG = array( 'view_invoice' => 'Zobacz fakturę', 'view_client' => 'Zobacz klienta', 'view_quote' => 'Zobacz ofertę', - 'updated_quote' => 'Successfully updated quote', - 'created_quote' => 'Successfully created quote', - 'cloned_quote' => 'Successfully cloned quote', - 'emailed_quote' => 'Successfully emailed quote', - 'archived_quote' => 'Successfully archived quote', - 'archived_quotes' => 'Successfully archived :count quotes', - 'deleted_quote' => 'Successfully deleted quote', - 'deleted_quotes' => 'Successfully deleted :count quotes', - 'converted_to_invoice' => 'Successfully converted quote to invoice', - 'quote_subject' => 'New quote $quote from :account', + 'updated_quote' => 'Oferta została zaktualizowana', + 'created_quote' => 'Oferta została utworzona', + 'cloned_quote' => 'Oferta została sklonowana', + 'emailed_quote' => 'Oferta została wysłana', + 'archived_quote' => 'Oferta została zarchiwizowana', + 'archived_quotes' => 'Zarchiwizowano :count ofert', + 'deleted_quote' => 'Oferta została usunięta', + 'deleted_quotes' => 'Usunięto :count ofert', + 'converted_to_invoice' => 'Utworzono fakturę z oferty', + 'quote_subject' => 'Nowa oferta $quote z :account', 'quote_message' => 'To view your quote for :amount, click the link below.', 'quote_link_message' => 'To view your client quote click the link below:', 'notification_quote_sent_subject' => 'Quote :invoice was sent to :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_viewed' => 'The following client :client viewed Quote :invoice for :amount.', - 'session_expired' => 'Your session has expired.', - 'invoice_fields' => 'Invoice Fields', - 'invoice_options' => 'Invoice Options', - 'hide_quantity' => 'Hide Quantity', + 'session_expired' => 'Twoja sesja wygasła.', + 'invoice_fields' => 'Pola faktury', + 'invoice_options' => 'Opcje faktury', + 'hide_quantity' => 'Ukryj ilość', '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' => 'Ukryj wypłacono do tej pory', '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', - 'user_management' => 'User Management', - 'add_user' => 'Add User', - 'send_invite' => 'Send invitation', - 'sent_invite' => 'Successfully sent invitation', - 'updated_user' => 'Successfully updated user', - 'invitation_message' => 'You\'ve been invited by :invitor. ', - 'register_to_add_user' => 'Please sign up to add a user', - 'user_state' => 'State', - 'edit_user' => 'Edit User', - 'delete_user' => 'Delete User', - 'active' => 'Active', - 'pending' => 'Pending', - 'deleted_user' => 'Successfully deleted user', - '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_recurring_email_invoice' => 'Are you sure you want this invoice emailed?', - 'cancel_account' => 'Usuń konto', - 'cancel_account_message' => 'Warning: This will permanently erase all of your data, there is no undo.', - 'go_back' => 'Go Back', - 'data_visualizations' => 'Data Visualizations', - 'sample_data' => 'Sample data shown', - 'hide' => 'Hide', + 'user_management' => 'Zarządzaj użytkownikiem', + 'add_user' => 'Dodaj użytkownika', + 'send_invite' => 'Wyślij zaproszenie', + 'sent_invite' => 'Zaproszenie zostało wysłane', + 'updated_user' => 'Użytkownik został zaktualizowany', + 'invitation_message' => 'Zostałeś zaproszony przez :invitor. ', + 'register_to_add_user' => 'Zaloguj się, aby dodać użytkownika', + 'user_state' => 'Stan', + 'edit_user' => 'Edytuj użytkownika', + 'delete_user' => 'Usuń użytkownika', + 'active' => 'Aktywny', + 'pending' => 'Oczekuję', + 'deleted_user' => 'Użytkownik został usunięty', + 'confirm_email_invoice' => 'Czy na pewno chcesz wysłać tą fakturę?', + 'confirm_email_quote' => 'Czy na pewno chcesz wysłać tą ofertę?', + 'confirm_recurring_email_invoice' => 'Czy na pewno chcesz wysłać tą fakturę?', + 'cancel_account' => 'Anuluj konto', + 'cancel_account_message' => 'Ostrzeżenie: Nie można cofnąć tej operacji, wszystkie twoje dane zostaną usunięte.', + 'go_back' => 'cofnij', + 'data_visualizations' => 'Wizualizacje danych', + 'sample_data' => 'Użyto przykładowych danych', + 'hide' => 'Ukryj', '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_number_prefix' => 'Invoice Number Prefix', - 'invoice_number_counter' => 'Invoice Number Counter', - 'quote_number_prefix' => 'Quote Number Prefix', - 'quote_number_counter' => 'Quote Number Counter', + 'invoice_settings' => 'Ustawienia faktury', + 'invoice_number_prefix' => 'Prefiks numeru faktury', + 'invoice_number_counter' => 'Licznik numeru faktury', + 'quote_number_prefix' => 'Prefiks numeru oferty', + 'quote_number_counter' => 'Licznik numeru oferty', 'share_invoice_counter' => 'Share invoice counter', - 'invoice_issued_to' => 'Invoice issued to', + 'invoice_issued_to' => 'Faktura wystawiona dla', 'invalid_counter' => 'To prevent a possible conflict please set either an invoice or quote number prefix', - 'mark_sent' => 'Mark Sent', + 'mark_sent' => 'Oznacz jako wysłane', 'gateway_help_1' => ':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_27' => ':link to sign up for TwoCheckout.', - 'more_designs' => 'More designs', - 'more_designs_title' => 'Additional Invoice Designs', - 'more_designs_cloud_header' => 'Go Pro for more invoice designs', + 'more_designs' => 'Więcej motywów', + 'more_designs_title' => 'Dodatkowe motywy faktur', + 'more_designs_cloud_header' => 'Więcej motywów faktur w wersji PRO', 'more_designs_cloud_text' => '', 'more_designs_self_host_text' => '', - 'buy' => 'Buy', - 'bought_designs' => 'Successfully added additional invoice designs', - 'sent' => 'sent', - 'vat_number' => 'VAT Number', - 'timesheets' => 'Timesheets', + 'buy' => 'Kup', + 'bought_designs' => 'Dodatkowe motywy faktur zostały dodane', + 'sent' => 'wysłane', + 'vat_number' => 'NIP', + 'timesheets' => 'Ewidencja czasu', '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_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.', - 'id_number' => 'ID Number', + 'id_number' => 'Regon', 'white_label_link' => 'White label', 'white_label_header' => 'White Label', 'bought_white_label' => 'Successfully enabled white label license', @@ -426,7 +426,7 @@ $LANG = array( 'select_version' => 'Wybierz wersję', 'view_history' => 'Zobacz historię', 'edit_payment' => 'Edytuj płatność', - 'updated_payment' => 'Successfully updated payment', + 'updated_payment' => 'Płatność została zaktualizowana', 'deleted' => 'Usunięte', 'restore_user' => 'Przywróć użytkownika', 'restored_user' => 'Użytkownik został przywrócony', @@ -443,9 +443,9 @@ $LANG = array( 'token_billing_2' => 'Opt-in - checkbox is shown but not selected', 'token_billing_3' => 'Opt-out - checkbox is shown and selected', 'token_billing_4' => 'Zawsze', - 'token_billing_checkbox' => 'Store credit card details', - 'view_in_stripe' => 'View in Stripe', - 'use_card_on_file' => 'Use card on file', + 'token_billing_checkbox' => 'Zapisz dane karty kredytowej', + 'view_in_gateway' => 'Zobacz w :gateway', + 'use_card_on_file' => 'Use Card on File', 'edit_payment_details' => 'Edit payment details', 'token_billing' => 'Save card details', 'token_billing_secure' => 'The data is stored securely by :stripe_link', @@ -455,20 +455,20 @@ $LANG = array( 'amount_due' => 'Amount due', 'billing_address' => 'Adres billingowy (rozliczeniowy)', 'billing_method' => 'Billing Method', - 'order_overview' => 'Order overview', + 'order_overview' => 'Podgląd zamówienia', '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.', 'invoice_footer' => 'Stopka faktury', - 'save_as_default_footer' => 'Save as default footer', - 'token_management' => 'Token Management', - 'tokens' => 'Tokens', - 'add_token' => 'Add Token', - 'show_deleted_tokens' => 'Show deleted tokens', - 'deleted_token' => 'Successfully deleted token', - 'created_token' => 'Successfully created token', - 'updated_token' => 'Successfully updated token', - 'edit_token' => 'Edit Token', - 'delete_token' => 'Delete Token', + 'save_as_default_footer' => 'Zapisz jako domyślna stopka', + 'token_management' => 'Zarządanie tokenem', + 'tokens' => 'Tokeny', + 'add_token' => 'Dodaj token', + 'show_deleted_tokens' => 'Pokaż usunięte tokeny', + 'deleted_token' => 'Token został usunięty', + 'created_token' => 'Token został utworzony', + 'updated_token' => 'Token został zaktualizowany', + 'edit_token' => 'Edytuj token', + 'delete_token' => 'Usuń token', 'token' => 'Token', 'add_gateway' => 'Add Gateway', 'delete_gateway' => 'Delete Gateway', @@ -482,46 +482,46 @@ $LANG = array( 'current_password' => 'Aktualne hasło', 'new_password' => 'Nowe hasło', 'confirm_password' => 'Potwierdź hasło', - 'password_error_incorrect' => 'The current password is incorrect.', - 'password_error_invalid' => 'The new password is invalid.', - 'updated_password' => 'Successfully updated password', - 'api_tokens' => 'API Tokens', - 'users_and_tokens' => 'Users & Tokens', + 'password_error_incorrect' => 'Hasło jest nieprawidłowe.', + 'password_error_invalid' => 'Nowe hasło jest nieprawidłowe.', + 'updated_password' => 'Hasło zostało zaktualizowane', + 'api_tokens' => 'Tokeny API', + 'users_and_tokens' => 'Użytkownicy i tokeny', 'account_login' => 'Account Login', - 'recover_password' => 'Recover your password', - 'forgot_password' => 'Forgot your password?', - 'email_address' => 'Email address', - 'lets_go' => 'Let\'s go', - 'password_recovery' => 'Password Recovery', + 'recover_password' => 'Przywróć swoje hasło', + 'forgot_password' => 'Zapomniałeś hasło?', + 'email_address' => 'Adres email', + 'lets_go' => 'Zaczynamy', + 'password_recovery' => 'Przywracanie hasła', 'send_email' => 'Wyślij email', 'set_password' => 'Ustaw hasło', - 'converted' => 'Converted', - 'email_approved' => 'Email me when a quote is approved', - 'notification_quote_approved_subject' => 'Quote :invoice was approved by :client', - 'notification_quote_approved' => 'The following client :client approved Quote :invoice for :amount.', - 'resend_confirmation' => 'Resend confirmation email', - 'confirmation_resent' => 'The confirmation email was resent', + 'converted' => 'Skonwertowano', + 'email_approved' => 'Wyślij email kiedy oferta będzie zatwierdzona', + 'notification_quote_approved_subject' => 'Oferta :invoice została zatwierdzona przez :client', + 'notification_quote_approved' => 'Klient :client zatwierdził ofertę :invoice na kwotę :amount.', + 'resend_confirmation' => 'Wyślij ponownie email potwierdzający', + 'confirmation_resent' => 'Email potwierdzający został wysłany', 'gateway_help_42' => ':link to sign up for BitPay.
    Note: use a Legacy API Key, not an API token.', 'payment_type_credit_card' => 'Karta kredytowa', 'payment_type_paypal' => 'PayPal', 'payment_type_bitcoin' => 'Bitcoin', 'knowledge_base' => 'Baza wiedzy', - 'partial' => 'Partial', - 'partial_remaining' => ':partial of :balance', - 'more_fields' => 'More Fields', - 'less_fields' => 'Less Fields', + 'partial' => 'Zaliczka', + 'partial_remaining' => ':partial z :balance', + 'more_fields' => 'Więcej pól', + 'less_fields' => 'Mniej pól', 'client_name' => 'Nazwa klienta', 'pdf_settings' => 'Ustawienia PDF', 'product_settings' => 'Ustawienia produktu', - 'auto_wrap' => 'Auto Line Wrap', + 'auto_wrap' => 'Zawijaj wiersze', 'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.', - 'view_documentation' => 'View Documentation', + 'view_documentation' => 'Zobacz dokumentację', '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.', 'rows' => 'wierszy', 'www' => 'www', 'logo' => 'Logo', - 'subdomain' => 'Subdomain', + 'subdomain' => 'subdomeny', 'provide_name_or_email' => 'Proszę podać imię i nazwisko lub adres e-mail', 'charts_and_reports' => 'Raporty i wykresy', 'chart' => 'Wykres', @@ -580,8 +580,8 @@ $LANG = array( 'stopped_task' => 'Successfully stopped task', 'invoice_task' => 'Invoice Task', 'invoice_labels' => 'Invoice Labels', - 'prefix' => 'Prefix', - 'counter' => 'Counter', + 'prefix' => 'Prefiks', + 'counter' => 'Licznik', 'payment_type_dwolla' => 'Dwolla', 'gateway_help_43' => ':link to sign up for Dwolla', 'partial_value' => 'Must be greater than zero and less than the total', @@ -596,10 +596,10 @@ $LANG = array( 'pro_plan_feature6' => 'Create Quotes & Pro-forma Invoices', 'pro_plan_feature7' => 'Customize Invoice Field Titles & Numbering', 'pro_plan_feature8' => 'Option to Attach PDFs to Client Emails', - 'resume' => 'Resume', - 'break_duration' => 'Break', - 'edit_details' => 'Edit Details', - 'work' => 'Work', + 'resume' => 'wznów', + 'break_duration' => 'zatrzymaj', + 'edit_details' => 'Edytuj szczegóły', + 'work' => 'Praca', 'timezone_unset' => 'Please :link to set your timezone', 'click_here' => 'click here', 'email_receipt' => 'Wyślij potwierdzenie zapłaty do klienta', @@ -620,31 +620,31 @@ $LANG = array( 'show_address_help' => 'Require client to provide their billing address', 'update_address' => 'Update Address', 'update_address_help' => 'Update client\'s address with provided details', - 'times' => 'krotnie', + 'times' => 'okres', 'set_now' => 'Ustaw na teraz', 'dark_mode' => 'Tryb ciemny', 'dark_mode_help' => 'Show white text on black background', - 'add_to_invoice' => 'Add to invoice :invoice', - 'create_new_invoice' => 'Create new invoice', + 'add_to_invoice' => 'Dodaj do faktury :invoice', + 'create_new_invoice' => 'Utwórz nową fakturę', 'task_errors' => 'Please correct any overlapping times', - 'from' => 'From', - 'to' => 'To', - 'font_size' => 'Font Size', - 'primary_color' => 'Primary Color', - 'secondary_color' => 'Secondary Color', - 'customize_design' => 'Customize Design', - 'content' => 'Content', - 'styles' => 'Styles', - 'defaults' => 'Defaults', - 'margins' => 'Margins', - 'header' => 'Header', - 'footer' => 'Footer', + 'from' => 'Od', + 'to' => 'Do', + 'font_size' => 'Rozmiar czcionki', + 'primary_color' => 'Główny kolor', + 'secondary_color' => 'Wtórny kolor', + 'customize_design' => 'Dostosuj motyw', + 'content' => 'Zawartość', + 'styles' => 'Style', + 'defaults' => 'Domyślne', + 'margins' => 'Marginesy', + 'header' => 'Nagłówek', + 'footer' => 'Stopka', 'custom' => 'Custom', 'invoice_to' => 'Invoice to', 'invoice_no' => 'Invoice No.', 'recent_payments' => 'Ostatnie płatności', 'outstanding' => 'Zaległe', - 'manage_companies' => 'Manage Companies', + 'manage_companies' => 'Zarządzaj kampaniami', 'total_revenue' => 'Całkowity dochód', 'current_user' => 'Aktualny użytkownik', 'new_recurring_invoice' => 'Nowa faktura okresowa', @@ -654,21 +654,21 @@ $LANG = array( 'primary_user' => 'Główny Użytkownik', 'help' => 'Pomoc', 'customize_help' => '

    We use pdfmake to define the invoice designs declaratively. The pdfmake playground provide\'s a great way to see the library in action.

    -

    To access a child property using dot notation. For example to show the client name you could use $client.name.

    -

    If you need help figuring something out post a question to our support forum.

    ', +

    You can access a child property using dot notation. For example to show the client name you could use $client.name.

    +

    If you need help figuring something out post a question to our support forum with the design you\'re using.

    ', 'invoice_due_date' => 'Termin', - 'quote_due_date' => 'Valid Until', - 'valid_until' => 'Valid Until', + 'quote_due_date' => 'Ważny do', + 'valid_until' => 'Ważny do', 'reset_terms' => 'Resetuj warunki', 'reset_footer' => 'Resetuj stópkę', 'invoices_sent' => ':count faktura wysłana|:count faktury wysłane', 'status_draft' => 'Wersja robocza', 'status_sent' => 'Wysłane', 'status_viewed' => 'Przeglądnięte', - 'status_partial' => 'Częściowo', + 'status_partial' => 'Zaliczka', 'status_paid' => 'Zapłacone', 'show_line_item_tax' => 'Wyświetl podatki pozycji w tej samej linii', - 'iframe_url' => 'Website', + 'iframe_url' => 'Strona internetowa', '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.', 'auto_bill' => 'Automatyczny Rachunek', @@ -710,10 +710,10 @@ $LANG = array( 'basic_settings' => 'Ustawienia podstawowe', 'pro' => 'Pro', 'gateways' => 'Payment Gateways', - 'next_send_on' => 'Send Next: :date', + 'next_send_on' => 'Wyślij ponownie: :date', 'no_longer_running' => 'This invoice is not scheduled to run', - 'general_settings' => 'General Settings', - 'customize' => 'Customize', + 'general_settings' => 'Ustawienia ogólne', + 'customize' => 'Dostosuj', 'oneclick_login_help' => 'Connect an account to login without a password', 'referral_code_help' => 'Earn money by sharing our app online', 'enable_with_stripe' => 'Aktywuj | Wymaga Stripe', @@ -721,21 +721,21 @@ $LANG = array( 'create_tax_rate' => 'Dodaj stawkę podatkową', 'updated_tax_rate' => 'Successfully updated tax rate', 'created_tax_rate' => 'Successfully created tax rate', - 'edit_tax_rate' => 'Edit tax rate', - 'archive_tax_rate' => 'Archive Tax Rate', - 'archived_tax_rate' => 'Successfully archived the tax rate', + 'edit_tax_rate' => 'Edytuj stawkę podatkową', + 'archive_tax_rate' => 'Archiwizuj stawkę podatkową', + 'archived_tax_rate' => 'Zarchiwizowano stawkę podatkową', 'default_tax_rate_id' => 'Domyśłna stawka podatkowa', 'tax_rate' => 'Stawka podatkowa', 'recurring_hour' => 'Okresowa godzina', - 'pattern' => 'Pattern', - 'pattern_help_title' => 'Pattern Help', + 'pattern' => 'Wzór', + 'pattern_help_title' => 'Wzór pomoc', 'pattern_help_1' => 'Create custom invoice and quote numbers by specifying a pattern', - 'pattern_help_2' => 'Available variables:', - 'pattern_help_3' => 'For example, :example would be converted to :value', - 'see_options' => 'See options', - 'invoice_counter' => 'Invoice Counter', - 'quote_counter' => 'Quote Counter', - 'type' => 'Type', + 'pattern_help_2' => 'Dostępne zmienne:', + 'pattern_help_3' => 'Na przykład, :example będzie skonwertowane do :value', + 'see_options' => 'Zobacz opcje', + 'invoice_counter' => 'Licznik faktur', + 'quote_counter' => 'Licznik ofert', + 'type' => 'Typ', 'activity_1' => ':user created client :client', 'activity_2' => ':user archived client :client', 'activity_3' => ':user deleted client :client', @@ -782,14 +782,14 @@ $LANG = array( 'default_invoice_terms' => 'Domyślne warunki faktury', 'default_invoice_footer' => 'Domyślna stopka faktury', 'quote_footer' => 'Quote Footer', - 'free' => 'Free', + 'free' => 'Darmowe', 'quote_is_approved' => 'This quote is approved', - 'apply_credit' => 'Apply Credit', - 'system_settings' => 'System Settings', - 'archive_token' => 'Archive Token', - 'archived_token' => 'Successfully archived token', - 'archive_user' => 'Archive User', - 'archived_user' => 'Successfully archived user', + 'apply_credit' => 'Zastosuj kredyt', + 'system_settings' => 'Ustawienia systemowe', + 'archive_token' => 'Archiwizuj token', + 'archived_token' => 'Token został zarchiwizowany', + 'archive_user' => 'Archiwizuj użytkownika', + 'archived_user' => 'Użytkownik został zarchiwizowany', 'archive_account_gateway' => 'Archive Gateway', 'archived_account_gateway' => 'Successfully archived gateway', 'archive_recurring_invoice' => 'Archiwizuj okresową fakturę', @@ -807,39 +807,39 @@ $LANG = array( 'export_data' => 'Exportuj dane', 'user' => 'Użytkownik', 'country' => 'Kraj', - 'include' => 'Include', + 'include' => 'Dołącz', '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_data' => 'Import Data', + 'import_data' => 'Importuj dane', 'source' => 'Źródło', 'csv' => 'CSV', 'client_file' => 'Plik klienta', 'invoice_file' => 'Plik faktury', 'task_file' => 'Plik zadania', 'no_mapper' => 'No valid mapping for file', - 'invalid_csv_header' => 'Invalid CSV Header', + 'invalid_csv_header' => 'Nieprawidłowy nagłówek CSV', 'client_portal' => 'Portal klienta', 'admin' => 'Administrator', 'disabled' => 'Wyłączony', 'show_archived_users' => 'Pokaż zarchiwizowanych użytkowników', 'notes' => 'Notatki', - 'invoice_will_create' => 'client will be created', - 'invoices_will_create' => 'invoices will be created', + 'invoice_will_create' => 'klient zostanie utworzony', + 'invoices_will_create' => 'faktury zostaną utworzone', 'failed_to_import' => 'The following records failed to import, they either already exist or are missing required fields.', 'publishable_key' => 'Publishable Key', 'secret_key' => 'Sekretny klucz', 'missing_publishable_key' => 'Set your Stripe publishable key for an improved checkout process', - 'email_design' => 'Email Design', + 'email_design' => 'Motyw email', 'due_by' => 'Płatny do :date', - 'enable_email_markup' => 'Enable Markup', + 'enable_email_markup' => 'Aktywuj Markup', 'enable_email_markup_help' => 'Make it easier for your clients to pay you by adding schema.org markup to your emails.', - 'template_help_title' => 'Templates Help', - 'template_help_1' => 'Available variables:', - 'email_design_id' => 'Email Style', + 'template_help_title' => 'Szablony Pomoc', + 'template_help_1' => 'Dostępne zmienne:', + 'email_design_id' => 'Motyw email', 'email_design_help' => 'Make your emails look more professional with HTML layouts', - 'plain' => 'Plain', - 'light' => 'Light', - 'dark' => 'Dark', + 'plain' => 'Zwykły', + 'light' => 'Jasny', + 'dark' => 'Ciemny', '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.', 'invoice_number_help' => 'Specify a prefix or use a custom pattern to dynamically set the invoice number.', @@ -849,61 +849,61 @@ $LANG = array( 'custom_invoice_fields_helps' => 'Add a field when creating an invoice and display the label and value on the PDF.', 'custom_invoice_charges_helps' => 'Add a field when creating an invoice and include the charge in the invoice subtotals.', 'token_expired' => 'Validation token was expired. Please try again.', - 'invoice_link' => 'Invoice Link', + 'invoice_link' => 'Link faktury', 'button_confirmation_message' => 'Click to confirm your email address.', - 'confirm' => 'Confirm', - 'email_preferences' => 'Email Preferences', + 'confirm' => 'Potwierdź', + 'email_preferences' => 'Preferencje email', 'created_invoices' => 'Successfully created :count invoice(s)', - 'next_invoice_number' => 'The next invoice number is :number.', - 'next_quote_number' => 'The next quote number is :number.', - 'days_before' => 'days before', - 'days_after' => 'days after', + 'next_invoice_number' => 'Następny numer faktury jest :number.', + 'next_quote_number' => 'Następny numer oferty jest :number.', + 'days_before' => 'dni przed', + 'days_after' => 'dni po', 'field_due_date' => 'termin', - 'field_invoice_date' => 'invoice date', - 'schedule' => 'Schedule', - 'email_designs' => 'Email Designs', + 'field_invoice_date' => 'data faktury', + 'schedule' => 'Zaplanuj', + 'email_designs' => 'Motyw email', 'assigned_when_sent' => 'Assigned when sent', 'white_label_purchase_link' => 'Purchase a white label license', 'expense' => 'Wydatek', 'expenses' => 'Wydatki', 'new_expense' => 'Nowy wydatek', 'enter_expense' => 'Dodaj wydatek', - 'vendors' => 'Vendors', - 'new_vendor' => 'New Vendor', + 'vendors' => 'Sprzedawcy', + 'new_vendor' => 'Nowy sprzedawca', 'payment_terms_net' => 'Net', - 'vendor' => 'Vendor', - 'edit_vendor' => 'Edit Vendor', - 'archive_vendor' => 'Archive Vendor', - 'delete_vendor' => 'Delete Vendor', - 'view_vendor' => 'View Vendor', - 'deleted_expense' => 'Successfully deleted expense', - 'archived_expense' => 'Successfully archived expense', - 'deleted_expenses' => 'Successfully deleted expenses', - 'archived_expenses' => 'Successfully archived expenses', - 'expense_amount' => 'Expense Amount', - 'expense_balance' => 'Expense Balance', - 'expense_date' => 'Expense Date', - 'expense_should_be_invoiced' => 'Should this expense be invoiced?', - 'public_notes' => 'Public Notes', - 'invoice_amount' => 'Invoice Amount', - 'exchange_rate' => 'Exchange Rate', - 'yes' => 'Yes', - 'no' => 'No', - 'should_be_invoiced' => 'Should be invoiced', - 'view_expense' => 'View expense # :expense', - 'edit_expense' => 'Edit Expense', - 'archive_expense' => 'Archive Expense', - 'delete_expense' => 'Delete Expense', - 'view_expense_num' => 'Expense # :expense', - 'updated_expense' => 'Successfully updated expense', - 'created_expense' => 'Successfully created expense', + 'vendor' => 'Sprzedawca', + 'edit_vendor' => 'Edytuj sprzedawcę', + 'archive_vendor' => 'Archiwizuj sprzedawcę', + 'delete_vendor' => 'Usuń sprzedawcę', + 'view_vendor' => 'Zobacz sprzedawcę', + 'deleted_expense' => 'Wydatki zostały usunięte', + 'archived_expense' => 'Wydatki zostały zarchiwizowane', + 'deleted_expenses' => 'Wydatki zostały usunięte', + 'archived_expenses' => 'Wydatki zostały zarchiwizowane', + 'expense_amount' => 'Wartość wydatków', + 'expense_balance' => 'Saldo wydatków', + 'expense_date' => 'Data obciążenia', + 'expense_should_be_invoiced' => 'Utwórz fakturę dla poniesionego kosztu?', + 'public_notes' => 'Notatki publiczne', + 'invoice_amount' => 'Kwota faktury', + 'exchange_rate' => 'Kurs wymiany', + 'yes' => 'Tak', + 'no' => 'Nie', + 'should_be_invoiced' => 'Utwórz fakturę', + 'view_expense' => 'Zobacz wydatek # :expense', + 'edit_expense' => 'Edytuj wydatek', + 'archive_expense' => 'Archiwizuj wydatek', + 'delete_expense' => 'Usuń wydatek', + 'view_expense_num' => 'Wydatek # :expense', + 'updated_expense' => 'Wydatek został zaktualizowany', + 'created_expense' => 'Wydatek został utworzony', 'enter_expense' => 'Dodaj wydatek', - 'view' => 'View', + 'view' => 'Podgląd', 'restore_expense' => 'Przywróć wydatek', 'invoice_expense' => 'Faktura na wydatek', - 'expense_error_multiple_clients' => 'The expenses can\'t belong to different clients', - 'expense_error_invoiced' => 'Expense has already been invoiced', - 'convert_currency' => 'Konwersja waluty', + 'expense_error_multiple_clients' => 'Wydatek nie może należeć do innych klientów', + 'expense_error_invoiced' => 'Faktura do wydatku została już utworzona', + 'convert_currency' => 'Konwertuj walutę', 'num_days' => 'Liczba dni', 'create_payment_term' => 'Utwórz warunki płatności', 'edit_payment_terms' => 'Edytuj warunki płatności', @@ -913,7 +913,7 @@ $LANG = array( 'recurring_due_date_help' => '

    Automatycznie ustawia termin faktury.

    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.

    Invoices on a weekly cycle set to be due on the day of the week they are created will be due the next week.

    -

    For example:

    +

    Na przykład:

    • Today is the 15th, due date is 1st of the month. The due date should likely be the 1st of the next month.
    • Today is the 15th, due date is the last day of the month. The due date will be the last day of the this month. @@ -927,7 +927,7 @@ $LANG = array( 'next_due_on' => 'Następna opłata: :date', 'use_client_terms' => 'Use client terms', 'day_of_month' => ':ordinal day of month', - 'last_day_of_month' => 'Last day of month', + 'last_day_of_month' => 'Ostatni dzień miesiąca', 'day_of_week_after' => ':ordinal :day after', 'sunday' => 'Niedziela', 'monday' => 'Poniedziałek', @@ -992,40 +992,26 @@ $LANG = array( 'overdue' => 'Zaległy', - 'white_label_text' => 'Kup white label licencję na JEDEN ROK za $'.WHITE_LABEL_PRICE.' aby usunąć z portalu klienta logo Invoice Ninja i wesprzeć nasz projekt.', - 'user_email_footer' => 'Aby dostosować ustawienia powiadomień email, zobacz '.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' => 'Kup 6 szablonów faktur za jedyne $'.INVOICE_DESIGNS_PRICE, - 'old_browser' => 'Proszę użyć nowszej przeglądarki', - '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 400+ US banks.', - 'security' => [ - 'too_many_attempts' => 'Zbyt wiele prób. Spróbuj ponownie za kilka minut.', - 'wrong_credentials' => 'Nieprawidłowy e-mail lub hasło.', - 'confirmation' => 'Twoje konto zostało potwierdzone!', - 'wrong_confirmation' => 'Błędny kod potwierdzający.', - 'password_forgot' => 'Informacje dotyczące resetowania hasła zostały wysłane na Twój adres e-mail.', - 'password_reset' => 'Twoje hasło zostało zmienione.', - 'wrong_password_reset' => 'Nieprawidłowe hasło. Spróbuj ponownie', - ], - 'pro_plan' => [ - 'remove_logo' => ':link to remove the Invoice Ninja logo by joining the Pro Plan', - 'remove_logo_link' => 'Kliknij tutaj', - ], - 'invitation_status' => [ - 'sent' => 'E-mail wysłany', - 'opened' => 'Email otwarty', - 'viewed' => 'Przeglądana faktura', - ], - 'email_errors' => [ - 'inactive_client' => 'E-maile nie mogą być wysyłane do klientów nieaktywnych', - 'inactive_contact' => 'E-mail nie może zostać wysłany do nieaktywnych kontaktów', - 'inactive_invoice' => 'E-mail nie może zostać wysłany do nieaktywnych faktur', - 'user_unregistered' => 'Proszę zarejestrować swoje konto, aby wysyłać e-maile', - 'user_unconfirmed' => 'Proszę potwierdzić swoje konto do wysyłania e-maili', - 'invalid_contact_email' => 'Nieprawidłowy e-mail kontaktowy', - ], + 'white_label_text' => 'Kup white label licencję na JEDEN ROK za $:price aby usunąć z portalu klienta logo Invoice Ninja i wesprzeć nasz projekt.', + 'user_email_footer' => 'Aby dostosować ustawienia powiadomień email, zobacz :link', + 'reset_password_footer' => 'If you did not request this password reset please email our support: :email', + 'limit_users' => 'Sorry, this will exceed the limit of :limit users', + 'more_designs_self_host_header' => 'Kup 6 szablonów faktur za jedyne $:price', + 'old_browser' => 'Proszę użyć nowszej przeglądarki', + 'white_label_custom_css' => ':link for $: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 400+ US banks.', + + 'pro_plan_remove_logo' => ':link to remove the Invoice Ninja logo by joining the Pro Plan', + 'pro_plan_remove_logo_link' => 'Kliknij tutaj', + 'invitation_status_sent' => 'E-mail wysłany', + 'invitation_status_opened' => 'Email otwarty', + 'invitation_status_viewed' => 'Przeglądana faktura', + 'email_error_inactive_client' => 'E-maile nie mogą być wysyłane do klientów nieaktywnych', + 'email_error_inactive_contact' => 'E-mail nie może zostać wysłany do nieaktywnych kontaktów', + 'email_error_inactive_invoice' => 'E-mail nie może zostać wysłany do nieaktywnych faktur', + 'email_error_user_unregistered' => 'Proszę zarejestrować swoje konto, aby wysyłać e-maile', + 'email_error_user_unconfirmed' => 'Proszę potwierdzić swoje konto do wysyłania e-maili', + 'email_error_invalid_contact_email' => 'Nieprawidłowy e-mail kontaktowy', 'navigation' => 'Nawigacja', 'list_invoices' => 'Lista faktur', @@ -1054,14 +1040,14 @@ $LANG = array( 'enable_portal_password_help'=>'Allows you to set a password for each contact. If a password is set, the contact will be required to enter a password before viewing invoices.', 'send_portal_password'=>'Generate password automatically', 'send_portal_password_help'=>'If no password is set, one will be generated and sent with the first invoice.', - + 'expired' => 'Wygasło', 'invalid_card_number' => 'Numer karty kredytowej jest nieprawidłowy.', 'invalid_expiry' => 'Data ważności jest nieprawidłowa.', 'invalid_cvv' => 'Kod CVV jest nieprawidłowy.', 'cost' => 'Koszt', 'create_invoice_for_sample' => 'Notatka: aby zobaczyć podgląd, utwórz fakturę.', - + // User Permissions 'owner' => 'Właściciel', 'administrator' => 'Administrator', @@ -1071,16 +1057,16 @@ $LANG = array( 'user_edit_all' => 'Edit all clients, invoices, etc.', 'gateway_help_20' => ':link to sign up for Sage Pay.', 'gateway_help_21' => ':link to sign up for Sage Pay.', - 'partial_due' => 'Partial Due', - 'restore_vendor' => 'Restore Vendor', - 'restored_vendor' => 'Successfully restored vendor', - 'restored_expense' => 'Successfully restored expense', - 'permissions' => 'Permissions', - 'create_all_help' => 'Allow user to create and modify records', + 'partial_due' => 'Zaliczka', + 'restore_vendor' => 'Przywróć sprzedawcę', + 'restored_vendor' => 'Sprzedawca został przywrócony', + 'restored_expense' => 'Wydatek został przywrócony', + 'permissions' => 'Uprawnienia', + 'create_all_help' => 'Pozwól urzytkownikowi tworzyć i aktualizować rekordy', 'view_all_help' => 'Allow user to view records they didn\'t create', 'edit_all_help' => 'Allow user to modify records they didn\'t create', 'view_payment' => 'Zobacz wpłatę', - + 'january' => 'Styczeń', 'february' => 'Luty', 'march' => 'Marzec', @@ -1093,7 +1079,7 @@ $LANG = array( 'october' => 'Październik', 'november' => 'Listopad', 'december' => 'Grudzień', - + // Documents 'documents_header' => 'Dokumenty:', 'email_documents_header' => 'Dokumenty:', @@ -1106,17 +1092,15 @@ $LANG = array( 'document_email_attachment' => 'Załącz dokumenty', 'download_documents' => 'Ściągnij dokumenty (:size)', 'documents_from_expenses' => 'From Expenses:', - 'dropzone' => array(// See http://www.dropzonejs.com/#config-dictDefaultMessage - 'DefaultMessage' => 'Upuść pliki lub kliknij, aby przesłać', - 'FallbackMessage' => 'Your browser does not support drag\'n\'drop file uploads.', - 'FallbackText' => 'Please use the fallback form below to upload your files like in the olden days.', - 'FileTooBig' => 'Plik jest zbyt duży ({{filesize}}MiB). Max rozmiar pliku: {{maxFilesize}}MiB.', - 'InvalidFileType' => 'Nie możesz przesłać plików tego typu.', - 'ResponseError' => 'Serwer zwraca {{statusCode}} kod.', - 'CancelUpload' => 'Anuluj przesyłanie', - 'CancelUploadConfirmation' => 'Czy na pewno chcesz anulować przesyłanie pliku?', - 'RemoveFile' => 'Usuń plik', - ), + 'dropzone_default_message' => 'Upuść pliki lub kliknij, aby przesłać', + 'dropzone_fallback_message' => 'Your browser does not support drag\'n\'drop file uploads.', + 'dropzone_fallback_text' => 'Please use the fallback form below to upload your files like in the olden days.', + 'dropzone_file_too_big' => 'Plik jest zbyt duży ({{filesize}}MiB). Max rozmiar pliku: {{maxFilesize}}MiB.', + 'dropzone_invalid_file_type' => 'Nie możesz przesłać plików tego typu.', + 'dropzone_response_error' => 'Serwer zwraca {{statusCode}} kod.', + 'dropzone_cancel_upload' => 'Anuluj przesyłanie', + 'dropzone_cancel_upload_confirmation' => 'Czy na pewno chcesz anulować przesyłanie pliku?', + 'dropzone_remove_file' => 'Usuń plik', 'documents' => 'Dokumenty', 'document_date' => 'Data dokumentu', 'document_size' => 'Rozmiar', @@ -1125,11 +1109,11 @@ $LANG = array( 'enable_client_portal_help' => 'Pokaż/ukryj portal klienta.', 'enable_client_portal_dashboard' => 'Pulpit', 'enable_client_portal_dashboard_help' => 'Pokaż/ukryj pulpit w panelu klienta.', - + // Plans 'account_management' => 'Zarządzanie kontem', 'plan_status' => 'Plan Status', - + 'plan_upgrade' => 'Aktualizuj', 'plan_change' => 'Zmień plan', 'pending_change_to' => 'Zmienia się na', @@ -1159,9 +1143,9 @@ $LANG = array( 'plan_paid' => 'Termin rozpoczął', 'plan_started' => 'Plan rozpoczął', 'plan_expires' => 'Plan Wygasa', - + 'white_label_button' => 'Biała etykieta', - + 'pro_plan_year_description' => 'One year enrollment in the Invoice Ninja Pro Plan.', 'pro_plan_month_description' => 'One month enrollment in the Invoice Ninja Pro Plan.', 'enterprise_plan_product' => 'Plan Enterprise', @@ -1179,11 +1163,207 @@ $LANG = array( 'preview' => 'Preview', 'list_vendors' => 'List Vendors', 'add_users_not_supported' => 'Upgrade to the Enterprise plan to add additional users to your account.', - 'enterprise_plan_features' => 'The Enterprise plan adds support for multiple users and file attachments.', + 'enterprise_plan_features' => 'The Enterprise plan adds support for multiple users and file attachments, :link to see the full list of features.', 'return_to_app' => 'Return to app', - + + + // Payment updates + 'refund_payment' => 'Zwrot płatności', + 'refund_max' => 'Max:', + 'refund' => 'Zwrot', + 'are_you_sure_refund' => 'Zwrot wybranych płatności', + 'status_pending' => 'Oczekuję', + 'status_completed' => 'Zakończone', + 'status_failed' => 'Niepowodzenie', + 'status_partially_refunded' => 'Częściowo zwrócone', + 'status_partially_refunded_amount' => 'zwrócone', + 'status_refunded' => 'Zwrócone', + 'status_voided' => 'Anulowane', + 'refunded_payment' => 'Zwrócono płatność', + 'activity_39' => ':user cancelled a :payment_amount payment (:payment)', + 'activity_40' => ':user refunded :adjustment of a :payment_amount payment (:payment)', + 'card_expiration' => 'Exp: :expires', + + 'card_creditcardother' => 'Nieznany', + 'card_americanexpress' => 'American Express', + 'card_carteblanche' => 'Carte Blanche', + 'card_unionpay' => 'UnionPay', + 'card_diners' => 'Diners Club', + 'card_discover' => 'Discover', + 'card_jcb' => 'JCB', + 'card_laser' => 'Laser', + 'card_maestro' => 'Maestro', + 'card_mastercard' => 'MasterCard', + 'card_solo' => 'Solo', + 'card_switch' => 'Switch', + 'card_visacard' => 'Visa', + 'card_ach' => 'ACH', + + 'payment_type_stripe' => 'Stripe', + 'ach' => 'ACH', + 'enable_ach' => 'Enable ACH', + 'stripe_ach_help' => 'ACH support must also be enabled at Stripe.', + 'ach_disabled' => 'Another gateway is already configured for direct debit.', + + 'plaid' => 'Plaid', + 'client_id' => 'Numer klienta', + 'secret' => 'Tajny', + 'public_key' => 'Klucz publiczny', + 'plaid_optional' => '(opcjonalne)', + 'plaid_environment_help' => 'When a Stripe test key is given, Plaid\'s development environement (tartan) will be used.', + 'other_providers' => 'Inni dostawcy', + 'country_not_supported' => 'Dany kraj nie jest obsługiwany.', + 'invalid_routing_number' => 'The routing number is not valid.', + 'invalid_account_number' => 'Numer konta jest nieprawidłowy', + 'account_number_mismatch' => 'Numery konta nie pasują.', + 'missing_account_holder_type' => 'Proszę wybrać osobiste lub firmowe konto.', + 'missing_account_holder_name' => 'Wprowadź nazwę właściciela konta', + 'routing_number' => 'Routing Number', + 'confirm_account_number' => 'Potwierdź numer konta', + 'individual_account' => 'Konto osobiste', + 'company_account' => 'Konto firmowe', + 'account_holder_name' => 'Nazwa właściciela konta', + 'add_account' => 'Dodaj konto', + 'payment_methods' => 'Formy płatności', + 'complete_verification' => 'Dokończ weryfikację', + 'verification_amount1' => '1 Kwota', + 'verification_amount2' => '2 Kwota', + 'payment_method_verified' => 'Veryfikacja zakończona pomyślnie', + 'verification_failed' => 'Nieudana weryfikacja', + 'remove_payment_method' => 'Usuń formę płatności', + 'confirm_remove_payment_method' => 'Czy na pewno chcesz usunąć tą formę płatności?', + 'remove' => 'Usuń', + 'payment_method_removed' => 'Forma płatności usunięta', + 'bank_account_verification_help' => 'We have made two deposits into your account with the description "VERIFICATION". These deposits will take 1-2 business days to appear on your statement. Please enter the amounts below.', + 'bank_account_verification_next_steps' => 'We have made two deposits into your account with the description "VERIFICATION". These deposits will take 1-2 business days to appear on your statement. + Once you have the amounts, come back to this payment methods page and click "Complete Verification" next to the account.', + 'unknown_bank' => 'Nieznany bank', + 'ach_verification_delay_help' => 'Konto będzie aktywne, po dokończeniu weryfikacji. Weryfikacja trwa 1-2 dni robocze.', + 'add_credit_card' => 'Dodaj kartę kredytową', + 'payment_method_added' => 'Dodano formę płatności', + 'use_for_auto_bill' => 'Use For Autobill', + 'used_for_auto_bill' => 'Autobill Payment Method', + 'payment_method_set_as_default' => 'Set Autobill payment method.', + 'activity_41' => ':payment_amount payment (:payment) failed', + 'webhook_url' => 'Webhook URL', + 'stripe_webhook_help' => 'You must :link.', + 'stripe_webhook_help_link_text' => 'add this URL as an endpoint at Stripe', + 'payment_method_error' => 'There was an error adding your payment methd. Please try again later.', + 'notification_invoice_payment_failed_subject' => 'Płatność dla faktury :invoice nie powiodła się', + 'notification_invoice_payment_failed' => 'A payment made by client :client towards Invoice :invoice failed. The payment has been marked as failed and :amount has been added to the client\'s balance.', + 'link_with_plaid' => 'Link Account Instantly with Plaid', + 'link_manually' => 'Link Manually', + 'secured_by_plaid' => 'Secured by Plaid', + 'plaid_linked_status' => 'Twoje konto bankowe w :bank', + 'add_payment_method' => 'Dodaj formę płatności', + 'account_holder_type' => 'Typ konta właściciela', + 'ach_authorization' => 'I authorize :company to use my bank account for future payments and, if necessary, electronically credit my account to correct erroneous debits. I understand that I may cancel this authorization at any time by removing the payment method or by contacting :email.', + 'ach_authorization_required' => 'You must consent to ACH transactions.', + 'off' => 'Off', + 'opt_in' => 'Opt-in', + 'opt_out' => 'Opt-out', + 'always' => 'Zawsze', + 'opted_out' => 'Opted out', + 'opted_in' => 'Opted in', + 'manage_auto_bill' => 'Manage Auto-bill', + 'enabled' => 'Aktywny', + 'paypal' => 'PayPal', + 'braintree_enable_paypal' => 'Enable PayPal payments through BrainTree', + 'braintree_paypal_disabled_help' => 'The PayPal gateway is processing PayPal payments', + 'braintree_paypal_help' => 'You must also :link.', + 'braintree_paypal_help_link_text' => 'link PayPal to your BrainTree account', + 'token_billing_braintree_paypal' => 'Zapisz dane płatności', + 'add_paypal_account' => 'Dodaj konto PayPal', + + + 'no_payment_method_specified' => 'Nie wybrano formy płatności', + 'chart_type' => 'Typ wykresu', + 'format' => 'Format', + 'import_ofx' => 'Importuj OFX', + 'ofx_file' => 'Plik OFX', + 'ofx_parse_failed' => 'Failed to parse OFX file', + + // WePay + 'wepay' => 'WePay', + 'sign_up_with_wepay' => 'Sign up with WePay', + 'use_another_provider' => 'Użyj innego dostawcy', + 'company_name' => 'Nazwa firmy', + 'wepay_company_name_help' => 'This will appear on client\'s credit card statements.', + 'wepay_description_help' => 'Cel konta', + 'wepay_tos_agree' => 'Zgadzam się z :link', + 'wepay_tos_link_text' => 'WePay Terms of Service', + 'resend_confirmation_email' => 'Wyślij ponownie email potwierdzający', + 'manage_wepay_account' => 'Manage WePay Account', + 'action_required' => 'Action Required', + 'finish_setup' => 'Zakończ konfigurację', + 'created_wepay_confirmation_required' => 'Please check your email and confirm your email address with WePay.', + 'switch_to_wepay' => 'Switch to WePay', + 'switch' => 'Zmień', + 'restore_account_gateway' => 'Restore Gateway', + 'restored_account_gateway' => 'Successfully restored gateway', + 'united_states' => 'Stany Zjednoczone', + 'canada' => 'Kanada', + 'accept_debit_cards' => 'Akceptuj karty debetowe', + 'debit_cards' => 'Karty debetowe', + + 'warn_start_date_changed' => 'The next invoice will be sent on the new start date.', + 'original_start_date' => 'Original start date', + 'new_start_date' => 'New start date', + 'security' => 'Security', + 'see_whats_new' => 'See what\'s new in v:version', + 'wait_for_upload' => 'Please wait for the document upload to complete.', + 'upgrade_for_permissions' => 'Upgrade to our Enterprise plan to enable permissions.', + 'enable_second_tax_rate' => 'Enable specifying a second tax rate', + 'payment_file' => 'Payment File', + 'expense_file' => 'Expense File', + 'product_file' => 'Product File', + 'import_products' => 'Import Products', + 'products_will_create' => 'products will be created.', + 'product_key' => 'Product', + 'created_products' => 'Successfully created :count product(s)', + 'export_help' => 'Use JSON if you plan to import the data into Invoice Ninja.', + 'JSON_file' => 'JSON File', + + 'view_dashboard' => 'View Dashboard', + 'client_session_expired' => 'Session Expired', + 'client_session_expired_message' => 'Your session has expired. Please click the link in your email again.', + + 'auto_bill_notification' => 'This invoice will automatically be billed to your :payment_method on file on :due_date.', + 'auto_bill_payment_method_bank_transfer' => 'bank account', + 'auto_bill_payment_method_credit_card' => 'credit card', + 'auto_bill_payment_method_paypal' => 'PayPal account', + 'auto_bill_notification_placeholder' => 'This invoice will automatically be billed to your credit card on file on the due date.', + 'payment_settings' => 'Payment Settings', + + 'on_send_date' => 'On send date', + 'on_due_date' => 'On due date', + 'auto_bill_ach_date_help' => 'ACH auto bill will always happen on the due date', + 'warn_change_auto_bill' => 'Due to NACHA rules, changes to this invoice may prevent ACH auto bill.', + + 'bank_account' => 'Bank Account', + 'payment_processed_through_wepay' => 'ACH payments will be processed using WePay.', + 'wepay_payment_tos_agree' => 'I agree to the WePay :terms and :privacy_policy.', + 'privacy_policy' => 'Privacy Policy', + 'wepay_payment_tos_agree_required' => 'You must agree to the WePay Terms of Service and Privacy Policy.', + 'payment_settings_supported_gateways' => 'These options are supported by the WePay, Stripe, and Braintree gateways.', + 'ach_email_prompt' => 'Please enter your email address:', + 'verification_pending' => 'Verification Pending', + + 'update_font_cache' => 'Please force refresh the page to update the font cache.', + 'more_options' => 'More options', + 'credit_card' => 'Credit Card', + 'bank_transfer' => 'Bank Transfer', + 'no_transaction_reference' => 'We did not recieve a payment transaction reference from the gateway.', + 'use_bank_on_file' => 'Use Bank on File', + 'auto_bill_email_message' => 'This invoice will automatically be billed to the payment method on file on the due date.', + 'bitcoin' => 'Bitcoin', + 'added_on' => 'Added :date', + 'failed_remove_payment_method' => 'Failed to remove the payment method', + 'gateway_exists' => 'This gateway already exists', + 'manual_entry' => 'Manual entry', + ); return $LANG; -?>. \ No newline at end of file +?> diff --git a/resources/lang/pt_BR/texts.php b/resources/lang/pt_BR/texts.php index 3791e5b0e6..6df4af6f8e 100644 --- a/resources/lang/pt_BR/texts.php +++ b/resources/lang/pt_BR/texts.php @@ -1,7 +1,6 @@ 'Organização', 'name' => 'Nome', 'website' => 'Website', @@ -24,8 +23,6 @@ return array( 'size_id' => 'Tamanho', 'industry_id' => 'Empresa', 'private_notes' => 'Notas Privadas', - - // invoice 'invoice' => 'Fatura', 'client' => 'Cliente', 'invoice_date' => 'Data da Fatura', @@ -49,7 +46,6 @@ return array( 'invoice_design_id' => 'Modelo', 'terms' => 'Condições', 'your_invoice' => 'Sua Fatura', - 'remove_contact' => 'Remover contato', 'add_contact' => 'Adicionar contato', 'create_new_client' => 'Criar novo cliente', @@ -73,8 +69,6 @@ return array( 'settings' => 'Configurações', 'enable_invoice_tax' => 'Permitir especificar a taxa da fatura', 'enable_line_item_tax' => 'Permitir especificar o taxas por item', - - // navigation 'dashboard' => 'Dashboard', 'clients' => 'Clientes', 'invoices' => 'Faturas', @@ -95,11 +89,10 @@ return array( 'import' => 'Importar', 'download' => 'Download', 'cancel' => 'Cancelar', + 'close' => 'Fechar', 'provide_email' => 'Forneça um endereço de e-mail válido', 'powered_by' => 'Powered by', 'no_items' => 'Sem itens', - - // recurring invoices 'recurring_invoices' => 'Faturas Recorrentes', 'recurring_help' => '

      Enviar automaticamente aos clientes as mesmas faturas semanalmente, mensalmente, bimenstralmente, trimestralmente ou anualmente.

      Use :MONTH, :QUARTER ou :YEAR para datas dinâmicas. Operadores matemáticos também funcionam, por exemplo :MONTH-1.

      @@ -109,8 +102,6 @@ return array(
    • "Plano anual de :YEAR+1" => "Plano anual de 2015"
    • "Pagamento retido para :QUARTER+1" => "Pagamento retido para Q2"
    ', - - // dashboard 'in_total_revenue' => 'no total de faturamento', 'billed_client' => 'Cliente faturado', 'billed_clients' => 'Clientes faturados', @@ -119,8 +110,6 @@ return array( 'invoices_past_due' => 'Faturas Vencidas', 'upcoming_invoices' => 'Próximas Faturas', 'average_invoice' => 'Média por Fatura', - - // list pages 'archive' => 'Arquivos', 'delete' => 'Apagar', 'archive_client' => 'Arquivar Cliente', @@ -156,8 +145,6 @@ return array( 'select' => 'Selecionar', 'edit_client' => 'Editar Cliente', 'edit_invoice' => 'Editar Fatura', - - // client view page 'create_invoice' => 'Criar Fatura', 'enter_credit' => 'Informar Crédito', 'last_logged_in' => 'Último acesso em', @@ -169,12 +156,8 @@ return array( 'message' => 'Mensagem', 'adjustment' => 'Movimento', 'are_you_sure' => 'Você tem certeza?', - - // payment pages 'payment_type_id' => 'Tipo de pagamento', 'amount' => 'Quantidade', - - // account/company pages 'work_email' => 'E-mail', 'language_id' => 'Idioma', 'timezone_id' => 'Fuso Horário', @@ -192,11 +175,7 @@ return array( 'email_paid' => 'Notificar-me por e-mail quando a fatura for paga', 'site_updates' => 'Atualizações', 'custom_messages' => 'Mensagens Customizadas', - 'default_invoice_terms' => 'Definir condições padrões da fatura', 'default_email_footer' => 'Definir assinatura de e-mail padrão', - 'import_clients' => 'Importar Dados do Cliente', - 'csv_file' => 'Selecionar arquivo CSV', - 'export_clients' => 'Exportar Dados do Cliente', 'select_file' => 'Favor selecionar um arquivo', 'first_row_headers' => 'Usar as primeiras linhas como cabeçalho', 'column' => 'Coluna', @@ -205,9 +184,12 @@ return array( 'client_will_create' => 'cliente será criado', 'clients_will_create' => 'clientes serão criados', 'email_settings' => 'Configurações de E-mail', + 'client_view_styling' => 'Client View Styling', 'pdf_email_attachment' => 'Anexar PDF aos e-mails', - - // application messages + 'custom_css' => 'CSS Personalizado', + 'import_clients' => 'Importar Dados do Cliente', + 'csv_file' => 'Selecionar arquivo CSV', + 'export_clients' => 'Exportar Dados do Cliente', 'created_client' => 'Cliente criado com sucesso', 'created_clients' => ':count clientes criados com sucesso', 'updated_settings' => 'Configurações atualizadas com sucesso', @@ -218,14 +200,12 @@ return array( 'payment_error' => 'Ocorreu um erro ao processar o pagamento. Por favor tente novamente mais tarde.', 'registration_required' => 'Favor logar-se para enviar uma fatura por e-mail', 'confirmation_required' => 'Favor confirmar o seu endereço de e-mail', - 'updated_client' => 'Cliente atualizado com sucesso', 'created_client' => 'Cliente criado com sucesso', 'archived_client' => 'Cliente arquivado com sucesso', 'archived_clients' => ':count clientes arquivados com sucesso', 'deleted_client' => 'Clientes removidos com sucesso', 'deleted_clients' => ':count clientes removidos com sucesso', - 'updated_invoice' => 'Fatura atualizado com sucesso', 'created_invoice' => 'Fatura criada com sucesso', 'cloned_invoice' => 'Fatura clonada com sucesso', @@ -235,30 +215,35 @@ return array( 'archived_invoices' => ':count faturas arquivados com sucesso', 'deleted_invoice' => 'Fatura apagados com sucesso', 'deleted_invoices' => ':count faturas apagados com sucesso', - 'created_payment' => 'Pagamento criado com sucesso', + 'created_payments' => ':count pagamento(s) criados com sucesso', 'archived_payment' => 'Pagamento arquivado com sucesso', 'archived_payments' => ':count pagamentos arquivados com sucesso', 'deleted_payment' => 'Pagamento apagado com sucesso', 'deleted_payments' => ':count pagamentos apagados com sucesso', 'applied_payment' => 'Pagamentos aplicados com sucesso', - 'created_credit' => 'Crédito criado com sucesso', 'archived_credit' => 'Crédito arquivado com sucesso', 'archived_credits' => ':count créditos arquivados com sucesso', 'deleted_credit' => 'Crédito apagado com sucesso', 'deleted_credits' => ':count créditos apagados com sucesso', - - // Emails + 'imported_file' => 'Arquivo importado com sucesso', + 'updated_vendor' => 'Fornecedor atualizado com sucesso', + 'created_vendor' => 'Fornecedor criado com sucesso', + 'archived_vendor' => 'Fornecedor arquivado com sucesso', + 'archived_vendors' => ':count fornecedores arquivados com sucesso', + 'deleted_vendor' => 'Fornecedor removido com sucesso', + 'deleted_vendors' => ':count fornecedores removidos com sucesso', 'confirmation_subject' => 'Confirmação de Conta do Invoice Ninja', 'confirmation_header' => 'Confirmação de Conta', 'confirmation_message' => 'Favor acessar o link abaixo para confirmar a sua conta.', + 'invoice_subject' => 'Nova fatura :invoice de :account', 'invoice_message' => 'Para visualizar a sua fatura de :amount, clique no link abaixo.', + 'payment_subject' => 'Recebimento de pagamento de', 'payment_message' => 'Obrigado, pagamento de :amount confirmado', 'email_salutation' => 'Caro :name,', 'email_signature' => 'Atenciosamente,', 'email_from' => 'Equipe InvoiceNinja', - 'user_email_footer' => 'Para ajustar suas configurações de notificações de e-mail acesse '.SITE_URL.'/settings/notifications', 'invoice_link_message' => 'Para visualizar a fatura do seu cliente clique no link abaixo:', 'notification_invoice_paid_subject' => 'Fatura :invoice foi pago por :client', 'notification_invoice_sent_subject' => 'Fatura :invoice foi enviado por :client', @@ -267,33 +252,11 @@ return array( 'notification_invoice_sent' => 'O cliente :client foi notificado por e-mail referente à fatura :invoice de :amount.', 'notification_invoice_viewed' => 'O cliente :client visualizou a fatura :invoice de :amount.', 'reset_password' => 'Você pode redefinir a sua senha clicando no seguinte link:', - 'reset_password_footer' => 'Se você não solicitou a redefinição de sua senha por favor envie um e-mail para o nosso suporte: '.CONTACT_EMAIL, - - // Payment page 'secure_payment' => 'Pagamento Seguro', 'card_number' => 'Número do cartão', 'expiration_month' => 'Mês de expiração', 'expiration_year' => 'Ano de expiração', 'cvv' => 'CVV', - - // This File was missing the security alerts. I'm not familiar with this language, Can someone translate? - // Security alerts - 'security' => [ - 'too_many_attempts' => 'Muitas tentativas. Tente novamente em alguns minutos.', - 'wrong_credentials' => 'E-mail ou senha incorretos.', - 'confirmation' => 'Sua conta foi confirmada!', - 'wrong_confirmation' => 'Código de confirmação incorreto.', - 'password_forgot' => 'As informações para redefinição de senha foi enviada para seu e-mail.', - 'password_reset' => 'Senha atualizada com sucesso.', - 'wrong_password_reset' => 'Senha inválida. Tente novamente', - ], - - // Pro Plan - 'pro_plan' => [ - 'remove_logo' => ':link para remover a logo do Invoice Ninja contratando o plano profissional', - 'remove_logo_link' => 'Clique aqui', - ], - 'logout' => 'Sair', 'sign_up_to_save' => 'Faça login para salvar o seu trabalho', 'agree_to_terms' => 'Eu concordo com os :terms do Invoice Ninja', @@ -304,14 +267,8 @@ return array( 'success_message' => 'Você se registrou com sucesso. Por favor acesse o link de confirmação recebido para confirmar o seu endereço de e-mail.', 'erase_data' => 'Isto irá apagar completamente todos os seus dados.', 'password' => 'Senha', - 'close' => 'Fechar', - 'invoice_subject' => 'Nova fatura :invoice de :account', - 'payment_subject' => 'Recebimento de pagamento de', - 'pro_plan_product' => 'Plano Profissional', - 'pro_plan_description' => 'Um ano de inscrição no Plano Invoice Ninja Pro', 'pro_plan_success' => 'Muito Obrigado! Assim que o pagamento for confirmado seu plano será ativado.', - 'unsaved_changes' => 'Existem alterações não salvas', 'custom_fields' => 'Campos Personalizados', 'company_fields' => 'Campos para Empresa', @@ -319,10 +276,8 @@ return array( 'field_label' => 'Nome do Campo', 'field_value' => 'Valor do Campo', 'edit' => 'Editar', - 'view_invoice' => 'Visualizar fatura', + 'set_name' => 'Informe o nome da sua empresa', 'view_as_recipient' => 'Visualizar como destinatário', - - // product management 'product_library' => 'Lista de Produtos', 'product' => 'Produto', 'products' => 'Produtos', @@ -337,18 +292,14 @@ return array( 'created_product' => 'Produto criado', 'archived_product' => 'Produto arquivado', 'pro_plan_custom_fields' => ':link para habilitar campos personalizados adquira o Plano Profissional', - 'advanced_settings' => 'Configurações Avançadas', 'pro_plan_advanced_settings' => ':link para habilitar as configurações avançadas adquira o Plano Profissional', 'invoice_design' => 'Modelo da Fatura', 'specify_colors' => 'Definição de Cores', 'specify_colors_label' => 'Selecione as cores para sua fatura', - 'chart_builder' => 'Contrutor de Gráficos', 'ninja_email_footer' => 'Use :site para gerenciar os orçamentos e faturas de seus clientes!', 'go_pro' => 'Adquira o Plano Pro', - - // Quotes 'quote' => 'Orçamento', 'quotes' => 'Orçamentos', 'quote_number' => 'Número do Orçamento', @@ -358,7 +309,6 @@ return array( 'your_quote' => 'Seu Orçamento', 'total' => 'Total', 'clone' => 'Clonar', - 'new_quote' => 'Novo Orçamento', 'create_quote' => 'Criar Orçamento', 'edit_quote' => 'Editar Orçamento', @@ -368,10 +318,9 @@ return array( 'email_quote' => 'Enviar Orçamento', 'clone_quote' => 'Clonar Orçamento', 'convert_to_invoice' => 'Faturar Orçamento', - 'view_invoice' => 'Visualizar Fatura', - 'view_quote' => 'Visualizar Orçamento', + 'view_invoice' => 'Visualizar fatura', 'view_client' => 'Visualizar Cliente', - + 'view_quote' => 'Visualizar Orçamento', 'updated_quote' => 'Orçamento atualizado', 'created_quote' => 'Orçamento criado', 'cloned_quote' => 'Orçamento clonaro', @@ -381,7 +330,6 @@ return array( 'deleted_quote' => 'Orçamento deletado', 'deleted_quotes' => ':count Orçamento(s) deletado(s)', 'converted_to_invoice' => 'Orçamento faturado', - 'quote_subject' => 'Novo Orçamento de :account', 'quote_message' => 'Para visualizar o oçamento de :amount, clique no link abaixo.', 'quote_link_message' => 'Para visualizar o orçamento clique no link abaixo', @@ -389,16 +337,13 @@ return array( 'notification_quote_viewed_subject' => 'Orçamento :invoice visualizado por :client', 'notification_quote_sent' => 'O cliente :client recebeu o Orçamento :invoice de:amount.', 'notification_quote_viewed' => 'O clinete :client visualizou o Orçamento :invoice de :amount.', - 'session_expired' => 'Sessão expirada.', - 'invoice_fields' => 'Campos da Fatura', 'invoice_options' => 'Opções da Fatura', 'hide_quantity' => 'Ocultar quantidade', 'hide_quantity_help' => 'Se a quantidade dos itens é sempre 1, então você pode definir para nao exibir na sua fatura.', 'hide_paid_to_date' => 'Ocultar data de pagamento', 'hide_paid_to_date_help' => 'Apenas mostrar a "Data de Pagamento" quanto o pagamento tiver sido efetuado.', - 'charge_taxes' => 'Taxas', 'user_management' => 'Gerenciamento de Usuários', 'add_user' => 'Adicionar Usuários', @@ -413,21 +358,16 @@ return array( 'active' => 'Ativo', 'pending' => 'Pendente', 'deleted_user' => 'Usuário deletado', - 'limit_users' => 'Desculpe, isto irá exceder o limite de '.MAX_NUM_USERS.' usuários', - 'confirm_email_invoice' => 'Deseja enviar esta fatura?', 'confirm_email_quote' => 'Deseja enviar este orçamento?', 'confirm_recurring_email_invoice' => 'Deseja enviar esta fatura?', - 'cancel_account' => 'Cancelar Conta', 'cancel_account_message' => 'Atenção: Esta ação irá remover todos os seus dados, e não pode ser desfeita.', 'go_back' => 'Voltar', - 'data_visualizations' => 'Visualização de Dados', 'sample_data' => 'Dados de Exemplo', 'hide' => 'Ocultar', 'new_version_available' => 'Uma nova versão :releases_link está disponível. Sua versão é v:user_version, a última versão é v:latest_version', - 'invoice_settings' => 'Configuração das Faturas', 'invoice_number_prefix' => 'Prefixo na Numeração das Faturas', 'invoice_number_counter' => 'Numeração das Faturas', @@ -437,59 +377,48 @@ return array( 'invoice_issued_to' => 'Fatura emitida para', 'invalid_counter' => 'Para evitar conflitos defina prefíxos de numeração para Faturas e Orçamentos', 'mark_sent' => 'Marcar como Enviada', - 'gateway_help_1' => ':link para acessar Authorize.net.', 'gateway_help_2' => ':link para acessar Authorize.net.', 'gateway_help_17' => ':link para adquirir sua "PayPal API signature".', 'gateway_help_27' => ':link para acessar TwoCheckout.', - 'more_designs' => 'Mais Modelos', 'more_designs_title' => 'Modelo Adicionais', 'more_designs_cloud_header' => 'Adquira o Plano Pro para mais modelos', 'more_designs_cloud_text' => '', - 'more_designs_self_host_header' => 'Obtenha mais 6 modelos de faturas por apenas $'.INVOICE_DESIGNS_PRICE, 'more_designs_self_host_text' => '', 'buy' => 'Comprar', 'bought_designs' => 'Novos Modelos Adicionados', - 'sent' => 'enviado', + 'vat_number' => 'Insc.', 'timesheets' => 'Planilha de Tempos', - 'payment_title' => 'Informe o endereço de cobrança e as informações do Cartão de Crédito', 'payment_cvv' => '*São os 3-4 digitos encontrados atrás do seu cartão.', 'payment_footer1' => '*O endereço de cobrança deve ser igual o endereço associado ao Cartã de Crédito.', 'payment_footer2' => '*Clique em "Pagar Agora" apenas uma vez - esta operação pode levar até 1 Minuto para processar.', - 'vat_number' => 'Insc.', 'id_number' => 'CNPJ', - 'white_label_link' => 'White Label', 'white_label_header' => 'White Label', 'bought_white_label' => 'Licença "white label" habilitada', 'white_labeled' => 'White labeled', - 'restore' => 'Restaurar', 'restore_invoice' => 'Restaurar Fatura', 'restore_quote' => 'Restaurar Orçamento', 'restore_client' => 'Restaurar Cliente', 'restore_credit' => 'Restaurar Credito', 'restore_payment' => 'Restaurar Pagamento', - 'restored_invoice' => 'Fatura restaurada', 'restored_quote' => 'Orçamento restaurado', 'restored_client' => 'Cliente restaurado', 'restored_payment' => 'Pagamento restaurado', 'restored_credit' => 'Crédito restaurado', - 'reason_for_canceling' => 'Ajude-nos a melhorar, envie suas sugestões.', 'discount_percent' => '%', 'discount_amount' => 'Valor', - 'invoice_history' => 'Histórico de Faturas', 'quote_history' => 'Histórico de Orçamentos', 'current_version' => 'Versão Atual', 'select_version' => 'Selecionar versão', 'view_history' => 'Visualizar Histórico', - 'edit_payment' => 'Editar Pagamento', 'updated_payment' => 'Pagamento atualizado', 'deleted' => 'Deletado', @@ -502,7 +431,6 @@ return array( 'quote_email' => 'E-mail de Orçamentos', 'reset_all' => 'Resetar Todos', 'approve' => 'Aprovar', - 'token_billing_type_id' => 'Token de Cobrança', 'token_billing_help' => 'Habilita o armazenamento das informações junto ao provedor, para cobrança posterior.', 'token_billing_1' => 'Desabilitado', @@ -510,12 +438,11 @@ return array( 'token_billing_3' => 'Opt-out - selecionado', 'token_billing_4' => 'Sempre', 'token_billing_checkbox' => 'Guardar detalhes do cartão', - 'view_in_stripe' => 'Ver no Stripe', - 'use_card_on_file' => 'Usar cartão no arquivo', + 'view_in_gateway' => 'Ver em :gateway', + 'use_card_on_file' => 'Use Card on File', 'edit_payment_details' => 'Editar detalhes do pagamento', 'token_billing' => 'Salvar detalhes do cartão', - 'token_billing_secure' => 'Dados armazenados com seguração por :stripe_link', - + 'token_billing_secure' => 'Dados armazenados com seguração por :link', 'support' => 'Suporte', 'contact_information' => 'Informações de Contato', '256_encryption' => 'Criptografia de 256-Bit', @@ -525,10 +452,8 @@ return array( 'order_overview' => 'Geral', 'match_address' => '*O endereço de cobrança deve ser igual o endereço associado ao Cartão de Crédito.', 'click_once' => '*Clique em "Pagar Agora" apenas uma vez - esta operação pode levar até 1 Minuto para processar.', - 'default_invoice_footer' => 'Definir padrão', 'invoice_footer' => 'Rodapé da Fatura', 'save_as_default_footer' => 'Salvar como rodapé padrão', - 'token_management' => 'Gerenciar Token', 'tokens' => 'Tokens', 'add_token' => 'Adicionar Token', @@ -539,7 +464,6 @@ return array( 'edit_token' => 'Editat Token', 'delete_token' => 'Deletar Token', 'token' => 'Token', - 'add_gateway' => 'Adicionar Provedor', 'delete_gateway' => 'Deletar Provedor', 'edit_gateway' => 'Editar Provedor', @@ -548,7 +472,6 @@ return array( 'deleted_gateway' => 'Provedor Deletado', 'pay_with_paypal' => 'PayPal', 'pay_with_card' => 'Cartão de Crédito', - 'change_password' => 'Altera senha', 'current_password' => 'Senha atual', 'new_password' => 'Nova senha', @@ -556,7 +479,6 @@ return array( 'password_error_incorrect' => 'Senha atual incorreta.', 'password_error_invalid' => 'Nova senha inválida.', 'updated_password' => 'Senha atualizada', - 'api_tokens' => 'API Tokens', 'users_and_tokens' => 'Usuários & Tokens', 'account_login' => 'Login', @@ -568,13 +490,11 @@ return array( 'send_email' => 'Enviar e-mail', 'set_password' => 'Definir Senha', 'converted' => 'Faturado', - 'email_approved' => 'Notificar-me por e-mail quando um orçamento for aprovado', 'notification_quote_approved_subject' => 'Orçamento :invoice foi aprovado por :client', 'notification_quote_approved' => 'O cliente :client aprovou Orçamento :invoice de :amount.', 'resend_confirmation' => 'Reenviar e-mail de confirmação', 'confirmation_resent' => 'E-mail de confirmação reenviado', - 'gateway_help_42' => ':link acessar BitPay.
    Aviso: use a "Legacy API Key", não "API token".', 'payment_type_credit_card' => 'Cartão de Crédito', 'payment_type_paypal' => 'PayPal', @@ -582,7 +502,6 @@ return array( 'knowledge_base' => 'Base de Conhecimento', 'partial' => 'Parcial', 'partial_remaining' => ':partial de :balance', - 'more_fields' => 'Mais Campos', 'less_fields' => 'Menos Campos', 'client_name' => 'Nome do Cliente', @@ -593,7 +512,6 @@ return array( 'view_documentation' => 'Ver Documentação', '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.', - 'rows' => 'linhas', 'www' => 'www', 'logo' => 'Logo', @@ -613,7 +531,6 @@ return array( 'zapier' => 'Zapier', 'recurring' => 'Recorrente', 'last_invoice_sent' => 'Última cobrança enviada em :date', - 'processed_updates' => 'Atualização completa', 'tasks' => 'Tarefas', 'new_task' => 'Nova Tarefa', @@ -659,12 +576,10 @@ return array( 'invoice_labels' => 'Etiquetas das Faturas', 'prefix' => 'Prefixo', 'counter' => 'Contador', - 'payment_type_dwolla' => 'Dwolla', 'gateway_help_43' => ':link acessar Dwolla.', 'partial_value' => 'Deve ser maior que zero e menor que o total', 'more_actions' => 'Mais ações', - 'pro_plan_title' => 'NINJA PRO', 'pro_plan_call_to_action' => 'Adquira Agora!', 'pro_plan_feature1' => 'Sem Limite de Clientes', @@ -675,14 +590,12 @@ return array( 'pro_plan_feature6' => 'Orçamentos & Pedidos', 'pro_plan_feature7' => 'Campos personalizados', 'pro_plan_feature8' => 'Opção para anexar PDFs aos e-mails', - 'resume' => 'Retormar', 'break_duration' => 'Interromper', 'edit_details' => 'Editar Detalhes', 'work' => 'Trabalhar', 'timezone_unset' => 'Por favor :link defina sua timezone', 'click_here' => 'clique aqui', - 'email_receipt' => 'E-mail para envio do recibo de pagamento', 'created_payment_emailed_client' => 'Pagamento informado e notificado ao cliente por e-mail', 'add_company' => 'Adicionar Empresa', @@ -692,10 +605,8 @@ return array( 'unlinked_account' => 'Contas desvinculadas', 'login' => 'Login', 'or' => 'ou', - 'email_error' => 'Houve um problema ao enviar o e-mail', 'confirm_recurring_timing' => 'Aviso: e-mails são enviados na hora de início.', - 'old_browser' => 'Utilize um navegador atualizado', 'payment_terms_help' => 'Defina a data de vencimento padrão', 'unlink_account' => 'Desvincular Conta', 'unlink' => 'Desvincular', @@ -716,7 +627,6 @@ return array( 'primary_color' => 'Cor Principal', 'secondary_color' => 'Cor Secundaria', 'customize_design' => 'Personalizar Modelo', - 'content' => 'Conteúdo', 'styles' => 'Estilos', 'defaults' => 'Padrões', @@ -730,7 +640,6 @@ return array( 'outstanding' => 'Em Aberto', 'manage_companies' => 'Gerenciar Empresas', 'total_revenue' => 'Faturamento', - 'current_user' => 'Usuário', 'new_recurring_invoice' => 'Nova Fatura Recorrente', 'recurring_invoice' => 'Fatura Recorrente', @@ -739,9 +648,8 @@ return array( 'primary_user' => 'Usuário Principal', 'help' => 'Ajuda', 'customize_help' => '

    We use pdfmake to define the invoice designs declaratively. The pdfmake playground provide\'s a great way to see the library in action.

    -

    To access a child property using dot notation. For example to show the client name you could use $client.name.

    -

    If you need help figuring something out post a question to our support forum.

    ', - +

    You can access a child property using dot notation. For example to show the client name you could use $client.name.

    +

    If you need help figuring something out post a question to our support forum with the design you\'re using.

    ', 'invoice_due_date' => 'Data de vencimento', 'quote_due_date' => 'Valido até', 'valid_until' => 'Válido até', @@ -754,15 +662,12 @@ return array( 'status_partial' => 'Parcial', 'status_paid' => 'Pago', 'show_line_item_tax' => 'Exibir taxas dos itens', - 'iframe_url' => 'Website', 'iframe_url_help1' => 'Copie o código abaixo em seu website.', 'iframe_url_help2' => 'Você pode testar clicando em \'Ver como destinatário\' em uma fatura.', - 'auto_bill' => 'Cobrança Automática', 'military_time' => '24h', 'last_sent' => 'Último Envio', - 'reminder_emails' => 'E-mails de Lembrete', 'templates_and_reminders' => 'Modelos & Lembretes', 'subject' => 'Assunto', @@ -774,15 +679,12 @@ return array( 'reminder_subject' => 'Lembrente: Fatura :invoice de :account', 'reset' => 'Resetar', 'invoice_not_found' => 'A fatura requisitada não está disponível', - 'referral_program' => 'Programa de Indicação', 'referral_code' => 'Código de Indicação', 'last_sent_on' => 'Último envio em :date', - 'page_expire' => 'Esta página está expirando, :click_here para continuar trabalhando', 'upcoming_quotes' => 'Próximos Orçamentos', 'expired_quotes' => 'Orçamentos Expirados', - 'sign_up_using' => 'Acesse', 'invalid_credentials' => 'Usuário e/ou senha inválidos', 'show_all_options' => 'Mostrar todas as opções', @@ -791,17 +693,10 @@ return array( 'disable' => 'Desabilitar', 'invoice_quote_number' => 'Numero de Faturas e Orçamentos', 'invoice_charges' => 'Encargos da Fatura', - - 'invitation_status' => [ - 'sent' => 'E-mail Enviado', - 'opened' => 'E-mail Aberto', - 'viewed' => 'E-mail Visualizado', - ], 'notification_invoice_bounced' => 'Não foi possível entregar a Fatura :invoice para :contact.', 'notification_invoice_bounced_subject' => 'Fatura :invoice não foi entregue', 'notification_quote_bounced' => 'Não foi possível entregar o Orçamento :invoice para :contact.', 'notification_quote_bounced_subject' => 'Orçamento :invoice não foi entregue', - 'custom_invoice_link' => 'Link de Fauturas Personalizado', 'total_invoiced' => 'Faturas', 'open_balance' => 'Em Aberto', @@ -809,15 +704,12 @@ return array( 'basic_settings' => 'Configurações Básicas', 'pro' => 'Pro', 'gateways' => 'Provedores de Pagamento', - 'next_send_on' => 'Próximo Envio: :date', 'no_longer_running' => 'Esta fatura não está agendada', 'general_settings' => 'Configurações Gerais', 'customize' => 'Personalizar', - 'oneclick_login_help' => 'Vincule uma conta para acesar sem senha.', 'referral_code_help' => 'Recomende nosso sistema.', - 'enable_with_stripe' => 'Habilite | Requer Stripe', 'tax_settings' => 'Configurações de Taxas', 'create_tax_rate' => 'Adicionar Taxa', @@ -838,7 +730,6 @@ return array( 'invoice_counter' => 'Contador de Faturas', 'quote_counter' => 'Contador de Orçamentos', 'type' => 'Tipo', - 'activity_1' => ':user cadastrou o cliente :client', 'activity_2' => ':user arquivo o cliente :client', 'activity_3' => ':user removeu o cliente :client', @@ -868,18 +759,24 @@ return array( 'activity_27' => ':user restaurou o pagamento :payment', 'activity_28' => ':user restaurou o crédito :credit', 'activity_29' => ':contact aprovou o orçamento :quote', - + 'activity_30' => ':user criou :vendor', + 'activity_31' => ':user criou :vendor', + 'activity_32' => ':user criou :vendor', + 'activity_33' => ':user criou :vendor', + 'activity_34' => ':user criou a despesa :expense', + 'activity_35' => ':user criou :vendor', + 'activity_36' => ':user criou :vendor', + 'activity_37' => ':user criou :vendor', 'payment' => 'Pagamento', 'system' => 'Sistema', 'signature' => 'Assinatura do E-mail', 'default_messages' => 'Mensagens Padrões', 'quote_terms' => 'Condições do Orçamento', 'default_quote_terms' => 'Condições Padrões dos Orçamentos', - 'default_invoice_terms' => 'Condições Padrões das Faturas', - 'default_invoice_footer' => 'Rodapé Padrão das Faturas', + 'default_invoice_terms' => 'Definir condições padrões da fatura', + 'default_invoice_footer' => 'Definir padrão', 'quote_footer' => 'Rodapé do Orçamento', 'free' => 'Grátis', - 'quote_is_approved' => 'Orçamento aprovado.', 'apply_credit' => 'Aplicar Crédito', 'system_settings' => 'Configurações do Sistema', @@ -897,7 +794,6 @@ return array( 'restored_recurring_invoice' => 'Fatura Recorrente restaurada', 'archived' => 'Arquivado', 'untitled_account' => 'Empresa Sem Nome', - 'before' => 'Antes', 'after' => 'Depois', 'reset_terms_help' => 'Resetar para as condições padrões', @@ -906,17 +802,7 @@ return array( 'user' => 'Usuário', 'country' => 'País', 'include' => 'Incluir', - 'logo_too_large' => 'Sua logo tem :size, para uma melhor performance sugerimos que este tamanho não ultrapasse 200KB', - 'email_errors' => [ - 'inactive_client' => 'Não é possível enviar e-mails para clientes intativos', - 'inactive_contact' => 'Não é possível enviar e-mails para contatos intativos', - 'inactive_invoice' => 'Não é possível enviar e-mails em faturas intativas', - 'user_unregistered' => 'Registre sua conta para enviar e-mails', - 'user_unconfirmed' => 'Confirme sua conta para enviar e-mails', - 'invalid_contact_email' => 'E-mail do contato inválido', - ], - 'import_freshbooks' => 'Importar de FreshBooks', 'import_data' => 'Importar Dados', 'source' => 'Fonte', @@ -926,7 +812,6 @@ return array( 'task_file' => 'Arquivo de Tarefas', 'no_mapper' => 'Mapeamento inválido', 'invalid_csv_header' => 'CSV com cabeçalho inválido', - 'client_portal' => 'Portal do Cliente', 'admin' => 'Admin', 'disabled' => 'Desabilitado', @@ -935,11 +820,9 @@ return array( 'invoice_will_create' => 'cliente será criado', 'invoices_will_create' => 'faturas serão criadas', 'failed_to_import' => 'A importação dos seguintes registros falhou', - 'publishable_key' => 'Chave Publicável', 'secret_key' => 'Chave Secreta', 'missing_publishable_key' => 'Defina o sua chave publicável do Stripe para um processo de pagamento melhorado', - 'email_design' => 'Template de E-mail', 'due_by' => 'Vencido em :date', 'enable_email_markup' => 'Habilitar Marcação', @@ -951,7 +834,6 @@ return array( 'plain' => 'Plano', 'light' => 'Claro', 'dark' => 'Escuro', - 'industry_help' => 'Usado para fornecer comparações contra as médias das empresas de tamanho e indústria similar.', 'subdomain_help' => 'Personalizar o link da fatura ou exibir a fatura em seu próprio site.', 'invoice_number_help' => 'Especifique um prefixo ou usar um padrão personalizado para definir dinamicamente o número da fatura.', @@ -960,8 +842,6 @@ return array( 'custom_account_fields_helps' => 'Adicionar um rótulo e um valor para a seção detalhes da empresa do PDF.', 'custom_invoice_fields_helps' => 'Adicionar uma entrada de texto na página Criar/Editar Fatura e exibir no PDF.', 'custom_invoice_charges_helps' => 'Adicionar uma entrada de texto na página Criar/Editar Fatura e incluir nos subtotais da fatura.', - 'color_help' => 'Nota: A cor primária também é utilizada nos projetos do portal do cliente e-mail personalizado.', - 'token_expired' => 'Token de acesso expirado. Tente novamente!', 'invoice_link' => 'Link da Fatura', 'button_confirmation_message' => 'Clique para confirmar seu endereço de e-mail.', @@ -970,7 +850,6 @@ return array( 'created_invoices' => ':count fatura(s) criadas com sucesso', 'next_invoice_number' => 'O número da próxima fatura será :number.', 'next_quote_number' => 'O número do próximo orçamento será :number.', - 'days_before' => 'dias antes', 'days_after' => 'dias depois', 'field_due_date' => 'data de vencimento', @@ -978,11 +857,7 @@ return array( 'schedule' => 'Agendamento', 'email_designs' => 'Design de E-mails', 'assigned_when_sent' => 'Assinar quando enviar', - - 'white_label_custom_css' => ':link apenas $'.WHITE_LABEL_PRICE.' para permitir um estilo personalizado e apoiar o nosso projecto.', 'white_label_purchase_link' => 'Adquira uma licença white label', - - // Expense / vendor 'expense' => 'Despesa', 'expenses' => 'Despesas', 'new_expense' => 'Adicionar Despesa', @@ -999,8 +874,6 @@ return array( 'archived_expense' => 'Despesa arquivada com sucesso', 'deleted_expenses' => 'Despesas excluídas com sucesso', 'archived_expenses' => 'Despesas arquivada com sucesso', - - // Expenses 'expense_amount' => 'Total de Despesas', 'expense_balance' => 'Saldo de Despesas', 'expense_date' => 'Data da Despesa', @@ -1025,15 +898,11 @@ return array( 'expense_error_multiple_clients' => 'Despesas não podem pertencer a clientes diferentes', 'expense_error_invoiced' => 'Despeja já faturada', 'convert_currency' => 'Converter moeda', - - // Payment terms 'num_days' => 'Número de dias', 'create_payment_term' => 'Criar Termo de Pagamento', 'edit_payment_terms' => 'Editar Termos de Pagamento', 'edit_payment_term' => 'Editar Termo de Pagamento', 'archive_payment_term' => 'Arquivar Termo de Pagamento', - - // recurring due dates 'recurring_due_dates' => 'Data de Vencimento das Faturas Recorrentes', 'recurring_due_date_help' => '

    Definir automaticamente a data de vencimento da fatura.

    Faturas em um ciclo mensal ou anual com vencimento anterior ou na data em que são criadas serão faturadas para o próximo mês. Faturas com vencimento no dia 29 ou 30 nos meses que não tem esse dia será faturada no último dia do mês..

    @@ -1058,15 +927,11 @@ return array( 'thursday' => 'Quinta-Feira', 'friday' => 'Sexta-Feira', 'saturday' => 'Sábado', - - // Fonts 'header_font_id' => 'Fonte do Cabeçalho', 'body_font_id' => 'Fonte dos Textos', 'color_font_help' => 'Nota: A cor primária também é utilizada nos projetos do portal do cliente e-mail personalizado.', - 'live_preview' => 'Preview', 'invalid_mail_config' => 'Falha ao enviar e-mail, verifique as configurações.', - 'invoice_message_button' => 'Para visualizar sua fatura de :amount, clique no botão abaixo.', 'quote_message_button' => 'Para visualizar seu orçamento de :amount, clique no botão abaixo.', 'payment_message_button' => 'Obrigado pelo seu pagamento de :amount.', @@ -1083,7 +948,6 @@ return array( 'archived_bank_account' => 'Conta bancária arquivada com sucesso', 'created_bank_account' => 'Conta bancária criada com sucesso', 'validate_bank_account' => 'Validar Conta Bancária', - 'bank_accounts_help' => 'Conecte sua conta bancária para importar suas despesas e criar fornecedores. Suporte ao American Express e 400+ bancos americanos.', 'bank_password_help' => 'Nota: sua senha é transferida de forma segura e não será armazenada em nossos servidores.', 'bank_password_warning' => 'Atenção: sua senha será transferida de forma não segura, considere habilitar HTTPS.', 'username' => 'Usuário', @@ -1097,7 +961,6 @@ return array( 'validate' => 'Validado', 'info' => 'Info', 'imported_expenses' => ':count_vendors fornecedor(s) e :count_expenses despesa(s) importadas com sucesso', - 'iframe_url_help3' => 'Nota: se o seu plano aceita detalhes do cartão de crédito recomendamos que seja habilitado o HTTPS em seu site.', 'expense_error_multiple_currencies' => 'As despesas não podem ter diferentes moedas.', 'expense_error_mismatch_currencies' => 'As configurações de moeda do cliente não coincide com a moeda nesta despesa.', @@ -1118,7 +981,28 @@ return array( 'trial_call_to_action' => 'Iniciar período de testes', 'trial_success' => 'Duas semanas de testes foi habilitado com sucesso', 'overdue' => 'Vencido', - 'white_label_text' => 'Adquira UM ano de licença white label por $'.WHITE_LABEL_PRICE.' para remover a marca Invoice Ninja do portal do cliente e ajudar nosso projeto.', + + + 'white_label_text' => 'Adquira UM ano de licença white label por $:price para remover a marca Invoice Ninja do portal do cliente e ajudar nosso projeto.', + 'user_email_footer' => 'Para ajustar suas configurações de notificações de e-mail acesse :link', + 'reset_password_footer' => 'Se você não solicitou a redefinição de sua senha por favor envie um e-mail para o nosso suporte: :email', + 'limit_users' => 'Desculpe, isto irá exceder o limite de :limit usuários', + 'more_designs_self_host_header' => 'Obtenha mais 6 modelos de faturas por apenas $:price', + 'old_browser' => 'Utilize um navegador atualizado', + 'white_label_custom_css' => ':link apenas $:price para permitir um estilo personalizado e apoiar o nosso projecto.', + 'bank_accounts_help' => 'Conecte sua conta bancária para importar suas despesas e criar fornecedores. Suporte ao American Express e 400+ bancos americanos.', + + 'pro_plan_remove_logo' => ':link para remover a logo do Invoice Ninja contratando o plano profissional', + 'pro_plan_remove_logo_link' => 'Clique aqui', + 'invitation_status_sent' => 'E-mail Enviado', + 'invitation_status_opened' => 'E-mail Aberto', + 'invitation_status_viewed' => 'E-mail Visualizado', + 'email_error_inactive_client' => 'Não é possível enviar e-mails para clientes intativos', + 'email_error_inactive_contact' => 'Não é possível enviar e-mails para contatos intativos', + 'email_error_inactive_invoice' => 'Não é possível enviar e-mails em faturas intativas', + 'email_error_user_unregistered' => 'Registre sua conta para enviar e-mails', + 'email_error_user_unconfirmed' => 'Confirme sua conta para enviar e-mails', + 'email_error_invalid_contact_email' => 'E-mail do contato inválido', 'navigation' => 'Navegação', 'list_invoices' => 'Listar Faturas', @@ -1141,22 +1025,20 @@ return array( 'custom_invoice_item_fields_help' => 'Adicionar um campo ao adicionar um ítem na fatura e exibir no PDF.', 'recurring_invoice_number' => 'Número da Fatura Recorrente', 'recurring_invoice_number_prefix_help' => 'Informe um prefixo para a numeração das faturas recorrentes. O valor padrão é \'R\'.', - 'enable_client_portal' => 'Painel', - 'enable_client_portal_help' => 'Mostrar/Ocultar o painel no portal do cliente.', // Client Passwords 'enable_portal_password'=>'Faturas protegidas por senha', 'enable_portal_password_help'=>'Permite definir uma senha para cada contato. Se uma senha for definida, o contato deverá informar sua senha antes de visualizar a fatura.', 'send_portal_password'=>'Gerar senha automaticamente', 'send_portal_password_help'=>'Se uma senha não for definida, uma senha será gerada e enviada juntamente com a primeira fatura.', - + 'expired' => 'Expireda', 'invalid_card_number' => 'Cartão de Crédito inválido.', 'invalid_expiry' => 'Data para expirar não é valida.', 'invalid_cvv' => 'O código CVV não é válido.', 'cost' => 'Custo', 'create_invoice_for_sample' => 'Nota: cria sua primeira fatura para visualizar aqui.', - + // User Permissions 'owner' => 'Proprietário', 'administrator' => 'Administrador', @@ -1174,8 +1056,8 @@ return array( 'create_all_help' => 'Permite o usuário criar e alterar todos os regitros', 'view_all_help' => 'Permite usuario visualizar regitros que ele não criou', 'edit_all_help' => 'Permite usuario editar regitros que ele não criou', - 'view_payment' => 'Visualizar ', - + 'view_payment' => 'Visualizar ', + 'january' => 'Janeiro', 'february' => 'Fevereiro', 'march' => 'Março', @@ -1201,30 +1083,28 @@ return array( 'document_email_attachment' => 'Attach Documents', 'download_documents' => 'Download Documents (:size)', 'documents_from_expenses' => 'From Expenses:', - 'dropzone' => array(// See http://www.dropzonejs.com/#config-dictDefaultMessage - 'DefaultMessage' => 'Drop files or click to upload', - 'FallbackMessage' => 'Your browser does not support drag\'n\'drop file uploads.', - 'FallbackText' => 'Please use the fallback form below to upload your files like in the olden days.', - 'FileTooBig' => 'File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.', - 'InvalidFileType' => 'You can\'t upload files of this type.', - 'ResponseError' => 'Server responded with {{statusCode}} code.', - 'CancelUpload' => 'Cancel upload', - 'CancelUploadConfirmation' => 'Are you sure you want to cancel this upload?', - 'RemoveFile' => 'Remove file', - ), + 'dropzone_default_message' => 'Drop files or click to upload', + 'dropzone_fallback_message' => 'Your browser does not support drag\'n\'drop file uploads.', + 'dropzone_fallback_text' => 'Please use the fallback form below to upload your files like in the olden days.', + 'dropzone_file_too_big' => 'File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.', + 'dropzone_invalid_file_type' => 'You can\'t upload files of this type.', + 'dropzone_response_error' => 'Server responded with {{statusCode}} code.', + 'dropzone_cancel_upload' => 'Cancel upload', + 'dropzone_cancel_upload_confirmation' => 'Are you sure you want to cancel this upload?', + 'dropzone_remove_file' => 'Remove file', 'documents' => 'Documents', 'document_date' => 'Document Date', 'document_size' => 'Size', - 'enable_client_portal' => 'Client Portal', - 'enable_client_portal_help' => 'Show/hide the client portal.', + 'enable_client_portal' => 'Painel', + 'enable_client_portal_help' => 'Mostrar/Ocultar o painel no portal do cliente.', 'enable_client_portal_dashboard' => 'Dashboard', 'enable_client_portal_dashboard_help' => 'Show/hide the dashboard page in the client portal.', - + // Plans - 'account_management' => 'Account Management', + 'account_management' => 'Gerenciamento da Conta', 'plan_status' => 'Plan Status', - + 'plan_upgrade' => 'Upgrade', 'plan_change' => 'Change Plan', 'pending_change_to' => 'Changes To', @@ -1254,9 +1134,9 @@ return array( 'plan_paid' => 'Term Started', 'plan_started' => 'Plan Started', 'plan_expires' => 'Plan Expires', - + 'white_label_button' => 'White Label', - + 'pro_plan_year_description' => 'One year enrollment in the Invoice Ninja Pro Plan.', 'pro_plan_month_description' => 'One month enrollment in the Invoice Ninja Pro Plan.', 'enterprise_plan_product' => 'Enterprise Plan', @@ -1267,14 +1147,214 @@ return array( 'plan_pending_monthly' => 'Will switch to monthly on :date', 'plan_refunded' => 'A refund has been issued.', - 'live_preview' => 'Live Preview', + 'live_preview' => 'Preview', 'page_size' => 'Page Size', 'live_preview_disabled' => 'Live preview has been disabled to support selected font', 'invoice_number_padding' => 'Padding', 'preview' => 'Preview', 'list_vendors' => 'List Vendors', 'add_users_not_supported' => 'Upgrade to the Enterprise plan to add additional users to your account.', - 'enterprise_plan_features' => 'The Enterprise plan adds support for multiple users and file attachments.', + 'enterprise_plan_features' => 'The Enterprise plan adds support for multiple users and file attachments, :link to see the full list of features.', 'return_to_app' => 'Return to app', - -); \ No newline at end of file + + + // Payment updates + 'refund_payment' => 'Reembolsar Pagamento', + 'refund_max' => 'Máx:', + 'refund' => 'Reembolsar', + 'are_you_sure_refund' => 'Reembolsar pagamentos selecionados?', + 'status_pending' => 'Pendente', + 'status_completed' => 'Completo', + 'status_failed' => 'Falhou', + 'status_partially_refunded' => 'Parcialmente Reembolsado', + 'status_partially_refunded_amount' => ':amount Reembolsado', + 'status_refunded' => 'Reembolsado', + 'status_voided' => 'Cancelado', + 'refunded_payment' => 'Pagamento Reembolsado', + 'activity_39' => ':user cancelou um pagamento de :payment_amount (:payment)', + 'activity_40' => ':user reembolsou :adjustment de um pagamento de :payment_amount (:payment)', + 'card_expiration' => 'Venc: :expires', + + 'card_creditcardother' => 'Desconhecido', + 'card_americanexpress' => 'American Express', + 'card_carteblanche' => 'Carte Blanche', + 'card_unionpay' => 'UnionPay', + 'card_diners' => 'Diners Club', + 'card_discover' => 'Discover', + 'card_jcb' => 'JCB', + 'card_laser' => 'Laser', + 'card_maestro' => 'Maestro', + 'card_mastercard' => 'MasterCard', + 'card_solo' => 'Solo', + 'card_switch' => 'Switch', + 'card_visacard' => 'Visa', + 'card_ach' => 'ACH', + + 'payment_type_stripe' => 'Stripe', + 'ach' => 'ACH', + 'enable_ach' => 'Habilitar ACH', + 'stripe_ach_help' => 'ACH também deve estar habilitado no Stripe.', + 'ach_disabled' => 'Another gateway is already configured for direct debit.', + + 'plaid' => 'Plaid', + 'client_id' => 'Cód Cliente', + 'secret' => 'Chave', + 'public_key' => 'Chave Pública', + 'plaid_optional' => '(opcional)', + 'plaid_environment_help' => 'Quando uma chave de teste do Stripe é informada, um ambiente de desenvolvimento (tartan) do Plaid será utilizado.', + 'other_providers' => 'Outros Provedores', + 'country_not_supported' => 'Este país não é suportado.', + 'invalid_routing_number' => 'O número de roteamento é inválido.', + 'invalid_account_number' => 'O número da conta e inválido.', + 'account_number_mismatch' => 'Números da conta não combinam.', + 'missing_account_holder_type' => 'Por favor, selecione uma conta ou empresa individual.', + 'missing_account_holder_name' => 'Por favor, informe o nome do proprietário da conta.', + 'routing_number' => 'Número de Roteamento', + 'confirm_account_number' => 'Confirmar Número da Conta', + 'individual_account' => 'Conta Individual', + 'company_account' => 'Conta Empresarial', + 'account_holder_name' => 'Nome do Proprietário da Conta', + 'add_account' => 'Adicionar Conta', + 'payment_methods' => 'Formas de Pagamentos', + 'complete_verification' => 'Verificação Completa', + 'verification_amount1' => 'Total 1', + 'verification_amount2' => 'Total 2', + 'payment_method_verified' => 'Verificação completa com sucesso', + 'verification_failed' => 'Verificação falhou', + 'remove_payment_method' => 'Remover método de Pagamento', + 'confirm_remove_payment_method' => 'Deseja remover este método de pagamento?', + 'remove' => 'Remover', + 'payment_method_removed' => 'Método de pagamento removido.', + 'bank_account_verification_help' => 'Nós fizemos dois depósitos na sua conta com a descrição "VERIFICATION". Esses depósitos podem levar 1-2 dias úteis para aprecer no seu extrato. Por favor informe os valores de cada um deles abaixo.', + 'bank_account_verification_next_steps' => 'Nós fizemos dois depósitos na sua conta com a descrição "VERIFICATION". Esses depósitos podem levar 1-2 dias úteis para aprecer no seu extrato. +Quando tiver os valores dos depósitos, volte a esta pagina e complete a verificação da sua conta.', + 'unknown_bank' => 'Banco Desconhecido', + 'ach_verification_delay_help' => 'Você poderá utilizar esta conta após a completar a verificação. A verficação normalmente leva 1-2 dias.', + 'add_credit_card' => 'Adicionar Cartão de Crédito', + 'payment_method_added' => 'Médodo de pagamento adicionado.', + 'use_for_auto_bill' => 'Usar para Cobrança Automática', + 'used_for_auto_bill' => 'Método de Pagamento Autobill', + 'payment_method_set_as_default' => 'Definir método de pagamento Autobill.', + 'activity_41' => ':payment_amount payment (:payment) falhou', + 'webhook_url' => 'Webhook URL', + 'stripe_webhook_help' => 'Você deve :link.', + 'stripe_webhook_help_link_text' => 'adicionar esta URL como um endpoint no Stripe', + 'payment_method_error' => 'Ouve um erro ao adicionar seu método de pagamento. Tente novamente.', + 'notification_invoice_payment_failed_subject' => 'Pagamento falhou para a Fatura :invoice', + 'notification_invoice_payment_failed' => 'U pagamento feito pelo Cliente :client para a Fatura :invoice falhou. O pagamento foi marcado como "erro" e :amount foi adicionado ao saldo do cliente.', + 'link_with_plaid' => 'Lincar Conta Instantâneamente com Plaid', + 'link_manually' => 'Linkar Manualmente', + 'secured_by_plaid' => 'Assegurado por Plaid', + 'plaid_linked_status' => 'Sua conta bancária no :bank', + 'add_payment_method' => 'Adicionar Método de Pagamento', + 'account_holder_type' => 'Tipo do Proprietário da Conta', + 'ach_authorization' => 'I authorize :company to use my bank account for future payments and, if necessary, electronically credit my account to correct erroneous debits. I understand that I may cancel this authorization at any time by removing the payment method or by contacting :email.', + 'ach_authorization_required' => 'Você deve permitir transações ACH.', + 'off' => 'Off', + 'opt_in' => 'Opt-in', + 'opt_out' => 'Opt-out', + 'always' => 'Sempre', + 'opted_out' => 'Optado por', + 'opted_in' => 'Optou', + 'manage_auto_bill' => 'Gerenciar Cobrança Automática', + 'enabled' => 'Habilitado', + 'paypal' => 'PayPal', + 'braintree_enable_paypal' => 'Habilitar pagamentos do PayPal através do BrainTree', + 'braintree_paypal_disabled_help' => 'O gateway PayPal está processando pagamentos do PayPal', + 'braintree_paypal_help' => 'Você deve também :link.', + 'braintree_paypal_help_link_text' => 'linkar o PayPal à sua conta do BrainTree', + 'token_billing_braintree_paypal' => 'Salvar detalhes do pagamento', + 'add_paypal_account' => 'Adicionar Conta do PayPal', + + + 'no_payment_method_specified' => 'Nenhum método de pagamento definido', + 'chart_type' => 'Tipo de Gráfico', + 'format' => 'Formato', + 'import_ofx' => 'Importar OFX', + 'ofx_file' => 'Arquivo OFX', + 'ofx_parse_failed' => 'Falha ao ler o arquivo OFX', + + // WePay + 'wepay' => 'WePay', + 'sign_up_with_wepay' => 'Acessar com WePay', + 'use_another_provider' => 'Usar outro provedor', + 'company_name' => 'Nome da Empresa', + 'wepay_company_name_help' => 'Isso vai aparecer na fatura do cartão de crédito do cliente.', + 'wepay_description_help' => 'O objetivo desta conta.', + 'wepay_tos_agree' => 'Concordo com :link.', + 'wepay_tos_link_text' => 'Termos de Serviço do WePay', + 'resend_confirmation_email' => 'Reenviar e-Mail de Confirmação', + 'manage_wepay_account' => 'Gerenciar Conta WePay', + 'action_required' => 'Ação Obrigatória', + 'finish_setup' => 'Finalizar Configuração', + 'created_wepay_confirmation_required' => 'Por favor verifique seu e-mail e confirme seu endereço de e-mail com o WePay', + 'switch_to_wepay' => 'Mudar para WePay', + 'switch' => 'Mudar', + 'restore_account_gateway' => 'Restaurar Gateway', + 'restored_account_gateway' => 'Gateway restaurado com sucesso', + 'united_states' => 'Estados Unidos', + 'canada' => 'Canadá', + 'accept_debit_cards' => 'Aceitar Cartão de Débito', + 'debit_cards' => 'Cartões de Débito', + + 'warn_start_date_changed' => 'The next invoice will be sent on the new start date.', + 'original_start_date' => 'Original start date', + 'new_start_date' => 'New start date', + 'security' => 'Security', + 'see_whats_new' => 'See what\'s new in v:version', + 'wait_for_upload' => 'Please wait for the document upload to complete.', + 'upgrade_for_permissions' => 'Upgrade to our Enterprise plan to enable permissions.', + 'enable_second_tax_rate' => 'Enable specifying a second tax rate', + 'payment_file' => 'Payment File', + 'expense_file' => 'Expense File', + 'product_file' => 'Product File', + 'import_products' => 'Import Products', + 'products_will_create' => 'products will be created.', + 'product_key' => 'Product', + 'created_products' => 'Successfully created :count product(s)', + 'export_help' => 'Use JSON if you plan to import the data into Invoice Ninja.', + 'JSON_file' => 'JSON File', + + 'view_dashboard' => 'View Dashboard', + 'client_session_expired' => 'Session Expired', + 'client_session_expired_message' => 'Your session has expired. Please click the link in your email again.', + + 'auto_bill_notification' => 'This invoice will automatically be billed to your :payment_method on file on :due_date.', + 'auto_bill_payment_method_bank_transfer' => 'bank account', + 'auto_bill_payment_method_credit_card' => 'credit card', + 'auto_bill_payment_method_paypal' => 'PayPal account', + 'auto_bill_notification_placeholder' => 'This invoice will automatically be billed to your credit card on file on the due date.', + 'payment_settings' => 'Payment Settings', + + 'on_send_date' => 'On send date', + 'on_due_date' => 'On due date', + 'auto_bill_ach_date_help' => 'ACH auto bill will always happen on the due date', + 'warn_change_auto_bill' => 'Due to NACHA rules, changes to this invoice may prevent ACH auto bill.', + + 'bank_account' => 'Bank Account', + 'payment_processed_through_wepay' => 'ACH payments will be processed using WePay.', + 'wepay_payment_tos_agree' => 'I agree to the WePay :terms and :privacy_policy.', + 'privacy_policy' => 'Privacy Policy', + 'wepay_payment_tos_agree_required' => 'You must agree to the WePay Terms of Service and Privacy Policy.', + 'payment_settings_supported_gateways' => 'These options are supported by the WePay, Stripe, and Braintree gateways.', + 'ach_email_prompt' => 'Please enter your email address:', + 'verification_pending' => 'Verification Pending', + + 'update_font_cache' => 'Please force refresh the page to update the font cache.', + 'more_options' => 'More options', + 'credit_card' => 'Credit Card', + 'bank_transfer' => 'Bank Transfer', + 'no_transaction_reference' => 'We did not recieve a payment transaction reference from the gateway.', + 'use_bank_on_file' => 'Use Bank on File', + 'auto_bill_email_message' => 'This invoice will automatically be billed to the payment method on file on the due date.', + 'bitcoin' => 'Bitcoin', + 'added_on' => 'Added :date', + 'failed_remove_payment_method' => 'Failed to remove the payment method', + 'gateway_exists' => 'This gateway already exists', + 'manual_entry' => 'Manual entry', + +); + +return $LANG; + +?> diff --git a/resources/lang/sv/texts.php b/resources/lang/sv/texts.php index 634a5bbe15..117870247e 100644 --- a/resources/lang/sv/texts.php +++ b/resources/lang/sv/texts.php @@ -1,8 +1,6 @@ 'Organisation', 'name' => 'Namn', 'website' => 'Hemsida', @@ -25,8 +23,6 @@ return array( 'size_id' => 'Storlek', 'industry_id' => 'Branch', 'private_notes' => 'Privata anteckningar', - - // invoice 'invoice' => 'Faktura', 'client' => 'Kund', 'invoice_date' => 'Fakturadatum', @@ -50,7 +46,6 @@ return array( 'invoice_design_id' => 'Utseende', 'terms' => 'Villkor', 'your_invoice' => 'Din faktura', - 'remove_contact' => 'Ta bort kontakt', 'add_contact' => 'Lägg till kontakt', 'create_new_client' => 'Skapa ny kund', @@ -74,8 +69,6 @@ return array( 'settings' => 'Inställningar', 'enable_invoice_tax' => 'Slå på moms per faktura', 'enable_line_item_tax' => 'Slå på moms per rad', - - // navigation 'dashboard' => 'Översikt', 'clients' => 'Kunder', 'invoices' => 'Fakturor', @@ -100,8 +93,6 @@ return array( 'provide_email' => 'Du måste ange en giltig e-postadress', 'powered_by' => 'Powered by', 'no_items' => 'Tomt', - - // recurring invoices 'recurring_invoices' => 'Återkommande fakturor', 'recurring_help' => '

    Skicka automatiskt fakturor till kund varje vecka, månad, kvartal eller årsvis.

    Använd :MONTH, :QUARTER eller :YEAR för dynamiskt datum. Enkla formler fungerar också, t.ex. :MONTH-1

    @@ -111,8 +102,6 @@ return array(
  • ":YEAR+1 årlig prenumeration" => "2015 årlig prenumeration"
  • "Underhåll för :QUARTER+1" => "Underhåll för Q2"
  • ', - - // dashboard 'in_total_revenue' => 'i totala intäkter', 'billed_client' => 'fakturerad kund', 'billed_clients' => 'fakturerade kunder', @@ -121,8 +110,6 @@ return array( 'invoices_past_due' => 'Försenade fakturor', 'upcoming_invoices' => 'Kommande fakturor', 'average_invoice' => 'Genomsnittlig faktura', - - // list pages 'archive' => 'Arkiv', 'delete' => 'Ta bort', 'archive_client' => 'Arkiverade kunder', @@ -158,8 +145,6 @@ return array( 'select' => 'Välj', 'edit_client' => 'Ändra kund', 'edit_invoice' => 'Ändra faktura', - - // client view page 'create_invoice' => 'Skapa faktura', 'enter_credit' => 'Ange kredit', 'last_logged_in' => 'Senast inloggad', @@ -171,12 +156,8 @@ return array( 'message' => 'Meddelande', 'adjustment' => 'Justering', 'are_you_sure' => 'Är du säker?', - - // payment pages 'payment_type_id' => 'Betalningssätt', 'amount' => 'Summa', - - // account/company pages 'work_email' => 'E-postadress', 'language_id' => 'Språk', 'timezone_id' => 'Tidszon', @@ -194,11 +175,7 @@ return array( 'email_paid' => 'Skicka mail när faktura betalas', 'site_updates' => 'Sajt-uppdateringar', 'custom_messages' => 'Anpassat meddelande', - 'default_invoice_terms' => 'Ange standard fakturavillkor', 'default_email_footer' => 'Ange standard mailsignatur', - 'import_clients' => 'Importera kunder', - 'csv_file' => 'Välj CSV-fil', - 'export_clients' => 'Exportera kunder', 'select_file' => 'Välj fil', 'first_row_headers' => 'Använd första raden som rubrik', 'column' => 'Kolumn', @@ -207,9 +184,12 @@ return array( 'client_will_create' => 'kund kommer skapas', 'clients_will_create' => 'kunder kommer skapas', 'email_settings' => 'Mail-inställningar', + 'client_view_styling' => 'Client View Styling', 'pdf_email_attachment' => 'bifoga PDF till mail', - - // application messages + 'custom_css' => 'Custom CSS', + 'import_clients' => 'Importera kunder', + 'csv_file' => 'Välj CSV-fil', + 'export_clients' => 'Exportera kunder', 'created_client' => 'Kund skapad', 'created_clients' => ':count kunder skapade', 'updated_settings' => 'Inställningar uppdaterade', @@ -220,14 +200,12 @@ return array( 'payment_error' => 'Något blev fel när din betalning bearbetades. Var vänlig och försök igen lite senare.', 'registration_required' => 'Du måste registrera dig för att kunna skicka en faktura som e-post', 'confirmation_required' => 'Var vänlig och bekräfta din e-postadress', - 'updated_client' => 'Kund uppdaterad', 'created_client' => 'Kund skapad', 'archived_client' => 'Kund arkiverad', 'archived_clients' => ':count kunder arkiverade', 'deleted_client' => 'kund borttagen', 'deleted_clients' => ':count kunder borttagna', - 'updated_invoice' => 'Faktura uppdaterad', 'created_invoice' => 'Faktura skapad', 'cloned_invoice' => 'Faktura kopierad', @@ -237,21 +215,25 @@ return array( 'archived_invoices' => ':count fakturor arkiverade', 'deleted_invoice' => 'Faktura borttagen', 'deleted_invoices' => ':count fakturor borttagna', - 'created_payment' => 'Betalning registrerad', + 'created_payments' => 'Successfully created :count payment(s)', 'archived_payment' => 'Betalning arkiverad', 'archived_payments' => ':count betalningar arkiverade', 'deleted_payment' => 'Betalning borttagen', 'deleted_payments' => ':count betalningar borttagna', 'applied_payment' => 'Betalning applicerad', - 'created_credit' => 'Kreditfaktura skapad', 'archived_credit' => 'Kreditfaktura arkiverad', 'archived_credits' => ':count kreditfakturor arkiverade', 'deleted_credit' => 'Kreditfaktura borttagen', 'deleted_credits' => ':count kreditfakturor borttagna', - - // Emails + 'imported_file' => 'Successfully imported file', + 'updated_vendor' => 'Successfully updated vendor', + 'created_vendor' => 'Successfully created vendor', + 'archived_vendor' => 'Successfully archived vendor', + 'archived_vendors' => 'Successfully archived :count vendors', + 'deleted_vendor' => 'Successfully deleted vendor', + 'deleted_vendors' => 'Successfully deleted :count vendors', 'confirmation_subject' => 'Bekräfta ditt Invoice Ninja konto', 'confirmation_header' => 'Bekräfta ditt konto', 'confirmation_message' => 'Vänligen klick på länken nedan för att bekräfta ditt konto.', @@ -262,7 +244,6 @@ return array( 'email_salutation' => 'Hej :name,', 'email_signature' => 'Vänliga hälsningar,', 'email_from' => 'Invoice Ninja teamet', - 'user_email_footer' => 'För att anpassa dina e-post notifieringar gå till '.SITE_URL.'/settings/notifications', 'invoice_link_message' => 'För att se din kundfaktura klicka på länken nedan:', 'notification_invoice_paid_subject' => 'Faktura :invoice är betald av :client', 'notification_invoice_sent_subject' => 'Faktura :invoice är skickad till :client', @@ -271,32 +252,11 @@ return array( 'notification_invoice_sent' => 'Följande kund :client har mailats fakturan :invoice på :amount.', 'notification_invoice_viewed' => 'Följande kund :client har sett fakturan :invoice på :amount.', 'reset_password' => 'Du kan återställa ditt lösenord genom att klicka på länken nedan:', - 'reset_password_footer' => 'Om du inte begärt en återställning av ditt lösenord så var snäll och maila vår support: '.CONTACT_EMAIL, - - // Payment page 'secure_payment' => 'Säker betalning', 'card_number' => 'Kortnummer', 'expiration_month' => 'Giltig till månad', 'expiration_year' => 'Giltig till år', 'cvv' => 'CVV', - - // Security alerts - 'confide' => [ - 'too_many_attempts' => 'För många felaktiga försök. Pröva igen om ett par minuter.', - 'wrong_credentials' => 'Felaktig e-postadress eller lösenord.', - 'confirmation' => 'Ditt konto har bekräftats!', - 'wrong_confirmation' => 'Felaktig bekräftelsekod.', - 'password_forgot' => 'Information angående återställning av ditt lösenord har skickats till dig via e-post.', - 'password_reset' => 'Ditt lösenord har uppdaterats.', - 'wrong_password_reset' => 'Felaktigt lösenord. Försök igen', - ], - - // Pro Plan - 'pro_plan' => [ - 'remove_logo' => ':link för att ta bort Invoice Ninja loggan genom att uppgradera till Pro Plan', - 'remove_logo_link' => 'Klicka här', - ], - 'logout' => 'Logga ut', 'sign_up_to_save' => 'Registrera dig för att spara ditt arbete', 'agree_to_terms' => 'Jag godkänner Invoice Ninja :terms', @@ -307,16 +267,13 @@ return array( 'success_message' => 'Du har nu registrerat dig. Klicka på länken i ditt bekräftelsemail för att verifiera din e-postadress.', 'erase_data' => 'Detta kommer radera all din data och går ej att ångra!', 'password' => 'Lösenord', - 'pro_plan_product' => 'Pro Plan', - 'pro_plan_description' => 'Ett års prenumeration på Invoice Ninja Pro.', 'pro_plan_success' => 'Tack för att du väljer Invoice Ninja\'s Pro!

     
    Nästa steg

    En faktura har skickats till din angivna e-postadress. Var vänlig och följ instruktionerna på fakturan för att betala för ett års Pro fakturering och få tillgång till alla fantastiska Pro-funktioner.

    Hittar du inte fakturan? Behöver du support? Vi hjälper dig! -- maila oss på contact@invoiceninja.com', - 'unsaved_changes' => 'Du har osparade ändringar', 'custom_fields' => 'Anpassade fält', 'company_fields' => 'Företagsfält', @@ -326,8 +283,6 @@ return array( 'edit' => 'Ändra', 'set_name' => 'Ange ditt företagsnamn', 'view_as_recipient' => 'Se som mottagare', - - // product management 'product_library' => 'Produktbibliotek', 'product' => 'Produkt', 'products' => 'Produkter', @@ -342,18 +297,14 @@ return array( 'created_product' => 'Produkt skapad', 'archived_product' => 'Produkt arkiverad', 'pro_plan_custom_fields' => ':link för att slå på anpassade fält genom att uppgradera till Pro', - 'advanced_settings' => 'Avancerade inställningar', 'pro_plan_advanced_settings' => ':link för att slå på avancerade inställningar genom att uppgradera till Pro', 'invoice_design' => 'Fakturadesign', 'specify_colors' => 'Ange färger', 'specify_colors_label' => 'Välj färger som ska användas på fakturan', - 'chart_builder' => 'Diagrambyggare', 'ninja_email_footer' => 'Använda :site för att fakturera dina kunder och få betalt online gratis!', 'go_pro' => 'Uppgradera till Pro', - - // Quotes 'quote' => 'Offert', 'quotes' => 'Offerter', 'quote_number' => 'Offertnummer', @@ -363,7 +314,6 @@ return array( 'your_quote' => 'Din offert', 'total' => 'Totalsumma', 'clone' => 'Kopiera', - 'new_quote' => 'Ny offert', 'create_quote' => 'Skapa offert', 'edit_quote' => 'Ändra offert', @@ -376,7 +326,6 @@ return array( 'view_invoice' => 'Visa faktura', 'view_client' => 'Visa kund', 'view_quote' => 'Visa offert', - 'updated_quote' => 'Offert uppdaterad', 'created_quote' => 'Offert skapad', 'cloned_quote' => 'Offert kopierad', @@ -386,7 +335,6 @@ return array( 'deleted_quote' => 'Offert borttagen', 'deleted_quotes' => ':count offerter borttagna', 'converted_to_invoice' => 'Offert konverterad till faktura', - 'quote_subject' => 'Ny offert från :account', 'quote_message' => 'Klicka på länken nedan för att visa din offert på :amount.', 'quote_link_message' => 'Klicka på länken nedan för att visa din offert:', @@ -394,16 +342,13 @@ return array( 'notification_quote_viewed_subject' => 'Offert :invoice har setts av :client', 'notification_quote_sent' => 'Följande kunder :client har skickats offerten :invoice på :amount.', 'notification_quote_viewed' => 'Följande kunder :client har sett offerten :invoice på :amount.', - 'session_expired' => 'Din session har avslutats.', - 'invoice_fields' => 'Fakturafält', 'invoice_options' => 'Fakturainställningar', 'hide_quantity' => 'Dölj antal', 'hide_quantity_help' => 'Om antal alltid är 1 så kan du göra fakturan tydligare genom att dölja detta fält.', 'hide_paid_to_date' => 'Dölj "Betald till"', 'hide_paid_to_date_help' => 'Visa bara "Betald till"-sektionen på fakturan när en betalning har mottagits.', - 'charge_taxes' => 'Inkludera moms', 'user_management' => 'Användarhantering', 'add_user' => 'Lägg till användare', @@ -418,21 +363,16 @@ return array( 'active' => 'Aktiv', 'pending' => 'Avvaktar', 'deleted_user' => 'Användare borttagen', - 'limit_users' => 'Ledsen, men du får skapa max '.MAX_NUM_USERS.' användare', - 'confirm_email_invoice' => 'Är du säker på att du vill maila denna fakturan?', 'confirm_email_quote' => 'Är du säker på att du vill maila denna offerten?', 'confirm_recurring_email_invoice' => 'Återkommande fakturor är påslaget, är du säker på att du vill maila denna fakturan?', - 'cancel_account' => 'Avsluta konto', 'cancel_account_message' => 'Varning: Detta kommer att ta bort all din data och går inte att ångra!', 'go_back' => 'Tillbaka', - 'data_visualizations' => 'Datavisualisering', 'sample_data' => 'Exempeldata visas', 'hide' => 'Dölj', 'new_version_available' => 'En ny version av :releases_link finns tillgänglig. Du kör just nu v:user_version och senaste är v:latest_version', - 'invoice_settings' => 'Fakturainställningar', 'invoice_number_prefix' => 'Fakturaprefix', 'invoice_number_counter' => 'Fakturaräknare', @@ -442,59 +382,48 @@ return array( 'invoice_issued_to' => 'Faktura ställd till', 'invalid_counter' => 'För att undvika nummerkonflikt så bör antingen faktura- eller offertprefix anges', 'mark_sent' => 'Markering skickad', - 'gateway_help_1' => ':link för att registrera dig på Authorize.net.', 'gateway_help_2' => ':link för att registrera dig på Authorize.net.', 'gateway_help_17' => ':link för att hämta din PayPal API-nyckel.', 'gateway_help_27' => ':link för att registrera dig för TwoCheckout.', - 'more_designs' => 'Fler fakturalayouter', 'more_designs_title' => 'Fler fakturalayouter', 'more_designs_cloud_header' => 'Uppgrader till Pro för fler fakturalayouter', 'more_designs_cloud_text' => '', - 'more_designs_self_host_header' => 'Få ytterliggare 6 fakturalayouter för bara $'.INVOICE_DESIGNS_PRICE, 'more_designs_self_host_text' => '', 'buy' => 'Köp', 'bought_designs' => 'Fler fakturalayouter tillagda', 'sent' => 'skickat', - 'vat_number' => 'Momsregistreringsnummer', 'timesheets' => 'Tidrapporter', - 'payment_title' => 'Ange din fakturaadress och betalkortsinformation', 'payment_cvv' => '*Detta är det 3-4 siffriga nummret på baksidan av kortet', 'payment_footer1' => '*Fakturaadressen måste stämma överens med adressen kopplad till betalkortet.', 'payment_footer2' => '*Klicka bara en gång på "BETALA NU" - transaktionen kan ta upp till 1 minut att behandla.', - 'id_number' => 'ID-nummer', 'white_label_link' => 'White label', 'white_label_header' => 'White Label', 'bought_white_label' => 'White label licens köpt', 'white_labeled' => 'White labeled', - 'restore' => 'Återställ', 'restore_invoice' => 'Återställ faktura', 'restore_quote' => 'Återställ offert', 'restore_client' => 'Återställ kund', 'restore_credit' => 'Återställ kreditfaktura', 'restore_payment' => 'Återställ betalning', - 'restored_invoice' => 'Faktura återställd', 'restored_quote' => 'Offert återställd', 'restored_client' => 'Kund återställd', 'restored_payment' => 'betalning återställd', 'restored_credit' => 'Kreditfaktura återställd', - 'reason_for_canceling' => 'Hjälp oss bli bättre genom att berätta varför du lämnar oss.', 'discount_percent' => 'Procent', 'discount_amount' => 'Summa', - 'invoice_history' => 'Fakturahistorik', 'quote_history' => 'Offerthistorik', 'current_version' => 'Nuvarande version', 'select_version' => 'Välj version', 'view_history' => 'Visa historik', - 'edit_payment' => 'Ändra betalning', 'updated_payment' => 'Betalning uppdaterad', 'deleted' => 'Ta bort', @@ -507,7 +436,6 @@ return array( 'quote_email' => 'Offert-mail', 'reset_all' => 'Återställ allt', 'approve' => 'Godkänn', - 'token_billing_type_id' => 'Token fakturering', 'token_billing_help' => 'Låter dig spara kortinformation i din gateway, och ta betalt vid ett senare tillfälle.', 'token_billing_1' => 'Avstängd', @@ -515,12 +443,11 @@ return array( 'token_billing_3' => 'Opt-out - Checkbox visas och är förvald', 'token_billing_4' => 'alltid', 'token_billing_checkbox' => 'Spara betalkortsinformation', - 'view_in_stripe' => 'Visa i Stripe', - 'use_card_on_file' => 'Använd kort på fil', + 'view_in_gateway' => 'Visa i :gateway', + 'use_card_on_file' => 'Use Card on File', 'edit_payment_details' => 'Ändra betalningsdetaljer', 'token_billing' => 'Spara kortinformation', - 'token_billing_secure' => 'Data sparas säkert med :stripe_link', - + 'token_billing_secure' => 'Data sparas säkert med :link', 'support' => 'Support', 'contact_information' => 'Kontaktinformation', '256_encryption' => '256-bitars kryptering', @@ -530,11 +457,8 @@ return array( 'order_overview' => 'Orderöversikt', 'match_address' => '*Adressen måste stämma överens med adressen kopplad till betalkortet.', 'click_once' => '*Klicka bara en gång på "BETALA NU" - transaktionen kan ta upp till 1 minut att behandla.', - - 'default_invoice_footer' => 'Ange som standard faktura sidfot', 'invoice_footer' => 'Faktura sidfot', 'save_as_default_footer' => 'Spara som standard sidfot', - 'token_management' => 'Token hantering', 'tokens' => 'Tokens', 'add_token' => 'Lägg till token', @@ -545,7 +469,6 @@ return array( 'edit_token' => 'Ändra token', 'delete_token' => 'Ta bort token', 'token' => 'Token', - 'add_gateway' => 'Lägg till gateway', 'delete_gateway' => 'Ta bort gateway', 'edit_gateway' => 'Ändra gateway', @@ -554,7 +477,6 @@ return array( 'deleted_gateway' => 'Gateway borttagen', 'pay_with_paypal' => 'PayPal', 'pay_with_card' => 'Betalkort', - 'change_password' => 'Ändra lösenord', 'current_password' => 'Nuvarande lösenord', 'new_password' => 'Nytt lösenord', @@ -562,7 +484,6 @@ return array( 'password_error_incorrect' => 'Nuvarande lösenord är felaktigt.', 'password_error_invalid' => 'Det nya lösenordet är felaktigt.', 'updated_password' => 'Lösenord uppdaterat', - 'api_tokens' => 'API Tokens', 'users_and_tokens' => 'Användare och tokens', 'account_login' => 'Inloggning', @@ -574,13 +495,11 @@ return array( 'send_email' => 'Skicka mail', 'set_password' => 'Ange lösenord', 'converted' => 'Konvertera', - 'email_approved' => 'Email me when a quote is approved', 'notification_quote_approved_subject' => 'Quote :invoice was approved by :client', 'notification_quote_approved' => 'The following client :client approved Quote :invoice for :amount.', 'resend_confirmation' => 'Resend confirmation email', 'confirmation_resent' => 'The confirmation email was resent', - 'gateway_help_42' => ':link to sign up for BitPay.
    Note: use a Legacy API Key, not an API token.', 'payment_type_credit_card' => 'Credit card', 'payment_type_paypal' => 'PayPal', @@ -588,7 +507,6 @@ return array( 'knowledge_base' => 'Knowledge Base', 'partial' => 'Partial', 'partial_remaining' => ':partial of :balance', - 'more_fields' => 'More Fields', 'less_fields' => 'Less Fields', 'client_name' => 'Client Name', @@ -599,7 +517,6 @@ return array( 'view_documentation' => 'View Documentation', '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.', - 'rows' => 'rows', 'www' => 'www', 'logo' => 'Logo', @@ -619,7 +536,6 @@ return array( 'zapier' => 'Zapier', 'recurring' => 'Recurring', 'last_invoice_sent' => 'Last invoice sent :date', - 'processed_updates' => 'Successfully completed update', 'tasks' => 'Tasks', 'new_task' => 'New Task', @@ -665,12 +581,10 @@ return array( 'invoice_labels' => 'Invoice Labels', 'prefix' => 'Prefix', 'counter' => 'Counter', - 'payment_type_dwolla' => 'Dwolla', 'gateway_help_43' => ':link to sign up for Dwolla.', 'partial_value' => 'Must be greater than zero and less than the total', 'more_actions' => 'More Actions', - 'pro_plan_title' => 'NINJA PRO', 'pro_plan_call_to_action' => 'Upgrade Now!', 'pro_plan_feature1' => 'Create Unlimited Clients', @@ -681,14 +595,12 @@ return array( 'pro_plan_feature6' => 'Create Quotes & Pro-forma Invoices', 'pro_plan_feature7' => 'Customize Invoice Field Titles & Numbering', 'pro_plan_feature8' => 'Option to Attach PDFs to Client Emails', - 'resume' => 'Resume', 'break_duration' => 'Break', 'edit_details' => 'Edit Details', 'work' => 'Work', 'timezone_unset' => 'Please :link to set your timezone', 'click_here' => 'click here', - 'email_receipt' => 'Email payment receipt to the client', 'created_payment_emailed_client' => 'Successfully created payment and emailed client', 'add_company' => 'Add Company', @@ -698,10 +610,8 @@ return array( 'unlinked_account' => 'Successfully unlinked accounts', 'login' => 'Login', 'or' => 'or', - 'email_error' => 'There was a problem sending the email', 'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.', - 'old_browser' => 'Please use a newer browser', 'payment_terms_help' => 'Sets the default invoice due date', 'unlink_account' => 'Unlink Account', 'unlink' => 'Unlink', @@ -722,7 +632,6 @@ return array( 'primary_color' => 'Primary Color', 'secondary_color' => 'Secondary Color', 'customize_design' => 'Customize Design', - 'content' => 'Content', 'styles' => 'Styles', 'defaults' => 'Defaults', @@ -736,7 +645,6 @@ return array( 'outstanding' => 'Outstanding', 'manage_companies' => 'Manage Companies', 'total_revenue' => 'Total Revenue', - 'current_user' => 'Current User', 'new_recurring_invoice' => 'New Recurring Invoice', 'recurring_invoice' => 'Recurring Invoice', @@ -745,9 +653,8 @@ return array( 'primary_user' => 'Primary User', 'help' => 'Help', 'customize_help' => '

    We use pdfmake to define the invoice designs declaratively. The pdfmake playground provide\'s a great way to see the library in action.

    -

    To access a child property using dot notation. For example to show the client name you could use $client.name.

    -

    If you need help figuring something out post a question to our support forum.

    ', - +

    You can access a child property using dot notation. For example to show the client name you could use $client.name.

    +

    If you need help figuring something out post a question to our support forum with the design you\'re using.

    ', 'invoice_due_date' => 'Due Date', 'quote_due_date' => 'Valid Until', 'valid_until' => 'Valid Until', @@ -760,15 +667,12 @@ return array( 'status_partial' => 'Partial', 'status_paid' => 'Paid', 'show_line_item_tax' => 'Display line item taxes inline', - 'iframe_url' => 'Website', '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.', - 'auto_bill' => 'Auto Bill', 'military_time' => '24 Hour Time', 'last_sent' => 'Last Sent', - 'reminder_emails' => 'Reminder Emails', 'templates_and_reminders' => 'Templates & Reminders', 'subject' => 'Subject', @@ -780,15 +684,12 @@ return array( 'reminder_subject' => 'Reminder: Invoice :invoice from :account', 'reset' => 'Reset', 'invoice_not_found' => 'The requested invoice is not available', - 'referral_program' => 'Referral Program', 'referral_code' => 'Referral Code', 'last_sent_on' => 'Last sent on :date', - 'page_expire' => 'This page will expire soon, :click_here to keep working', 'upcoming_quotes' => 'Upcoming Quotes', 'expired_quotes' => 'Expired Quotes', - 'sign_up_using' => 'Sign up using', 'invalid_credentials' => 'These credentials do not match our records', 'show_all_options' => 'Show all options', @@ -797,17 +698,10 @@ return array( 'disable' => 'Disable', 'invoice_quote_number' => 'Invoice and Quote Numbers', '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_subject' => 'Unable to deliver Invoice :invoice', 'notification_quote_bounced' => 'We were unable to deliver Quote :invoice to :contact.', 'notification_quote_bounced_subject' => 'Unable to deliver Quote :invoice', - 'custom_invoice_link' => 'Custom Invoice Link', 'total_invoiced' => 'Total Invoiced', 'open_balance' => 'Open Balance', @@ -815,14 +709,12 @@ return array( 'basic_settings' => 'Basic Settings', 'pro' => 'Pro', 'gateways' => 'Payment Gateways', - 'next_send_on' => 'Send Next: :date', 'no_longer_running' => 'This invoice is not scheduled to run', 'general_settings' => 'General Settings', 'customize' => 'Customize', 'oneclick_login_help' => 'Connect an account to login without a password', 'referral_code_help' => 'Earn money by sharing our app online', - 'enable_with_stripe' => 'Enable | Requires Stripe', 'tax_settings' => 'Tax Settings', 'create_tax_rate' => 'Add Tax Rate', @@ -843,7 +735,6 @@ return array( 'invoice_counter' => 'Invoice Counter', 'quote_counter' => 'Quote Counter', 'type' => 'Type', - 'activity_1' => ':user created client :client', 'activity_2' => ':user archived client :client', 'activity_3' => ':user deleted client :client', @@ -873,18 +764,24 @@ return array( 'activity_27' => ':user restored payment :payment', 'activity_28' => ':user restored :credit credit', 'activity_29' => ':contact approved quote :quote', - + 'activity_30' => ':user created :vendor', + 'activity_31' => ':user created :vendor', + 'activity_32' => ':user created :vendor', + 'activity_33' => ':user created :vendor', + 'activity_34' => ':user created expense :expense', + 'activity_35' => ':user created :vendor', + 'activity_36' => ':user created :vendor', + 'activity_37' => ':user created :vendor', 'payment' => 'Payment', 'system' => 'System', 'signature' => 'Email Signature', 'default_messages' => 'Default Messages', 'quote_terms' => 'Quote Terms', 'default_quote_terms' => 'Default Quote Terms', - 'default_invoice_terms' => 'Default Invoice Terms', - 'default_invoice_footer' => 'Default Invoice Footer', + 'default_invoice_terms' => 'Ange standard fakturavillkor', + 'default_invoice_footer' => 'Ange som standard faktura sidfot', 'quote_footer' => 'Quote Footer', 'free' => 'Free', - 'quote_is_approved' => 'This quote is approved', 'apply_credit' => 'Apply Credit', 'system_settings' => 'System Settings', @@ -902,7 +799,6 @@ return array( 'restored_recurring_invoice' => 'Successfully restored recurring invoice', 'archived' => 'Archived', 'untitled_account' => 'Untitled Company', - 'before' => 'Before', 'after' => 'After', 'reset_terms_help' => 'Reset to the default account terms', @@ -911,7 +807,6 @@ return array( 'user' => 'User', 'country' => 'Country', 'include' => 'Include', - '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_data' => 'Import Data', @@ -922,16 +817,6 @@ return array( 'task_file' => 'Task File', 'no_mapper' => 'No valid mapping for file', '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', 'admin' => 'Admin', 'disabled' => 'Disabled', @@ -940,11 +825,9 @@ return array( 'invoice_will_create' => 'client will be created', 'invoices_will_create' => 'invoices will be created', 'failed_to_import' => 'The following records failed to import, they either already exist or are missing required fields.', - 'publishable_key' => 'Publishable Key', 'secret_key' => 'Secret Key', 'missing_publishable_key' => 'Set your Stripe publishable key for an improved checkout process', - 'email_design' => 'Email Design', 'due_by' => 'Due by :date', 'enable_email_markup' => 'Enable Markup', @@ -956,7 +839,6 @@ return array( 'plain' => 'Plain', 'light' => 'Light', 'dark' => 'Dark', - '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.', 'invoice_number_help' => 'Specify a prefix or use a custom pattern to dynamically set the invoice number.', @@ -965,8 +847,6 @@ return array( '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_charges_helps' => 'Add a text input to the invoice create/edit page and include the charge in the invoice subtotals.', - 'color_help' => 'Note: the primary color is also used in the client portal and custom email designs.', - 'token_expired' => 'Validation token was expired. Please try again.', 'invoice_link' => 'Invoice Link', 'button_confirmation_message' => 'Click to confirm your email address.', @@ -975,7 +855,6 @@ return array( 'created_invoices' => 'Successfully created :count invoice(s)', 'next_invoice_number' => 'The next invoice number is :number.', 'next_quote_number' => 'The next quote number is :number.', - 'days_before' => 'days before', 'days_after' => 'days after', 'field_due_date' => 'due date', @@ -983,11 +862,7 @@ return array( 'schedule' => 'Schedule', 'email_designs' => 'Email Designs', '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', - - // Expense / vendor 'expense' => 'Expense', 'expenses' => 'Expenses', 'new_expense' => 'Enter Expense', @@ -1004,8 +879,6 @@ return array( 'archived_expense' => 'Successfully archived expense', 'deleted_expenses' => 'Successfully deleted expenses', 'archived_expenses' => 'Successfully archived expenses', - - // Expenses 'expense_amount' => 'Expense Amount', 'expense_balance' => 'Expense Balance', 'expense_date' => 'Expense Date', @@ -1030,15 +903,11 @@ return array( 'expense_error_multiple_clients' => 'The expenses can\'t belong to different clients', 'expense_error_invoiced' => 'Expense has already been invoiced', 'convert_currency' => 'Convert currency', - - // Payment terms 'num_days' => 'Number of days', 'create_payment_term' => 'Create Payment Term', 'edit_payment_terms' => 'Edit Payment Term', 'edit_payment_term' => 'Edit Payment Term', 'archive_payment_term' => 'Archive Payment Term', - - // recurring due dates 'recurring_due_dates' => 'Recurring Invoice Due Dates', 'recurring_due_date_help' => '

    Automatically sets a due date for the invoice.

    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.

    @@ -1066,15 +935,11 @@ return array( 'thursday' => 'Thursday', 'friday' => 'Friday', 'saturday' => 'Saturday', - - // Fonts 'header_font_id' => 'Header 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.', - 'live_preview' => 'Live Preview', '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.', 'quote_message_button' => 'To view your quote for :amount, click the button below.', 'payment_message_button' => 'Thank you for your payment of :amount.', @@ -1091,7 +956,6 @@ return array( 'archived_bank_account' => 'Successfully archived bank account', 'created_bank_account' => 'Successfully created 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 400+ US banks.', '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.', 'username' => 'Username', @@ -1105,7 +969,6 @@ return array( 'validate' => 'Validate', 'info' => 'Info', '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.', '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.', @@ -1126,7 +989,28 @@ return array( 'trial_call_to_action' => 'Start Free Trial', '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.', + + + 'white_label_text' => 'Purchase a ONE YEAR white label license for $:price to remove the Invoice Ninja branding from the client portal and help support our project.', + 'user_email_footer' => 'För att anpassa dina e-post notifieringar gå till :link', + 'reset_password_footer' => 'Om du inte begärt en återställning av ditt lösenord så var snäll och maila vår support: :email', + 'limit_users' => 'Ledsen, men du får skapa max :limit användare', + 'more_designs_self_host_header' => 'Få ytterliggare 6 fakturalayouter för bara $:price', + 'old_browser' => 'Please use a newer browser', + 'white_label_custom_css' => ':link for $: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 400+ US banks.', + + 'pro_plan_remove_logo' => ':link för att ta bort Invoice Ninja loggan genom att uppgradera till Pro Plan', + 'pro_plan_remove_logo_link' => 'Klicka här', + 'invitation_status_sent' => 'Email Sent', + 'invitation_status_opened' => 'Email Openend', + 'invitation_status_viewed' => 'Invoice Viewed', + 'email_error_inactive_client' => 'Emails can not be sent to inactive clients', + 'email_error_inactive_contact' => 'Emails can not be sent to inactive contacts', + 'email_error_inactive_invoice' => 'Emails can not be sent to inactive invoices', + 'email_error_user_unregistered' => 'Please register your account to send emails', + 'email_error_user_unconfirmed' => 'Please confirm your account to send emails', + 'email_error_invalid_contact_email' => 'Invalid contact email', 'navigation' => 'Navigation', 'list_invoices' => 'List Invoices', @@ -1149,22 +1033,20 @@ return array( 'custom_invoice_item_fields_help' => 'Add a field when creating an invoice item and display the label and value on the PDF.', 'recurring_invoice_number' => 'Recurring Invoice Number', 'recurring_invoice_number_prefix_help' => 'Speciy a prefix to be added to the invoice number for recurring invoices. The default value is \'R\'.', - 'enable_client_portal' => 'Dashboard', - 'enable_client_portal_help' => 'Show/hide the dashboard page in the client portal.', // Client Passwords 'enable_portal_password'=>'Password protect invoices', 'enable_portal_password_help'=>'Allows you to set a password for each contact. If a password is set, the contact will be required to enter a password before viewing invoices.', 'send_portal_password'=>'Generate password automatically', 'send_portal_password_help'=>'If no password is set, one will be generated and sent with the first invoice.', - + 'expired' => 'Expired', 'invalid_card_number' => 'The credit card number is not valid.', 'invalid_expiry' => 'The expiration date is not valid.', 'invalid_cvv' => 'The CVV is not valid.', 'cost' => 'Cost', 'create_invoice_for_sample' => 'Note: create your first invoice to see a preview here.', - + // User Permissions 'owner' => 'Owner', 'administrator' => 'Administrator', @@ -1182,8 +1064,8 @@ return array( 'create_all_help' => 'Allow user to create and modify records', 'view_all_help' => 'Allow user to view records they didn\'t create', 'edit_all_help' => 'Allow user to modify records they didn\'t create', - 'view_payment' => 'View Payment', - + 'view_payment' => 'View Payment', + 'january' => 'January', 'february' => 'February', 'march' => 'March', @@ -1209,30 +1091,28 @@ return array( 'document_email_attachment' => 'Attach Documents', 'download_documents' => 'Download Documents (:size)', 'documents_from_expenses' => 'From Expenses:', - 'dropzone' => array(// See http://www.dropzonejs.com/#config-dictDefaultMessage - 'DefaultMessage' => 'Drop files or click to upload', - 'FallbackMessage' => 'Your browser does not support drag\'n\'drop file uploads.', - 'FallbackText' => 'Please use the fallback form below to upload your files like in the olden days.', - 'FileTooBig' => 'File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.', - 'InvalidFileType' => 'You can\'t upload files of this type.', - 'ResponseError' => 'Server responded with {{statusCode}} code.', - 'CancelUpload' => 'Cancel upload', - 'CancelUploadConfirmation' => 'Are you sure you want to cancel this upload?', - 'RemoveFile' => 'Remove file', - ), + 'dropzone_default_message' => 'Drop files or click to upload', + 'dropzone_fallback_message' => 'Your browser does not support drag\'n\'drop file uploads.', + 'dropzone_fallback_text' => 'Please use the fallback form below to upload your files like in the olden days.', + 'dropzone_file_too_big' => 'File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.', + 'dropzone_invalid_file_type' => 'You can\'t upload files of this type.', + 'dropzone_response_error' => 'Server responded with {{statusCode}} code.', + 'dropzone_cancel_upload' => 'Cancel upload', + 'dropzone_cancel_upload_confirmation' => 'Are you sure you want to cancel this upload?', + 'dropzone_remove_file' => 'Remove file', 'documents' => 'Documents', 'document_date' => 'Document Date', 'document_size' => 'Size', - 'enable_client_portal' => 'Client Portal', - 'enable_client_portal_help' => 'Show/hide the client portal.', + 'enable_client_portal' => 'Dashboard', + 'enable_client_portal_help' => 'Show/hide the dashboard page in the client portal.', 'enable_client_portal_dashboard' => 'Dashboard', 'enable_client_portal_dashboard_help' => 'Show/hide the dashboard page in the client portal.', - + // Plans 'account_management' => 'Account Management', 'plan_status' => 'Plan Status', - + 'plan_upgrade' => 'Upgrade', 'plan_change' => 'Change Plan', 'pending_change_to' => 'Changes To', @@ -1262,9 +1142,9 @@ return array( 'plan_paid' => 'Term Started', 'plan_started' => 'Plan Started', 'plan_expires' => 'Plan Expires', - + 'white_label_button' => 'White Label', - + 'pro_plan_year_description' => 'One year enrollment in the Invoice Ninja Pro Plan.', 'pro_plan_month_description' => 'One month enrollment in the Invoice Ninja Pro Plan.', 'enterprise_plan_product' => 'Enterprise Plan', @@ -1282,7 +1162,207 @@ return array( 'preview' => 'Preview', 'list_vendors' => 'List Vendors', 'add_users_not_supported' => 'Upgrade to the Enterprise plan to add additional users to your account.', - 'enterprise_plan_features' => 'The Enterprise plan adds support for multiple users and file attachments.', + 'enterprise_plan_features' => 'The Enterprise plan adds support for multiple users and file attachments, :link to see the full list of features.', 'return_to_app' => 'Return to app', - + + + // Payment updates + 'refund_payment' => 'Refund Payment', + 'refund_max' => 'Max:', + 'refund' => 'Refund', + 'are_you_sure_refund' => 'Refund selected payments?', + 'status_pending' => 'Pending', + 'status_completed' => 'Completed', + 'status_failed' => 'Failed', + 'status_partially_refunded' => 'Partially Refunded', + 'status_partially_refunded_amount' => ':amount Refunded', + 'status_refunded' => 'Refunded', + 'status_voided' => 'Cancelled', + 'refunded_payment' => 'Refunded Payment', + 'activity_39' => ':user cancelled a :payment_amount payment (:payment)', + 'activity_40' => ':user refunded :adjustment of a :payment_amount payment (:payment)', + 'card_expiration' => 'Exp: :expires', + + 'card_creditcardother' => 'Unknown', + 'card_americanexpress' => 'American Express', + 'card_carteblanche' => 'Carte Blanche', + 'card_unionpay' => 'UnionPay', + 'card_diners' => 'Diners Club', + 'card_discover' => 'Discover', + 'card_jcb' => 'JCB', + 'card_laser' => 'Laser', + 'card_maestro' => 'Maestro', + 'card_mastercard' => 'MasterCard', + 'card_solo' => 'Solo', + 'card_switch' => 'Switch', + 'card_visacard' => 'Visa', + 'card_ach' => 'ACH', + + 'payment_type_stripe' => 'Stripe', + 'ach' => 'ACH', + 'enable_ach' => 'Enable ACH', + 'stripe_ach_help' => 'ACH support must also be enabled at Stripe.', + 'ach_disabled' => 'Another gateway is already configured for direct debit.', + + 'plaid' => 'Plaid', + 'client_id' => 'Client Id', + 'secret' => 'Secret', + 'public_key' => 'Public Key', + 'plaid_optional' => '(optional)', + 'plaid_environment_help' => 'When a Stripe test key is given, Plaid\'s development environement (tartan) will be used.', + 'other_providers' => 'Other Providers', + 'country_not_supported' => 'That country is not supported.', + 'invalid_routing_number' => 'The routing number is not valid.', + 'invalid_account_number' => 'The account number is not valid.', + 'account_number_mismatch' => 'The account numbers do not match.', + 'missing_account_holder_type' => 'Please select an individual or company account.', + 'missing_account_holder_name' => 'Please enter the account holder\'s name.', + 'routing_number' => 'Routing Number', + 'confirm_account_number' => 'Confirm Account Number', + 'individual_account' => 'Individual Account', + 'company_account' => 'Company Account', + 'account_holder_name' => 'Account Holder Name', + 'add_account' => 'Add Account', + 'payment_methods' => 'Payment Methods', + 'complete_verification' => 'Complete Verification', + 'verification_amount1' => 'Amount 1', + 'verification_amount2' => 'Amount 2', + 'payment_method_verified' => 'Verification completed successfully', + 'verification_failed' => 'Verification Failed', + 'remove_payment_method' => 'Remove Payment Method', + 'confirm_remove_payment_method' => 'Are you sure you want to remove this payment method?', + 'remove' => 'Remove', + 'payment_method_removed' => 'Removed payment method.', + 'bank_account_verification_help' => 'We have made two deposits into your account with the description "VERIFICATION". These deposits will take 1-2 business days to appear on your statement. Please enter the amounts below.', + 'bank_account_verification_next_steps' => 'We have made two deposits into your account with the description "VERIFICATION". These deposits will take 1-2 business days to appear on your statement. + Once you have the amounts, come back to this payment methods page and click "Complete Verification" next to the account.', + 'unknown_bank' => 'Unknown Bank', + 'ach_verification_delay_help' => 'You will be able to use the account after completing verification. Verification usually takes 1-2 business days.', + 'add_credit_card' => 'Add Credit Card', + 'payment_method_added' => 'Added payment method.', + 'use_for_auto_bill' => 'Use For Autobill', + 'used_for_auto_bill' => 'Autobill Payment Method', + 'payment_method_set_as_default' => 'Set Autobill payment method.', + 'activity_41' => ':payment_amount payment (:payment) failed', + 'webhook_url' => 'Webhook URL', + 'stripe_webhook_help' => 'You must :link.', + 'stripe_webhook_help_link_text' => 'add this URL as an endpoint at Stripe', + 'payment_method_error' => 'There was an error adding your payment methd. Please try again later.', + 'notification_invoice_payment_failed_subject' => 'Payment failed for Invoice :invoice', + 'notification_invoice_payment_failed' => 'A payment made by client :client towards Invoice :invoice failed. The payment has been marked as failed and :amount has been added to the client\'s balance.', + 'link_with_plaid' => 'Link Account Instantly with Plaid', + 'link_manually' => 'Link Manually', + 'secured_by_plaid' => 'Secured by Plaid', + 'plaid_linked_status' => 'Your bank account at :bank', + 'add_payment_method' => 'Add Payment Method', + 'account_holder_type' => 'Account Holder Type', + 'ach_authorization' => 'I authorize :company to use my bank account for future payments and, if necessary, electronically credit my account to correct erroneous debits. I understand that I may cancel this authorization at any time by removing the payment method or by contacting :email.', + 'ach_authorization_required' => 'You must consent to ACH transactions.', + 'off' => 'Off', + 'opt_in' => 'Opt-in', + 'opt_out' => 'Opt-out', + 'always' => 'Always', + 'opted_out' => 'Opted out', + 'opted_in' => 'Opted in', + 'manage_auto_bill' => 'Manage Auto-bill', + 'enabled' => 'Enabled', + 'paypal' => 'PayPal', + 'braintree_enable_paypal' => 'Enable PayPal payments through BrainTree', + 'braintree_paypal_disabled_help' => 'The PayPal gateway is processing PayPal payments', + 'braintree_paypal_help' => 'You must also :link.', + 'braintree_paypal_help_link_text' => 'link PayPal to your BrainTree account', + 'token_billing_braintree_paypal' => 'Save payment details', + 'add_paypal_account' => 'Add PayPal Account', + + + 'no_payment_method_specified' => 'No payment method specified', + 'chart_type' => 'Chart Type', + 'format' => 'Format', + 'import_ofx' => 'Import OFX', + 'ofx_file' => 'OFX File', + 'ofx_parse_failed' => 'Failed to parse OFX file', + + // WePay + 'wepay' => 'WePay', + 'sign_up_with_wepay' => 'Sign up with WePay', + 'use_another_provider' => 'Use another provider', + 'company_name' => 'Company Name', + 'wepay_company_name_help' => 'This will appear on client\'s credit card statements.', + 'wepay_description_help' => 'The purpose of this account.', + 'wepay_tos_agree' => 'I agree to the :link.', + 'wepay_tos_link_text' => 'WePay Terms of Service', + 'resend_confirmation_email' => 'Resend Confirmation Email', + 'manage_wepay_account' => 'Manage WePay Account', + 'action_required' => 'Action Required', + 'finish_setup' => 'Finish Setup', + 'created_wepay_confirmation_required' => 'Please check your email and confirm your email address with WePay.', + 'switch_to_wepay' => 'Switch to WePay', + 'switch' => 'Switch', + 'restore_account_gateway' => 'Restore Gateway', + 'restored_account_gateway' => 'Successfully restored gateway', + 'united_states' => 'United States', + 'canada' => 'Canada', + 'accept_debit_cards' => 'Accept Debit Cards', + 'debit_cards' => 'Debit Cards', + + 'warn_start_date_changed' => 'The next invoice will be sent on the new start date.', + 'original_start_date' => 'Original start date', + 'new_start_date' => 'New start date', + 'security' => 'Security', + 'see_whats_new' => 'See what\'s new in v:version', + 'wait_for_upload' => 'Please wait for the document upload to complete.', + 'upgrade_for_permissions' => 'Upgrade to our Enterprise plan to enable permissions.', + 'enable_second_tax_rate' => 'Enable specifying a second tax rate', + 'payment_file' => 'Payment File', + 'expense_file' => 'Expense File', + 'product_file' => 'Product File', + 'import_products' => 'Import Products', + 'products_will_create' => 'products will be created.', + 'product_key' => 'Product', + 'created_products' => 'Successfully created :count product(s)', + 'export_help' => 'Use JSON if you plan to import the data into Invoice Ninja.', + 'JSON_file' => 'JSON File', + + 'view_dashboard' => 'View Dashboard', + 'client_session_expired' => 'Session Expired', + 'client_session_expired_message' => 'Your session has expired. Please click the link in your email again.', + + 'auto_bill_notification' => 'This invoice will automatically be billed to your :payment_method on file on :due_date.', + 'auto_bill_payment_method_bank_transfer' => 'bank account', + 'auto_bill_payment_method_credit_card' => 'credit card', + 'auto_bill_payment_method_paypal' => 'PayPal account', + 'auto_bill_notification_placeholder' => 'This invoice will automatically be billed to your credit card on file on the due date.', + 'payment_settings' => 'Payment Settings', + + 'on_send_date' => 'On send date', + 'on_due_date' => 'On due date', + 'auto_bill_ach_date_help' => 'ACH auto bill will always happen on the due date', + 'warn_change_auto_bill' => 'Due to NACHA rules, changes to this invoice may prevent ACH auto bill.', + + 'bank_account' => 'Bank Account', + 'payment_processed_through_wepay' => 'ACH payments will be processed using WePay.', + 'wepay_payment_tos_agree' => 'I agree to the WePay :terms and :privacy_policy.', + 'privacy_policy' => 'Privacy Policy', + 'wepay_payment_tos_agree_required' => 'You must agree to the WePay Terms of Service and Privacy Policy.', + 'payment_settings_supported_gateways' => 'These options are supported by the WePay, Stripe, and Braintree gateways.', + 'ach_email_prompt' => 'Please enter your email address:', + 'verification_pending' => 'Verification Pending', + + 'update_font_cache' => 'Please force refresh the page to update the font cache.', + 'more_options' => 'More options', + 'credit_card' => 'Credit Card', + 'bank_transfer' => 'Bank Transfer', + 'no_transaction_reference' => 'We did not recieve a payment transaction reference from the gateway.', + 'use_bank_on_file' => 'Use Bank on File', + 'auto_bill_email_message' => 'This invoice will automatically be billed to the payment method on file on the due date.', + 'bitcoin' => 'Bitcoin', + 'added_on' => 'Added :date', + 'failed_remove_payment_method' => 'Failed to remove the payment method', + 'gateway_exists' => 'This gateway already exists', + 'manual_entry' => 'Manual entry', + ); + +return $LANG; + +?> diff --git a/resources/lang/th/auth.php b/resources/lang/th/auth.php new file mode 100644 index 0000000000..ae2426c4cd --- /dev/null +++ b/resources/lang/th/auth.php @@ -0,0 +1,19 @@ + 'ข้อมูลที่ใช้ในการยืนยันตัวตนไม่ถูกต้อง', + 'throttle' => 'คุณได้พยายามเข้าระบบหลายครั้งเกินไป กรุณาลองใหม่ใน :seconds วินาทีข้างหน้า.', + +]; diff --git a/resources/lang/th/pagination.php b/resources/lang/th/pagination.php new file mode 100644 index 0000000000..1e3738f251 --- /dev/null +++ b/resources/lang/th/pagination.php @@ -0,0 +1,19 @@ + '« ก่อนหน้า', + 'next' => 'ถัดไป »', + +]; diff --git a/resources/lang/th/passwords.php b/resources/lang/th/passwords.php new file mode 100644 index 0000000000..098ff8228e --- /dev/null +++ b/resources/lang/th/passwords.php @@ -0,0 +1,22 @@ + 'รหัสผ่านต้องมีความยาวอย่างน้อยหกตัวอักษรและต้องตรงกับช่องยืนยันรหัสผ่าน', + 'reset' => 'ทำการตั้งค่ารหัสผ่านใหม่แล้ว', + 'sent' => 'ส่งเครื่องช่วยเตือนความจำรหัสผ่านแล้ว!', + 'token' => 'ชุดรหัสสำหรับการเปลี่ยนรหัสผ่านไม่ถูกต้อง', + 'user' => 'ไม่พบผู้ใช้งานที่ตรงกับอีเมล์นี้', + +]; diff --git a/resources/lang/th/texts.php b/resources/lang/th/texts.php new file mode 100644 index 0000000000..33870af85f --- /dev/null +++ b/resources/lang/th/texts.php @@ -0,0 +1,1369 @@ + 'องค์กร', + 'name' => 'ชื่อ', + 'website' => 'เว็บไซต์', + 'work_phone' => 'โทรศัพท์', + 'address' => 'ที่อยู่', + 'address1' => 'ถนน', + 'address2' => 'อาคาร', + 'city' => 'อำเภอ', + 'state' => 'จังหวัด', + 'postal_code' => 'รหัสไปรษณีย์', + 'country_id' => 'ประเทศ', + 'contacts' => 'ผู้ติดต่อ', + 'first_name' => 'ชื่อ', + 'last_name' => 'นามสกุล', + 'phone' => 'โทร.', + 'email' => 'อีเมล', + 'additional_info' => 'ข้อมูลเพิ่มเติม', + 'payment_terms' => 'เงื่อนไขการชำระ', + 'currency_id' => 'สกุลเงิน', + 'size_id' => 'ขนาดบริษัท', + 'industry_id' => 'อุตสาหกรรม', + 'private_notes' => 'หมายเหตุภายใน', + 'invoice' => 'ใบแจ้งหนี้', + 'client' => 'ลูกค้า', + 'invoice_date' => 'วันที่แจ้งหนี้', + 'due_date' => 'วันถึงกำหนดชำระ', + 'invoice_number' => 'เลขที่ใบแจ้งหนี้', + 'invoice_number_short' => 'Invoice #', + 'po_number' => 'เลขที่ใบสั่งซื้อ', + 'po_number_short' => 'PO #', + 'frequency_id' => 'ความถี่', + 'discount' => 'ส่วนลด', + 'taxes' => 'ภาษี', + 'tax' => 'ภาษี', + 'item' => 'รายการ', + 'description' => 'รายละเอียด', + 'unit_cost' => 'ราคาต่อหน่วย', + 'quantity' => 'จำนวน', + 'line_total' => 'รวมเงิน', + 'subtotal' => 'รวมเงิน', + 'paid_to_date' => 'ยอดชำระแล้ว', + 'balance_due' => 'ยอดคงเหลือ', + 'invoice_design_id' => 'ออกแบบ', + 'terms' => 'เงื่อนไข', + 'your_invoice' => 'ใบแจ้งหนี้ของคุณ', + 'remove_contact' => 'ลบผู้ติดต่อ', + 'add_contact' => 'เพิ่มผู้ติดต่อ', + 'create_new_client' => 'สร้างลูกค้าใหม่', + 'edit_client_details' => 'แก้ไขรายละเอียดลูกค้า', + 'enable' => 'Enable', + 'learn_more' => 'อ่านต่อ', + 'manage_rates' => 'Manage rates', + 'note_to_client' => 'หมายเหตุสำหรับลูกค้า', + 'invoice_terms' => 'Invoice Terms', + 'save_as_default_terms' => 'บันทึกเป็น Default Terms', + 'download_pdf' => 'ดาวน์โหลด PDF', + 'pay_now' => 'จ่ายเดี๋ยวนี้', + 'save_invoice' => 'บันทึกใบแจ้งหนี้', + 'clone_invoice' => 'Clone Invoice', + 'archive_invoice' => 'Archive Invoice', + 'delete_invoice' => 'ลบใบแจ้งหนี้', + 'email_invoice' => 'ส่งอีเมล', + 'enter_payment' => 'เพิ่มรายการจ่ายเงิน', + 'tax_rates' => 'อัตราภาษี', + 'rate' => 'อัตรา', + 'settings' => 'การตั้งค่า', + 'enable_invoice_tax' => 'Enable specifying an invoice tax', + 'enable_line_item_tax' => 'Enable specifying line item taxes', + 'dashboard' => 'Dashboard', + 'clients' => 'ลูกค้า', + 'invoices' => 'ใบแจ้งหนี้', + 'payments' => 'การจ่ายเงิน', + 'credits' => 'เครดิต', + 'history' => 'ประวัติ', + 'search' => 'ค้นหา', + 'sign_up' => 'ลงทะเบียน', + 'guest' => 'Guest', + 'company_details' => 'รายละเอียดบริษัท', + 'online_payments' => 'การจ่ายเงิน Online', + 'notifications' => 'การแจ้งเตือนทางอีเมล', + 'import_export' => 'นำเข้า | ส่งออก', + 'done' => 'เรียบร้อย', + 'save' => 'บันทึก', + 'create' => 'สร้าง', + 'upload' => 'อัพโหลด', + 'import' => 'นำเข้า', + 'download' => 'ดาวน์โหลด', + 'cancel' => 'ยกเลิก', + 'close' => 'ปิด', + 'provide_email' => 'กรุณาระบุอีเมลที่ถูกต้อง', + 'powered_by' => 'สนับสนุนโดย', + 'no_items' => 'ไม่มีรายการ', + 'recurring_invoices' => 'Recurring Invoices', + 'recurring_help' => '

    Automatically send clients the same invoices weekly, bi-monthly, monthly, quarterly or annually.

    +

    Use :MONTH, :QUARTER or :YEAR for dynamic dates. Basic math works as well, for example :MONTH-1.

    +

    Examples of dynamic invoice variables:

    +
      +
    • "Gym membership for the month of :MONTH" => "Gym membership for the month of July"
    • +
    • ":YEAR+1 yearly subscription" => "2015 Yearly Subscription"
    • +
    • "Retainer payment for :QUARTER+1" => "Retainer payment for Q2"
    • +
    ', + 'in_total_revenue' => 'in total revenue', + 'billed_client' => 'billed client', + 'billed_clients' => 'billed clients', + 'active_client' => 'active client', + 'active_clients' => 'active clients', + 'invoices_past_due' => 'Invoices Past Due', + 'upcoming_invoices' => 'Upcoming Invoices', + 'average_invoice' => 'Average Invoice', + 'archive' => 'Archive', + 'delete' => 'ลบ', + 'archive_client' => 'Archive Client', + 'delete_client' => 'ลบลูกค้า', + 'archive_payment' => 'Archive Payment', + 'delete_payment' => 'ลบการจ่ายเงิน', + 'archive_credit' => 'Archive Credit', + 'delete_credit' => 'ลบเครดิต', + 'show_archived_deleted' => 'Show archived/deleted', + 'filter' => 'กรอง', + 'new_client' => 'เพิ่มลูกค้า', + 'new_invoice' => 'เพิ่มใบแจ้งหนี้', + 'new_payment' => 'เพิ่มการจ่ายเงิน', + 'new_credit' => 'เพิ่มเครดิต', + 'contact' => 'ผู้ติดต่อ', + 'date_created' => 'วันที่ทำรายการ', + 'last_login' => 'ล็อกอินล่าล่าสุด', + 'balance' => 'ยอดคงเหลือ', + 'action' => 'Action', + 'status' => 'สถานะ', + 'invoice_total' => 'ยอดรวมตามใบแจ้งหนี้', + 'frequency' => 'ความถี่', + 'start_date' => 'วันที่เริ่ม', + 'end_date' => 'วันที่สิ้นสุด', + 'transaction_reference' => 'รายการอ้างอิง', + 'method' => 'วิธี', + 'payment_amount' => 'ยอดจ่าย', + 'payment_date' => 'กำหนดจ่าย', + 'credit_amount' => 'ยอดเครดิต', + 'credit_balance' => 'เครดิตคงเหลือ', + 'credit_date' => 'วันที่เครดิต', + 'empty_table' => 'ไม่มีข้อมูลในตารางฐานข้อมูล', + 'select' => 'เลือก', + 'edit_client' => 'แก้ไขลูกค้า', + 'edit_invoice' => 'แก้ไขใบแจ้งหนี้', + 'create_invoice' => 'สร้างใบแจ้งหนี้', + 'enter_credit' => 'Enter Credit', + 'last_logged_in' => 'เข้าระบบล่าสุด', + 'details' => 'รายละเอียด', + 'standing' => 'ยอดคงค้าง', + 'credit' => 'เครดิต', + 'activity' => 'กิจกรรม', + 'date' => 'วันที่', + 'message' => 'ข้อความ', + 'adjustment' => 'ปรับปรุงรายการ', + 'are_you_sure' => 'แน่ใจหรือไม่?', + 'payment_type_id' => 'ประเภทการจ่ายเงิน', + 'amount' => 'ยอดเงิน', + 'work_email' => 'อีเมล', + 'language_id' => 'ภาษา', + 'timezone_id' => 'Time Zone', + 'date_format_id' => 'รูปแบบวันที่', + 'datetime_format_id' => 'รูปแบบวันที่/เวลา', + 'users' => 'ผู้ใช้งาน', + 'localization' => 'Localization', + 'remove_logo' => 'ลบโลโก้', + 'logo_help' => 'รองรับ: JPEG, GIF และ PNG', + 'payment_gateway' => 'Payment Gateway', + 'gateway_id' => 'Gateway', + 'email_notifications' => 'การแจ้งเตือนทางอีเมล', + 'email_sent' => 'ส่งอีเมลถึงฉันเมื่อใบแจ้งหนี้ถูก ส่ง', + 'email_viewed' => 'ส่งอีเมลถึงฉันเมื่อใบแจ้งหนี้ถูก อ่าน', + 'email_paid' => 'ส่งอีเมลถึงฉันเมื่อใบแจ้งหนี้ได้รับการ ชำระเงิน', + 'site_updates' => 'Site Updates', + 'custom_messages' => 'Custom Messages', + 'default_email_footer' => 'Set default email signature', + 'select_file' => 'กรุณาเลือกไฟล์', + 'first_row_headers' => 'Use first row as headers', + 'column' => 'คอลัมน์', + 'sample' => 'ตัวอย่าง', + 'import_to' => 'Import to', + 'client_will_create' => 'client will be created', + 'clients_will_create' => 'clients will be created', + 'email_settings' => 'Email Settings', + 'client_view_styling' => 'Client View Styling', + 'pdf_email_attachment' => 'Attach PDFs', + 'custom_css' => 'Custom CSS', + 'import_clients' => 'Import Client Data', + 'csv_file' => 'ไฟล์ CSV', + 'export_clients' => 'Export Client Data', + 'created_client' => 'Successfully created client', + 'created_clients' => 'Successfully created :count client(s)', + 'updated_settings' => 'Successfully updated settings', + 'removed_logo' => 'Successfully removed logo', + 'sent_message' => 'Successfully sent message', + 'invoice_error' => 'Please make sure to select a client and correct any errors', + 'limit_clients' => 'Sorry, this will exceed the limit of :count clients', + 'payment_error' => 'There was an error processing your payment. Please try again later.', + 'registration_required' => 'Please sign up to email an invoice', + 'confirmation_required' => 'Please confirm your email address', + 'updated_client' => 'Successfully updated client', + 'created_client' => 'Successfully created client', + 'archived_client' => 'Successfully archived client', + 'archived_clients' => 'Successfully archived :count clients', + 'deleted_client' => 'Successfully deleted client', + 'deleted_clients' => 'Successfully deleted :count clients', + 'updated_invoice' => 'Successfully updated invoice', + 'created_invoice' => 'Successfully created invoice', + 'cloned_invoice' => 'Successfully cloned invoice', + 'emailed_invoice' => 'Successfully emailed invoice', + 'and_created_client' => 'and created client', + 'archived_invoice' => 'Successfully archived invoice', + 'archived_invoices' => 'Successfully archived :count invoices', + 'deleted_invoice' => 'Successfully deleted invoice', + 'deleted_invoices' => 'Successfully deleted :count invoices', + 'created_payment' => 'Successfully created payment', + 'created_payments' => 'Successfully created :count payment(s)', + 'archived_payment' => 'Successfully archived payment', + 'archived_payments' => 'Successfully archived :count payments', + 'deleted_payment' => 'Successfully deleted payment', + 'deleted_payments' => 'Successfully deleted :count payments', + 'applied_payment' => 'Successfully applied payment', + 'created_credit' => 'Successfully created credit', + 'archived_credit' => 'Successfully archived credit', + 'archived_credits' => 'Successfully archived :count credits', + 'deleted_credit' => 'Successfully deleted credit', + 'deleted_credits' => 'Successfully deleted :count credits', + 'imported_file' => 'Successfully imported file', + 'updated_vendor' => 'Successfully updated vendor', + 'created_vendor' => 'Successfully created vendor', + 'archived_vendor' => 'Successfully archived vendor', + 'archived_vendors' => 'Successfully archived :count vendors', + 'deleted_vendor' => 'Successfully deleted vendor', + 'deleted_vendors' => 'Successfully deleted :count vendors', + 'confirmation_subject' => 'Invoice Ninja Account Confirmation', + 'confirmation_header' => 'Account Confirmation', + 'confirmation_message' => 'Please access the link below to confirm your account.', + 'invoice_subject' => 'New invoice :invoice from :account', + 'invoice_message' => 'To view your invoice for :amount, click the link below.', + 'payment_subject' => 'Payment Received', + 'payment_message' => 'Thank you for your payment of :amount.', + 'email_salutation' => 'เรียนคุณ :name,', + 'email_signature' => 'ด้วยความเคารพ', + 'email_from' => 'The Invoice Ninja Team', + 'invoice_link_message' => 'To view the invoice click the link below:', + 'notification_invoice_paid_subject' => 'ใบแจ้งหนี้ :invoice ได้รับการชำระแล้วโดย :client', + 'notification_invoice_sent_subject' => 'ใบแจ้งหนี้ :invoice ได้ถูกส่งให้ :client', + 'notification_invoice_viewed_subject' => 'ใบแจ้งหนี้ :invoice ถูกอ่านแล้วโดย :client', + 'notification_invoice_paid' => 'A payment of :amount was made by client :client towards Invoice :invoice.', + '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.', + 'reset_password' => 'You can reset your account password by clicking the following button:', + 'secure_payment' => 'Secure Payment', + 'card_number' => 'Card Number', + 'expiration_month' => 'Expiration Month', + 'expiration_year' => 'Expiration Year', + 'cvv' => 'CVV', + 'logout' => 'Log Out', + 'sign_up_to_save' => 'Sign up to save your work', + 'agree_to_terms' => 'I agree to the Invoice Ninja :terms', + 'terms_of_service' => 'Terms of Service', + 'email_taken' => 'The email address is already registered', + 'working' => 'Working', + 'success' => 'Success', + '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.', + 'password' => 'รหัสผ่าน', + 'pro_plan_product' => 'Pro Plan', + 'pro_plan_success' => 'Thanks for choosing Invoice Ninja\'s Pro plan!

     
    + Next Steps

    A payable invoice has been sent to the email + address associated with your account. To unlock all of the awesome + Pro features, please follow the instructions on the invoice to pay + for a year of Pro-level invoicing.

    + Can\'t find the invoice? Need further assistance? We\'re happy to help + -- email us at contact@invoiceninja.com', + 'unsaved_changes' => 'You have unsaved changes', + 'custom_fields' => 'Custom Fields', + 'company_fields' => 'Company Fields', + 'client_fields' => 'Client Fields', + 'field_label' => 'Field Label', + 'field_value' => 'Field Value', + 'edit' => 'แก้ไข', + 'set_name' => 'Set your company name', + 'view_as_recipient' => 'View as recipient', + 'product_library' => 'สินค้า', + 'product' => 'สินค้า', + 'products' => 'สินค้า', + 'fill_products' => 'Auto-fill products', + 'fill_products_help' => 'Selecting a product will automatically fill in the description and cost', + 'update_products' => 'Auto-update products', + 'update_products_help' => 'Updating an invoice will automatically update the product library', + 'create_product' => 'เพิ่มสินค้า', + 'edit_product' => 'แก้ไขสินค้า', + 'archive_product' => 'Archive Product', + 'updated_product' => 'Successfully updated product', + 'created_product' => 'Successfully created product', + 'archived_product' => 'Successfully archived product', + 'pro_plan_custom_fields' => ':link to enable custom fields by joining the Pro Plan', + 'advanced_settings' => 'Advanced Settings', + 'pro_plan_advanced_settings' => ':link to enable the advanced settings by joining the Pro Plan', + 'invoice_design' => 'Invoice Design', + 'specify_colors' => 'Specify colors', + 'specify_colors_label' => 'Select the colors used in the invoice', + 'chart_builder' => 'Chart Builder', + 'ninja_email_footer' => 'Use :site to invoice your clients and get paid online for free!', + 'go_pro' => 'Go Pro', + 'quote' => 'Quote', + 'quotes' => 'Quotes', + 'quote_number' => 'Quote Number', + 'quote_number_short' => 'Quote #', + 'quote_date' => 'Quote Date', + 'quote_total' => 'Quote Total', + 'your_quote' => 'Your Quote', + 'total' => 'Total', + 'clone' => 'Clone', + 'new_quote' => 'New Quote', + 'create_quote' => 'Create Quote', + 'edit_quote' => 'Edit Quote', + 'archive_quote' => 'Archive Quote', + 'delete_quote' => 'Delete Quote', + 'save_quote' => 'Save Quote', + 'email_quote' => 'Email Quote', + 'clone_quote' => 'Clone Quote', + 'convert_to_invoice' => 'Convert to Invoice', + 'view_invoice' => 'View Invoice', + 'view_client' => 'View Client', + 'view_quote' => 'View Quote', + 'updated_quote' => 'Successfully updated quote', + 'created_quote' => 'Successfully created quote', + 'cloned_quote' => 'Successfully cloned quote', + 'emailed_quote' => 'Successfully emailed quote', + 'archived_quote' => 'Successfully archived quote', + 'archived_quotes' => 'Successfully archived :count quotes', + 'deleted_quote' => 'Successfully deleted quote', + 'deleted_quotes' => 'Successfully deleted :count quotes', + 'converted_to_invoice' => 'Successfully converted quote to invoice', + 'quote_subject' => 'New quote $quote from :account', + 'quote_message' => 'To view your quote for :amount, click the link below.', + 'quote_link_message' => 'To view your client quote click the link below:', + 'notification_quote_sent_subject' => 'Quote :invoice was sent to :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_viewed' => 'The following client :client viewed Quote :invoice for :amount.', + 'session_expired' => 'Your session has expired.', + 'invoice_fields' => 'Invoice Fields', + 'invoice_options' => 'Invoice Options', + '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_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.', + 'charge_taxes' => 'Charge taxes', + 'user_management' => 'User Management', + 'add_user' => 'Add User', + 'send_invite' => 'Send invitation', + 'sent_invite' => 'Successfully sent invitation', + 'updated_user' => 'Successfully updated user', + 'invitation_message' => 'You\'ve been invited by :invitor. ', + 'register_to_add_user' => 'Please sign up to add a user', + 'user_state' => 'State', + 'edit_user' => 'Edit User', + 'delete_user' => 'Delete User', + 'active' => 'Active', + 'pending' => 'Pending', + 'deleted_user' => 'Successfully deleted user', + '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_recurring_email_invoice' => 'Are you sure you want this invoice emailed?', + 'cancel_account' => 'Delete Account', + 'cancel_account_message' => 'Warning: This will permanently erase all of your data, there is no undo.', + 'go_back' => 'Go Back', + 'data_visualizations' => 'Data Visualizations', + 'sample_data' => 'Sample data shown', + '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', + 'invoice_settings' => 'Invoice Settings', + 'invoice_number_prefix' => 'Invoice Number Prefix', + 'invoice_number_counter' => 'Invoice Number Counter', + 'quote_number_prefix' => 'Quote Number Prefix', + 'quote_number_counter' => 'Quote Number Counter', + 'share_invoice_counter' => 'Share invoice counter', + 'invoice_issued_to' => 'Invoice issued to', + 'invalid_counter' => 'To prevent a possible conflict please set either an invoice or quote number prefix', + 'mark_sent' => 'Mark Sent', + 'gateway_help_1' => ':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_27' => ':link to sign up for TwoCheckout.', + 'more_designs' => 'More designs', + 'more_designs_title' => 'Additional Invoice Designs', + 'more_designs_cloud_header' => 'Go Pro for more invoice designs', + 'more_designs_cloud_text' => '', + 'more_designs_self_host_text' => '', + 'buy' => 'Buy', + 'bought_designs' => 'Successfully added additional invoice designs', + 'sent' => 'sent', + 'vat_number' => 'VAT Number', + 'timesheets' => 'Timesheets', + '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_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.', + 'id_number' => 'ID Number', + 'white_label_link' => 'White label', + 'white_label_header' => 'White Label', + 'bought_white_label' => 'Successfully enabled white label license', + 'white_labeled' => 'White labeled', + 'restore' => 'Restore', + 'restore_invoice' => 'Restore Invoice', + 'restore_quote' => 'Restore Quote', + 'restore_client' => 'Restore Client', + 'restore_credit' => 'Restore Credit', + 'restore_payment' => 'Restore Payment', + 'restored_invoice' => 'Successfully restored invoice', + 'restored_quote' => 'Successfully restored quote', + 'restored_client' => 'Successfully restored client', + 'restored_payment' => 'Successfully restored payment', + 'restored_credit' => 'Successfully restored credit', + 'reason_for_canceling' => 'Help us improve our site by telling us why you\'re leaving.', + 'discount_percent' => 'Percent', + 'discount_amount' => 'Amount', + 'invoice_history' => 'Invoice History', + 'quote_history' => 'Quote History', + 'current_version' => 'Current version', + 'select_version' => 'Select version', + 'view_history' => 'View History', + 'edit_payment' => 'Edit Payment', + 'updated_payment' => 'Successfully updated payment', + 'deleted' => 'Deleted', + 'restore_user' => 'Restore User', + 'restored_user' => 'Successfully restored user', + 'show_deleted_users' => 'Show deleted users', + 'email_templates' => 'Email Templates', + 'invoice_email' => 'Invoice Email', + 'payment_email' => 'Payment Email', + 'quote_email' => 'Quote Email', + 'reset_all' => 'Reset All', + 'approve' => 'Approve', + '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_1' => 'Disabled', + 'token_billing_2' => 'Opt-in - checkbox is shown but not selected', + 'token_billing_3' => 'Opt-out - checkbox is shown and selected', + 'token_billing_4' => 'Always', + 'token_billing_checkbox' => 'Store credit card details', + 'view_in_gateway' => 'View in :gateway', + 'use_card_on_file' => 'Use Card on File', + 'edit_payment_details' => 'Edit payment details', + 'token_billing' => 'Save card details', + 'token_billing_secure' => 'The data is stored securely by :link', + 'support' => 'Support', + 'contact_information' => 'Contact Information', + '256_encryption' => '256-Bit Encryption', + 'amount_due' => 'Amount due', + 'billing_address' => 'Billing Address', + 'billing_method' => 'Billing Method', + 'order_overview' => 'Order overview', + '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.', + 'invoice_footer' => 'Invoice Footer', + 'save_as_default_footer' => 'Save as default footer', + 'token_management' => 'Token Management', + 'tokens' => 'Tokens', + 'add_token' => 'Add Token', + 'show_deleted_tokens' => 'Show deleted tokens', + 'deleted_token' => 'Successfully deleted token', + 'created_token' => 'Successfully created token', + 'updated_token' => 'Successfully updated token', + 'edit_token' => 'Edit Token', + 'delete_token' => 'Delete Token', + 'token' => 'Token', + 'add_gateway' => 'Add Gateway', + 'delete_gateway' => 'Delete Gateway', + 'edit_gateway' => 'Edit Gateway', + 'updated_gateway' => 'Successfully updated gateway', + 'created_gateway' => 'Successfully created gateway', + 'deleted_gateway' => 'Successfully deleted gateway', + 'pay_with_paypal' => 'PayPal', + 'pay_with_card' => 'Credit Card', + 'change_password' => 'Change password', + 'current_password' => 'Current password', + 'new_password' => 'New password', + 'confirm_password' => 'Confirm password', + 'password_error_incorrect' => 'The current password is incorrect.', + 'password_error_invalid' => 'The new password is invalid.', + 'updated_password' => 'Successfully updated password', + 'api_tokens' => 'API Tokens', + 'users_and_tokens' => 'Users & Tokens', + 'account_login' => 'Account Login', + 'recover_password' => 'Recover your password', + 'forgot_password' => 'Forgot your password?', + 'email_address' => 'Email address', + 'lets_go' => 'Let\'s go', + 'password_recovery' => 'Password Recovery', + 'send_email' => 'Send email', + 'set_password' => 'Set Password', + 'converted' => 'Converted', + 'email_approved' => 'Email me when a quote is approved', + 'notification_quote_approved_subject' => 'Quote :invoice was approved by :client', + 'notification_quote_approved' => 'The following client :client approved Quote :invoice for :amount.', + 'resend_confirmation' => 'Resend confirmation email', + 'confirmation_resent' => 'The confirmation email was resent', + 'gateway_help_42' => ':link to sign up for BitPay.
    Note: use a Legacy API Key, not an API token.', + 'payment_type_credit_card' => 'Credit Card', + 'payment_type_paypal' => 'PayPal', + 'payment_type_bitcoin' => 'Bitcoin', + 'knowledge_base' => 'Knowledge Base', + 'partial' => 'Partial', + 'partial_remaining' => ':partial of :balance', + 'more_fields' => 'More Fields', + 'less_fields' => 'Less Fields', + 'client_name' => 'Client Name', + 'pdf_settings' => 'PDF Settings', + 'product_settings' => 'Product Settings', + 'auto_wrap' => 'Auto Line Wrap', + 'duplicate_post' => 'Warning: the previous page was submitted twice. The second submission had been ignored.', + 'view_documentation' => 'View Documentation', + '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.', + 'rows' => 'rows', + 'www' => 'www', + 'logo' => 'Logo', + 'subdomain' => 'Subdomain', + 'provide_name_or_email' => 'Please provide a contact name or email', + 'charts_and_reports' => 'Charts & Reports', + 'chart' => 'Chart', + 'report' => 'Report', + 'group_by' => 'Group by', + 'paid' => 'Paid', + 'enable_report' => 'Report', + 'enable_chart' => 'Chart', + 'totals' => 'Totals', + 'run' => 'Run', + 'export' => 'Export', + 'documentation' => 'Documentation', + 'zapier' => 'Zapier', + 'recurring' => 'Recurring', + 'last_invoice_sent' => 'Last invoice sent :date', + 'processed_updates' => 'Successfully completed update', + 'tasks' => 'Tasks', + 'new_task' => 'New Task', + 'start_time' => 'Start Time', + 'created_task' => 'Successfully created task', + 'updated_task' => 'Successfully updated task', + 'edit_task' => 'Edit Task', + 'archive_task' => 'Archive Task', + 'restore_task' => 'Restore Task', + 'delete_task' => 'Delete Task', + 'stop_task' => 'Stop Task', + 'time' => 'Time', + 'start' => 'Start', + 'stop' => 'Stop', + 'now' => 'Now', + 'timer' => 'Timer', + 'manual' => 'Manual', + 'date_and_time' => 'Date & Time', + 'second' => 'second', + 'seconds' => 'seconds', + 'minute' => 'minute', + 'minutes' => 'minutes', + 'hour' => 'hour', + 'hours' => 'hours', + 'task_details' => 'Task Details', + 'duration' => 'Duration', + 'end_time' => 'End Time', + 'end' => 'End', + 'invoiced' => 'Invoiced', + 'logged' => 'Logged', + 'running' => 'Running', + 'task_error_multiple_clients' => 'The tasks can\'t belong to different clients', + 'task_error_running' => 'Please stop running tasks first', + 'task_error_invoiced' => 'Tasks have already been invoiced', + 'restored_task' => 'Successfully restored task', + 'archived_task' => 'Successfully archived task', + 'archived_tasks' => 'Successfully archived :count tasks', + 'deleted_task' => 'Successfully deleted task', + 'deleted_tasks' => 'Successfully deleted :count tasks', + 'create_task' => 'Create Task', + 'stopped_task' => 'Successfully stopped task', + 'invoice_task' => 'Invoice Task', + 'invoice_labels' => 'Invoice Labels', + 'prefix' => 'Prefix', + 'counter' => 'Counter', + 'payment_type_dwolla' => 'Dwolla', + 'gateway_help_43' => ':link to sign up for Dwolla', + 'partial_value' => 'Must be greater than zero and less than the total', + 'more_actions' => 'More Actions', + 'pro_plan_title' => 'NINJA PRO', + 'pro_plan_call_to_action' => 'Upgrade Now!', + 'pro_plan_feature1' => 'Create Unlimited Clients', + 'pro_plan_feature2' => 'Access to 10 Beautiful Invoice Designs', + 'pro_plan_feature3' => 'Custom URLs - "YourBrand.InvoiceNinja.com"', + 'pro_plan_feature4' => 'Remove "Created by Invoice Ninja"', + 'pro_plan_feature5' => 'Multi-user Access & Activity Tracking', + 'pro_plan_feature6' => 'Create Quotes & Pro-forma Invoices', + 'pro_plan_feature7' => 'Customize Invoice Field Titles & Numbering', + 'pro_plan_feature8' => 'Option to Attach PDFs to Client Emails', + 'resume' => 'Resume', + 'break_duration' => 'Break', + 'edit_details' => 'Edit Details', + 'work' => 'Work', + 'timezone_unset' => 'Please :link to set your timezone', + 'click_here' => 'click here', + 'email_receipt' => 'Email payment receipt to the client', + 'created_payment_emailed_client' => 'Successfully created payment and emailed client', + 'add_company' => 'Add Company', + 'untitled' => 'Untitled', + 'new_company' => 'New Company', + 'associated_accounts' => 'Successfully linked accounts', + 'unlinked_account' => 'Successfully unlinked accounts', + 'login' => 'Login', + 'or' => 'or', + 'email_error' => 'There was a problem sending the email', + 'confirm_recurring_timing' => 'Note: emails are sent at the start of the hour.', + 'payment_terms_help' => 'Sets the default invoice due date', + 'unlink_account' => 'Unlink Account', + 'unlink' => 'Unlink', + 'show_address' => 'Show Address', + 'show_address_help' => 'Require client to provide their billing address', + 'update_address' => 'Update Address', + 'update_address_help' => 'Update client\'s address with provided details', + 'times' => 'Times', + 'set_now' => 'Set to now', + 'dark_mode' => 'Dark Mode', + 'dark_mode_help' => 'Show white text on black background', + 'add_to_invoice' => 'Add to invoice :invoice', + 'create_new_invoice' => 'Create new invoice', + 'task_errors' => 'Please correct any overlapping times', + 'from' => 'From', + 'to' => 'To', + 'font_size' => 'Font Size', + 'primary_color' => 'Primary Color', + 'secondary_color' => 'Secondary Color', + 'customize_design' => 'Customize Design', + 'content' => 'Content', + 'styles' => 'Styles', + 'defaults' => 'Defaults', + 'margins' => 'Margins', + 'header' => 'Header', + 'footer' => 'Footer', + 'custom' => 'Custom', + 'invoice_to' => 'Invoice to', + 'invoice_no' => 'Invoice No.', + 'recent_payments' => 'Recent Payments', + 'outstanding' => 'Outstanding', + 'manage_companies' => 'Manage Companies', + 'total_revenue' => 'Total Revenue', + 'current_user' => 'Current User', + 'new_recurring_invoice' => 'New Recurring Invoice', + 'recurring_invoice' => 'Recurring Invoice', + 'recurring_too_soon' => 'It\'s too soon to create the next recurring invoice, it\'s scheduled for :date', + 'created_by_invoice' => 'Created by :invoice', + 'primary_user' => 'Primary User', + 'help' => 'Help', + 'customize_help' => '

    We use pdfmake to define the invoice designs declaratively. The pdfmake playground provide\'s a great way to see the library in action.

    +

    You can access a child property using dot notation. For example to show the client name you could use $client.name.

    +

    If you need help figuring something out post a question to our support forum with the design you\'re using.

    ', + 'invoice_due_date' => 'Due Date', + 'quote_due_date' => 'Valid Until', + 'valid_until' => 'Valid Until', + 'reset_terms' => 'Reset terms', + 'reset_footer' => 'Reset footer', + 'invoices_sent' => ':count invoice sent|:count invoices sent', + 'status_draft' => 'Draft', + 'status_sent' => 'Sent', + 'status_viewed' => 'Viewed', + 'status_partial' => 'Partial', + 'status_paid' => 'Paid', + 'show_line_item_tax' => 'Display line item taxes inline', + 'iframe_url' => 'Website', + '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.', + 'auto_bill' => 'Auto Bill', + 'military_time' => '24 Hour Time', + 'last_sent' => 'Last Sent', + 'reminder_emails' => 'Reminder Emails', + 'templates_and_reminders' => 'Templates & Reminders', + 'subject' => 'Subject', + 'body' => 'Body', + 'first_reminder' => 'First Reminder', + 'second_reminder' => 'Second Reminder', + 'third_reminder' => 'Third Reminder', + 'num_days_reminder' => 'Days after due date', + 'reminder_subject' => 'Reminder: Invoice :invoice from :account', + 'reset' => 'Reset', + 'invoice_not_found' => 'The requested invoice is not available', + 'referral_program' => 'Referral Program', + 'referral_code' => 'Referral URL', + 'last_sent_on' => 'Sent Last: :date', + 'page_expire' => 'This page will expire soon, :click_here to keep working', + 'upcoming_quotes' => 'Upcoming Quotes', + 'expired_quotes' => 'Expired Quotes', + 'sign_up_using' => 'Sign up using', + 'invalid_credentials' => 'These credentials do not match our records', + 'show_all_options' => 'Show all options', + 'user_details' => 'User Details', + 'oneclick_login' => 'One-Click Login', + 'disable' => 'Disable', + 'invoice_quote_number' => 'Invoice and Quote Numbers', + 'invoice_charges' => 'Invoice Charges', + 'notification_invoice_bounced' => 'We were unable to deliver Invoice :invoice to :contact.', + 'notification_invoice_bounced_subject' => 'Unable to deliver Invoice :invoice', + 'notification_quote_bounced' => 'We were unable to deliver Quote :invoice to :contact.', + 'notification_quote_bounced_subject' => 'Unable to deliver Quote :invoice', + 'custom_invoice_link' => 'Custom Invoice Link', + 'total_invoiced' => 'Total Invoiced', + 'open_balance' => 'Open Balance', + 'verify_email' => 'Please visit the link in the account confirmation email to verify your email address.', + 'basic_settings' => 'Basic Settings', + 'pro' => 'Pro', + 'gateways' => 'Payment Gateways', + 'next_send_on' => 'Send Next: :date', + 'no_longer_running' => 'This invoice is not scheduled to run', + 'general_settings' => 'General Settings', + 'customize' => 'Customize', + 'oneclick_login_help' => 'Connect an account to login without a password', + 'referral_code_help' => 'Earn money by sharing our app online', + 'enable_with_stripe' => 'Enable | Requires Stripe', + 'tax_settings' => 'Tax Settings', + 'create_tax_rate' => 'Add Tax Rate', + 'updated_tax_rate' => 'Successfully updated tax rate', + 'created_tax_rate' => 'Successfully created tax rate', + 'edit_tax_rate' => 'Edit tax rate', + 'archive_tax_rate' => 'Archive Tax Rate', + 'archived_tax_rate' => 'Successfully archived the tax rate', + 'default_tax_rate_id' => 'Default Tax Rate', + 'tax_rate' => 'Tax Rate', + 'recurring_hour' => 'Recurring Hour', + 'pattern' => 'Pattern', + 'pattern_help_title' => 'Pattern Help', + 'pattern_help_1' => 'Create custom invoice and quote numbers by specifying a pattern', + 'pattern_help_2' => 'Available variables:', + 'pattern_help_3' => 'For example, :example would be converted to :value', + 'see_options' => 'See options', + 'invoice_counter' => 'Invoice Counter', + 'quote_counter' => 'Quote Counter', + 'type' => 'Type', + 'activity_1' => ':user created client :client', + 'activity_2' => ':user archived client :client', + 'activity_3' => ':user deleted client :client', + 'activity_4' => ':user created invoice :invoice', + 'activity_5' => ':user updated invoice :invoice', + 'activity_6' => ':user emailed invoice :invoice to :contact', + 'activity_7' => ':contact viewed invoice :invoice', + 'activity_8' => ':user archived invoice :invoice', + 'activity_9' => ':user deleted invoice :invoice', + 'activity_10' => ':contact entered payment :payment for :invoice', + 'activity_11' => ':user updated payment :payment', + 'activity_12' => ':user archived payment :payment', + 'activity_13' => ':user deleted payment :payment', + 'activity_14' => ':user entered :credit credit', + 'activity_15' => ':user updated :credit credit', + 'activity_16' => ':user archived :credit credit', + 'activity_17' => ':user deleted :credit credit', + 'activity_18' => ':user created quote :quote', + 'activity_19' => ':user updated quote :quote', + 'activity_20' => ':user emailed quote :quote to :contact', + 'activity_21' => ':contact viewed quote :quote', + 'activity_22' => ':user archived quote :quote', + 'activity_23' => ':user deleted quote :quote', + 'activity_24' => ':user restored quote :quote', + 'activity_25' => ':user restored invoice :invoice', + 'activity_26' => ':user restored client :client', + 'activity_27' => ':user restored payment :payment', + 'activity_28' => ':user restored :credit credit', + 'activity_29' => ':contact approved quote :quote', + 'activity_30' => ':user created :vendor', + 'activity_31' => ':user created :vendor', + 'activity_32' => ':user created :vendor', + 'activity_33' => ':user created :vendor', + 'activity_34' => ':user created expense :expense', + 'activity_35' => ':user created :vendor', + 'activity_36' => ':user created :vendor', + 'activity_37' => ':user created :vendor', + 'payment' => 'Payment', + 'system' => 'System', + 'signature' => 'Email Signature', + 'default_messages' => 'Default Messages', + 'quote_terms' => 'Quote Terms', + 'default_quote_terms' => 'Default Quote Terms', + 'default_invoice_terms' => 'Default Invoice Terms', + 'default_invoice_footer' => 'Default Invoice Footer', + 'quote_footer' => 'Quote Footer', + 'free' => 'Free', + 'quote_is_approved' => 'This quote is approved', + 'apply_credit' => 'Apply Credit', + 'system_settings' => 'System Settings', + 'archive_token' => 'Archive Token', + 'archived_token' => 'Successfully archived token', + 'archive_user' => 'Archive User', + 'archived_user' => 'Successfully archived user', + 'archive_account_gateway' => 'Archive Gateway', + 'archived_account_gateway' => 'Successfully archived gateway', + 'archive_recurring_invoice' => 'Archive Recurring Invoice', + 'archived_recurring_invoice' => 'Successfully archived recurring invoice', + 'delete_recurring_invoice' => 'Delete Recurring Invoice', + 'deleted_recurring_invoice' => 'Successfully deleted recurring invoice', + 'restore_recurring_invoice' => 'Restore Recurring Invoice', + 'restored_recurring_invoice' => 'Successfully restored recurring invoice', + 'archived' => 'Archived', + 'untitled_account' => 'Untitled Company', + 'before' => 'Before', + 'after' => 'After', + 'reset_terms_help' => 'Reset to the default account terms', + 'reset_footer_help' => 'Reset to the default account footer', + 'export_data' => 'Export Data', + 'user' => 'User', + 'country' => 'Country', + 'include' => 'Include', + '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_data' => 'Import Data', + 'source' => 'Source', + 'csv' => 'CSV', + 'client_file' => 'Client File', + 'invoice_file' => 'Invoice File', + 'task_file' => 'Task File', + 'no_mapper' => 'No valid mapping for file', + 'invalid_csv_header' => 'Invalid CSV Header', + 'client_portal' => 'Client Portal', + 'admin' => 'Admin', + 'disabled' => 'Disabled', + 'show_archived_users' => 'Show archived users', + 'notes' => 'Notes', + 'invoice_will_create' => 'client will be created', + 'invoices_will_create' => 'invoices will be created', + 'failed_to_import' => 'The following records failed to import, they either already exist or are missing required fields.', + 'publishable_key' => 'Publishable Key', + 'secret_key' => 'Secret Key', + 'missing_publishable_key' => 'Set your Stripe publishable key for an improved checkout process', + 'email_design' => 'Email Design', + 'due_by' => 'Due by :date', + 'enable_email_markup' => 'Enable Markup', + 'enable_email_markup_help' => 'Make it easier for your clients to pay you by adding schema.org markup to your emails.', + 'template_help_title' => 'Templates Help', + 'template_help_1' => 'Available variables:', + 'email_design_id' => 'Email Style', + 'email_design_help' => 'Make your emails look more professional with HTML layouts', + 'plain' => 'Plain', + 'light' => 'Light', + 'dark' => 'Dark', + '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.', + 'invoice_number_help' => 'Specify a prefix or use a custom pattern to dynamically set the invoice number.', + 'quote_number_help' => 'Specify a prefix or use a custom pattern to dynamically set the quote number.', + 'custom_client_fields_helps' => 'Add a field when creating a client and display the label and value on 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 field when creating an invoice and display the label and value on the PDF.', + 'custom_invoice_charges_helps' => 'Add a field when creating an invoice and include the charge in the invoice subtotals.', + 'token_expired' => 'Validation token was expired. Please try again.', + 'invoice_link' => 'Invoice Link', + 'button_confirmation_message' => 'Click to confirm your email address.', + 'confirm' => 'Confirm', + 'email_preferences' => 'Email Preferences', + 'created_invoices' => 'Successfully created :count invoice(s)', + 'next_invoice_number' => 'The next invoice number is :number.', + 'next_quote_number' => 'The next quote number is :number.', + 'days_before' => 'days before', + 'days_after' => 'days after', + 'field_due_date' => 'due date', + 'field_invoice_date' => 'invoice date', + 'schedule' => 'Schedule', + 'email_designs' => 'Email Designs', + 'assigned_when_sent' => 'Assigned when sent', + 'white_label_purchase_link' => 'Purchase a white label license', + 'expense' => 'Expense', + 'expenses' => 'Expenses', + 'new_expense' => 'New Expense', + 'enter_expense' => 'Enter Expense', + 'vendors' => 'Vendors', + 'new_vendor' => 'New Vendor', + 'payment_terms_net' => 'Net', + 'vendor' => 'Vendor', + 'edit_vendor' => 'Edit Vendor', + 'archive_vendor' => 'Archive Vendor', + 'delete_vendor' => 'Delete Vendor', + 'view_vendor' => 'View Vendor', + 'deleted_expense' => 'Successfully deleted expense', + 'archived_expense' => 'Successfully archived expense', + 'deleted_expenses' => 'Successfully deleted expenses', + 'archived_expenses' => 'Successfully archived expenses', + 'expense_amount' => 'Expense Amount', + 'expense_balance' => 'Expense Balance', + 'expense_date' => 'Expense Date', + 'expense_should_be_invoiced' => 'Should this expense be invoiced?', + 'public_notes' => 'Public Notes', + 'invoice_amount' => 'Invoice Amount', + 'exchange_rate' => 'Exchange Rate', + 'yes' => 'Yes', + 'no' => 'No', + 'should_be_invoiced' => 'Should be invoiced', + 'view_expense' => 'View expense # :expense', + 'edit_expense' => 'Edit Expense', + 'archive_expense' => 'Archive Expense', + 'delete_expense' => 'Delete Expense', + 'view_expense_num' => 'Expense # :expense', + 'updated_expense' => 'Successfully updated expense', + 'created_expense' => 'Successfully created expense', + 'enter_expense' => 'Enter Expense', + 'view' => 'View', + 'restore_expense' => 'Restore Expense', + 'invoice_expense' => 'Invoice Expense', + 'expense_error_multiple_clients' => 'The expenses can\'t belong to different clients', + 'expense_error_invoiced' => 'Expense has already been invoiced', + 'convert_currency' => 'Convert currency', + 'num_days' => 'Number of days', + 'create_payment_term' => 'Create Payment Term', + 'edit_payment_terms' => 'Edit Payment Term', + 'edit_payment_term' => 'Edit Payment Term', + 'archive_payment_term' => 'Archive Payment Term', + 'recurring_due_dates' => 'Recurring Invoice Due Dates', + 'recurring_due_date_help' => '

    Automatically sets a due date for the invoice.

    +

    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.

    +

    Invoices on a weekly cycle set to be due on the day of the week they are created will be due the next week.

    +

    For example:

    +
      +
    • Today is the 15th, due date is 1st of the month. The due date should likely be the 1st of the next month.
    • +
    • Today is the 15th, due date is the last day of the month. The due date will be the last day of the this month. +
    • +
    • Today is the 15th, due date is the 15th day of the month. The due date will be the 15th day of next month. +
    • +
    • Today is the Friday, due date is the 1st Friday after. The due date will be next Friday, not today. +
    • +
    ', + 'due' => 'Due', + 'next_due_on' => 'Due Next: :date', + 'use_client_terms' => 'Use client terms', + 'day_of_month' => ':ordinal day of month', + 'last_day_of_month' => 'Last day of month', + 'day_of_week_after' => ':ordinal :day after', + 'sunday' => 'Sunday', + 'monday' => 'Monday', + 'tuesday' => 'Tuesday', + 'wednesday' => 'Wednesday', + 'thursday' => 'Thursday', + 'friday' => 'Friday', + 'saturday' => 'Saturday', + 'header_font_id' => 'Header 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.', + 'live_preview' => 'Live Preview', + '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.', + 'quote_message_button' => 'To view your quote for :amount, click the button below.', + 'payment_message_button' => 'Thank you for your payment of :amount.', + 'payment_type_direct_debit' => 'Direct Debit', + 'bank_accounts' => 'Credit Cards & Banks', + 'add_bank_account' => 'Add Bank Account', + 'setup_account' => 'Setup Account', + 'import_expenses' => 'Import Expenses', + 'bank_id' => 'Bank', + 'integration_type' => 'Integration Type', + 'updated_bank_account' => 'Successfully updated bank account', + 'edit_bank_account' => 'Edit Bank Account', + 'archive_bank_account' => 'Archive Bank Account', + 'archived_bank_account' => 'Successfully archived bank account', + 'created_bank_account' => 'Successfully created bank account', + 'validate_bank_account' => 'Validate Bank Account', + '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.', + 'username' => 'Username', + 'account_number' => 'Account Number', + 'account_name' => 'Account Name', + 'bank_account_error' => 'Failed to retreive account details, please check your credentials.', + 'status_approved' => 'Approved', + 'quote_settings' => 'Quote Settings', + 'auto_convert_quote' => 'Auto convert quote', + 'auto_convert_quote_help' => 'Automatically convert a quote to an invoice when approved by a client.', + 'validate' => 'Validate', + 'info' => 'Info', + '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.', + '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.', + 'trello_roadmap' => 'Trello Roadmap', + 'header_footer' => 'Header/Footer', + 'first_page' => 'First page', + 'all_pages' => 'All pages', + 'last_page' => 'Last page', + 'all_pages_header' => 'Show Header on', + 'all_pages_footer' => 'Show Footer on', + 'invoice_currency' => 'Invoice Currency', + 'enable_https' => 'We strongly recommend using HTTPS to accept credit card details online.', + 'quote_issued_to' => 'Quote issued to', + 'show_currency_code' => 'Currency Code', + 'trial_message' => 'Your account will receive a free two week trial of our pro plan.', + 'trial_footer' => 'Your free trial lasts :count more days, :link to upgrade now.', + 'trial_footer_last_day' => 'This is the last day of your free trial, :link to upgrade now.', + 'trial_call_to_action' => 'Start Free Trial', + 'trial_success' => 'Successfully enabled two week free pro plan trial', + 'overdue' => 'Overdue', + + + 'white_label_text' => 'Purchase a ONE YEAR white label license for $: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 :link', + 'reset_password_footer' => 'If you did not request this password reset please email our support: :email', + 'limit_users' => 'Sorry, this will exceed the limit of :limit users', + 'more_designs_self_host_header' => 'Get 6 more invoice designs for just $:price', + 'old_browser' => 'Please use a newer browser', + 'white_label_custom_css' => ':link for $: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 400+ US banks.', + + 'pro_plan_remove_logo' => ':link to remove the Invoice Ninja logo by joining the Pro Plan', + 'pro_plan_remove_logo_link' => 'Click here', + 'invitation_status_sent' => 'Email Sent', + 'invitation_status_opened' => 'Email Openend', + 'invitation_status_viewed' => 'Invoice Viewed', + 'email_error_inactive_client' => 'Emails can not be sent to inactive clients', + 'email_error_inactive_contact' => 'Emails can not be sent to inactive contacts', + 'email_error_inactive_invoice' => 'Emails can not be sent to inactive invoices', + 'email_error_user_unregistered' => 'Please register your account to send emails', + 'email_error_user_unconfirmed' => 'Please confirm your account to send emails', + 'email_error_invalid_contact_email' => 'Invalid contact email', + + 'navigation' => 'Navigation', + 'list_invoices' => 'List Invoices', + 'list_clients' => 'List Clients', + 'list_quotes' => 'List Quotes', + 'list_tasks' => 'List Tasks', + 'list_expenses' => 'List Expenses', + 'list_recurring_invoices' => 'List Recurring Invoices', + 'list_payments' => 'List Payments', + 'list_credits' => 'List Credits', + 'tax_name' => 'Tax Name', + 'report_settings' => 'Report Settings', + 'search_hotkey' => 'shortcut is /', + + 'new_user' => 'New User', + 'new_product' => 'New Product', + 'new_tax_rate' => 'New Tax Rate', + 'invoiced_amount' => 'Invoiced Amount', + 'invoice_item_fields' => 'Invoice Item Fields', + 'custom_invoice_item_fields_help' => 'Add a field when creating an invoice item and display the label and value on the PDF.', + 'recurring_invoice_number' => 'Recurring Invoice Number', + 'recurring_invoice_number_prefix_help' => 'Speciy a prefix to be added to the invoice number for recurring invoices. The default value is \'R\'.', + + // Client Passwords + 'enable_portal_password'=>'Password protect invoices', + 'enable_portal_password_help'=>'Allows you to set a password for each contact. If a password is set, the contact will be required to enter a password before viewing invoices.', + 'send_portal_password'=>'Generate password automatically', + 'send_portal_password_help'=>'If no password is set, one will be generated and sent with the first invoice.', + + 'expired' => 'Expired', + 'invalid_card_number' => 'เลขที่บัตรเครดิตไม่ถูกต้อง', + 'invalid_expiry' => 'วันที่หมดอายุไม่ถูกต้อง', + 'invalid_cvv' => 'รสัส CVV ไม่ถูกต้อง', + 'cost' => 'ค่าใช้จ่าย', + 'create_invoice_for_sample' => 'หมายเหตุ: สร้างใบแจ้งหนี้เพื่อดู Preview ได้ที่นี่', + + // User Permissions + 'owner' => 'เจ้าของ', + 'administrator' => 'ผู้ดูแลระบบ', + 'administrator_help' => 'Allow user to manage users, change settings and modify all records', + 'user_create_all' => 'Create clients, invoices, etc.', + 'user_view_all' => 'View all clients, invoices, etc.', + 'user_edit_all' => 'Edit all clients, invoices, etc.', + 'gateway_help_20' => ':link to sign up for Sage Pay.', + 'gateway_help_21' => ':link to sign up for Sage Pay.', + 'partial_due' => 'Partial Due', + 'restore_vendor' => 'Restore Vendor', + 'restored_vendor' => 'Successfully restored vendor', + 'restored_expense' => 'Successfully restored expense', + 'permissions' => 'Permissions', + 'create_all_help' => 'อนุญาตให้ผู้ใช้สร้างและแก้ไขรายการ', + 'view_all_help' => 'อนุญาตให้ผู้ใช้มองเห็นรายการที่ตนเองไม่ได้สร้าง', + 'edit_all_help' => 'อนุญาตให้ผู้ใช้แก้ไขรายการที่ไม่ได้สร้างขึ้นเอง', + 'view_payment' => 'ดูรายการจ่ายเงิน', + + 'january' => 'มกราคม', + 'february' => 'กุมภาพันธ์', + 'march' => 'มีนาคม', + 'april' => 'เมษายน', + 'may' => 'พฤษภาคม', + 'june' => 'มิถุนายน', + 'july' => 'กรกฎาคม', + 'august' => 'สิงหาคม', + 'september' => 'กันยายน', + 'october' => 'ตุลาคม', + 'november' => 'พฤศจิกายน', + 'december' => 'ธันวาคม', + + // Documents + 'documents_header' => 'เอกสาร', + 'email_documents_header' => 'เอกสาร:', + 'email_documents_example_1' => 'Widgets Receipt.pdf', + 'email_documents_example_2' => 'Final Deliverable.zip', + 'invoice_documents' => 'เอกสาร', + 'expense_documents' => 'เอกสารแนบ', + 'invoice_embed_documents' => 'Embed Documents', + 'invoice_embed_documents_help' => 'Include attached images in the invoice.', + 'document_email_attachment' => 'Attach Documents', + 'download_documents' => 'Download Documents (:size)', + 'documents_from_expenses' => 'From Expenses:', + 'dropzone_default_message' => 'Drop files or click to upload', + 'dropzone_fallback_message' => 'Your browser does not support drag\'n\'drop file uploads.', + 'dropzone_fallback_text' => 'Please use the fallback form below to upload your files like in the olden days.', + 'dropzone_file_too_big' => 'File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.', + 'dropzone_invalid_file_type' => 'You can\'t upload files of this type.', + 'dropzone_response_error' => 'Server responded with {{statusCode}} code.', + 'dropzone_cancel_upload' => 'Cancel upload', + 'dropzone_cancel_upload_confirmation' => 'Are you sure you want to cancel this upload?', + 'dropzone_remove_file' => 'ลบไฟล์', + 'documents' => 'เอกสาร:', + 'document_date' => 'วันที่เอกสาร', + 'document_size' => 'ขนาด', + + 'enable_client_portal' => 'Client Portal', + 'enable_client_portal_help' => 'Show/hide the client portal.', + 'enable_client_portal_dashboard' => 'Dashboard', + 'enable_client_portal_dashboard_help' => 'Show/hide the dashboard page in the client portal.', + + // Plans + 'account_management' => 'Account Management', + 'plan_status' => 'Plan Status', + + 'plan_upgrade' => 'Upgrade', + 'plan_change' => 'Change Plan', + 'pending_change_to' => 'Changes To', + 'plan_changes_to' => ':plan on :date', + 'plan_term_changes_to' => ':plan (:term) on :date', + 'cancel_plan_change' => 'Cancel Change', + 'plan' => 'Plan', + 'expires' => 'หมดอายุ', + 'renews' => 'Renews', + 'plan_expired' => ':plan Plan Expired', + 'trial_expired' => ':plan Plan Trial Ended', + 'never' => 'Never', + 'plan_free' => 'Free', + 'plan_pro' => 'Pro', + 'plan_enterprise' => 'Enterprise', + 'plan_white_label' => 'Self Hosted (White labeled)', + 'plan_free_self_hosted' => 'Self Hosted (Free)', + 'plan_trial' => 'Trial', + 'plan_term' => 'Term', + 'plan_term_monthly' => 'Monthly', + 'plan_term_yearly' => 'รายปี', + 'plan_term_month' => 'เดือน', + 'plan_term_year' => 'ปี', + 'plan_price_monthly' => '$:price/เดือน', + 'plan_price_yearly' => '$:price/ปี', + 'updated_plan' => 'Updated plan settings', + 'plan_paid' => 'Term Started', + 'plan_started' => 'Plan Started', + 'plan_expires' => 'Plan Expires', + + 'white_label_button' => 'White Label', + + 'pro_plan_year_description' => 'One year enrollment in the Invoice Ninja Pro Plan.', + 'pro_plan_month_description' => 'One month enrollment in the Invoice Ninja Pro Plan.', + 'enterprise_plan_product' => 'Enterprise Plan', + 'enterprise_plan_year_description' => 'One year enrollment in the Invoice Ninja Enterprise Plan.', + 'enterprise_plan_month_description' => 'One month enrollment in the Invoice Ninja Enterprise Plan.', + 'plan_credit_product' => 'Credit', + 'plan_credit_description' => 'Credit for unused time', + 'plan_pending_monthly' => 'Will switch to monthly on :date', + 'plan_refunded' => 'A refund has been issued.', + + 'live_preview' => 'Live Preview', + 'page_size' => 'Page Size', + 'live_preview_disabled' => 'Live preview has been disabled to support selected font', + 'invoice_number_padding' => 'Padding', + 'preview' => 'Preview', + 'list_vendors' => 'List Vendors', + 'add_users_not_supported' => 'Upgrade to the Enterprise plan to add additional users to your account.', + 'enterprise_plan_features' => 'The Enterprise plan adds support for multiple users and file attachments, :link to see the full list of features.', + 'return_to_app' => 'Return to app', + + + // Payment updates + 'refund_payment' => 'Refund Payment', + 'refund_max' => 'สูงสุด:', + 'refund' => 'Refund', + 'are_you_sure_refund' => 'Refund selected payments?', + 'status_pending' => 'Pending', + 'status_completed' => 'Completed', + 'status_failed' => 'Failed', + 'status_partially_refunded' => 'Partially Refunded', + 'status_partially_refunded_amount' => ':amount Refunded', + 'status_refunded' => 'Refunded', + 'status_voided' => 'Cancelled', + 'refunded_payment' => 'Refunded Payment', + 'activity_39' => ':user cancelled a :payment_amount payment (:payment)', + 'activity_40' => ':user refunded :adjustment of a :payment_amount payment (:payment)', + 'card_expiration' => 'Exp: :expires', + + 'card_creditcardother' => 'Unknown', + 'card_americanexpress' => 'American Express', + 'card_carteblanche' => 'Carte Blanche', + 'card_unionpay' => 'UnionPay', + 'card_diners' => 'Diners Club', + 'card_discover' => 'Discover', + 'card_jcb' => 'JCB', + 'card_laser' => 'Laser', + 'card_maestro' => 'Maestro', + 'card_mastercard' => 'MasterCard', + 'card_solo' => 'Solo', + 'card_switch' => 'Switch', + 'card_visacard' => 'Visa', + 'card_ach' => 'ACH', + + 'payment_type_stripe' => 'Stripe', + 'ach' => 'ACH', + 'enable_ach' => 'Enable ACH', + 'stripe_ach_help' => 'ACH support must also be enabled at Stripe.', + 'ach_disabled' => 'Another gateway is already configured for direct debit.', + + 'plaid' => 'Plaid', + 'client_id' => 'Client Id', + 'secret' => 'Secret', + 'public_key' => 'กุญแจสาธารณะ', + 'plaid_optional' => '(optional)', + 'plaid_environment_help' => 'When a Stripe test key is given, Plaid\'s development environement (tartan) will be used.', + 'other_providers' => 'Other Providers', + 'country_not_supported' => 'That country is not supported.', + 'invalid_routing_number' => 'The routing number is not valid.', + 'invalid_account_number' => 'The account number is not valid.', + 'account_number_mismatch' => 'The account numbers do not match.', + 'missing_account_holder_type' => 'Please select an individual or company account.', + 'missing_account_holder_name' => 'Please enter the account holder\'s name.', + 'routing_number' => 'Routing Number', + 'confirm_account_number' => 'Confirm Account Number', + 'individual_account' => 'Individual Account', + 'company_account' => 'Company Account', + 'account_holder_name' => 'Account Holder Name', + 'add_account' => 'Add Account', + 'payment_methods' => 'Payment Methods', + 'complete_verification' => 'Complete Verification', + 'verification_amount1' => 'Amount 1', + 'verification_amount2' => 'Amount 2', + 'payment_method_verified' => 'Verification completed successfully', + 'verification_failed' => 'Verification Failed', + 'remove_payment_method' => 'Remove Payment Method', + 'confirm_remove_payment_method' => 'Are you sure you want to remove this payment method?', + 'remove' => 'Remove', + 'payment_method_removed' => 'Removed payment method.', + 'bank_account_verification_help' => 'We have made two deposits into your account with the description "VERIFICATION". These deposits will take 1-2 business days to appear on your statement. Please enter the amounts below.', + 'bank_account_verification_next_steps' => 'We have made two deposits into your account with the description "VERIFICATION". These deposits will take 1-2 business days to appear on your statement. + Once you have the amounts, come back to this payment methods page and click "Complete Verification" next to the account.', + 'unknown_bank' => 'Unknown Bank', + 'ach_verification_delay_help' => 'You will be able to use the account after completing verification. Verification usually takes 1-2 business days.', + 'add_credit_card' => 'Add Credit Card', + 'payment_method_added' => 'Added payment method.', + 'use_for_auto_bill' => 'Use For Autobill', + 'used_for_auto_bill' => 'Autobill Payment Method', + 'payment_method_set_as_default' => 'Set Autobill payment method.', + 'activity_41' => ':payment_amount payment (:payment) failed', + 'webhook_url' => 'Webhook URL', + 'stripe_webhook_help' => 'You must :link.', + 'stripe_webhook_help_link_text' => 'add this URL as an endpoint at Stripe', + 'payment_method_error' => 'There was an error adding your payment methd. Please try again later.', + 'notification_invoice_payment_failed_subject' => 'Payment failed for Invoice :invoice', + 'notification_invoice_payment_failed' => 'A payment made by client :client towards Invoice :invoice failed. The payment has been marked as failed and :amount has been added to the client\'s balance.', + 'link_with_plaid' => 'Link Account Instantly with Plaid', + 'link_manually' => 'Link Manually', + 'secured_by_plaid' => 'Secured by Plaid', + 'plaid_linked_status' => 'Your bank account at :bank', + 'add_payment_method' => 'Add Payment Method', + 'account_holder_type' => 'Account Holder Type', + 'ach_authorization' => 'I authorize :company to use my bank account for future payments and, if necessary, electronically credit my account to correct erroneous debits. I understand that I may cancel this authorization at any time by removing the payment method or by contacting :email.', + 'ach_authorization_required' => 'You must consent to ACH transactions.', + 'off' => 'Off', + 'opt_in' => 'Opt-in', + 'opt_out' => 'Opt-out', + 'always' => 'Always', + 'opted_out' => 'Opted out', + 'opted_in' => 'Opted in', + 'manage_auto_bill' => 'Manage Auto-bill', + 'enabled' => 'Enabled', + 'paypal' => 'PayPal', + 'braintree_enable_paypal' => 'Enable PayPal payments through BrainTree', + 'braintree_paypal_disabled_help' => 'The PayPal gateway is processing PayPal payments', + 'braintree_paypal_help' => 'You must also :link.', + 'braintree_paypal_help_link_text' => 'link PayPal to your BrainTree account', + 'token_billing_braintree_paypal' => 'Save payment details', + 'add_paypal_account' => 'Add PayPal Account', + + + 'no_payment_method_specified' => 'No payment method specified', + 'chart_type' => 'Chart Type', + 'format' => 'Format', + 'import_ofx' => 'Import OFX', + 'ofx_file' => 'OFX File', + 'ofx_parse_failed' => 'Failed to parse OFX file', + + // WePay + 'wepay' => 'WePay', + 'sign_up_with_wepay' => 'Sign up with WePay', + 'use_another_provider' => 'Use another provider', + 'company_name' => 'ชื่อบริษัท', + 'wepay_company_name_help' => 'This will appear on client\'s credit card statements.', + 'wepay_description_help' => 'The purpose of this account.', + 'wepay_tos_agree' => 'I agree to the :link.', + 'wepay_tos_link_text' => 'WePay Terms of Service', + 'resend_confirmation_email' => 'Resend Confirmation Email', + 'manage_wepay_account' => 'Manage WePay Account', + 'action_required' => 'Action Required', + 'finish_setup' => 'การติดตั้งเสร็จสมบูรณ์', + 'created_wepay_confirmation_required' => 'Please check your email and confirm your email address with WePay.', + 'switch_to_wepay' => 'Switch to WePay', + 'switch' => 'Switch', + 'restore_account_gateway' => 'Restore Gateway', + 'restored_account_gateway' => 'Successfully restored gateway', + 'united_states' => 'United States', + 'canada' => 'Canada', + 'accept_debit_cards' => 'Accept Debit Cards', + 'debit_cards' => 'บัตรเดบิต', + + 'warn_start_date_changed' => 'The next invoice will be sent on the new start date.', + 'original_start_date' => 'Original start date', + 'new_start_date' => 'New start date', + 'security' => 'Security', + 'see_whats_new' => 'See what\'s new in v:version', + 'wait_for_upload' => 'Please wait for the document upload to complete.', + 'upgrade_for_permissions' => 'Upgrade to our Enterprise plan to enable permissions.', + 'enable_second_tax_rate' => 'Enable specifying a second tax rate', + 'payment_file' => 'Payment File', + 'expense_file' => 'Expense File', + 'product_file' => 'Product File', + 'import_products' => 'Import Products', + 'products_will_create' => 'products will be created.', + 'product_key' => 'Product', + 'created_products' => 'Successfully created :count product(s)', + 'export_help' => 'Use JSON if you plan to import the data into Invoice Ninja.', + 'JSON_file' => 'JSON File', + + 'view_dashboard' => 'View Dashboard', + 'client_session_expired' => 'Session Expired', + 'client_session_expired_message' => 'Your session has expired. Please click the link in your email again.', + + 'auto_bill_notification' => 'This invoice will automatically be billed to your :payment_method on file on :due_date.', + 'auto_bill_payment_method_bank_transfer' => 'bank account', + 'auto_bill_payment_method_credit_card' => 'credit card', + 'auto_bill_payment_method_paypal' => 'PayPal account', + 'auto_bill_notification_placeholder' => 'This invoice will automatically be billed to your credit card on file on the due date.', + 'payment_settings' => 'Payment Settings', + + 'on_send_date' => 'On send date', + 'on_due_date' => 'On due date', + 'auto_bill_ach_date_help' => 'ACH auto bill will always happen on the due date', + 'warn_change_auto_bill' => 'Due to NACHA rules, changes to this invoice may prevent ACH auto bill.', + + 'bank_account' => 'Bank Account', + 'payment_processed_through_wepay' => 'ACH payments will be processed using WePay.', + 'wepay_payment_tos_agree' => 'I agree to the WePay :terms and :privacy_policy.', + 'privacy_policy' => 'Privacy Policy', + 'wepay_payment_tos_agree_required' => 'You must agree to the WePay Terms of Service and Privacy Policy.', + 'payment_settings_supported_gateways' => 'These options are supported by the WePay, Stripe, and Braintree gateways.', + 'ach_email_prompt' => 'Please enter your email address:', + 'verification_pending' => 'Verification Pending', + + 'update_font_cache' => 'Please force refresh the page to update the font cache.', + 'more_options' => 'More options', + 'credit_card' => 'Credit Card', + 'bank_transfer' => 'Bank Transfer', + 'no_transaction_reference' => 'We did not recieve a payment transaction reference from the gateway.', + 'use_bank_on_file' => 'Use Bank on File', + 'auto_bill_email_message' => 'This invoice will automatically be billed to the payment method on file on the due date.', + 'bitcoin' => 'Bitcoin', + 'added_on' => 'Added :date', + 'failed_remove_payment_method' => 'Failed to remove the payment method', + 'gateway_exists' => 'This gateway already exists', + 'manual_entry' => 'Manual entry', + +); + +return $LANG; + +?> diff --git a/resources/lang/th/validation.php b/resources/lang/th/validation.php new file mode 100644 index 0000000000..17d5f87d92 --- /dev/null +++ b/resources/lang/th/validation.php @@ -0,0 +1,116 @@ + 'ข้อมูล :attribute ต้องผ่านการยอมรับก่อน', + 'active_url' => 'ข้อมูล :attribute ต้องเป็น URL เท่านั้น', + 'after' => 'ข้อมูล :attribute ต้องเป็นวันที่หลังจาก :date.', + 'alpha' => 'ข้อมูล :attribute ต้องเป็นตัวอักษรภาษาอังกฤษเท่านั้น', + 'alpha_dash' => 'ข้อมูล :attribute ต้องเป็นตัวอักษรภาษาอังกฤษ ตัวเลข และ _ เท่านั้น', + 'alpha_num' => 'ข้อมูล :attribute ต้องเป็นตัวอักษรภาษาอังกฤษ ตัวเลข เท่านั้น', + 'array' => 'ข้อมูล :attribute ต้องเป็น array เท่านั้น', + 'before' => 'ข้อมูล :attribute ต้องเป็นวันที่ก่อน :date.', + 'between' => [ + 'numeric' => 'ข้อมูล :attribute ต้องอยู่ในช่วงระหว่าง :min - :max.', + 'file' => 'ข้อมูล :attribute ต้องอยู่ในช่วงระหว่าง :min - :max กิโลไบต์', + 'string' => 'ข้อมูล :attribute ต้องอยู่ในช่วงระหว่าง :min - :max ตัวอักษร', + 'array' => 'ข้อมูล :attribute ต้องอยู่ในช่วงระหว่าง :min - :max ค่า', + ], + 'boolean' => 'ข้อมูล :attribute ต้องเป็นจริง หรือเท็จ เท่านั้น', + 'confirmed' => 'ข้อมูล :attribute ไม่ตรงกัน', + 'date' => 'ข้อมูล :attribute ต้องเป็นวันที่', + 'date_format' => 'ข้อมูล :attribute ไม่ตรงกับข้อมูลกำหนด :format.', + 'different' => 'ข้อมูล :attribute และ :other ต้องไม่เท่ากัน', + 'digits' => 'ข้อมูล :attribute ต้องเป็น :digits', + 'digits_between' => 'ข้อมูล :attribute ต้องอยู่ในช่วงระหว่าง :min ถึง :max', + 'dimensions' => 'The :attribute has invalid image dimensions.', + 'distinct' => 'ข้อมูล :attribute มีค่าที่ซ้ำกัน', + 'email' => 'ข้อมูล :attribute ต้องเป็นอีเมล์', + 'exists' => 'ข้อมูล ที่ถูกเลือกจาก :attribute ไม่ถูกต้อง', + 'filled' => 'ข้อมูล :attribute จำเป็นต้องกรอก', + 'image' => 'ข้อมูล :attribute ต้องเป็นรูปภาพ', + 'in' => 'ข้อมูล ที่ถูกเลือกใน :attribute ไม่ถูกต้อง', + 'in_array' => 'ข้อมูล :attribute ไม่มีอยู่ภายในค่าของ :other', + 'integer' => 'ข้อมูล :attribute ต้องเป็นตัวเลข', + 'ip' => 'ข้อมูล :attribute ต้องเป็น IP', + 'json' => 'ข้อมูล :attribute ต้องเป็นอักขระ JSON ที่สมบูรณ์', + 'max' => [ + 'numeric' => 'ข้อมูล :attribute ต้องมีจำนวนไม่เกิน :max.', + 'file' => 'ข้อมูล :attribute ต้องมีจำนวนไม่เกิน :max กิโลไบต์', + 'string' => 'ข้อมูล :attribute ต้องมีจำนวนไม่เกิน :max ตัวอักษร', + 'array' => 'ข้อมูล :attribute ต้องมีจำนวนไม่เกิน :max ค่า', + ], + 'mimes' => 'ข้อมูล :attribute ต้องเป็นชนิดไฟล์: :values.', + 'min' => [ + 'numeric' => 'ข้อมูล :attribute ต้องมีจำนวนอย่างน้อย :min.', + 'file' => 'ข้อมูล :attribute ต้องมีจำนวนอย่างน้อย :min กิโลไบต์', + 'string' => 'ข้อมูล :attribute ต้องมีจำนวนอย่างน้อย :min ตัวอักษร', + 'array' => 'ข้อมูล :attribute ต้องมีจำนวนอย่างน้อย :min ค่า', + ], + 'not_in' => 'ข้อมูล ที่เลือกจาก :attribute ไม่ถูกต้อง', + 'numeric' => 'ข้อมูล :attribute ต้องเป็นตัวเลข', + 'present' => 'ข้อมูล :attribute ต้องเป็นปัจจุบัน', + 'regex' => 'ข้อมูล :attribute มีรูปแบบไม่ถูกต้อง', + 'required' => 'ข้อมูล :attribute จำเป็นต้องกรอก', + 'required_if' => 'ข้อมูล :attribute จำเป็นต้องกรอกเมื่อ :other เป็น :value.', + 'required_unless' => 'ข้อมูล :attribute จำเป็นต้องกรอกเว้นแต่ :other เป็น :values.', + 'required_with' => 'ข้อมูล :attribute จำเป็นต้องกรอกเมื่อ :values มีค่า', + 'required_with_all' => 'ข้อมูล :attribute จำเป็นต้องกรอกเมื่อ :values มีค่าทั้งหมด', + 'required_without' => 'ข้อมูล :attribute จำเป็นต้องกรอกเมื่อ :values ไม่มีค่า', + 'required_without_all' => 'ข้อมูล :attribute จำเป็นต้องกรอกเมื่อ :values ไม่มีค่าทั้งหมด', + 'same' => 'ข้อมูล :attribute และ :other ต้องถูกต้อง', + 'size' => [ + 'numeric' => 'ข้อมูล :attribute ต้องเท่ากับ :size', + 'file' => 'ข้อมูล :attribute ต้องเท่ากับ :size กิโลไบต์', + 'string' => 'ข้อมูล :attribute ต้องเท่ากับ :size ตัวอักษร', + 'array' => 'ข้อมูล :attribute ต้องเท่ากับ :size ค่า', + ], + 'string' => 'ข้อมูล :attribute ต้องเป็นอักขระ', + 'timezone' => 'ข้อมูล :attribute ต้องเป็นข้อมูลเขตเวลาที่ถูกต้อง', + 'unique' => 'ข้อมูล :attribute ไม่สามารถใช้ได้', + 'url' => 'ข้อมูล :attribute ไม่ถูกต้อง', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'custom-message', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [ + // + ], + +]; diff --git a/resources/views/accounts/account_gateway.blade.php b/resources/views/accounts/account_gateway.blade.php index db72009072..5823a37fce 100644 --- a/resources/views/accounts/account_gateway.blade.php +++ b/resources/views/accounts/account_gateway.blade.php @@ -5,23 +5,24 @@ @include('accounts.nav', ['selected' => ACCOUNT_PAYMENTS]) - {!! Former::open($url)->method($method)->rule()->addClass('warn-on-exit') !!} - {!! Former::populateField('token_billing_type_id', $account->token_billing_type_id) !!} - -

    {!! trans($title) !!}

    + {!! Former::open($url)->method($method)->rule()->addClass('warn-on-exit') !!} @if ($accountGateway) - {!! Former::populateField('gateway_id', $accountGateway->gateway_id) !!} - {!! Former::populateField('payment_type_id', $paymentTypeId) !!} + {!! Former::populateField('primary_gateway_id', $accountGateway->gateway_id) !!} {!! Former::populateField('recommendedGateway_id', $accountGateway->gateway_id) !!} {!! Former::populateField('show_address', intval($accountGateway->show_address)) !!} {!! Former::populateField('update_address', intval($accountGateway->update_address)) !!} {!! Former::populateField('publishable_key', $accountGateway->getPublishableStripeKey() ? str_repeat('*', strlen($accountGateway->getPublishableStripeKey())) : '') !!} + {!! Former::populateField('enable_ach', $accountGateway->getAchEnabled() ? '1' : null) !!} + {!! Former::populateField('enable_paypal', $accountGateway->getPayPalEnabled() ? '1' : null) !!} + {!! Former::populateField('plaid_client_id', $accountGateway->getPlaidClientId() ? str_repeat('*', strlen($accountGateway->getPlaidClientId())) : '') !!} + {!! Former::populateField('plaid_secret', $accountGateway->getPlaidSecret() ? str_repeat('*', strlen($accountGateway->getPlaidSecret())) : '') !!} + {!! Former::populateField('plaid_public_key', $accountGateway->getPlaidPublicKey() ? str_repeat('*', strlen($accountGateway->getPlaidPublicKey())) : '') !!} @if ($config) @foreach ($accountGateway->fields as $field => $junk) @@ -33,34 +34,36 @@ @endforeach @endif @else - {!! Former::populateField('gateway_id', GATEWAY_STRIPE) !!} {!! Former::populateField('show_address', 1) !!} {!! Former::populateField('update_address', 1) !!} + + @if (Utils::isNinjaDev()) + @include('accounts.partials.payment_credentials') + @endif @endif - {!! Former::select('payment_type_id') - ->options($paymentTypes) - ->addGroupClass('payment-type-option') - ->onchange('setPaymentType()') !!} + @if ($accountGateway) +
    + {!! Former::text('primary_gateway_id') !!} +
    + @else + {!! Former::select('primary_gateway_id') + ->fromQuery($primaryGateways, 'name', 'id') + ->label(trans('texts.gateway_id')) + ->onchange('setFieldsShown()') !!} - {!! Former::select('gateway_id') - ->dataClass('gateway-dropdown') - ->addGroupClass('gateway-option') - ->fromQuery($selectGateways, 'name', 'id') - ->onchange('setFieldsShown()') !!} + @if (count($secondaryGateways)) + {!! Former::select('secondary_gateway_id') + ->fromQuery($secondaryGateways, 'name', 'id') + ->addGroupClass('secondary-gateway') + ->label(' ') + ->onchange('setFieldsShown()') !!} + @endif + @endif @foreach ($gateways as $gateway) @endforeach - {!! Former::checkbox('show_address') - ->label(trans('texts.billing_address')) - ->text(trans('texts.show_address_help')) - ->addGroupClass('gateway-option') !!} - {!! Former::checkbox('update_address') - ->label(' ') - ->text(trans('texts.update_address_help')) - ->addGroupClass('gateway-option') !!} + + + @if (!$accountGateway || $accountGateway->gateway_id == GATEWAY_STRIPE) +
    + {!! Former::checkbox('enable_ach') + ->label(trans('texts.ach')) + ->text(trans('texts.enable_ach')) + ->help(trans('texts.stripe_ach_help')) !!} +
    +
    +
    +

    {{trans('texts.plaid')}}

    +
    {{trans('texts.plaid_optional')}}
    +
    +
    + {!! Former::text('plaid_client_id')->label(trans('texts.client_id')) !!} + {!! Former::text('plaid_secret')->label(trans('texts.secret')) !!} + {!! Former::text('plaid_public_key')->label(trans('texts.public_key')) + ->help(trans('texts.plaid_environment_help')) !!} +
    +
    + @endif
    -

     

    +
    + +

    + {!! Button::normal(trans('texts.cancel'))->large()->asLinkTo(URL::to('/settings/online_payments'))->appendIcon(Icon::create('remove-circle')) !!} + {!! Button::success(trans('texts.save'))->submit()->large()->appendIcon(Icon::create('floppy-disk')) !!} +
    - {!! Former::actions( - $countGateways > 0 ? Button::normal(trans('texts.cancel'))->large()->asLinkTo(URL::to('/settings/online_payments'))->appendIcon(Icon::create('remove-circle')) : false, - Button::success(trans('texts.save'))->submit()->large()->appendIcon(Icon::create('floppy-disk'))) !!} {!! Former::close() !!} - -@stop \ No newline at end of file +@stop diff --git a/resources/views/accounts/account_gateway_wepay.blade.php b/resources/views/accounts/account_gateway_wepay.blade.php new file mode 100644 index 0000000000..5017f43fc2 --- /dev/null +++ b/resources/views/accounts/account_gateway_wepay.blade.php @@ -0,0 +1,109 @@ +@extends('header') + +@section('content') + @parent + + @include('accounts.nav', ['selected' => ACCOUNT_PAYMENTS]) + + {!! Former::open($url)->method($method)->rules(array( + 'first_name' => 'required', + 'last_name' => 'required', + 'email' => 'required', + 'description' => 'required', + 'company_name' => 'required', + 'tos_agree' => 'required', + 'country' => 'required', + ))->addClass('warn-on-exit') !!} + + {!! Former::populateField('company_name', $account->getDisplayName()) !!} + + @if ($account->country) + {!! Former::populateField('country', $account->country->iso_3166_2) !!} + @endif + + {!! Former::populateField('first_name', $user->first_name) !!} + {!! Former::populateField('last_name', $user->last_name) !!} + {!! Former::populateField('email', $user->email) !!} + {!! Former::populateField('show_address', 1) !!} + {!! Former::populateField('update_address', 1) !!} + + @if (WEPAY_ENABLE_CANADA) + {!! Former::populateField('country', 'US') !!} + @endif + +
    +
    +

    {!! trans('texts.online_payments') !!}

    +
    +
    + {!! Former::text('first_name') !!} + {!! Former::text('last_name') !!} + {!! Former::text('email') !!} + {!! Former::text('company_name')->help('wepay_company_name_help')->maxlength(255) !!} + {!! Former::text('description')->help('wepay_description_help') !!} + + @if (WEPAY_ENABLE_CANADA) +
    + {!! Former::radios('country') + ->radios([ + trans('texts.united_states') => ['value' => 'US'], + trans('texts.canada') => ['value' => 'CA'], + ]) !!} +
    +
    + {!! Former::checkbox('debit_cards') + ->text(trans('texts.accept_debit_cards')) !!} +
    + @endif + + {!! Former::checkbox('show_address') + ->label(trans('texts.billing_address')) + ->text(trans('texts.show_address_help')) !!} + {!! Former::checkbox('update_address') + ->label(' ') + ->text(trans('texts.update_address_help')) !!} + {!! Former::checkboxes('creditCardTypes[]') + ->label('Accepted Credit Cards') + ->checkboxes($creditCardTypes) + ->class('creditcard-types') !!} + {!! Former::checkbox('enable_ach') + ->label(trans('texts.ach')) + ->text(trans('texts.enable_ach')) !!} + + {!! Former::checkbox('tos_agree')->label(' ')->text(trans('texts.wepay_tos_agree', + ['link'=>''.trans('texts.wepay_tos_link_text').''] + ))->value('true') !!} +
    +
    + +
    +
    + {!! Button::normal(trans('texts.use_another_provider'))->large()->asLinkTo(URL::to('/gateways/create?other_providers=true')) !!} + {!! Button::success(trans('texts.sign_up_with_wepay'))->submit()->large() !!} +
    + + + + + + + + {!! Former::close() !!} + +@stop diff --git a/resources/views/accounts/bank_account.blade.php b/resources/views/accounts/bank_account.blade.php index ff1a0affef..8291b95373 100644 --- a/resources/views/accounts/bank_account.blade.php +++ b/resources/views/accounts/bank_account.blade.php @@ -2,7 +2,7 @@ @section('head') @parent - + @include('money_script') @@ -34,7 +32,7 @@ @foreach (\App\Services\ImportService::$entityTypes as $entityType) {!! Former::file("{$entityType}_file") - ->addGroupClass("{$entityType}-file") !!} + ->addGroupClass("import-file {$entityType}-file") !!} @endforeach {!! Former::actions( Button::info(trans('texts.upload'))->submit()->large()->appendIcon(Icon::create('open'))) !!} @@ -55,25 +53,49 @@ ->addOption('CSV', 'CSV') ->addOption('XLS', 'XLS') ->addOption('JSON', 'JSON') - ->style('max-width: 200px') !!} + ->style('max-width: 200px') + ->inlineHelp('export_help') !!} - {!! Former::checkbox('entity_types') - ->label('include') - ->addGroupClass('entity-types') - ->checkboxes([ - trans('texts.clients') => array('name' => ENTITY_CLIENT, 'value' => 1), - trans('texts.tasks') => array('name' => ENTITY_TASK, 'value' => 1), - trans('texts.invoices') => array('name' => ENTITY_INVOICE, 'value' => 1), - trans('texts.payments') => array('name' => ENTITY_PAYMENT, 'value' => 1), - ])->check(ENTITY_CLIENT)->check(ENTITY_TASK)->check(ENTITY_INVOICE)->check(ENTITY_PAYMENT) !!} - {!! Former::actions( Button::primary(trans('texts.download'))->submit()->large()->appendIcon(Icon::create('download-alt'))) !!} + {!! Former::inline_radios('include_radio') + ->onchange('onIncludeChange()') + ->label(trans('texts.include')) + ->radios([ + trans('texts.all') . '   ' => ['value' => 'all', 'name' => 'include'], + trans('texts.selected') => ['value' => 'selected', 'name' => 'include'], + ])->check('all') !!} + + +
    + +
    + @include('partials/checkbox', ['field' => 'clients']) + @include('partials/checkbox', ['field' => 'contacts']) + @include('partials/checkbox', ['field' => 'credits']) + @include('partials/checkbox', ['field' => 'tasks']) + @include('partials/checkbox', ['field' => 'invoices']) +
    +
    + @include('partials/checkbox', ['field' => 'quotes']) + @include('partials/checkbox', ['field' => 'recurring']) + @include('partials/checkbox', ['field' => 'payments']) + @include('partials/checkbox', ['field' => 'vendors']) + @include('partials/checkbox', ['field' => 'vendor_contacts']) +
    +
    + + {!! Former::actions( Button::primary(trans('texts.download'))->submit()->large()->appendIcon(Icon::create('download-alt'))) !!} {!! Former::close() !!} -@stop \ No newline at end of file +@stop diff --git a/resources/views/accounts/import_map.blade.php b/resources/views/accounts/import_map.blade.php index 12ac6766d6..5c3c76ac7c 100644 --- a/resources/views/accounts/import_map.blade.php +++ b/resources/views/accounts/import_map.blade.php @@ -7,18 +7,16 @@ {!! Former::open('/import_csv')->addClass('warn-on-exit') !!} - @if (isset($data[ENTITY_CLIENT])) - @include('accounts.partials.map', $data[ENTITY_CLIENT]) - @endif + @foreach (App\Services\ImportService::$entityTypes as $entityType) + @if (isset($data[$entityType])) + @include('accounts.partials.map', $data[$entityType]) + @endif + @endforeach - @if (isset($data[ENTITY_INVOICE])) - @include('accounts.partials.map', $data[ENTITY_INVOICE]) - @endif - - {!! Former::actions( + {!! Former::actions( Button::normal(trans('texts.cancel'))->large()->asLinkTo(URL::to('/settings/import_export'))->appendIcon(Icon::create('remove-circle')), Button::success(trans('texts.import'))->submit()->large()->appendIcon(Icon::create('floppy-disk'))) !!} - + {!! Former::close() !!} -@stop \ No newline at end of file +@stop diff --git a/resources/views/accounts/import_ofx.blade.php b/resources/views/accounts/import_ofx.blade.php new file mode 100644 index 0000000000..cb6e0356cf --- /dev/null +++ b/resources/views/accounts/import_ofx.blade.php @@ -0,0 +1,30 @@ +@extends('header') + +@section('content') + @parent + + @include('accounts.nav', ['selected' => ACCOUNT_BANKS]) + +
    +
    +

    {{ trans('texts.import_ofx') }}

    +
    +
    + + {!! Former::open_for_files('bank_accounts/import_ofx') + ->rules(['ofx_file' => 'required']) + ->addClass('warn-on-exit') !!} + + {!! Former::file("ofx_file") !!} + +
    +
    + + {!! Former::actions( + Button::normal(trans('texts.cancel'))->large()->asLinkTo(URL::to('settings/bank_accounts'))->appendIcon(Icon::create('remove-circle')), + Button::success(trans('texts.upload'))->submit()->large()->appendIcon(Icon::create('open')) + ) !!} + + {!! Former::close() !!} + +@stop diff --git a/resources/views/accounts/invoice_design.blade.php b/resources/views/accounts/invoice_design.blade.php index 28a550e703..5dbf26c839 100644 --- a/resources/views/accounts/invoice_design.blade.php +++ b/resources/views/accounts/invoice_design.blade.php @@ -116,8 +116,8 @@ {!! Former::open()->addClass('warn-on-exit')->onchange('if(!window.loadingFonts)refreshPDF()') !!} {!! Former::populateField('invoice_design_id', $account->invoice_design_id) !!} - {!! Former::populateField('body_font_id', $account->body_font_id) !!} - {!! Former::populateField('header_font_id', $account->header_font_id) !!} + {!! Former::populateField('body_font_id', $account->getBodyFontId()) !!} + {!! Former::populateField('header_font_id', $account->getHeaderFontId()) !!} {!! Former::populateField('live_preview', intval($account->live_preview)) !!} {!! Former::populateField('font_size', $account->font_size) !!} {!! Former::populateField('page_size', $account->page_size) !!} @@ -208,12 +208,15 @@ {!! Former::text('labels_description')->label(trans('texts.description')) !!} {!! Former::text('labels_unit_cost')->label(trans('texts.unit_cost')) !!} {!! Former::text('labels_quantity')->label(trans('texts.quantity')) !!} + {!! Former::text('labels_line_total')->label(trans('texts.line_total')) !!} + {!! Former::text('labels_terms')->label(trans('texts.terms')) !!}
    - {!! Former::text('labels_line_total')->label(trans('texts.line_total')) !!} - {!! Former::text('labels_terms')->label(trans('texts.terms')) !!} - {!! Former::text('labels_balance_due')->label(trans('texts.balance_due')) !!} - {!! Former::text('labels_partial_due')->label(trans('texts.partial_due')) !!} + {!! Former::text('labels_subtotal')->label(trans('texts.subtotal')) !!} + {!! Former::text('labels_discount')->label(trans('texts.discount')) !!} + {!! Former::text('labels_paid_to_date')->label(trans('texts.paid_to_date')) !!} + {!! Former::text('labels_balance_due')->label(trans('texts.balance_due')) !!} + {!! Former::text('labels_partial_due')->label(trans('texts.partial_due')) !!}
    @@ -258,21 +261,15 @@ ->appendIcon(Icon::create('edit')) ->asLinkTo(URL::to('/settings/customize_design')) ->large(), - Button::success(trans('texts.save')) - ->submit()->large() - ->appendIcon(Icon::create('floppy-disk')) - ->withAttributes(['class' => 'save-button']) + Auth::user()->hasFeature(FEATURE_CUSTOMIZE_INVOICE_DESIGN) ? + Button::success(trans('texts.save')) + ->submit()->large() + ->appendIcon(Icon::create('floppy-disk')) + ->withAttributes(['class' => 'save-button']) : + false ) !!}
    - @if (!Auth::user()->hasFeature(FEATURE_CUSTOMIZE_INVOICE_DESIGN)) - - @endif - {!! Former::close() !!} diff --git a/resources/views/accounts/localization.blade.php b/resources/views/accounts/localization.blade.php index b921c87105..1aa0722dcf 100644 --- a/resources/views/accounts/localization.blade.php +++ b/resources/views/accounts/localization.blade.php @@ -1,6 +1,6 @@ @extends('header') -@section('content') +@section('content') @parent {!! Former::open_for_files()->addClass('warn-on-exit') !!} @@ -11,7 +11,7 @@ @include('accounts.nav', ['selected' => ACCOUNT_LOCALIZATION])
    - +
    @@ -21,15 +21,17 @@
    {!! Former::select('currency_id')->addOption('','') - ->fromQuery($currencies, 'name', 'id') !!} + ->fromQuery($currencies, 'name', 'id') !!} {!! Former::select('language_id')->addOption('','') - ->fromQuery($languages, 'name', 'id') !!} + ->fromQuery($languages, 'name', 'id') !!} {!! Former::select('timezone_id')->addOption('','') ->fromQuery($timezones, 'location', 'id') !!} {!! Former::select('date_format_id')->addOption('','') - ->fromQuery($dateFormats, 'label', 'id') !!} + ->fromQuery($dateFormats) !!} {!! Former::select('datetime_format_id')->addOption('','') - ->fromQuery($datetimeFormats, 'label', 'id') !!} + ->fromQuery($datetimeFormats) !!} + {!! Former::select('start_of_week')->addOption('','') + ->fromQuery($weekdays) !!} {!! Former::checkbox('military_time')->text(trans('texts.enable')) !!} {{-- Former::checkbox('show_currency_code')->text(trans('texts.enable')) --}} @@ -48,4 +50,4 @@ @section('onReady') $('#currency_id').focus(); -@stop \ No newline at end of file +@stop diff --git a/resources/views/accounts/management.blade.php b/resources/views/accounts/management.blade.php index da3b42a8b1..1e9a25b5fe 100644 --- a/resources/views/accounts/management.blade.php +++ b/resources/views/accounts/management.blade.php @@ -24,6 +24,9 @@ @elseif ($planDetails['expires']) ({{ trans('texts.plan_term_'.$planDetails['term'].'ly') }}) @endif + @if ($planDetails['plan'] == PLAN_ENTERPRISE) + {{ trans('texts.min_to_max_users', ['min' => Utils::getMinNumUsers($planDetails['num_users']), 'max' => $planDetails['num_users']])}} + @endif @elseif(Utils::isNinjaProd()) {{ trans('texts.plan_free') }} @else @@ -116,27 +119,40 @@
    @@ -197,30 +213,48 @@ $('form.cancel-account').submit(); } + function onPlanChange() { + if ($('#plan').val() == '{{ PLAN_ENTERPRISE }}') { + $('#numUsersDiv').show(); + } else { + $('#numUsersDiv').hide(); + } + } + @if ($account->company->pending_plan) - function cancelPendingChange(){ - $('#plan').val('{{ $planDetails['plan'] }}') - $('#plan_term').val('{{ $planDetails['term'] }}') - confirmChangePlan(); - return false; - } + function cancelPendingChange(){ + $('#plan').val('{{ $planDetails['plan'] }}') + $('#plan_term').val('{{ $planDetails['term'] }}') + confirmChangePlan(); + return false; + } @endif jQuery(document).ready(function($){ function updatePlanModal() { var plan = $('#plan').val(); + var numUsers = $('#num_users').val(); $('#plan_term').closest('.form-group').toggle(plan!='free'); if(plan=='{{PLAN_PRO}}'){ $('#plan_term option[value=month]').text({!! json_encode(trans('texts.plan_price_monthly', ['price'=>PLAN_PRICE_PRO_MONTHLY])) !!}); - $('#plan_term option[value=year]').text({!! json_encode(trans('texts.plan_price_yearly', ['price'=>PLAN_PRICE_PRO_YEARLY])) !!}); + $('#plan_term option[value=year]').text({!! json_encode(trans('texts.plan_price_yearly', ['price'=>PLAN_PRICE_PRO_MONTHLY * 10])) !!}); } else if(plan=='{{PLAN_ENTERPRISE}}') { - $('#plan_term option[value=month]').text({!! json_encode(trans('texts.plan_price_monthly', ['price'=>PLAN_PRICE_ENTERPRISE_MONTHLY])) !!}); - $('#plan_term option[value=year]').text({!! json_encode(trans('texts.plan_price_yearly', ['price'=>PLAN_PRICE_ENTERPRISE_YEARLY])) !!}); + if (numUsers == 2) { + $('#plan_term option[value=month]').text({!! json_encode(trans('texts.plan_price_monthly', ['price'=>PLAN_PRICE_ENTERPRISE_MONTHLY_2])) !!}); + $('#plan_term option[value=year]').text({!! json_encode(trans('texts.plan_price_yearly', ['price'=>PLAN_PRICE_ENTERPRISE_MONTHLY_2 * 10])) !!}); + } else if (numUsers == 5) { + $('#plan_term option[value=month]').text({!! json_encode(trans('texts.plan_price_monthly', ['price'=>PLAN_PRICE_ENTERPRISE_MONTHLY_5])) !!}); + $('#plan_term option[value=year]').text({!! json_encode(trans('texts.plan_price_yearly', ['price'=>PLAN_PRICE_ENTERPRISE_MONTHLY_5 * 10])) !!}); + } else { + $('#plan_term option[value=month]').text({!! json_encode(trans('texts.plan_price_monthly', ['price'=>PLAN_PRICE_ENTERPRISE_MONTHLY_10])) !!}); + $('#plan_term option[value=year]').text({!! json_encode(trans('texts.plan_price_yearly', ['price'=>PLAN_PRICE_ENTERPRISE_MONTHLY_10 * 10])) !!}); + } } } - $('#plan_term, #plan').change(updatePlanModal); + $('#plan_term, #plan, #num_users').change(updatePlanModal); updatePlanModal(); + onPlanChange(); if(window.location.hash) { var hash = window.location.hash; @@ -230,6 +264,6 @@ @if (Request::input('upgrade')) showChangePlan(); @endif - }); + }); @stop diff --git a/resources/views/accounts/nav.blade.php b/resources/views/accounts/nav.blade.php index ae7f38c2fa..d7250a8c3f 100644 --- a/resources/views/accounts/nav.blade.php +++ b/resources/views/accounts/nav.blade.php @@ -1,7 +1,7 @@ @if (!Utils::isPro() && isset($advanced) && $advanced)
    - {!! trans('texts.pro_plan_advanced_settings', ['link'=>''.trans('texts.pro_plan.remove_logo_link').'']) !!} + {!! trans('texts.pro_plan_advanced_settings', ['link'=>link_to('/settings/account_management?upgrade=true', trans('texts.pro_plan_remove_logo_link'))]) !!}
    @endif @@ -22,11 +22,11 @@
    @foreach ($settings as $section) - {{ trans("texts.{$section}") }} @endforeach @if ($type === ADVANCED_SETTINGS && !Utils::isNinjaProd()) - {{ trans("texts.system_settings") }} @endif
    @@ -34,4 +34,4 @@ @endforeach
    -
    \ No newline at end of file +
    diff --git a/resources/views/accounts/partials/payment_credentials.blade.php b/resources/views/accounts/partials/payment_credentials.blade.php new file mode 100644 index 0000000000..b2e641f4e0 --- /dev/null +++ b/resources/views/accounts/partials/payment_credentials.blade.php @@ -0,0 +1,47 @@ +{!! Former::populateField(GATEWAY_STRIPE . '_apiKey', env('STRIPE_TEST_SECRET_KEY')) !!} +{!! Former::populateField('publishable_key', env('STRIPE_TEST_PUBLISHABLE_KEY')) !!} +{!! Former::populateField('enable_ach', 1) !!} +{!! Former::populateField('plaid_client_id', env('PLAID_TEST_CLIENT_ID')) !!} +{!! Former::populateField('plaid_secret', env('PLAID_TEST_SECRET')) !!} +{!! Former::populateField('plaid_public_key', env('PLAID_TEST_PUBLIC_KEY')) !!} + +{!! Former::populateField(GATEWAY_PAYPAL_EXPRESS . '_username', env('PAYPAL_TEST_USERNAME')) !!} +{!! Former::populateField(GATEWAY_PAYPAL_EXPRESS . '_password', env('PAYPAL_TEST_PASSWORD')) !!} +{!! Former::populateField(GATEWAY_PAYPAL_EXPRESS . '_signature', env('PAYPAL_TEST_SIGNATURE')) !!} +{!! Former::populateField(GATEWAY_PAYPAL_EXPRESS . '_testMode', 1) !!} + +{!! Former::populateField(GATEWAY_DWOLLA . '_destinationId', env('DWOLLA_TEST_DESTINATION_ID')) !!} + +{!! Former::populateField(GATEWAY_BITPAY . '_testMode', 1) !!} +{!! Former::populateField(GATEWAY_BITPAY . '_apiKey', env('BITPAY_TEST_API_KEY')) !!} + +{!! Former::populateField(GATEWAY_TWO_CHECKOUT . '_secretWord', env('TWO_CHECKOUT_SECRET_WORD')) !!} +{!! Former::populateField(GATEWAY_TWO_CHECKOUT . '_accountNumber', env('TWO_CHECKOUT_ACCOUNT_NUMBER')) !!} +{!! Former::populateField(GATEWAY_TWO_CHECKOUT . '_testMode', 1) !!} + +{!! Former::populateField(GATEWAY_MOLLIE . '_apiKey', env('MOLLIE_TEST_API_KEY')) !!} + +{!! Former::populateField(GATEWAY_AUTHORIZE_NET . '_apiLoginId', env('AUTHORIZE_NET_TEST_API_LOGIN_ID')) !!} +{!! Former::populateField(GATEWAY_AUTHORIZE_NET . '_transactionKey', env('AUTHORIZE_NET_TEST_TRANSACTION_KEY')) !!} +{!! Former::populateField(GATEWAY_AUTHORIZE_NET . '_secretKey', env('AUTHORIZE_NET_TEST_SECRET_KEY')) !!} +{!! Former::populateField(GATEWAY_AUTHORIZE_NET . '_testMode', 1) !!} +{!! Former::populateField(GATEWAY_AUTHORIZE_NET . '_developerMode', 1) !!} + +{!! Former::populateField(GATEWAY_CHECKOUT_COM . '_publicApiKey', env('CHECKOUT_COM_TEST_PUBLIC_API_KEY')) !!} +{!! Former::populateField(GATEWAY_CHECKOUT_COM . '_secretApiKey', env('CHECKOUT_COM_TEST_SECRET_API_KEY')) !!} +{!! Former::populateField(GATEWAY_CHECKOUT_COM . '_testMode', 1) !!} + +{!! Former::populateField(GATEWAY_CYBERSOURCE . '_accessKey', env('CYBERSOURCE_TEST_ACCESS_KEY')) !!} +{!! Former::populateField(GATEWAY_CYBERSOURCE . '_secretKey', env('CYBERSOURCE_TEST_SECRET_KEY')) !!} +{!! Former::populateField(GATEWAY_CYBERSOURCE . '_profileId', env('CYBERSOURCE_TEST_PROFILE_ID')) !!} +{!! Former::populateField(GATEWAY_CYBERSOURCE . '_testMode', 1) !!} + +{!! Former::populateField(GATEWAY_EWAY . '_apiKey', env('EWAY_TEST_API_KEY')) !!} +{!! Former::populateField(GATEWAY_EWAY . '_password', env('EWAY_TEST_PASSWORD')) !!} +{!! Former::populateField(GATEWAY_EWAY . '_testMode', 1) !!} + +{!! Former::populateField(GATEWAY_BRAINTREE . '_privateKey', env('BRAINTREE_TEST_PRIVATE_KEY')) !!} +{!! Former::populateField(GATEWAY_BRAINTREE . '_publicKey', env('BRAINTREE_TEST_PUBLIC_KEY')) !!} +{!! Former::populateField(GATEWAY_BRAINTREE . '_merchantId', env('BRAINTREE_TEST_MERCHANT_ID')) !!} +{!! Former::populateField(GATEWAY_BRAINTREE . '_testMode', 1) !!} +{!! Former::populateField('enable_paypal', 1) !!} diff --git a/resources/views/accounts/payments.blade.php b/resources/views/accounts/payments.blade.php index d2fcde8952..5bb401c274 100644 --- a/resources/views/accounts/payments.blade.php +++ b/resources/views/accounts/payments.blade.php @@ -1,9 +1,43 @@ @extends('header') -@section('content') - @parent +@section('content') + @parent @include('accounts.nav', ['selected' => ACCOUNT_PAYMENTS]) + {!! Former::open()->addClass('warn-on-exit') !!} + {!! Former::populateField('token_billing_type_id', $account->token_billing_type_id) !!} + {!! Former::populateField('auto_bill_on_due_date', $account->auto_bill_on_due_date) !!} + + +
    +
    +

    {!! trans('texts.payment_settings') !!}

    +
    +
    + {!! Former::select('token_billing_type_id') + ->options($tokenBillingOptions) + ->help(trans('texts.token_billing_help')) !!} + {!! Former::inline_radios('auto_bill_on_due_date') + ->label(trans('texts.auto_bill')) + ->radios([ + trans('texts.on_send_date') => ['value'=>0, 'name'=>'auto_bill_on_due_date'], + trans('texts.on_due_date') => ['value'=>1, 'name'=>'auto_bill_on_due_date'], + ])->help(trans('texts.auto_bill_ach_date_help')) !!} +
    +

    {!! trans('texts.payment_settings_supported_gateways') !!}

    +
    + {!! Former::actions( Button::success(trans('texts.save'))->submit()->appendIcon(Icon::create('floppy-disk')) ) !!} +
    +
    + {!! Former::close() !!} + + + @if ($showAdd) {!! Button::primary(trans('texts.add_gateway')) ->asLinkTo(URL::to('/gateways/create')) @@ -16,18 +50,25 @@ {!! Datatable::table() ->addColumn( trans('texts.name'), - trans('texts.payment_type_id'), trans('texts.action')) ->setUrl(url('api/gateways/')) ->setOptions('sPaginationType', 'bootstrap') ->setOptions('bFilter', false) ->setOptions('bAutoWidth', false) - ->setOptions('aoColumns', [[ "sWidth"=> "50%" ], [ "sWidth"=> "30%" ], ["sWidth"=> "20%"]]) - ->setOptions('aoColumnDefs', [['bSortable'=>false, 'aTargets'=>[2]]]) + ->setOptions('aoColumns', [[ "sWidth"=> "80%" ], ["sWidth"=> "20%"]]) + ->setOptions('aoColumnDefs', [['bSortable'=>false, 'aTargets'=>[1]]]) ->render('datatable') !!} -@stop \ No newline at end of file +@stop diff --git a/resources/views/accounts/tax_rates.blade.php b/resources/views/accounts/tax_rates.blade.php index 2079d72f21..1a482dff8c 100644 --- a/resources/views/accounts/tax_rates.blade.php +++ b/resources/views/accounts/tax_rates.blade.php @@ -1,6 +1,6 @@ @extends('header') -@section('content') +@section('content') @parent @include('accounts.nav', ['selected' => ACCOUNT_TAX_RATES]) @@ -10,12 +10,13 @@ {{ Former::populateField('invoice_taxes', intval($account->invoice_taxes)) }} {{ Former::populateField('invoice_item_taxes', intval($account->invoice_item_taxes)) }} {{ Former::populateField('show_item_taxes', intval($account->show_item_taxes)) }} + {{ Former::populateField('enable_second_tax_rate', intval($account->enable_second_tax_rate)) }}

    {!! trans('texts.tax_settings') !!}

    -
    +
    {!! Former::checkbox('invoice_taxes') @@ -30,6 +31,10 @@ ->text(trans('texts.show_line_item_tax')) ->label(' ') !!} + {!! Former::checkbox('enable_second_tax_rate') + ->text(trans('texts.enable_second_tax_rate')) + ->label(' ') !!} +   {!! Former::select('default_tax_rate_id') @@ -51,22 +56,22 @@ @include('partials.bulk_form', ['entityType' => ENTITY_TAX_RATE]) - {!! Datatable::table() + {!! Datatable::table() ->addColumn( trans('texts.name'), trans('texts.rate'), trans('texts.action')) - ->setUrl(url('api/tax_rates/')) + ->setUrl(url('api/tax_rates/')) ->setOptions('sPaginationType', 'bootstrap') - ->setOptions('bFilter', false) - ->setOptions('bAutoWidth', false) + ->setOptions('bFilter', false) + ->setOptions('bAutoWidth', false) ->setOptions('aoColumns', [[ "sWidth"=> "40%" ], [ "sWidth"=> "40%" ], ["sWidth"=> "20%"]]) ->setOptions('aoColumnDefs', [['bSortable'=>false, 'aTargets'=>[2]]]) ->render('datatable') !!} + -@stop \ No newline at end of file +@stop diff --git a/resources/views/accounts/templates_and_reminders.blade.php b/resources/views/accounts/templates_and_reminders.blade.php index 87453e80da..a54d23440b 100644 --- a/resources/views/accounts/templates_and_reminders.blade.php +++ b/resources/views/accounts/templates_and_reminders.blade.php @@ -132,10 +132,10 @@
  • $customInvoice1
  • @endif @if (count($account->account_gateways) > 1) - @foreach (\App\Models\Gateway::$paymentTypes as $type) + @foreach (\App\Models\Gateway::$gatewayTypes as $type) @if ($account->getGatewayByType($type)) -
  • ${{ \App\Models\Gateway::getPaymentTypeName($type) }}Link
  • -
  • ${{ \App\Models\Gateway::getPaymentTypeName($type) }}Button
  • +
  • ${{ Utils::toCamelCase($type) }}Link
  • +
  • ${{ Utils::toCamelCase($type) }}Button
  • @endif @endforeach @endif @@ -180,7 +180,7 @@ var previewName = '#' + entityType + '_' + stringType + '_preview'; $(previewName).html(processVariables(value)); } - } + } } function serverPreview(field) { @@ -189,14 +189,14 @@ var template = $('#email_template_' + field).val(); var url = '{{ URL::to('settings/email_preview') }}?template=' + template; $('#server-preview').attr('src', url).load(function() { - // disable links in the preview + // disable links in the preview $('iframe').contents().find('a').each(function(index) { $(this).on('click', function(event) { event.preventDefault(); event.stopPropagation(); }); }); - }); + }); } $(function() { @@ -219,7 +219,7 @@ refreshPreview(); }); - function enableReminder(id) { + function enableReminder(id) { var checked = $('#enable_reminder' + id).is(':checked'); $('.enable-reminder' + id).attr('disabled', !checked) } @@ -242,30 +242,33 @@ var keys = {!! json_encode(\App\Ninja\Mailers\ContactMailer::$variableFields) !!}; var passwordHtml = "{!! $account->isPro() && $account->enable_portal_password && $account->send_portal_password?'

    '.trans('texts.password').': 6h2NWNdw6

    ':'' !!}"; - + @if ($account->isPro()) var documentsHtml = "{!! trans('texts.email_documents_header').'

    ' !!}"; @else var documentsHtml = ""; @endif - + var vals = [ - {!! json_encode($emailFooter) !!}, - "{{ $account->getDisplayName() }}", + {!! json_encode($emailFooter) !!}, + "{{ $account->getDisplayName() }}", "{{ $account->formatDate($account->getDateTime()) }}", "{{ $account->formatDate($account->getDateTime()) }}", - "Client Name", - formatMoney(100), - "Contact Name", + "Client Name", + formatMoney(100), + "Contact Name", "First Name", - "0001", + "0001", "0001", passwordHtml, documentsHtml, - "{{ URL::to('/view/...') }}$password", + "{{ URL::to('/view/...') }}$password", '{!! Form::flatButton('view_invoice', '#0b4d78') !!}$password', - "{{ URL::to('/payment/...') }}$password", + "{{ URL::to('/payment/...') }}$password", '{!! Form::flatButton('pay_now', '#36c157') !!}$password', + '{{ trans('texts.auto_bill_notification_placeholder') }}', + "{{ URL::to('/client/portal/...') }}", + '{!! Form::flatButton('view_portal', '#36c157') !!}', ]; // Add blanks for custom values @@ -273,21 +276,21 @@ vals.push('custom value', 'custom value', 'custom value', 'custom value'); // Add any available payment method links - @foreach (\App\Models\Gateway::$paymentTypes as $type) - {!! "keys.push('" . \App\Models\Gateway::getPaymentTypeName($type).'Link' . "');" !!} + @foreach (\App\Models\Gateway::$gatewayTypes as $type) + {!! "keys.push('" . Utils::toCamelCase($type).'Link' . "');" !!} {!! "vals.push('" . URL::to('/payment/...') . "');" !!} - {!! "keys.push('" . \App\Models\Gateway::getPaymentTypeName($type).'Button' . "');" !!} + {!! "keys.push('" . Utils::toCamelCase($type).'Button' . "');" !!} {!! "vals.push('" . Form::flatButton('pay_now', '#36c157') . "');" !!} @endforeach var includesPasswordPlaceholder = str.indexOf('$password') != -1; - + for (var i=0; i ACCOUNT_USER_MANAGEMENT, 'advanced' => true]) @if (Utils::hasFeature(FEATURE_USERS)) -
    - {!! Button::primary(trans('texts.add_user'))->asLinkTo(URL::to('/users/create'))->appendIcon(Icon::create('plus-sign')) !!} -
    + @if (Auth::user()->caddAddUsers()) +
    + {!! Button::primary(trans('texts.add_user'))->asLinkTo(URL::to('/users/create'))->appendIcon(Icon::create('plus-sign')) !!} +
    + @endif @elseif (Utils::isTrial()) -
    {!! trans('texts.add_users_not_supported') !!}
    +
    {!! trans('texts.add_users_not_supported') !!}
    @endif