mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Merge remote-tracking branch 'upstream/v5-develop' into v5-2701-dynamic-dates-for-recurring
This commit is contained in:
commit
8e3875da96
11
.github/workflows/phpunit.yml
vendored
11
.github/workflows/phpunit.yml
vendored
@ -39,7 +39,7 @@ jobs:
|
|||||||
mariadb:
|
mariadb:
|
||||||
image: mariadb:latest
|
image: mariadb:latest
|
||||||
ports:
|
ports:
|
||||||
- 3306
|
- 32768:3306
|
||||||
env:
|
env:
|
||||||
MYSQL_ALLOW_EMPTY_PASSWORD: yes
|
MYSQL_ALLOW_EMPTY_PASSWORD: yes
|
||||||
MYSQL_USER: ninja
|
MYSQL_USER: ninja
|
||||||
@ -52,7 +52,6 @@ jobs:
|
|||||||
- name: Start mysql service
|
- name: Start mysql service
|
||||||
run: |
|
run: |
|
||||||
sudo /etc/init.d/mysql start
|
sudo /etc/init.d/mysql start
|
||||||
|
|
||||||
- name: Verify MariaDB connection
|
- name: Verify MariaDB connection
|
||||||
env:
|
env:
|
||||||
DB_PORT: ${{ job.services.mariadb.ports[3306] }}
|
DB_PORT: ${{ job.services.mariadb.ports[3306] }}
|
||||||
@ -62,7 +61,6 @@ jobs:
|
|||||||
while ! mysqladmin ping -h"127.0.0.1" -P"$DB_PORT" --silent; do
|
while ! mysqladmin ping -h"127.0.0.1" -P"$DB_PORT" --silent; do
|
||||||
sleep 1
|
sleep 1
|
||||||
done
|
done
|
||||||
|
|
||||||
- name: Setup PHP
|
- name: Setup PHP
|
||||||
uses: shivammathur/setup-php@v2
|
uses: shivammathur/setup-php@v2
|
||||||
with:
|
with:
|
||||||
@ -77,33 +75,27 @@ jobs:
|
|||||||
- name: Copy .env
|
- name: Copy .env
|
||||||
run: |
|
run: |
|
||||||
cp .env.ci .env
|
cp .env.ci .env
|
||||||
|
|
||||||
- name: Install composer dependencies
|
- name: Install composer dependencies
|
||||||
run: |
|
run: |
|
||||||
composer config -g github-oauth.github.com ${{ secrets.GITHUB_TOKEN }}
|
composer config -g github-oauth.github.com ${{ secrets.GITHUB_TOKEN }}
|
||||||
composer install
|
composer install
|
||||||
|
|
||||||
- name: Prepare Laravel Application
|
- name: Prepare Laravel Application
|
||||||
run: |
|
run: |
|
||||||
php artisan key:generate
|
php artisan key:generate
|
||||||
php artisan optimize
|
php artisan optimize
|
||||||
php artisan cache:clear
|
php artisan cache:clear
|
||||||
php artisan config:cache
|
php artisan config:cache
|
||||||
|
|
||||||
- name: Create DB and schemas
|
- name: Create DB and schemas
|
||||||
run: |
|
run: |
|
||||||
mkdir -p database
|
mkdir -p database
|
||||||
touch database/database.sqlite
|
touch database/database.sqlite
|
||||||
|
|
||||||
- name: Migrate Database
|
- name: Migrate Database
|
||||||
run: |
|
run: |
|
||||||
php artisan migrate:fresh --seed --force && php artisan db:seed --force
|
php artisan migrate:fresh --seed --force && php artisan db:seed --force
|
||||||
|
|
||||||
- name: Prepare JS/CSS assets
|
- name: Prepare JS/CSS assets
|
||||||
run: |
|
run: |
|
||||||
npm i
|
npm i
|
||||||
npm run production
|
npm run production
|
||||||
|
|
||||||
- name: Run Testsuite
|
- name: Run Testsuite
|
||||||
run: |
|
run: |
|
||||||
cat .env
|
cat .env
|
||||||
@ -114,4 +106,3 @@ jobs:
|
|||||||
- name: Run php-cs-fixer
|
- name: Run php-cs-fixer
|
||||||
run: |
|
run: |
|
||||||
vendor/bin/php-cs-fixer fix
|
vendor/bin/php-cs-fixer fix
|
||||||
|
|
||||||
|
19
README.md
19
README.md
@ -4,12 +4,18 @@
|
|||||||
|
|
||||||

|

|
||||||

|

|
||||||
[](https://codecov.io/gh/invoiceninja/invoiceninja)
|
|
||||||
[](https://www.codacy.com/app/turbo124/invoiceninja?utm_source=github.com&utm_medium=referral&utm_content=invoiceninja/invoiceninja&utm_campaign=Badge_Grade)
|
[](https://www.codacy.com/app/turbo124/invoiceninja?utm_source=github.com&utm_medium=referral&utm_content=invoiceninja/invoiceninja&utm_campaign=Badge_Grade)
|
||||||
|
|
||||||
# Invoice Ninja version 5 is in Beta!
|
# Invoice Ninja version 5.1 RC2!
|
||||||
|
|
||||||
We will be using the lessons learnt in Invoice Ninja 4.0 to build a bigger better platform to work from. If you would like to contribute to the project we will gladly accept contributions for code, user guides, bug tracking and feedback! Please consider the following guidelines prior to submitting a pull request:
|
Invoice Ninja version 5.1 has now reached Release Candidate 2!
|
||||||
|
|
||||||
|
What does this mean exactly? We consider this version _almost_ stable. There may be some remaining small issues which we would love to get feedback on. We would really appreciate the community booting up this version and attempting the migration from their Invoice Ninja V4 application and inspect the migrated data.
|
||||||
|
|
||||||
|
We'd also like feedback on any issues that you can see, and help us nail down the few remaining issues before Version 5 graduates to Stable Gold Release.
|
||||||
|
|
||||||
|
Please note we do not consider this version ready for production use, please stick with your V4 installation for your production clients!
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
@ -17,13 +23,10 @@ Currently the client portal and API are of alpha quality, to get started:
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/invoiceninja/invoiceninja.git
|
git clone https://github.com/invoiceninja/invoiceninja.git
|
||||||
git checkout v2
|
git checkout v5-stable
|
||||||
cp .env.example .env
|
cp .env.example .env
|
||||||
cp .env.dusk.example .env.dusk.local
|
|
||||||
php artisan key:generate
|
php artisan key:generate
|
||||||
composer update
|
composer update
|
||||||
npm i
|
|
||||||
npm run production
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Please Note: Your APP_KEY in the .env file is used to encrypt data, if you lose this you will not be able to run the application.
|
Please Note: Your APP_KEY in the .env file is used to encrypt data, if you lose this you will not be able to run the application.
|
||||||
@ -33,7 +36,7 @@ Run if you want to load sample data, remember to configure .env
|
|||||||
php artisan migrate:fresh --seed && php artisan db:seed && php artisan ninja:create-test-data
|
php artisan migrate:fresh --seed && php artisan db:seed && php artisan ninja:create-test-data
|
||||||
```
|
```
|
||||||
|
|
||||||
To Run the web server
|
To run the web server
|
||||||
```
|
```
|
||||||
php artisan serve
|
php artisan serve
|
||||||
```
|
```
|
||||||
|
@ -1 +1 @@
|
|||||||
5.0.54
|
5.1.7
|
@ -73,6 +73,7 @@ class CheckData extends Command
|
|||||||
protected $description = 'Check/fix data';
|
protected $description = 'Check/fix data';
|
||||||
|
|
||||||
protected $log = '';
|
protected $log = '';
|
||||||
|
|
||||||
protected $isValid = true;
|
protected $isValid = true;
|
||||||
|
|
||||||
public function handle()
|
public function handle()
|
||||||
@ -90,13 +91,10 @@ class CheckData extends Command
|
|||||||
$this->checkContacts();
|
$this->checkContacts();
|
||||||
$this->checkCompanyData();
|
$this->checkCompanyData();
|
||||||
|
|
||||||
//$this->checkLogoFiles();
|
|
||||||
|
|
||||||
if (! $this->option('client_id')) {
|
if (! $this->option('client_id')) {
|
||||||
$this->checkOAuth();
|
$this->checkOAuth();
|
||||||
//$this->checkInvitations();
|
//$this->checkFailedJobs();
|
||||||
|
|
||||||
$this->checkFailedJobs();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->logMessage('Done: '.strtoupper($this->isValid ? Account::RESULT_SUCCESS : Account::RESULT_FAILURE));
|
$this->logMessage('Done: '.strtoupper($this->isValid ? Account::RESULT_SUCCESS : Account::RESULT_FAILURE));
|
||||||
@ -289,30 +287,6 @@ class CheckData extends Command
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function checkInvoiceBalances()
|
|
||||||
{
|
|
||||||
$wrong_balances = 0;
|
|
||||||
$wrong_paid_to_dates = 0;
|
|
||||||
|
|
||||||
foreach (Client::where('is_deleted', 0)->cursor() as $client) {
|
|
||||||
$invoice_balance = $client->invoices->where('is_deleted', false)->where('status_id', '>', 1)->sum('balance');
|
|
||||||
$credit_balance = $client->credits->where('is_deleted', false)->sum('balance');
|
|
||||||
|
|
||||||
// $invoice_balance -= $credit_balance;//doesn't make sense to remove the credit amount
|
|
||||||
|
|
||||||
$ledger = CompanyLedger::where('client_id', $client->id)->orderBy('id', 'DESC')->first();
|
|
||||||
|
|
||||||
if ($ledger && number_format($invoice_balance, 4) != number_format($client->balance, 4)) {
|
|
||||||
$wrong_balances++;
|
|
||||||
$this->logMessage("# {$client->id} " . $client->present()->name.' - '.$client->number." - Balance Failure - Invoice Balances = {$invoice_balance} Client Balance = {$client->balance} Ledger Balance = {$ledger->balance}");
|
|
||||||
|
|
||||||
$this->isValid = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->logMessage("{$wrong_balances} clients with incorrect balances");
|
|
||||||
}
|
|
||||||
|
|
||||||
private function checkPaidToDates()
|
private function checkPaidToDates()
|
||||||
{
|
{
|
||||||
$wrong_paid_to_dates = 0;
|
$wrong_paid_to_dates = 0;
|
||||||
@ -322,8 +296,6 @@ class CheckData extends Command
|
|||||||
$total_invoice_payments = 0;
|
$total_invoice_payments = 0;
|
||||||
|
|
||||||
foreach ($client->invoices->where('is_deleted', false)->where('status_id', '>', 1) as $invoice) {
|
foreach ($client->invoices->where('is_deleted', false)->where('status_id', '>', 1) as $invoice) {
|
||||||
// $total_amount = $invoice->payments->whereNull('deleted_at')->sum('pivot.amount');
|
|
||||||
// $total_refund = $invoice->payments->whereNull('deleted_at')->sum('pivot.refunded');
|
|
||||||
|
|
||||||
$total_amount = $invoice->payments->where('is_deleted', false)->whereIn('status_id', [Payment::STATUS_COMPLETED, Payment:: STATUS_PENDING, Payment::STATUS_PARTIALLY_REFUNDED, Payment::STATUS_REFUNDED])->sum('pivot.amount');
|
$total_amount = $invoice->payments->where('is_deleted', false)->whereIn('status_id', [Payment::STATUS_COMPLETED, Payment:: STATUS_PENDING, Payment::STATUS_PARTIALLY_REFUNDED, Payment::STATUS_REFUNDED])->sum('pivot.amount');
|
||||||
$total_refund = $invoice->payments->where('is_deleted', false)->whereIn('status_id', [Payment::STATUS_COMPLETED, Payment:: STATUS_PENDING, Payment::STATUS_PARTIALLY_REFUNDED, Payment::STATUS_REFUNDED])->sum('pivot.refunded');
|
$total_refund = $invoice->payments->where('is_deleted', false)->whereIn('status_id', [Payment::STATUS_COMPLETED, Payment:: STATUS_PENDING, Payment::STATUS_PARTIALLY_REFUNDED, Payment::STATUS_REFUNDED])->sum('pivot.refunded');
|
||||||
@ -331,15 +303,15 @@ class CheckData extends Command
|
|||||||
$total_invoice_payments += ($total_amount - $total_refund);
|
$total_invoice_payments += ($total_amount - $total_refund);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 10/02/21
|
||||||
foreach ($client->payments as $payment) {
|
foreach ($client->payments as $payment) {
|
||||||
$credit_total_applied += $payment->paymentables->where('paymentable_type', App\Models\Credit::class)->sum(DB::raw('amount'));
|
$credit_total_applied += $payment->paymentables->where('paymentable_type', App\Models\Credit::class)->sum(DB::raw('amount'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($credit_total_applied < 0) {
|
if ($credit_total_applied < 0) {
|
||||||
$total_invoice_payments += $credit_total_applied;
|
$total_invoice_payments += $credit_total_applied;
|
||||||
} //todo this is contentious
|
}
|
||||||
|
|
||||||
nlog("total invoice payments = {$total_invoice_payments} with client paid to date of of {$client->paid_to_date}");
|
|
||||||
|
|
||||||
if (round($total_invoice_payments, 2) != round($client->paid_to_date, 2)) {
|
if (round($total_invoice_payments, 2) != round($client->paid_to_date, 2)) {
|
||||||
$wrong_paid_to_dates++;
|
$wrong_paid_to_dates++;
|
||||||
@ -390,7 +362,9 @@ class CheckData extends Command
|
|||||||
$invoice_balance = Invoice::where('client_id', $client->id)->where('is_deleted', false)->where('status_id', '>', 1)->withTrashed()->sum('balance');
|
$invoice_balance = Invoice::where('client_id', $client->id)->where('is_deleted', false)->where('status_id', '>', 1)->withTrashed()->sum('balance');
|
||||||
$credit_balance = Credit::where('client_id', $client->id)->where('is_deleted', false)->withTrashed()->sum('balance');
|
$credit_balance = Credit::where('client_id', $client->id)->where('is_deleted', false)->withTrashed()->sum('balance');
|
||||||
|
|
||||||
// $invoice_balance -= $credit_balance;
|
/*Legacy - V4 will add credits to the balance - we may need to reverse engineer this and remove the credits from the client balance otherwise we need this hack here and in the invoice balance check.*/
|
||||||
|
if($client->balance != $invoice_balance)
|
||||||
|
$invoice_balance -= $credit_balance;
|
||||||
|
|
||||||
$ledger = CompanyLedger::where('client_id', $client->id)->orderBy('id', 'DESC')->first();
|
$ledger = CompanyLedger::where('client_id', $client->id)->orderBy('id', 'DESC')->first();
|
||||||
|
|
||||||
@ -405,6 +379,32 @@ class CheckData extends Command
|
|||||||
$this->logMessage("{$wrong_paid_to_dates} clients with incorrect client balances");
|
$this->logMessage("{$wrong_paid_to_dates} clients with incorrect client balances");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function checkInvoiceBalances()
|
||||||
|
{
|
||||||
|
$wrong_balances = 0;
|
||||||
|
$wrong_paid_to_dates = 0;
|
||||||
|
|
||||||
|
foreach (Client::where('is_deleted', 0)->cursor() as $client) {
|
||||||
|
$invoice_balance = $client->invoices->where('is_deleted', false)->where('status_id', '>', 1)->sum('balance');
|
||||||
|
$credit_balance = $client->credits->where('is_deleted', false)->sum('balance');
|
||||||
|
|
||||||
|
// if($client->balance != $invoice_balance)
|
||||||
|
// $invoice_balance -= $credit_balance;//doesn't make sense to remove the credit amount
|
||||||
|
|
||||||
|
$ledger = CompanyLedger::where('client_id', $client->id)->orderBy('id', 'DESC')->first();
|
||||||
|
|
||||||
|
if ($ledger && number_format($invoice_balance, 4) != number_format($client->balance, 4)) {
|
||||||
|
$wrong_balances++;
|
||||||
|
$this->logMessage("# {$client->id} " . $client->present()->name.' - '.$client->number." - Balance Failure - Invoice Balances = {$invoice_balance} Client Balance = {$client->balance} Ledger Balance = {$ledger->balance}");
|
||||||
|
|
||||||
|
$this->isValid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->logMessage("{$wrong_balances} clients with incorrect balances");
|
||||||
|
}
|
||||||
|
|
||||||
private function checkLogoFiles()
|
private function checkLogoFiles()
|
||||||
{
|
{
|
||||||
// $accounts = DB::table('accounts')
|
// $accounts = DB::table('accounts')
|
||||||
|
@ -120,7 +120,7 @@ class CreateSingleAccount extends Command
|
|||||||
$company_token->company_id = $company->id;
|
$company_token->company_id = $company->id;
|
||||||
$company_token->account_id = $account->id;
|
$company_token->account_id = $account->id;
|
||||||
$company_token->name = 'test token';
|
$company_token->name = 'test token';
|
||||||
$company_token->token = Str::random(64);
|
$company_token->token = 'company-token-test';
|
||||||
$company_token->is_system = true;
|
$company_token->is_system = true;
|
||||||
|
|
||||||
$company_token->save();
|
$company_token->save();
|
||||||
|
@ -339,7 +339,7 @@ class DemoMode extends Command
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
$vendor->id_number = $this->getNextVendorNumber($vendor);
|
$vendor->number = $this->getNextVendorNumber($vendor);
|
||||||
$vendor->save();
|
$vendor->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Libraries\MultiDB;
|
||||||
use App\Models\Design;
|
use App\Models\Design;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use stdClass;
|
use stdClass;
|
||||||
@ -47,6 +48,30 @@ class DesignUpdate extends Command
|
|||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
|
{
|
||||||
|
//always return state to first DB
|
||||||
|
|
||||||
|
$current_db = config('database.default');
|
||||||
|
|
||||||
|
if (! config('ninja.db.multi_db_enabled')) {
|
||||||
|
$this->handleOnDb();
|
||||||
|
} else {
|
||||||
|
|
||||||
|
//multiDB environment, need to
|
||||||
|
foreach (MultiDB::$dbs as $db) {
|
||||||
|
MultiDB::setDB($db);
|
||||||
|
|
||||||
|
$this->handleOnDb($db);
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiDB::setDB($current_db);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function handleOnDb()
|
||||||
{
|
{
|
||||||
foreach (Design::whereIsCustom(false)->get() as $design) {
|
foreach (Design::whereIsCustom(false)->get() as $design) {
|
||||||
$invoice_design = new \App\Services\PdfMaker\Design(strtolower($design->name));
|
$invoice_design = new \App\Services\PdfMaker\Design(strtolower($design->name));
|
||||||
|
@ -80,6 +80,8 @@ class ImportMigrations extends Command
|
|||||||
|
|
||||||
$path = $this->option('path') ?? public_path('storage/migrations/import');
|
$path = $this->option('path') ?? public_path('storage/migrations/import');
|
||||||
|
|
||||||
|
nlog(public_path('storage/migrations/import'));
|
||||||
|
|
||||||
$directory = new DirectoryIterator($path);
|
$directory = new DirectoryIterator($path);
|
||||||
|
|
||||||
foreach ($directory as $file) {
|
foreach ($directory as $file) {
|
||||||
|
66
app/Console/Commands/ParallelCheckData.php
Normal file
66
app/Console/Commands/ParallelCheckData.php
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App;
|
||||||
|
use App\Jobs\Ninja\CheckCompanyData;
|
||||||
|
use App\Models\Account;
|
||||||
|
use App\Models\Client;
|
||||||
|
use App\Models\ClientContact;
|
||||||
|
use App\Models\Company;
|
||||||
|
use App\Models\CompanyLedger;
|
||||||
|
use App\Models\Contact;
|
||||||
|
use App\Models\Credit;
|
||||||
|
use App\Models\Invoice;
|
||||||
|
use App\Models\InvoiceInvitation;
|
||||||
|
use App\Models\Payment;
|
||||||
|
use App\Utils\Ninja;
|
||||||
|
use DB;
|
||||||
|
use Exception;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use Mail;
|
||||||
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class CheckData.
|
||||||
|
*/
|
||||||
|
class ParallelCheckData extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $name = 'ninja:pcheck-data';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Check company data in parallel';
|
||||||
|
|
||||||
|
protected $log = '';
|
||||||
|
|
||||||
|
protected $isValid = true;
|
||||||
|
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
|
||||||
|
$hash = Str::random(32);
|
||||||
|
|
||||||
|
Company::cursor()->each(function ($company) use ($hash){
|
||||||
|
|
||||||
|
CheckCompanyData::dispatch($company, $hash)->onQueue('checkdata');
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -53,6 +53,7 @@ class PostUpdate extends Command
|
|||||||
nlog("finished migrating");
|
nlog("finished migrating");
|
||||||
|
|
||||||
exec('vendor/bin/composer install --no-dev');
|
exec('vendor/bin/composer install --no-dev');
|
||||||
|
exec('vendor/bin/composer dump');
|
||||||
|
|
||||||
nlog("finished running composer install ");
|
nlog("finished running composer install ");
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ namespace App\Console\Commands;
|
|||||||
|
|
||||||
use App\Jobs\Ninja\SendReminders;
|
use App\Jobs\Ninja\SendReminders;
|
||||||
use App\Jobs\Util\WebHookHandler;
|
use App\Jobs\Util\WebHookHandler;
|
||||||
|
use App\Libraries\MultiDB;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
use App\Models\Quote;
|
use App\Models\Quote;
|
||||||
use App\Models\Webhook;
|
use App\Models\Webhook;
|
||||||
@ -58,6 +59,24 @@ class SendRemindersCron extends Command
|
|||||||
}
|
}
|
||||||
|
|
||||||
private function webHookOverdueInvoices()
|
private function webHookOverdueInvoices()
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
if (! config('ninja.db.multi_db_enabled')) {
|
||||||
|
$this->executeWebhooks();
|
||||||
|
} else {
|
||||||
|
//multiDB environment, need to
|
||||||
|
foreach (MultiDB::$dbs as $db) {
|
||||||
|
MultiDB::setDB($db);
|
||||||
|
|
||||||
|
$this->executeWebhooks();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function executeWebhooks()
|
||||||
{
|
{
|
||||||
$invoices = Invoice::where('is_deleted', 0)
|
$invoices = Invoice::where('is_deleted', 0)
|
||||||
->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL])
|
->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL])
|
||||||
@ -68,10 +87,7 @@ class SendRemindersCron extends Command
|
|||||||
$invoices->each(function ($invoice) {
|
$invoices->each(function ($invoice) {
|
||||||
WebHookHandler::dispatch(Webhook::EVENT_LATE_INVOICE, $invoice, $invoice->company);
|
WebHookHandler::dispatch(Webhook::EVENT_LATE_INVOICE, $invoice, $invoice->company);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
private function webHookExpiredQuotes()
|
|
||||||
{
|
|
||||||
$quotes = Quote::where('is_deleted', 0)
|
$quotes = Quote::where('is_deleted', 0)
|
||||||
->where('status_id', Quote::STATUS_SENT)
|
->where('status_id', Quote::STATUS_SENT)
|
||||||
->whereDate('due_date', '<=', now()->subDays(1)->startOfDay())
|
->whereDate('due_date', '<=', now()->subDays(1)->startOfDay())
|
||||||
@ -81,4 +97,6 @@ class SendRemindersCron extends Command
|
|||||||
WebHookHandler::dispatch(Webhook::EVENT_EXPIRED_QUOTE, $quote, $quote->company);
|
WebHookHandler::dispatch(Webhook::EVENT_EXPIRED_QUOTE, $quote, $quote->company);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -148,6 +148,7 @@ class CompanySettings extends BaseSettings
|
|||||||
public $gmail_sending_user_id = '0'; //@implemented
|
public $gmail_sending_user_id = '0'; //@implemented
|
||||||
|
|
||||||
public $reply_to_email = ''; //@TODO
|
public $reply_to_email = ''; //@TODO
|
||||||
|
public $reply_to_name = ''; //@TODO
|
||||||
public $bcc_email = ''; //@TODO
|
public $bcc_email = ''; //@TODO
|
||||||
public $pdf_email_attachment = false; //@implemented
|
public $pdf_email_attachment = false; //@implemented
|
||||||
public $ubl_email_attachment = false; //@implemented
|
public $ubl_email_attachment = false; //@implemented
|
||||||
@ -232,11 +233,11 @@ class CompanySettings extends BaseSettings
|
|||||||
public $id_number = ''; //@implemented
|
public $id_number = ''; //@implemented
|
||||||
|
|
||||||
public $page_size = 'A4'; //Letter, Legal, Tabloid, Ledger, A0, A1, A2, A3, A4, A5, A6
|
public $page_size = 'A4'; //Letter, Legal, Tabloid, Ledger, A0, A1, A2, A3, A4, A5, A6
|
||||||
public $font_size = 9; //@implemented
|
public $font_size = 7; //@implemented
|
||||||
public $primary_font = 'Roboto';
|
public $primary_font = 'Roboto';
|
||||||
public $secondary_font = 'Roboto';
|
public $secondary_font = 'Roboto';
|
||||||
public $primary_color = '#4caf50';
|
public $primary_color = '#142cb5';
|
||||||
public $secondary_color = '#2196f3';
|
public $secondary_color = '#7081e0';
|
||||||
|
|
||||||
public $hide_paid_to_date = false; //@TODO where?
|
public $hide_paid_to_date = false; //@TODO where?
|
||||||
public $embed_documents = false; //@TODO where?
|
public $embed_documents = false; //@TODO where?
|
||||||
@ -261,6 +262,7 @@ class CompanySettings extends BaseSettings
|
|||||||
public $hide_empty_columns_on_pdf = false;
|
public $hide_empty_columns_on_pdf = false;
|
||||||
|
|
||||||
public static $casts = [
|
public static $casts = [
|
||||||
|
'reply_to_name' => 'string',
|
||||||
'hide_empty_columns_on_pdf' => 'bool',
|
'hide_empty_columns_on_pdf' => 'bool',
|
||||||
'enable_reminder_endless' => 'bool',
|
'enable_reminder_endless' => 'bool',
|
||||||
'use_credits_payment' => 'string',
|
'use_credits_payment' => 'string',
|
||||||
|
@ -224,8 +224,7 @@ class EmailTemplateDefaults
|
|||||||
private static function transformText($string)
|
private static function transformText($string)
|
||||||
{
|
{
|
||||||
//preformat the string, removing trailing colons.
|
//preformat the string, removing trailing colons.
|
||||||
$string = rtrim($string, ":");
|
|
||||||
|
|
||||||
return str_replace(':', '$', ctrans('texts.'.$string));
|
return str_replace(':', '$', rtrim( ctrans('texts.'.$string), ":"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,10 +39,10 @@ class PaymentWasEmailedAndFailed
|
|||||||
* PaymentWasEmailedAndFailed constructor.
|
* PaymentWasEmailedAndFailed constructor.
|
||||||
* @param Payment $payment
|
* @param Payment $payment
|
||||||
* @param $company
|
* @param $company
|
||||||
* @param array $errors
|
* @param string $errors
|
||||||
* @param array $event_vars
|
* @param array $event_vars
|
||||||
*/
|
*/
|
||||||
public function __construct(Payment $payment, Company $company, array $errors, array $event_vars)
|
public function __construct(Payment $payment, Company $company, string $errors, array $event_vars)
|
||||||
{
|
{
|
||||||
$this->payment = $payment;
|
$this->payment = $payment;
|
||||||
|
|
||||||
|
@ -99,17 +99,21 @@ class Handler extends ExceptionHandler
|
|||||||
|
|
||||||
private function validException($exception)
|
private function validException($exception)
|
||||||
{
|
{
|
||||||
if (strpos($exception->getMessage(), 'file_put_contents') !== false) {
|
if (strpos($exception->getMessage(), 'file_put_contents') !== false)
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
if (strpos($exception->getMessage(), 'Permission denied') !== false) {
|
if (strpos($exception->getMessage(), 'Permission denied') !== false)
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
if (strpos($exception->getMessage(), 'flock()') !== false) {
|
if (strpos($exception->getMessage(), 'flock()') !== false)
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
if (strpos($exception->getMessage(), 'expects parameter 1 to be resource') !== false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (strpos($exception->getMessage(), 'fwrite()') !== false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -35,10 +35,10 @@ function nlog($output, $context = []): void
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!function_exists('ray')) {
|
// if (!function_exists('ray')) {
|
||||||
function ray($payload)
|
// function ray($payload)
|
||||||
{
|
// {
|
||||||
return true;
|
// return true;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
@ -27,7 +27,8 @@ trait CustomValuer
|
|||||||
|
|
||||||
public function valuerTax($custom_value, $has_custom_invoice_taxes)
|
public function valuerTax($custom_value, $has_custom_invoice_taxes)
|
||||||
{
|
{
|
||||||
if (isset($custom_value) && is_numeric($custom_value) && $has_custom_invoice_taxes === true) {
|
|
||||||
|
if (isset($custom_value) && is_numeric($custom_value) && $has_custom_invoice_taxes) {
|
||||||
return round($custom_value * ($this->invoice->tax_rate1 / 100), 2) + round($custom_value * ($this->invoice->tax_rate2 / 100), 2) + round($custom_value * ($this->invoice->tax_rate3 / 100), 2);
|
return round($custom_value * ($this->invoice->tax_rate1 / 100), 2) + round($custom_value * ($this->invoice->tax_rate2 / 100), 2) + round($custom_value * ($this->invoice->tax_rate3 / 100), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,25 +122,23 @@ class InvoiceItemSum
|
|||||||
|
|
||||||
$item_tax += $item_tax_rate1_total;
|
$item_tax += $item_tax_rate1_total;
|
||||||
|
|
||||||
if ($item_tax_rate1_total > 0) {
|
if($item_tax_rate1_total != 0)
|
||||||
$this->groupTax($this->item->tax_name1, $this->item->tax_rate1, $item_tax_rate1_total);
|
$this->groupTax($this->item->tax_name1, $this->item->tax_rate1, $item_tax_rate1_total);
|
||||||
}
|
|
||||||
|
|
||||||
$item_tax_rate2_total = $this->calcAmountLineTax($this->item->tax_rate2, $amount);
|
$item_tax_rate2_total = $this->calcAmountLineTax($this->item->tax_rate2, $amount);
|
||||||
|
|
||||||
$item_tax += $item_tax_rate2_total;
|
$item_tax += $item_tax_rate2_total;
|
||||||
|
|
||||||
if ($item_tax_rate2_total > 0) {
|
if($item_tax_rate2_total != 0)
|
||||||
$this->groupTax($this->item->tax_name2, $this->item->tax_rate2, $item_tax_rate2_total);
|
$this->groupTax($this->item->tax_name2, $this->item->tax_rate2, $item_tax_rate2_total);
|
||||||
}
|
|
||||||
|
|
||||||
$item_tax_rate3_total = $this->calcAmountLineTax($this->item->tax_rate3, $amount);
|
$item_tax_rate3_total = $this->calcAmountLineTax($this->item->tax_rate3, $amount);
|
||||||
|
|
||||||
$item_tax += $item_tax_rate3_total;
|
$item_tax += $item_tax_rate3_total;
|
||||||
|
|
||||||
if ($item_tax_rate3_total > 0) {
|
if($item_tax_rate3_total != 0)
|
||||||
$this->groupTax($this->item->tax_name3, $this->item->tax_rate3, $item_tax_rate3_total);
|
$this->groupTax($this->item->tax_name3, $this->item->tax_rate3, $item_tax_rate3_total);
|
||||||
}
|
|
||||||
|
|
||||||
$this->setTotalTaxes($this->formatValue($item_tax, $this->currency->precision));
|
$this->setTotalTaxes($this->formatValue($item_tax, $this->currency->precision));
|
||||||
|
|
||||||
@ -240,7 +238,7 @@ class InvoiceItemSum
|
|||||||
|
|
||||||
$item_tax += $item_tax_rate1_total;
|
$item_tax += $item_tax_rate1_total;
|
||||||
|
|
||||||
if ($item_tax_rate1_total > 0) {
|
if ($item_tax_rate1_total != 0) {
|
||||||
$this->groupTax($this->item->tax_name1, $this->item->tax_rate1, $item_tax_rate1_total);
|
$this->groupTax($this->item->tax_name1, $this->item->tax_rate1, $item_tax_rate1_total);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,7 +246,7 @@ class InvoiceItemSum
|
|||||||
|
|
||||||
$item_tax += $item_tax_rate2_total;
|
$item_tax += $item_tax_rate2_total;
|
||||||
|
|
||||||
if ($item_tax_rate2_total > 0) {
|
if ($item_tax_rate2_total != 0) {
|
||||||
$this->groupTax($this->item->tax_name2, $this->item->tax_rate2, $item_tax_rate2_total);
|
$this->groupTax($this->item->tax_name2, $this->item->tax_rate2, $item_tax_rate2_total);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,7 +254,7 @@ class InvoiceItemSum
|
|||||||
|
|
||||||
$item_tax += $item_tax_rate3_total;
|
$item_tax += $item_tax_rate3_total;
|
||||||
|
|
||||||
if ($item_tax_rate3_total > 0) {
|
if ($item_tax_rate3_total != 0) {
|
||||||
$this->groupTax($this->item->tax_name3, $this->item->tax_rate3, $item_tax_rate3_total);
|
$this->groupTax($this->item->tax_name3, $this->item->tax_rate3, $item_tax_rate3_total);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -119,25 +119,23 @@ class InvoiceItemSumInclusive
|
|||||||
|
|
||||||
$item_tax += $this->formatValue($item_tax_rate1_total, $this->currency->precision);
|
$item_tax += $this->formatValue($item_tax_rate1_total, $this->currency->precision);
|
||||||
|
|
||||||
if ($item_tax_rate1_total > 0) {
|
if($item_tax_rate1_total != 0)
|
||||||
$this->groupTax($this->item->tax_name1, $this->item->tax_rate1, $item_tax_rate1_total);
|
$this->groupTax($this->item->tax_name1, $this->item->tax_rate1, $item_tax_rate1_total);
|
||||||
}
|
|
||||||
|
|
||||||
$item_tax_rate2_total = $this->calcInclusiveLineTax($this->item->tax_rate2, $amount);
|
$item_tax_rate2_total = $this->calcInclusiveLineTax($this->item->tax_rate2, $amount);
|
||||||
|
|
||||||
$item_tax += $this->formatValue($item_tax_rate2_total, $this->currency->precision);
|
$item_tax += $this->formatValue($item_tax_rate2_total, $this->currency->precision);
|
||||||
|
|
||||||
if ($item_tax_rate2_total > 0) {
|
if($item_tax_rate2_total != 0)
|
||||||
$this->groupTax($this->item->tax_name2, $this->item->tax_rate2, $item_tax_rate2_total);
|
$this->groupTax($this->item->tax_name2, $this->item->tax_rate2, $item_tax_rate2_total);
|
||||||
}
|
|
||||||
|
|
||||||
$item_tax_rate3_total = $this->calcInclusiveLineTax($this->item->tax_rate3, $amount);
|
$item_tax_rate3_total = $this->calcInclusiveLineTax($this->item->tax_rate3, $amount);
|
||||||
|
|
||||||
$item_tax += $this->formatValue($item_tax_rate3_total, $this->currency->precision);
|
$item_tax += $this->formatValue($item_tax_rate3_total, $this->currency->precision);
|
||||||
|
|
||||||
if ($item_tax_rate3_total > 0) {
|
if($item_tax_rate3_total != 0)
|
||||||
$this->groupTax($this->item->tax_name3, $this->item->tax_rate3, $item_tax_rate3_total);
|
$this->groupTax($this->item->tax_name3, $this->item->tax_rate3, $item_tax_rate3_total);
|
||||||
}
|
|
||||||
|
|
||||||
$this->setTotalTaxes($this->formatValue($item_tax, $this->currency->precision));
|
$this->setTotalTaxes($this->formatValue($item_tax, $this->currency->precision));
|
||||||
|
|
||||||
@ -225,12 +223,17 @@ class InvoiceItemSumInclusive
|
|||||||
$item_tax = 0;
|
$item_tax = 0;
|
||||||
|
|
||||||
foreach ($this->line_items as $this->item) {
|
foreach ($this->line_items as $this->item) {
|
||||||
|
|
||||||
|
if($this->sub_total == 0)
|
||||||
|
$amount = $this->item->line_total;
|
||||||
|
else
|
||||||
$amount = $this->item->line_total - ($this->item->line_total * ($this->invoice->discount / $this->sub_total));
|
$amount = $this->item->line_total - ($this->item->line_total * ($this->invoice->discount / $this->sub_total));
|
||||||
|
|
||||||
$item_tax_rate1_total = $this->calcInclusiveLineTax($this->item->tax_rate1, $amount);
|
$item_tax_rate1_total = $this->calcInclusiveLineTax($this->item->tax_rate1, $amount);
|
||||||
|
|
||||||
$item_tax += $item_tax_rate1_total;
|
$item_tax += $item_tax_rate1_total;
|
||||||
|
|
||||||
if ($item_tax_rate1_total > 0) {
|
if ($item_tax_rate1_total != 0) {
|
||||||
$this->groupTax($this->item->tax_name1, $this->item->tax_rate1, $item_tax_rate1_total);
|
$this->groupTax($this->item->tax_name1, $this->item->tax_rate1, $item_tax_rate1_total);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,7 +241,7 @@ class InvoiceItemSumInclusive
|
|||||||
|
|
||||||
$item_tax += $item_tax_rate2_total;
|
$item_tax += $item_tax_rate2_total;
|
||||||
|
|
||||||
if ($item_tax_rate2_total > 0) {
|
if ($item_tax_rate2_total != 0) {
|
||||||
$this->groupTax($this->item->tax_name2, $this->item->tax_rate2, $item_tax_rate2_total);
|
$this->groupTax($this->item->tax_name2, $this->item->tax_rate2, $item_tax_rate2_total);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,7 +249,7 @@ class InvoiceItemSumInclusive
|
|||||||
|
|
||||||
$item_tax += $item_tax_rate3_total;
|
$item_tax += $item_tax_rate3_total;
|
||||||
|
|
||||||
if ($item_tax_rate3_total > 0) {
|
if ($item_tax_rate3_total != 0) {
|
||||||
$this->groupTax($this->item->tax_name3, $this->item->tax_rate3, $item_tax_rate3_total);
|
$this->groupTax($this->item->tax_name3, $this->item->tax_rate3, $item_tax_rate3_total);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,8 +57,8 @@ class InvoiceSum
|
|||||||
{
|
{
|
||||||
$this->calculateLineItems()
|
$this->calculateLineItems()
|
||||||
->calculateDiscount()
|
->calculateDiscount()
|
||||||
->calculateCustomValues()
|
|
||||||
->calculateInvoiceTaxes()
|
->calculateInvoiceTaxes()
|
||||||
|
->calculateCustomValues()
|
||||||
->setTaxMap()
|
->setTaxMap()
|
||||||
->calculateTotals()
|
->calculateTotals()
|
||||||
->calculateBalance()
|
->calculateBalance()
|
||||||
@ -89,16 +89,17 @@ class InvoiceSum
|
|||||||
|
|
||||||
private function calculateCustomValues()
|
private function calculateCustomValues()
|
||||||
{
|
{
|
||||||
$this->total_taxes += $this->valuerTax($this->invoice->custom_surcharge1, $this->invoice->custom_surcharge_taxes1);
|
|
||||||
|
$this->total_taxes += $this->valuerTax($this->invoice->custom_surcharge1, $this->invoice->custom_surcharge_tax1);
|
||||||
$this->total_custom_values += $this->valuer($this->invoice->custom_surcharge1);
|
$this->total_custom_values += $this->valuer($this->invoice->custom_surcharge1);
|
||||||
|
|
||||||
$this->total_taxes += $this->valuerTax($this->invoice->custom_surcharge2, $this->invoice->custom_surcharge_taxes2);
|
$this->total_taxes += $this->valuerTax($this->invoice->custom_surcharge2, $this->invoice->custom_surcharge_tax2);
|
||||||
$this->total_custom_values += $this->valuer($this->invoice->custom_surcharge2);
|
$this->total_custom_values += $this->valuer($this->invoice->custom_surcharge2);
|
||||||
|
|
||||||
$this->total_taxes += $this->valuerTax($this->invoice->custom_surcharge3, $this->invoice->custom_surcharge_taxes3);
|
$this->total_taxes += $this->valuerTax($this->invoice->custom_surcharge3, $this->invoice->custom_surcharge_tax3);
|
||||||
$this->total_custom_values += $this->valuer($this->invoice->custom_surcharge3);
|
$this->total_custom_values += $this->valuer($this->invoice->custom_surcharge3);
|
||||||
|
|
||||||
$this->total_taxes += $this->valuerTax($this->invoice->custom_surcharge4, $this->invoice->custom_surcharge_taxes4);
|
$this->total_taxes += $this->valuerTax($this->invoice->custom_surcharge4, $this->invoice->custom_surcharge_tax4);
|
||||||
$this->total_custom_values += $this->valuer($this->invoice->custom_surcharge4);
|
$this->total_custom_values += $this->valuer($this->invoice->custom_surcharge4);
|
||||||
|
|
||||||
$this->total += $this->total_custom_values;
|
$this->total += $this->total_custom_values;
|
||||||
@ -108,19 +109,20 @@ class InvoiceSum
|
|||||||
|
|
||||||
private function calculateInvoiceTaxes()
|
private function calculateInvoiceTaxes()
|
||||||
{
|
{
|
||||||
if ($this->invoice->tax_rate1 > 0) {
|
|
||||||
|
if (strlen($this->invoice->tax_name1) > 1) {
|
||||||
$tax = $this->taxer($this->total, $this->invoice->tax_rate1);
|
$tax = $this->taxer($this->total, $this->invoice->tax_rate1);
|
||||||
$this->total_taxes += $tax;
|
$this->total_taxes += $tax;
|
||||||
$this->total_tax_map[] = ['name' => $this->invoice->tax_name1.' '.floatval($this->invoice->tax_rate1).'%', 'total' => $tax];
|
$this->total_tax_map[] = ['name' => $this->invoice->tax_name1.' '.floatval($this->invoice->tax_rate1).'%', 'total' => $tax];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->invoice->tax_rate2 > 0) {
|
if (strlen($this->invoice->tax_name2) > 1) {
|
||||||
$tax = $this->taxer($this->total, $this->invoice->tax_rate2);
|
$tax = $this->taxer($this->total, $this->invoice->tax_rate2);
|
||||||
$this->total_taxes += $tax;
|
$this->total_taxes += $tax;
|
||||||
$this->total_tax_map[] = ['name' => $this->invoice->tax_name2.' '.floatval($this->invoice->tax_rate2).'%', 'total' => $tax];
|
$this->total_tax_map[] = ['name' => $this->invoice->tax_name2.' '.floatval($this->invoice->tax_rate2).'%', 'total' => $tax];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->invoice->tax_rate3 > 0) {
|
if (strlen($this->invoice->tax_name3) > 1) {
|
||||||
$tax = $this->taxer($this->total, $this->invoice->tax_rate3);
|
$tax = $this->taxer($this->total, $this->invoice->tax_rate3);
|
||||||
$this->total_taxes += $tax;
|
$this->total_taxes += $tax;
|
||||||
$this->total_tax_map[] = ['name' => $this->invoice->tax_name3.' '.floatval($this->invoice->tax_rate3).'%', 'total' => $tax];
|
$this->total_tax_map[] = ['name' => $this->invoice->tax_name3.' '.floatval($this->invoice->tax_rate3).'%', 'total' => $tax];
|
||||||
|
@ -89,16 +89,16 @@ class InvoiceSumInclusive
|
|||||||
|
|
||||||
private function calculateCustomValues()
|
private function calculateCustomValues()
|
||||||
{
|
{
|
||||||
$this->total_taxes += $this->valuerTax($this->invoice->custom_surcharge1, $this->invoice->custom_surcharge_taxes1);
|
$this->total_taxes += $this->valuerTax($this->invoice->custom_surcharge1, $this->invoice->custom_surcharge_tax1);
|
||||||
$this->total_custom_values += $this->valuer($this->invoice->custom_surcharge1);
|
$this->total_custom_values += $this->valuer($this->invoice->custom_surcharge1);
|
||||||
|
|
||||||
$this->total_taxes += $this->valuerTax($this->invoice->custom_surcharge2, $this->invoice->custom_surcharge_taxes2);
|
$this->total_taxes += $this->valuerTax($this->invoice->custom_surcharge2, $this->invoice->custom_surcharge_tax2);
|
||||||
$this->total_custom_values += $this->valuer($this->invoice->custom_surcharge2);
|
$this->total_custom_values += $this->valuer($this->invoice->custom_surcharge2);
|
||||||
|
|
||||||
$this->total_taxes += $this->valuerTax($this->invoice->custom_surcharge3, $this->invoice->custom_surcharge_taxes3);
|
$this->total_taxes += $this->valuerTax($this->invoice->custom_surcharge3, $this->invoice->custom_surcharge_tax3);
|
||||||
$this->total_custom_values += $this->valuer($this->invoice->custom_surcharge3);
|
$this->total_custom_values += $this->valuer($this->invoice->custom_surcharge3);
|
||||||
|
|
||||||
$this->total_taxes += $this->valuerTax($this->invoice->custom_surcharge4, $this->invoice->custom_surcharge_taxes4);
|
$this->total_taxes += $this->valuerTax($this->invoice->custom_surcharge4, $this->invoice->custom_surcharge_tax4);
|
||||||
$this->total_custom_values += $this->valuer($this->invoice->custom_surcharge4);
|
$this->total_custom_values += $this->valuer($this->invoice->custom_surcharge4);
|
||||||
|
|
||||||
$this->total += $this->total_custom_values;
|
$this->total += $this->total_custom_values;
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
|
|
||||||
namespace App\Helpers\Mail;
|
namespace App\Helpers\Mail;
|
||||||
|
|
||||||
|
use App\Utils\TempFile;
|
||||||
|
use Dacastro4\LaravelGmail\Facade\LaravelGmail;
|
||||||
use Dacastro4\LaravelGmail\Services\Message\Mail;
|
use Dacastro4\LaravelGmail\Services\Message\Mail;
|
||||||
use Illuminate\Mail\Transport\Transport;
|
use Illuminate\Mail\Transport\Transport;
|
||||||
use Swift_Mime_SimpleMessage;
|
use Swift_Mime_SimpleMessage;
|
||||||
@ -27,49 +29,59 @@ class GmailTransport extends Transport
|
|||||||
*/
|
*/
|
||||||
protected $gmail;
|
protected $gmail;
|
||||||
|
|
||||||
/**
|
|
||||||
* The GMail OAuth Token.
|
|
||||||
* @var string token
|
|
||||||
*/
|
|
||||||
protected $token;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new Gmail transport instance.
|
* Create a new Gmail transport instance.
|
||||||
*
|
*
|
||||||
* @param Mail $gmail
|
* @param Mail $gmail
|
||||||
* @param string $token
|
* @param string $token
|
||||||
*/
|
*/
|
||||||
public function __construct(Mail $gmail, string $token)
|
public function __construct(Mail $gmail)
|
||||||
{
|
{
|
||||||
$this->gmail = $gmail;
|
$this->gmail = $gmail;
|
||||||
$this->token = $token;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null)
|
public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null)
|
||||||
{
|
{
|
||||||
|
/* For some reason the Injected Mail class carries cached tokens, so we need to reinit the Mail class*/
|
||||||
|
$this->gmail = null;
|
||||||
|
$this->gmail = new Mail;
|
||||||
|
|
||||||
/*We should nest the token in the message and then discard it as needed*/
|
/*We should nest the token in the message and then discard it as needed*/
|
||||||
|
$token = $message->getHeaders()->get('GmailToken')->getValue();
|
||||||
|
|
||||||
|
$message->getHeaders()->remove('GmailToken');
|
||||||
|
|
||||||
$this->beforeSendPerformed($message);
|
$this->beforeSendPerformed($message);
|
||||||
|
|
||||||
$this->gmail->using($this->token);
|
$this->gmail->using($token);
|
||||||
$this->gmail->to($message->getTo());
|
$this->gmail->to($message->getTo());
|
||||||
$this->gmail->from($message->getFrom());
|
$this->gmail->from($message->getFrom());
|
||||||
$this->gmail->subject($message->getSubject());
|
$this->gmail->subject($message->getSubject());
|
||||||
$this->gmail->message($message->getBody());
|
$this->gmail->message($message->getBody());
|
||||||
//$this->gmail->message($message->toString());
|
|
||||||
$this->gmail->cc($message->getCc());
|
$this->gmail->cc($message->getCc());
|
||||||
$this->gmail->bcc($message->getBcc());
|
$this->gmail->bcc($message->getBcc());
|
||||||
|
|
||||||
nlog(print_r($message->getChildren(), 1));
|
foreach ($message->getChildren() as $child)
|
||||||
|
{
|
||||||
|
|
||||||
foreach ($message->getChildren() as $child) {
|
nlog("trying to attach");
|
||||||
$this->gmail->attach($child);
|
|
||||||
} //todo this should 'just work'
|
if($child->getContentType() != 'text/plain')
|
||||||
|
{
|
||||||
|
|
||||||
|
$this->gmail->attach(TempFile::filePath($child->getBody(), $child->getHeaders()->get('Content-Type')->getParameter('name') ));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
$this->gmail->send();
|
$this->gmail->send();
|
||||||
|
|
||||||
$this->sendPerformed($message);
|
$this->sendPerformed($message);
|
||||||
|
|
||||||
|
|
||||||
return $this->numberOfRecipients($message);
|
return $this->numberOfRecipients($message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,25 @@
|
|||||||
<?php
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
namespace App\Helpers\Mail;
|
namespace App\Helpers\Mail;
|
||||||
|
|
||||||
|
use Illuminate\Mail\MailManager;
|
||||||
|
use App\CustomMailDriver\CustomTransport;
|
||||||
use Dacastro4\LaravelGmail\Services\Message\Mail;
|
use Dacastro4\LaravelGmail\Services\Message\Mail;
|
||||||
use Illuminate\Mail\TransportManager;
|
use Illuminate\Support\Facades\Config;
|
||||||
|
|
||||||
class GmailTransportManager extends TransportManager
|
|
||||||
{
|
|
||||||
protected function createGmailDriver()
|
|
||||||
{
|
|
||||||
$token = $this->app['config']->get('services.gmail.token', []);
|
|
||||||
$mail = new Mail;
|
|
||||||
|
|
||||||
return new GmailTransport($mail, $token);
|
class GmailTransportManager extends MailManager
|
||||||
|
{
|
||||||
|
protected function createGmailTransport()
|
||||||
|
{
|
||||||
|
return new GmailTransport(new Mail);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -12,8 +12,10 @@
|
|||||||
namespace App\Http\Controllers\Auth;
|
namespace App\Http\Controllers\Auth;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Libraries\MultiDB;
|
||||||
use Illuminate\Contracts\View\Factory;
|
use Illuminate\Contracts\View\Factory;
|
||||||
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
|
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\Password;
|
use Illuminate\Support\Facades\Password;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
@ -65,4 +67,31 @@ class ContactForgotPasswordController extends Controller
|
|||||||
{
|
{
|
||||||
return Password::broker('contacts');
|
return Password::broker('contacts');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function sendResetLinkEmail(Request $request)
|
||||||
|
{
|
||||||
|
//MultiDB::userFindAndSetDb($request->input('email'));
|
||||||
|
|
||||||
|
$user = MultiDB::hasContact(['email' => $request->input('email')]);
|
||||||
|
|
||||||
|
$this->validateEmail($request);
|
||||||
|
|
||||||
|
// We will send the password reset link to this user. Once we have attempted
|
||||||
|
// to send the link, we will examine the response then see the message we
|
||||||
|
// need to show to the user. Finally, we'll send out a proper response.
|
||||||
|
$response = $this->broker()->sendResetLink(
|
||||||
|
$this->credentials($request)
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($request->ajax()) {
|
||||||
|
return $response == Password::RESET_LINK_SENT
|
||||||
|
? response()->json(['message' => 'Reset link sent to your email.', 'status' => true], 201)
|
||||||
|
: response()->json(['message' => 'Email not found', 'status' => false], 401);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $response == Password::RESET_LINK_SENT
|
||||||
|
? $this->sendResetLinkResponse($request, $response)
|
||||||
|
: $this->sendResetLinkFailedResponse($request, $response);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -18,11 +18,13 @@ class ContactRegisterController extends Controller
|
|||||||
$this->middleware(['guest', 'contact.register']);
|
$this->middleware(['guest', 'contact.register']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function showRegisterForm(string $company_key)
|
public function showRegisterForm(string $company_key = '')
|
||||||
{
|
{
|
||||||
$company = Company::where('company_key', $company_key)->firstOrFail();
|
$key = request()->has('key') ? request('key') : $company_key;
|
||||||
|
|
||||||
return render('auth.register', compact(['company']));
|
$company = Company::where('company_key', $key)->firstOrFail();
|
||||||
|
|
||||||
|
return render('auth.register', ['company' => $company]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function register(RegisterRequest $request)
|
public function register(RegisterRequest $request)
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
namespace App\Http\Controllers\Auth;
|
namespace App\Http\Controllers\Auth;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Libraries\MultiDB;
|
||||||
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
|
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Password;
|
use Illuminate\Support\Facades\Password;
|
||||||
@ -103,6 +104,10 @@ class ForgotPasswordController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function sendResetLinkEmail(Request $request)
|
public function sendResetLinkEmail(Request $request)
|
||||||
{
|
{
|
||||||
|
//MultiDB::userFindAndSetDb($request->input('email'));
|
||||||
|
|
||||||
|
$user = MultiDB::hasUser(['email' => $request->input('email')]);
|
||||||
|
|
||||||
$this->validateEmail($request);
|
$this->validateEmail($request);
|
||||||
|
|
||||||
// We will send the password reset link to this user. Once we have attempted
|
// We will send the password reset link to this user. Once we have attempted
|
||||||
|
@ -289,7 +289,7 @@ class LoginController extends BaseController
|
|||||||
$client = new Google_Client();
|
$client = new Google_Client();
|
||||||
$client->setClientId(config('ninja.auth.google.client_id'));
|
$client->setClientId(config('ninja.auth.google.client_id'));
|
||||||
$client->setClientSecret(config('ninja.auth.google.client_secret'));
|
$client->setClientSecret(config('ninja.auth.google.client_secret'));
|
||||||
|
$client->setRedirectUri(config('ninja.app_url'));
|
||||||
$token = $client->authenticate(request()->input('server_auth_code'));
|
$token = $client->authenticate(request()->input('server_auth_code'));
|
||||||
|
|
||||||
$refresh_token = '';
|
$refresh_token = '';
|
||||||
|
@ -184,7 +184,9 @@ class BaseController extends Controller
|
|||||||
|
|
||||||
protected function refreshResponse($query)
|
protected function refreshResponse($query)
|
||||||
{
|
{
|
||||||
if (auth()->user()->getCompany()->is_large)
|
$user = auth()->user();
|
||||||
|
|
||||||
|
if ($user->getCompany()->is_large)
|
||||||
$this->manager->parseIncludes($this->mini_load);
|
$this->manager->parseIncludes($this->mini_load);
|
||||||
else
|
else
|
||||||
$this->manager->parseIncludes($this->first_load);
|
$this->manager->parseIncludes($this->first_load);
|
||||||
@ -200,74 +202,145 @@ class BaseController extends Controller
|
|||||||
$transformer = new $this->entity_transformer($this->serializer);
|
$transformer = new $this->entity_transformer($this->serializer);
|
||||||
$updated_at = request()->has('updated_at') ? request()->input('updated_at') : 0;
|
$updated_at = request()->has('updated_at') ? request()->input('updated_at') : 0;
|
||||||
|
|
||||||
// if (auth()->user()->getCompany()->is_large && ! request()->has('updated_at')) {
|
|
||||||
// return response()->json(['message' => ctrans('texts.large_account_update_parameter'), 'errors' =>[]], 401);
|
|
||||||
// }
|
|
||||||
|
|
||||||
$updated_at = date('Y-m-d H:i:s', $updated_at);
|
$updated_at = date('Y-m-d H:i:s', $updated_at);
|
||||||
|
|
||||||
$query->with(
|
$query->with(
|
||||||
[
|
[
|
||||||
'company' => function ($query) use ($updated_at) {
|
'company' => function ($query) use ($updated_at, $user) {
|
||||||
$query->whereNotNull('updated_at')->with('documents');
|
$query->whereNotNull('updated_at')->with('documents');
|
||||||
},
|
},
|
||||||
'company.clients' => function ($query) use ($updated_at) {
|
'company.clients' => function ($query) use ($updated_at, $user) {
|
||||||
$query->where('clients.updated_at', '>=', $updated_at)->with('contacts.company', 'gateway_tokens', 'documents');
|
$query->where('clients.updated_at', '>=', $updated_at)->with('contacts.company', 'gateway_tokens', 'documents');
|
||||||
|
|
||||||
|
if(!$user->hasPermission('view_client'))
|
||||||
|
$query->where('clients.user_id', $user->id)->orWhere('clients.assigned_user_id', $user->id);
|
||||||
|
|
||||||
},
|
},
|
||||||
'company.company_gateways' => function ($query) {
|
'company.company_gateways' => function ($query) use ($user) {
|
||||||
$query->whereNotNull('updated_at');
|
$query->whereNotNull('updated_at');
|
||||||
|
|
||||||
|
if(!$user->isAdmin())
|
||||||
|
$query->where('company_gateways.user_id', $user->id);
|
||||||
|
|
||||||
},
|
},
|
||||||
'company.credits'=> function ($query) use ($updated_at) {
|
'company.credits'=> function ($query) use ($updated_at, $user) {
|
||||||
$query->where('updated_at', '>=', $updated_at)->with('invitations', 'documents');
|
$query->where('updated_at', '>=', $updated_at)->with('invitations', 'documents');
|
||||||
|
|
||||||
|
if(!$user->hasPermission('view_credit'))
|
||||||
|
$query->where('credits.user_id', $user->id)->orWhere('credits.assigned_user_id', $user->id);
|
||||||
|
|
||||||
},
|
},
|
||||||
'company.designs'=> function ($query) use ($updated_at) {
|
'company.designs'=> function ($query) use ($updated_at, $user) {
|
||||||
$query->where('updated_at', '>=', $updated_at)->with('company');
|
$query->where('updated_at', '>=', $updated_at)->with('company');
|
||||||
|
|
||||||
|
if(!$user->isAdmin())
|
||||||
|
$query->where('designs.user_id', $user->id);
|
||||||
},
|
},
|
||||||
'company.documents'=> function ($query) use ($updated_at) {
|
'company.documents'=> function ($query) use ($updated_at, $user) {
|
||||||
$query->where('updated_at', '>=', $updated_at);
|
$query->where('updated_at', '>=', $updated_at);
|
||||||
},
|
},
|
||||||
'company.expenses'=> function ($query) use ($updated_at) {
|
'company.expenses'=> function ($query) use ($updated_at, $user) {
|
||||||
$query->where('updated_at', '>=', $updated_at)->with('documents');
|
$query->where('updated_at', '>=', $updated_at)->with('documents');
|
||||||
|
|
||||||
|
if(!$user->hasPermission('view_expense'))
|
||||||
|
$query->where('expenses.user_id', $user->id)->orWhere('expenses.assigned_user_id', $user->id);
|
||||||
},
|
},
|
||||||
'company.groups' => function ($query) use ($updated_at) {
|
'company.groups' => function ($query) use ($updated_at, $user) {
|
||||||
$query->where('updated_at', '>=', $updated_at);
|
$query->where('updated_at', '>=', $updated_at);
|
||||||
|
|
||||||
|
if(!$user->isAdmin())
|
||||||
|
$query->where('group_settings.user_id', $user->id);
|
||||||
},
|
},
|
||||||
'company.invoices'=> function ($query) use ($updated_at) {
|
'company.invoices'=> function ($query) use ($updated_at, $user) {
|
||||||
$query->where('updated_at', '>=', $updated_at)->with('invitations', 'documents');
|
$query->where('updated_at', '>=', $updated_at)->with('invitations', 'documents');
|
||||||
|
|
||||||
|
if(!$user->hasPermission('view_invoice'))
|
||||||
|
$query->where('invoices.user_id', $user->id)->orWhere('invoices.assigned_user_id', $user->id);
|
||||||
|
|
||||||
},
|
},
|
||||||
'company.payments'=> function ($query) use ($updated_at) {
|
'company.payments'=> function ($query) use ($updated_at, $user) {
|
||||||
$query->where('updated_at', '>=', $updated_at)->with('paymentables', 'documents');
|
$query->where('updated_at', '>=', $updated_at)->with('paymentables', 'documents');
|
||||||
|
|
||||||
|
if(!$user->hasPermission('view_payment'))
|
||||||
|
$query->where('payments.user_id', $user->id)->orWhere('payments.assigned_user_id', $user->id);
|
||||||
|
|
||||||
},
|
},
|
||||||
'company.payment_terms'=> function ($query) use ($updated_at) {
|
'company.payment_terms'=> function ($query) use ($updated_at, $user) {
|
||||||
$query->where('updated_at', '>=', $updated_at);
|
$query->where('updated_at', '>=', $updated_at);
|
||||||
|
|
||||||
|
if(!$user->isAdmin())
|
||||||
|
$query->where('payment_terms.user_id', $user->id);
|
||||||
|
|
||||||
},
|
},
|
||||||
'company.products' => function ($query) use ($updated_at) {
|
'company.products' => function ($query) use ($updated_at, $user) {
|
||||||
$query->where('updated_at', '>=', $updated_at)->with('documents');
|
$query->where('updated_at', '>=', $updated_at)->with('documents');
|
||||||
|
|
||||||
|
if(!$user->hasPermission('view_product'))
|
||||||
|
$query->where('products.user_id', $user->id)->orWhere('products.assigned_user_id', $user->id);
|
||||||
|
|
||||||
},
|
},
|
||||||
'company.projects'=> function ($query) use ($updated_at) {
|
'company.projects'=> function ($query) use ($updated_at, $user) {
|
||||||
$query->where('updated_at', '>=', $updated_at)->with('documents');
|
$query->where('updated_at', '>=', $updated_at)->with('documents');
|
||||||
|
|
||||||
|
if(!$user->hasPermission('view_project'))
|
||||||
|
$query->where('projects.user_id', $user->id)->orWhere('projects.assigned_user_id', $user->id);
|
||||||
|
|
||||||
},
|
},
|
||||||
'company.quotes'=> function ($query) use ($updated_at) {
|
'company.quotes'=> function ($query) use ($updated_at, $user) {
|
||||||
$query->where('updated_at', '>=', $updated_at)->with('invitations', 'documents');
|
$query->where('updated_at', '>=', $updated_at)->with('invitations', 'documents');
|
||||||
|
|
||||||
|
if(!$user->hasPermission('view_quote'))
|
||||||
|
$query->where('quotes.user_id', $user->id)->orWhere('quotes.assigned_user_id', $user->id);
|
||||||
|
|
||||||
},
|
},
|
||||||
'company.recurring_invoices'=> function ($query) use ($updated_at) {
|
'company.recurring_invoices'=> function ($query) use ($updated_at, $user) {
|
||||||
$query->where('updated_at', '>=', $updated_at)->with('invitations', 'documents');
|
$query->where('updated_at', '>=', $updated_at)->with('invitations', 'documents');
|
||||||
|
|
||||||
|
if(!$user->hasPermission('view_recurring_invoice'))
|
||||||
|
$query->where('recurring_invoices.user_id', $user->id)->orWhere('recurring_invoices.assigned_user_id', $user->id);
|
||||||
|
|
||||||
},
|
},
|
||||||
'company.tasks'=> function ($query) use ($updated_at) {
|
'company.tasks'=> function ($query) use ($updated_at, $user) {
|
||||||
$query->where('updated_at', '>=', $updated_at)->with('documents');
|
$query->where('updated_at', '>=', $updated_at)->with('documents');
|
||||||
|
|
||||||
|
if(!$user->hasPermission('view_task'))
|
||||||
|
$query->where('tasks.user_id', $user->id)->orWhere('tasks.assigned_user_id', $user->id);
|
||||||
|
|
||||||
},
|
},
|
||||||
'company.tax_rates' => function ($query) use ($updated_at) {
|
'company.tax_rates' => function ($query) use ($updated_at, $user) {
|
||||||
$query->where('updated_at', '>=', $updated_at);
|
$query->where('updated_at', '>=', $updated_at);
|
||||||
|
|
||||||
|
if(!$user->isAdmin())
|
||||||
|
$query->where('tax_rates.user_id', $user->id);
|
||||||
|
|
||||||
},
|
},
|
||||||
'company.vendors'=> function ($query) use ($updated_at) {
|
'company.vendors'=> function ($query) use ($updated_at, $user) {
|
||||||
$query->where('updated_at', '>=', $updated_at)->with('contacts', 'documents');
|
$query->where('updated_at', '>=', $updated_at)->with('contacts', 'documents');
|
||||||
|
|
||||||
|
if(!$user->hasPermission('view_vendor'))
|
||||||
|
$query->where('vendors.user_id', $user->id)->orWhere('vendors.assigned_user_id', $user->id);
|
||||||
|
|
||||||
},
|
},
|
||||||
'company.expense_categories'=> function ($query) use ($updated_at) {
|
'company.expense_categories'=> function ($query) use ($updated_at, $user) {
|
||||||
$query->where('updated_at', '>=', $updated_at);
|
$query->where('updated_at', '>=', $updated_at);
|
||||||
|
|
||||||
|
if(!$user->isAdmin())
|
||||||
|
$query->where('expense_categories.user_id', $user->id);
|
||||||
|
|
||||||
},
|
},
|
||||||
'company.task_statuses'=> function ($query) use ($updated_at) {
|
'company.task_statuses'=> function ($query) use ($updated_at, $user) {
|
||||||
$query->where('updated_at', '>=', $updated_at);
|
$query->where('updated_at', '>=', $updated_at);
|
||||||
|
|
||||||
|
if(!$user->isAdmin())
|
||||||
|
$query->where('task_statuses.user_id', $user->id);
|
||||||
|
|
||||||
},
|
},
|
||||||
|
'company.activities'=> function ($query) use($user) {
|
||||||
|
|
||||||
|
if(!$user->isAdmin())
|
||||||
|
$query->where('activities.user_id', $user->id);
|
||||||
|
|
||||||
|
}
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ use App\Http\Requests\Client\EditClientRequest;
|
|||||||
use App\Http\Requests\Client\ShowClientRequest;
|
use App\Http\Requests\Client\ShowClientRequest;
|
||||||
use App\Http\Requests\Client\StoreClientRequest;
|
use App\Http\Requests\Client\StoreClientRequest;
|
||||||
use App\Http\Requests\Client\UpdateClientRequest;
|
use App\Http\Requests\Client\UpdateClientRequest;
|
||||||
|
use App\Http\Requests\Client\UploadClientRequest;
|
||||||
use App\Jobs\Client\StoreClient;
|
use App\Jobs\Client\StoreClient;
|
||||||
use App\Jobs\Client\UpdateClient;
|
use App\Jobs\Client\UpdateClient;
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
@ -29,6 +30,7 @@ use App\Transformers\ClientTransformer;
|
|||||||
use App\Utils\Ninja;
|
use App\Utils\Ninja;
|
||||||
use App\Utils\Traits\BulkOptions;
|
use App\Utils\Traits\BulkOptions;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use App\Utils\Traits\SavesDocuments;
|
||||||
use App\Utils\Traits\Uploadable;
|
use App\Utils\Traits\Uploadable;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
@ -42,6 +44,7 @@ class ClientController extends BaseController
|
|||||||
use MakesHash;
|
use MakesHash;
|
||||||
use Uploadable;
|
use Uploadable;
|
||||||
use BulkOptions;
|
use BulkOptions;
|
||||||
|
use SavesDocuments;
|
||||||
|
|
||||||
protected $entity_type = Client::class;
|
protected $entity_type = Client::class;
|
||||||
|
|
||||||
@ -269,6 +272,7 @@ class ClientController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function update(UpdateClientRequest $request, Client $client)
|
public function update(UpdateClientRequest $request, Client $client)
|
||||||
{
|
{
|
||||||
|
|
||||||
if ($request->entityIsDeleted($client)) {
|
if ($request->entityIsDeleted($client)) {
|
||||||
return $request->disallowUpdate();
|
return $request->disallowUpdate();
|
||||||
}
|
}
|
||||||
@ -515,4 +519,66 @@ class ClientController extends BaseController
|
|||||||
{
|
{
|
||||||
//todo
|
//todo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*
|
||||||
|
* @param UploadClientRequest $request
|
||||||
|
* @param Client $client
|
||||||
|
* @return Response
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @OA\Put(
|
||||||
|
* path="/api/v1/clients/{id}/upload",
|
||||||
|
* operationId="uploadClient",
|
||||||
|
* tags={"clients"},
|
||||||
|
* summary="Uploads a document to a client",
|
||||||
|
* description="Handles the uploading of a document to a client",
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/include"),
|
||||||
|
* @OA\Parameter(
|
||||||
|
* name="id",
|
||||||
|
* in="path",
|
||||||
|
* description="The Client Hashed ID",
|
||||||
|
* example="D2J234DFA",
|
||||||
|
* required=true,
|
||||||
|
* @OA\Schema(
|
||||||
|
* type="string",
|
||||||
|
* format="string",
|
||||||
|
* ),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Returns the client object",
|
||||||
|
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Client"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=422,
|
||||||
|
* description="Validation error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
|
||||||
|
*
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="Unexpected Error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Error"),
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function upload(UploadClientRequest $request, Client $client)
|
||||||
|
{
|
||||||
|
|
||||||
|
if ($request->has('documents'))
|
||||||
|
$this->saveDocuments($request->file('documents'), $client);
|
||||||
|
|
||||||
|
return $this->itemResponse($client->fresh());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -76,10 +76,10 @@ class DocumentController extends Controller
|
|||||||
|
|
||||||
$options->setSendHttpHeaders(true);
|
$options->setSendHttpHeaders(true);
|
||||||
|
|
||||||
$zip = new ZipStream('files.zip', $options);
|
$zip = new ZipStream(now() . '-documents.zip', $options);
|
||||||
|
|
||||||
foreach ($documents as $document) {
|
foreach ($documents as $document) {
|
||||||
$zip->addFileFromPath(basename($document->filePath()), TempFile::path($document->filePath()));
|
$zip->addFileFromPath(basename($document->diskPath()), TempFile::path($document->diskPath()));
|
||||||
}
|
}
|
||||||
|
|
||||||
$zip->finish();
|
$zip->finish();
|
||||||
|
@ -33,6 +33,8 @@ class InvitationController extends Controller
|
|||||||
|
|
||||||
public function router(string $entity, string $invitation_key)
|
public function router(string $entity, string $invitation_key)
|
||||||
{
|
{
|
||||||
|
Auth::logout();
|
||||||
|
|
||||||
return $this->genericRouter($entity, $invitation_key);
|
return $this->genericRouter($entity, $invitation_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,6 +45,7 @@ class InvitationController extends Controller
|
|||||||
|
|
||||||
private function genericRouter(string $entity, string $invitation_key)
|
private function genericRouter(string $entity, string $invitation_key)
|
||||||
{
|
{
|
||||||
|
|
||||||
$key = $entity.'_id';
|
$key = $entity.'_id';
|
||||||
|
|
||||||
$entity_obj = 'App\Models\\'.ucfirst(Str::camel($entity)).'Invitation';
|
$entity_obj = 'App\Models\\'.ucfirst(Str::camel($entity)).'Invitation';
|
||||||
@ -51,17 +54,22 @@ class InvitationController extends Controller
|
|||||||
->with('contact.client')
|
->with('contact.client')
|
||||||
->firstOrFail();
|
->firstOrFail();
|
||||||
|
|
||||||
|
|
||||||
/* Return early if we have the correct client_hash embedded */
|
/* Return early if we have the correct client_hash embedded */
|
||||||
|
|
||||||
if (request()->has('client_hash') && request()->input('client_hash') == $invitation->contact->client->client_hash) {
|
if (request()->has('client_hash') && request()->input('client_hash') == $invitation->contact->client->client_hash) {
|
||||||
auth()->guard('contact')->login($invitation->contact, true);
|
auth()->guard('contact')->login($invitation->contact, true);
|
||||||
|
|
||||||
} elseif ((bool) $invitation->contact->client->getSetting('enable_client_portal_password') !== false) {
|
} elseif ((bool) $invitation->contact->client->getSetting('enable_client_portal_password') !== false) {
|
||||||
|
|
||||||
|
//If no contact password is set - this will cause a 401 error - instead redirect to the client.login route
|
||||||
$this->middleware('auth:contact');
|
$this->middleware('auth:contact');
|
||||||
|
return redirect()->route('client.login');
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
auth()->guard('contact')->login($invitation->contact, true);
|
auth()->guard('contact')->login($invitation->contact, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (auth()->guard('contact') && ! request()->has('silent') && ! $invitation->viewed_date) {
|
if (auth()->guard('contact') && ! request()->has('silent') && ! $invitation->viewed_date) {
|
||||||
$invitation->markViewed();
|
$invitation->markViewed();
|
||||||
|
|
||||||
|
@ -54,11 +54,11 @@ class InvoiceController extends Controller
|
|||||||
'invoice' => $invoice,
|
'invoice' => $invoice,
|
||||||
];
|
];
|
||||||
|
|
||||||
if ($request->query('mode') === 'portal') {
|
if ($request->query('mode') === 'fullscreen') {
|
||||||
return $this->render('invoices.show', $data);
|
return response()->file($invoice->pdf_file_path(null, 'path'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->render('invoices.show.fullscreen', $data);
|
return $this->render('invoices.show', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -90,7 +90,7 @@ class InvoiceController extends Controller
|
|||||||
|
|
||||||
//filter invoices which are payable
|
//filter invoices which are payable
|
||||||
$invoices = $invoices->filter(function ($invoice) {
|
$invoices = $invoices->filter(function ($invoice) {
|
||||||
return $invoice->isPayable() && $invoice->balance > 0;
|
return $invoice->isPayable();
|
||||||
});
|
});
|
||||||
|
|
||||||
//return early if no invoices.
|
//return early if no invoices.
|
||||||
|
@ -106,7 +106,7 @@ class PaymentController extends Controller
|
|||||||
if ($payable_invoices->count() == 0) {
|
if ($payable_invoices->count() == 0) {
|
||||||
return redirect()
|
return redirect()
|
||||||
->route('client.invoices.index')
|
->route('client.invoices.index')
|
||||||
->with(['warning' => 'No payable invoices selected.']);
|
->with(['message' => 'No payable invoices selected.']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$settings = auth()->user()->client->getMergedSettings();
|
$settings = auth()->user()->client->getMergedSettings();
|
||||||
@ -137,33 +137,37 @@ class PaymentController extends Controller
|
|||||||
$payable_invoice['amount'] = Number::roundValue(($invoice->partial > 0 ? $invoice->partial : $invoice->balance), auth()->user()->client->currency()->precision);
|
$payable_invoice['amount'] = Number::roundValue(($invoice->partial > 0 ? $invoice->partial : $invoice->balance), auth()->user()->client->currency()->precision);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we DO allow under payments check the minimum amount is present else return */
|
if (!$settings->client_portal_allow_under_payment && $payable_amount < $invoice_balance) {
|
||||||
|
return redirect()
|
||||||
|
->route('client.invoices.index')
|
||||||
|
->with('message', ctrans('texts.minimum_required_payment', ['amount' => $invoice_balance]));
|
||||||
|
}
|
||||||
|
|
||||||
if ($settings->client_portal_allow_under_payment) {
|
if ($settings->client_portal_allow_under_payment) {
|
||||||
if ($payable_invoice['amount'] < $settings->client_portal_under_payment_minimum) {
|
if ($invoice_balance < $settings->client_portal_under_payment_minimum && $payable_amount < $invoice_balance) {
|
||||||
|
return redirect()
|
||||||
|
->route('client.invoices.index')
|
||||||
|
->with('message', ctrans('texts.minimum_required_payment', ['amount' => $invoice_balance]));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($invoice_balance < $settings->client_portal_under_payment_minimum) {
|
||||||
|
// Skip the under payment rule.
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($invoice_balance >= $settings->client_portal_under_payment_minimum && $payable_amount < $settings->client_portal_under_payment_minimum) {
|
||||||
return redirect()
|
return redirect()
|
||||||
->route('client.invoices.index')
|
->route('client.invoices.index')
|
||||||
->with('message', ctrans('texts.minimum_required_payment', ['amount' => $settings->client_portal_under_payment_minimum]));
|
->with('message', ctrans('texts.minimum_required_payment', ['amount' => $settings->client_portal_under_payment_minimum]));
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
|
|
||||||
/*Double check!!*/
|
|
||||||
if ($payable_amount < $invoice_balance) {
|
|
||||||
return redirect()
|
|
||||||
->route('client.invoices.index')
|
|
||||||
->with('message', ctrans('texts.under_payments_disabled'));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we don't allow over payments and the amount exceeds the balance */
|
/* If we don't allow over payments and the amount exceeds the balance */
|
||||||
|
|
||||||
if (!$settings->client_portal_allow_over_payment) {
|
if (!$settings->client_portal_allow_over_payment && $payable_amount > $invoice_balance) {
|
||||||
if ($payable_amount > $invoice_balance) {
|
|
||||||
return redirect()
|
return redirect()
|
||||||
->route('client.invoices.index')
|
->route('client.invoices.index')
|
||||||
->with('message', ctrans('texts.over_payments_disabled'));
|
->with('message', ctrans('texts.over_payments_disabled'));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ class QuoteController extends Controller
|
|||||||
*
|
*
|
||||||
* @param ShowQuoteRequest $request
|
* @param ShowQuoteRequest $request
|
||||||
* @param Quote $quote
|
* @param Quote $quote
|
||||||
* @return Factory|View
|
* @return Factory|View|\Symfony\Component\HttpFoundation\BinaryFileResponse
|
||||||
*/
|
*/
|
||||||
public function show(ShowQuoteRequest $request, Quote $quote)
|
public function show(ShowQuoteRequest $request, Quote $quote)
|
||||||
{
|
{
|
||||||
@ -43,11 +43,11 @@ class QuoteController extends Controller
|
|||||||
'quote' => $quote,
|
'quote' => $quote,
|
||||||
];
|
];
|
||||||
|
|
||||||
if ($request->query('mode') === 'portal') {
|
if ($request->query('mode') === 'fullscreen') {
|
||||||
return $this->render('quotes.show', $data);
|
return response()->file($quote->pdf_file_path(null, 'path'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->render('quotes.show.fullscreen', $data);
|
return $this->render('quotes.show', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function bulk(ProcessQuotesInBulkRequest $request)
|
public function bulk(ProcessQuotesInBulkRequest $request)
|
||||||
|
@ -13,10 +13,15 @@ namespace App\Http\Controllers\ClientPortal;
|
|||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\ClientPortal\ShowRecurringInvoiceRequest;
|
use App\Http\Requests\ClientPortal\ShowRecurringInvoiceRequest;
|
||||||
|
use App\Jobs\Mail\NinjaMailer;
|
||||||
|
use App\Jobs\Mail\NinjaMailerJob;
|
||||||
|
use App\Jobs\Mail\NinjaMailerObject;
|
||||||
|
use App\Mail\RecurringInvoice\ClientContactRequestCancellationObject;
|
||||||
use App\Models\RecurringInvoice;
|
use App\Models\RecurringInvoice;
|
||||||
use App\Notifications\ClientContactRequestCancellation;
|
use App\Notifications\ClientContactRequestCancellation;
|
||||||
use App\Utils\Traits\MakesDates;
|
use App\Utils\Traits\MakesDates;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use App\Utils\Traits\Notifications\UserNotifies;
|
||||||
use Illuminate\Contracts\View\Factory;
|
use Illuminate\Contracts\View\Factory;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
@ -28,6 +33,7 @@ class RecurringInvoiceController extends Controller
|
|||||||
{
|
{
|
||||||
use MakesHash;
|
use MakesHash;
|
||||||
use MakesDates;
|
use MakesDates;
|
||||||
|
use UserNotifies;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the list of recurring invoices.
|
* Show the list of recurring invoices.
|
||||||
@ -57,7 +63,22 @@ class RecurringInvoiceController extends Controller
|
|||||||
{
|
{
|
||||||
//todo double check the user is able to request a cancellation
|
//todo double check the user is able to request a cancellation
|
||||||
//can add locale specific by chaining ->locale();
|
//can add locale specific by chaining ->locale();
|
||||||
$recurring_invoice->user->notify(new ClientContactRequestCancellation($recurring_invoice, auth()->user()));
|
|
||||||
|
$nmo = new NinjaMailerObject;
|
||||||
|
$nmo->mailable = (new NinjaMailer((new ClientContactRequestCancellationObject($recurring_invoice, auth()->user()))->build()));
|
||||||
|
$nmo->company = $recurring_invoice->company;
|
||||||
|
$nmo->settings = $recurring_invoice->company->settings;
|
||||||
|
|
||||||
|
$notifiable_users = $this->filterUsersByPermissions($recurring_invoice->company->company_users, $recurring_invoice, ['recurring_cancellation']);
|
||||||
|
|
||||||
|
$notifiable_users->each(function ($company_user) use($nmo){
|
||||||
|
|
||||||
|
$nmo->to_user = $company_user->user;
|
||||||
|
NinjaMailerJob::dispatch($nmo);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
//$recurring_invoice->user->notify(new ClientContactRequestCancellation($recurring_invoice, auth()->user()));
|
||||||
|
|
||||||
return $this->render('recurring_invoices.cancellation.index', [
|
return $this->render('recurring_invoices.cancellation.index', [
|
||||||
'invoice' => $recurring_invoice,
|
'invoice' => $recurring_invoice,
|
||||||
|
@ -20,6 +20,7 @@ use App\Http\Requests\Company\EditCompanyRequest;
|
|||||||
use App\Http\Requests\Company\ShowCompanyRequest;
|
use App\Http\Requests\Company\ShowCompanyRequest;
|
||||||
use App\Http\Requests\Company\StoreCompanyRequest;
|
use App\Http\Requests\Company\StoreCompanyRequest;
|
||||||
use App\Http\Requests\Company\UpdateCompanyRequest;
|
use App\Http\Requests\Company\UpdateCompanyRequest;
|
||||||
|
use App\Http\Requests\Company\UploadCompanyRequest;
|
||||||
use App\Jobs\Company\CreateCompany;
|
use App\Jobs\Company\CreateCompany;
|
||||||
use App\Jobs\Company\CreateCompanyPaymentTerms;
|
use App\Jobs\Company\CreateCompanyPaymentTerms;
|
||||||
use App\Jobs\Company\CreateCompanyTaskStatuses;
|
use App\Jobs\Company\CreateCompanyTaskStatuses;
|
||||||
@ -503,4 +504,65 @@ class CompanyController extends BaseController
|
|||||||
|
|
||||||
return response()->json(['message' => ctrans('texts.success')], 200);
|
return response()->json(['message' => ctrans('texts.success')], 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*
|
||||||
|
* @param UploadCompanyRequest $request
|
||||||
|
* @param Company $client
|
||||||
|
* @return Response
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @OA\Put(
|
||||||
|
* path="/api/v1/companies/{id}/upload",
|
||||||
|
* operationId="uploadCompanies",
|
||||||
|
* tags={"companies"},
|
||||||
|
* summary="Uploads a document to a company",
|
||||||
|
* description="Handles the uploading of a document to a company",
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/include"),
|
||||||
|
* @OA\Parameter(
|
||||||
|
* name="id",
|
||||||
|
* in="path",
|
||||||
|
* description="The Company Hashed ID",
|
||||||
|
* example="D2J234DFA",
|
||||||
|
* required=true,
|
||||||
|
* @OA\Schema(
|
||||||
|
* type="string",
|
||||||
|
* format="string",
|
||||||
|
* ),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Returns the client object",
|
||||||
|
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Company"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=422,
|
||||||
|
* description="Validation error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
|
||||||
|
*
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="Unexpected Error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Error"),
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function upload(UploadCompanyRequest $request, Company $company)
|
||||||
|
{
|
||||||
|
|
||||||
|
if ($request->has('documents'))
|
||||||
|
$this->saveDocuments($request->file('documents'), $company);
|
||||||
|
|
||||||
|
return $this->itemResponse($company->fresh());
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
139
app/Http/Controllers/ConnectedAccountController.php
Normal file
139
app/Http/Controllers/ConnectedAccountController.php
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Libraries\MultiDB;
|
||||||
|
use App\Libraries\OAuth\Providers\Google;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class ConnectedAccountController extends BaseController
|
||||||
|
{
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connect an OAuth account to a regular email/password combination account
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @return User Refresh Feed.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @OA\Post(
|
||||||
|
* path="/api/v1/connected_account",
|
||||||
|
* operationId="connected_account",
|
||||||
|
* tags={"connected_account"},
|
||||||
|
* summary="Connect an oauth user to an existing user",
|
||||||
|
* description="Refreshes the dataset",
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/include"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/include_static"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/clear_cache"),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="The Company User response",
|
||||||
|
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/User"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=422,
|
||||||
|
* description="Validation error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="Unexpected Error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Error"),
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
if ($request->input('provider') == 'google') {
|
||||||
|
return $this->handleGoogleOauth();
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()
|
||||||
|
->json(['message' => 'Provider not supported'], 400)
|
||||||
|
->header('X-App-Version', config('ninja.app_version'))
|
||||||
|
->header('X-Api-Version', config('ninja.minimum_client_version'));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function handleGoogleOauth()
|
||||||
|
{
|
||||||
|
$user = false;
|
||||||
|
|
||||||
|
$google = new Google();
|
||||||
|
|
||||||
|
$user = $google->getTokenResponse(request()->input('id_token'));
|
||||||
|
|
||||||
|
if (is_array($user)) {
|
||||||
|
|
||||||
|
$query = [
|
||||||
|
'oauth_user_id' => $google->harvestSubField($user),
|
||||||
|
'oauth_provider_id'=> 'google',
|
||||||
|
];
|
||||||
|
|
||||||
|
/* Cannot allow duplicates! */
|
||||||
|
if ($existing_user = MultiDB::hasUser($query)) {
|
||||||
|
return response()
|
||||||
|
->json(['message' => 'User already exists in system.'], 401)
|
||||||
|
->header('X-App-Version', config('ninja.app_version'))
|
||||||
|
->header('X-Api-Version', config('ninja.minimum_client_version'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($user) {
|
||||||
|
$client = new Google_Client();
|
||||||
|
$client->setClientId(config('ninja.auth.google.client_id'));
|
||||||
|
$client->setClientSecret(config('ninja.auth.google.client_secret'));
|
||||||
|
$client->setRedirectUri(config('ninja.app_url'));
|
||||||
|
$token = $client->authenticate(request()->input('server_auth_code'));
|
||||||
|
|
||||||
|
$refresh_token = '';
|
||||||
|
|
||||||
|
if (array_key_exists('refresh_token', $token)) {
|
||||||
|
$refresh_token = $token['refresh_token'];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$connected_account = [
|
||||||
|
'password' => '',
|
||||||
|
'email' => $google->harvestEmail($user),
|
||||||
|
'oauth_user_id' => $google->harvestSubField($user),
|
||||||
|
'oauth_user_token' => $token,
|
||||||
|
'oauth_user_refresh_token' => $refresh_token,
|
||||||
|
'oauth_provider_id' => 'google',
|
||||||
|
'email_verified_at' =>now()
|
||||||
|
];
|
||||||
|
|
||||||
|
auth()->user()->update($connected_account);
|
||||||
|
auth()->user()->email_verified_at = now();
|
||||||
|
auth()->user()->save();
|
||||||
|
|
||||||
|
//$ct = CompanyUser::whereUserId(auth()->user()->id);
|
||||||
|
|
||||||
|
return $this->listResponse(auth()->user());
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()
|
||||||
|
->json(['message' => ctrans('texts.invalid_credentials')], 401)
|
||||||
|
->header('X-App-Version', config('ninja.app_version'))
|
||||||
|
->header('X-Api-Version', config('ninja.minimum_client_version'));
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
@ -14,6 +23,7 @@ use App\Http\Requests\Credit\EditCreditRequest;
|
|||||||
use App\Http\Requests\Credit\ShowCreditRequest;
|
use App\Http\Requests\Credit\ShowCreditRequest;
|
||||||
use App\Http\Requests\Credit\StoreCreditRequest;
|
use App\Http\Requests\Credit\StoreCreditRequest;
|
||||||
use App\Http\Requests\Credit\UpdateCreditRequest;
|
use App\Http\Requests\Credit\UpdateCreditRequest;
|
||||||
|
use App\Http\Requests\Credit\UploadCreditRequest;
|
||||||
use App\Jobs\Entity\EmailEntity;
|
use App\Jobs\Entity\EmailEntity;
|
||||||
use App\Jobs\Invoice\EmailCredit;
|
use App\Jobs\Invoice\EmailCredit;
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
@ -24,6 +34,7 @@ use App\Transformers\CreditTransformer;
|
|||||||
use App\Utils\Ninja;
|
use App\Utils\Ninja;
|
||||||
use App\Utils\TempFile;
|
use App\Utils\TempFile;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use App\Utils\Traits\SavesDocuments;
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -32,6 +43,7 @@ use Illuminate\Http\Response;
|
|||||||
class CreditController extends BaseController
|
class CreditController extends BaseController
|
||||||
{
|
{
|
||||||
use MakesHash;
|
use MakesHash;
|
||||||
|
use SavesDocuments;
|
||||||
|
|
||||||
protected $entity_type = Credit::class;
|
protected $entity_type = Credit::class;
|
||||||
|
|
||||||
@ -56,7 +68,7 @@ class CreditController extends BaseController
|
|||||||
* @OA\Get(
|
* @OA\Get(
|
||||||
* path="/api/v1/credits",
|
* path="/api/v1/credits",
|
||||||
* operationId="getCredits",
|
* operationId="getCredits",
|
||||||
* tags={"invoices"},
|
* tags={"credits"},
|
||||||
* summary="Gets a list of credits",
|
* summary="Gets a list of credits",
|
||||||
* description="Lists credits, search and filters allow fine grained lists to be generated.
|
* description="Lists credits, search and filters allow fine grained lists to be generated.
|
||||||
*
|
*
|
||||||
@ -576,4 +588,66 @@ class CreditController extends BaseController
|
|||||||
|
|
||||||
return response()->download($file_path);
|
return response()->download($file_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*
|
||||||
|
* @param UploadCreditRequest $request
|
||||||
|
* @param Credit $client
|
||||||
|
* @return Response
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @OA\Put(
|
||||||
|
* path="/api/v1/credits/{id}/upload",
|
||||||
|
* operationId="uploadCredits",
|
||||||
|
* tags={"credits"},
|
||||||
|
* summary="Uploads a document to a credit",
|
||||||
|
* description="Handles the uploading of a document to a credit",
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/include"),
|
||||||
|
* @OA\Parameter(
|
||||||
|
* name="id",
|
||||||
|
* in="path",
|
||||||
|
* description="The Credit Hashed ID",
|
||||||
|
* example="D2J234DFA",
|
||||||
|
* required=true,
|
||||||
|
* @OA\Schema(
|
||||||
|
* type="string",
|
||||||
|
* format="string",
|
||||||
|
* ),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Returns the Credit object",
|
||||||
|
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Credit"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=422,
|
||||||
|
* description="Validation error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
|
||||||
|
*
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="Unexpected Error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Error"),
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function upload(UploadCreditRequest $request, Credit $credit)
|
||||||
|
{
|
||||||
|
|
||||||
|
if ($request->has('documents'))
|
||||||
|
$this->saveDocuments($request->file('documents'), $credit);
|
||||||
|
|
||||||
|
return $this->itemResponse($credit->fresh());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -21,12 +21,14 @@ use App\Http\Requests\Expense\EditExpenseRequest;
|
|||||||
use App\Http\Requests\Expense\ShowExpenseRequest;
|
use App\Http\Requests\Expense\ShowExpenseRequest;
|
||||||
use App\Http\Requests\Expense\StoreExpenseRequest;
|
use App\Http\Requests\Expense\StoreExpenseRequest;
|
||||||
use App\Http\Requests\Expense\UpdateExpenseRequest;
|
use App\Http\Requests\Expense\UpdateExpenseRequest;
|
||||||
|
use App\Http\Requests\Expense\UploadExpenseRequest;
|
||||||
use App\Models\Expense;
|
use App\Models\Expense;
|
||||||
use App\Repositories\ExpenseRepository;
|
use App\Repositories\ExpenseRepository;
|
||||||
use App\Transformers\ExpenseTransformer;
|
use App\Transformers\ExpenseTransformer;
|
||||||
use App\Utils\Ninja;
|
use App\Utils\Ninja;
|
||||||
use App\Utils\Traits\BulkOptions;
|
use App\Utils\Traits\BulkOptions;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use App\Utils\Traits\SavesDocuments;
|
||||||
use App\Utils\Traits\Uploadable;
|
use App\Utils\Traits\Uploadable;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
@ -40,6 +42,7 @@ class ExpenseController extends BaseController
|
|||||||
use MakesHash;
|
use MakesHash;
|
||||||
use Uploadable;
|
use Uploadable;
|
||||||
use BulkOptions;
|
use BulkOptions;
|
||||||
|
use SavesDocuments;
|
||||||
|
|
||||||
protected $entity_type = Expense::class;
|
protected $entity_type = Expense::class;
|
||||||
|
|
||||||
@ -507,4 +510,65 @@ class ExpenseController extends BaseController
|
|||||||
{
|
{
|
||||||
//todo
|
//todo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*
|
||||||
|
* @param UploadExpenseRequest $request
|
||||||
|
* @param Expense $expense
|
||||||
|
* @return Response
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @OA\Put(
|
||||||
|
* path="/api/v1/expenses/{id}/upload",
|
||||||
|
* operationId="uploadExpense",
|
||||||
|
* tags={"expense"},
|
||||||
|
* summary="Uploads a document to a expense",
|
||||||
|
* description="Handles the uploading of a document to a expense",
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/include"),
|
||||||
|
* @OA\Parameter(
|
||||||
|
* name="id",
|
||||||
|
* in="path",
|
||||||
|
* description="The Expense Hashed ID",
|
||||||
|
* example="D2J234DFA",
|
||||||
|
* required=true,
|
||||||
|
* @OA\Schema(
|
||||||
|
* type="string",
|
||||||
|
* format="string",
|
||||||
|
* ),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Returns the Expense object",
|
||||||
|
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Expense"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=422,
|
||||||
|
* description="Validation error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
|
||||||
|
*
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="Unexpected Error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Error"),
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function upload(UploadExpenseRequest $request, Expense $expense)
|
||||||
|
{
|
||||||
|
|
||||||
|
if ($request->has('documents'))
|
||||||
|
$this->saveDocuments($request->file('documents'), $expense);
|
||||||
|
|
||||||
|
return $this->itemResponse($expense->fresh());
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,19 +14,20 @@ namespace App\Http\Controllers;
|
|||||||
use App\Http\Requests\Import\ImportRequest;
|
use App\Http\Requests\Import\ImportRequest;
|
||||||
use App\Http\Requests\Import\PreImportRequest;
|
use App\Http\Requests\Import\PreImportRequest;
|
||||||
use App\Jobs\Import\CSVImport;
|
use App\Jobs\Import\CSVImport;
|
||||||
|
use Illuminate\Http\UploadedFile;
|
||||||
use Illuminate\Support\Facades\Cache;
|
use Illuminate\Support\Facades\Cache;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use League\Csv\Reader;
|
use League\Csv\Reader;
|
||||||
use League\Csv\Statement;
|
use League\Csv\Statement;
|
||||||
|
|
||||||
class ImportController extends Controller
|
class ImportController extends Controller {
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Store a newly created resource in storage.
|
* Store a newly created resource in storage.
|
||||||
*
|
*
|
||||||
* @param StoreImportRequest $request
|
* @param PreImportRequest $request
|
||||||
* @return Response
|
*
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*
|
*
|
||||||
* @OA\Post(
|
* @OA\Post(
|
||||||
* path="/api/v1/preimport",
|
* path="/api/v1/preimport",
|
||||||
@ -69,42 +70,61 @@ class ImportController extends Controller
|
|||||||
* ),
|
* ),
|
||||||
* )
|
* )
|
||||||
*/
|
*/
|
||||||
public function preimport(PreImportRequest $request)
|
public function preimport( PreImportRequest $request ) {
|
||||||
{
|
// Create a reference
|
||||||
//create a reference
|
|
||||||
$hash = Str::random( 32 );
|
$hash = Str::random( 32 );
|
||||||
|
|
||||||
//store the csv in cache with an expiry of 10 minutes
|
|
||||||
Cache::put($hash, base64_encode(file_get_contents($request->file('file')->getPathname())), 3600);
|
|
||||||
|
|
||||||
//parse CSV
|
|
||||||
$csv_array = $this->getCsvData(file_get_contents($request->file('file')->getPathname()));
|
|
||||||
|
|
||||||
$class_map = $this->getEntityMap($request->input('entity_type'));
|
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'hash' => $hash,
|
'hash' => $hash,
|
||||||
'available' => $class_map::importable(),
|
'mappings' => [],
|
||||||
'headers' => array_slice($csv_array, 0, 2)
|
|
||||||
];
|
];
|
||||||
|
/** @var UploadedFile $file */
|
||||||
|
foreach ( $request->files->get( 'files' ) as $entityType => $file ) {
|
||||||
|
$contents = file_get_contents( $file->getPathname() );
|
||||||
|
|
||||||
|
// Store the csv in cache with an expiry of 10 minutes
|
||||||
|
Cache::put( $hash . '-' . $entityType, base64_encode( $contents ), 3600 );
|
||||||
|
|
||||||
|
// Parse CSV
|
||||||
|
$csv_array = $this->getCsvData( $contents );
|
||||||
|
|
||||||
|
$class_map = $this->getEntityMap( $entityType );
|
||||||
|
|
||||||
|
$data['mappings'][ $entityType ] = [
|
||||||
|
'available' => $class_map::importable(),
|
||||||
|
'headers' => array_slice( $csv_array, 0, 2 ),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
return response()->json( $data );
|
return response()->json( $data );
|
||||||
}
|
}
|
||||||
|
|
||||||
public function import(ImportRequest $request)
|
public function import( ImportRequest $request ) {
|
||||||
{
|
$data = $request->all();
|
||||||
CSVImport::dispatch($request->all(), auth()->user()->company());
|
|
||||||
|
if ( empty( $data['hash'] ) ) {
|
||||||
|
// Create a reference
|
||||||
|
$data['hash'] = $hash = Str::random( 32 );
|
||||||
|
|
||||||
|
/** @var UploadedFile $file */
|
||||||
|
foreach ( $request->files->get( 'files' ) as $entityType => $file ) {
|
||||||
|
$contents = file_get_contents( $file->getPathname() );
|
||||||
|
|
||||||
|
// Store the csv in cache with an expiry of 10 minutes
|
||||||
|
Cache::put( $hash . '-' . $entityType, base64_encode( $contents ), 3600 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CSVImport::dispatch( $data, auth()->user()->company() );
|
||||||
|
|
||||||
return response()->json( [ 'message' => ctrans( 'texts.import_started' ) ], 200 );
|
return response()->json( [ 'message' => ctrans( 'texts.import_started' ) ], 200 );
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getEntityMap($entity_type)
|
private function getEntityMap( $entity_type ) {
|
||||||
{
|
|
||||||
return sprintf( 'App\\Import\\Definitions\%sMap', ucfirst( $entity_type ) );
|
return sprintf( 'App\\Import\\Definitions\%sMap', ucfirst( $entity_type ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getCsvData($csvfile)
|
private function getCsvData( $csvfile ) {
|
||||||
{
|
|
||||||
if ( ! ini_get( 'auto_detect_line_endings' ) ) {
|
if ( ! ini_get( 'auto_detect_line_endings' ) ) {
|
||||||
ini_set( 'auto_detect_line_endings', '1' );
|
ini_set( 'auto_detect_line_endings', '1' );
|
||||||
}
|
}
|
||||||
@ -123,7 +143,7 @@ class ImportController extends Controller
|
|||||||
if (strstr($firstCell, (string)config('ninja.app_name'))) {
|
if (strstr($firstCell, (string)config('ninja.app_name'))) {
|
||||||
array_shift( $data ); // Invoice Ninja...
|
array_shift( $data ); // Invoice Ninja...
|
||||||
array_shift( $data ); // <blank line>
|
array_shift( $data ); // <blank line>
|
||||||
array_shift($data); // Enitty Type Header
|
array_shift( $data ); // Entity Type Header
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ use App\Http\Requests\Invoice\EditInvoiceRequest;
|
|||||||
use App\Http\Requests\Invoice\ShowInvoiceRequest;
|
use App\Http\Requests\Invoice\ShowInvoiceRequest;
|
||||||
use App\Http\Requests\Invoice\StoreInvoiceRequest;
|
use App\Http\Requests\Invoice\StoreInvoiceRequest;
|
||||||
use App\Http\Requests\Invoice\UpdateInvoiceRequest;
|
use App\Http\Requests\Invoice\UpdateInvoiceRequest;
|
||||||
|
use App\Http\Requests\Invoice\UploadInvoiceRequest;
|
||||||
use App\Jobs\Entity\EmailEntity;
|
use App\Jobs\Entity\EmailEntity;
|
||||||
use App\Jobs\Invoice\StoreInvoice;
|
use App\Jobs\Invoice\StoreInvoice;
|
||||||
use App\Jobs\Invoice\ZipInvoices;
|
use App\Jobs\Invoice\ZipInvoices;
|
||||||
@ -38,6 +39,7 @@ use App\Transformers\QuoteTransformer;
|
|||||||
use App\Utils\Ninja;
|
use App\Utils\Ninja;
|
||||||
use App\Utils\TempFile;
|
use App\Utils\TempFile;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use App\Utils\Traits\SavesDocuments;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
use Illuminate\Support\Facades\File;
|
use Illuminate\Support\Facades\File;
|
||||||
@ -49,6 +51,7 @@ use Illuminate\Support\Facades\Storage;
|
|||||||
class InvoiceController extends BaseController
|
class InvoiceController extends BaseController
|
||||||
{
|
{
|
||||||
use MakesHash;
|
use MakesHash;
|
||||||
|
use SavesDocuments;
|
||||||
|
|
||||||
protected $entity_type = Invoice::class;
|
protected $entity_type = Invoice::class;
|
||||||
|
|
||||||
@ -204,6 +207,7 @@ class InvoiceController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function store(StoreInvoiceRequest $request)
|
public function store(StoreInvoiceRequest $request)
|
||||||
{
|
{
|
||||||
|
|
||||||
$client = Client::find($request->input('client_id'));
|
$client = Client::find($request->input('client_id'));
|
||||||
|
|
||||||
$invoice = $this->invoice_repo->save($request->all(), InvoiceFactory::create(auth()->user()->company()->id, auth()->user()->id));
|
$invoice = $this->invoice_repo->save($request->all(), InvoiceFactory::create(auth()->user()->company()->id, auth()->user()->id));
|
||||||
@ -392,8 +396,6 @@ class InvoiceController extends BaseController
|
|||||||
|
|
||||||
$invoice = $this->invoice_repo->save($request->all(), $invoice);
|
$invoice = $this->invoice_repo->save($request->all(), $invoice);
|
||||||
|
|
||||||
UnlinkFile::dispatchNow(config('filesystems.default'), $invoice->client->invoice_filepath().$invoice->number.'.pdf');
|
|
||||||
|
|
||||||
event(new InvoiceWasUpdated($invoice, $invoice->company, Ninja::eventVars()));
|
event(new InvoiceWasUpdated($invoice, $invoice->company, Ninja::eventVars()));
|
||||||
|
|
||||||
return $this->itemResponse($invoice);
|
return $this->itemResponse($invoice);
|
||||||
@ -530,7 +532,7 @@ class InvoiceController extends BaseController
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ZipInvoices::dispatch($invoices, $invoices->first()->company, auth()->user()->email);
|
ZipInvoices::dispatch($invoices, $invoices->first()->company, auth()->user());
|
||||||
|
|
||||||
return response()->json(['message' => ctrans('texts.sent_message')], 200);
|
return response()->json(['message' => ctrans('texts.sent_message')], 200);
|
||||||
}
|
}
|
||||||
@ -850,4 +852,65 @@ class InvoiceController extends BaseController
|
|||||||
return response(['message' => 'Oops, something went wrong. Make sure you have symlink to storage/ in public/ directory.'], 500);
|
return response(['message' => 'Oops, something went wrong. Make sure you have symlink to storage/ in public/ directory.'], 500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*
|
||||||
|
* @param UploadInvoiceRequest $request
|
||||||
|
* @param Invoice $invoice
|
||||||
|
* @return Response
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @OA\Put(
|
||||||
|
* path="/api/v1/invoices/{id}/upload",
|
||||||
|
* operationId="uploadInvoice",
|
||||||
|
* tags={"invoices"},
|
||||||
|
* summary="Uploads a document to a invoice",
|
||||||
|
* description="Handles the uploading of a document to a invoice",
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/include"),
|
||||||
|
* @OA\Parameter(
|
||||||
|
* name="id",
|
||||||
|
* in="path",
|
||||||
|
* description="The Invoice Hashed ID",
|
||||||
|
* example="D2J234DFA",
|
||||||
|
* required=true,
|
||||||
|
* @OA\Schema(
|
||||||
|
* type="string",
|
||||||
|
* format="string",
|
||||||
|
* ),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Returns the Invoice object",
|
||||||
|
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Invoice"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=422,
|
||||||
|
* description="Validation error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
|
||||||
|
*
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="Unexpected Error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Error"),
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function upload(UploadInvoiceRequest $request, Invoice $invoice)
|
||||||
|
{
|
||||||
|
|
||||||
|
if ($request->has('documents'))
|
||||||
|
$this->saveDocuments($request->file('documents'), $invoice);
|
||||||
|
|
||||||
|
return $this->itemResponse($invoice->fresh());
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,8 @@ namespace App\Http\Controllers;
|
|||||||
|
|
||||||
use App\Console\Commands\ImportMigrations;
|
use App\Console\Commands\ImportMigrations;
|
||||||
use App\DataMapper\CompanySettings;
|
use App\DataMapper\CompanySettings;
|
||||||
use App\Jobs\Mail\MailRouter;
|
use App\Jobs\Mail\NinjaMailerJob;
|
||||||
|
use App\Jobs\Mail\NinjaMailerObject;
|
||||||
use App\Jobs\Util\StartMigration;
|
use App\Jobs\Util\StartMigration;
|
||||||
use App\Mail\ExistingMigration;
|
use App\Mail\ExistingMigration;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
@ -218,6 +219,8 @@ class MigrationController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function startMigration(Request $request)
|
public function startMigration(Request $request)
|
||||||
{
|
{
|
||||||
|
nlog("Starting Migration");
|
||||||
|
|
||||||
$companies = json_decode($request->companies);
|
$companies = json_decode($request->companies);
|
||||||
|
|
||||||
if (app()->environment() === 'local') {
|
if (app()->environment() === 'local') {
|
||||||
@ -246,7 +249,13 @@ class MigrationController extends BaseController
|
|||||||
if ($checks['existing_company'] == true && $checks['force'] == false) {
|
if ($checks['existing_company'] == true && $checks['force'] == false) {
|
||||||
nlog('Migrating: Existing company without force. (CASE_01)');
|
nlog('Migrating: Existing company without force. (CASE_01)');
|
||||||
|
|
||||||
MailRouter::dispatch(new ExistingMigration(), $existing_company, $user);
|
$nmo = new NinjaMailerObject;
|
||||||
|
$nmo->mailable = new ExistingMigration();
|
||||||
|
$nmo->company = $existing_company;
|
||||||
|
$nmo->settings = $existing_company->settings;
|
||||||
|
$nmo->to_user = $user;
|
||||||
|
|
||||||
|
NinjaMailerJob::dispatch($nmo);
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'_id' => Str::uuid(),
|
'_id' => Str::uuid(),
|
||||||
@ -290,6 +299,9 @@ class MigrationController extends BaseController
|
|||||||
|
|
||||||
// If there's no existing company migrate just normally.
|
// If there's no existing company migrate just normally.
|
||||||
if ($checks['existing_company'] == false) {
|
if ($checks['existing_company'] == false) {
|
||||||
|
|
||||||
|
nlog("creating fresh company");
|
||||||
|
|
||||||
$account = auth()->user()->account;
|
$account = auth()->user()->account;
|
||||||
$fresh_company = (new ImportMigrations())->getCompany($account);
|
$fresh_company = (new ImportMigrations())->getCompany($account);
|
||||||
|
|
||||||
@ -325,11 +337,13 @@ class MigrationController extends BaseController
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (app()->environment() == 'testing') {
|
if (app()->environment() == 'testing') {
|
||||||
|
nlog("environment is testing = bailing out now");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// StartMigration::dispatch(base_path("storage/app/public/$migration_file"), $user, $fresh_company)->delay(now()->addSeconds(5));
|
// StartMigration::dispatch(base_path("storage/app/public/$migration_file"), $user, $fresh_company)->delay(now()->addSeconds(5));
|
||||||
|
nlog("starting migration job");
|
||||||
nlog($migration_file);
|
nlog($migration_file);
|
||||||
StartMigration::dispatch($migration_file, $user, $fresh_company);
|
StartMigration::dispatch($migration_file, $user, $fresh_company);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
|
@ -49,6 +49,9 @@
|
|||||||
* @OA\Property(property="custom_surcharge2", type="number", format="float", example="10.00", description="Second Custom Surcharge"),
|
* @OA\Property(property="custom_surcharge2", type="number", format="float", example="10.00", description="Second Custom Surcharge"),
|
||||||
* @OA\Property(property="custom_surcharge3", type="number", format="float", example="10.00", description="Third Custom Surcharge"),
|
* @OA\Property(property="custom_surcharge3", type="number", format="float", example="10.00", description="Third Custom Surcharge"),
|
||||||
* @OA\Property(property="custom_surcharge4", type="number", format="float", example="10.00", description="Fourth Custom Surcharge"),
|
* @OA\Property(property="custom_surcharge4", type="number", format="float", example="10.00", description="Fourth Custom Surcharge"),
|
||||||
* @OA\Property(property="custom_surcharge_taxes", type="boolean", example=true, description="Toggles charging taxes on custom surcharge amounts"),
|
* @OA\Property(property="custom_surcharge_tax1", type="boolean", example=true, description="Toggles charging taxes on custom surcharge amounts"),
|
||||||
|
* @OA\Property(property="custom_surcharge_tax2", type="boolean", example=true, description="Toggles charging taxes on custom surcharge amounts"),
|
||||||
|
* @OA\Property(property="custom_surcharge_tax3", type="boolean", example=true, description="Toggles charging taxes on custom surcharge amounts"),
|
||||||
|
* @OA\Property(property="custom_surcharge_tax4", type="boolean", example=true, description="Toggles charging taxes on custom surcharge amounts"),
|
||||||
* )
|
* )
|
||||||
*/
|
*/
|
||||||
|
23
app/Http/Controllers/OpenAPI/DocumentSchema.php
Normal file
23
app/Http/Controllers/OpenAPI/DocumentSchema.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @OA\Schema(
|
||||||
|
* schema="Document",
|
||||||
|
* type="object",
|
||||||
|
* @OA\Property(property="id", type="string", example="AS3df3A", description="The design hashed id"),
|
||||||
|
* @OA\Property(property="user_id", type="string", example="", description="__________"),
|
||||||
|
* @OA\Property(property="assigned_user_id", type="string", example="", description="__________"),
|
||||||
|
* @OA\Property(property="project_id", type="string", example="", description="__________"),
|
||||||
|
* @OA\Property(property="vendor_id", type="string", example="", description="__________"),
|
||||||
|
* @OA\Property(property="name", type="string", example="Beauty", description="The design name"),
|
||||||
|
* @OA\Property(property="url", type="string", example="Beauty", description="The design name"),
|
||||||
|
* @OA\Property(property="preview", type="string", example="Beauty", description="The design name"),
|
||||||
|
* @OA\Property(property="type", type="string", example="Beauty", description="The design name"),
|
||||||
|
* @OA\Property(property="disk", type="string", example="Beauty", description="The design name"),
|
||||||
|
* @OA\Property(property="hash", type="string", example="Beauty", description="The design name"),
|
||||||
|
* @OA\Property(property="is_deleted", type="boolean", example=true, description="Flag to determine if the design is deleted"),
|
||||||
|
* @OA\Property(property="is_default", type="boolean", example=true, description="Flag to determine if the document is a default doc"),
|
||||||
|
* @OA\Property(property="created_at", type="number", format="integer", example="134341234234", description="Timestamp"),
|
||||||
|
* @OA\Property(property="updated_at", type="number", format="integer", example="134341234234", description="Timestamp"),
|
||||||
|
* @OA\Property(property="deleted_at", type="number", format="integer", example="134341234234", description="Timestamp"),
|
||||||
|
* )
|
||||||
|
*/
|
@ -48,6 +48,9 @@
|
|||||||
* @OA\Property(property="custom_surcharge2", type="number", format="float", example="10.00", description="Second Custom Surcharge"),
|
* @OA\Property(property="custom_surcharge2", type="number", format="float", example="10.00", description="Second Custom Surcharge"),
|
||||||
* @OA\Property(property="custom_surcharge3", type="number", format="float", example="10.00", description="Third Custom Surcharge"),
|
* @OA\Property(property="custom_surcharge3", type="number", format="float", example="10.00", description="Third Custom Surcharge"),
|
||||||
* @OA\Property(property="custom_surcharge4", type="number", format="float", example="10.00", description="Fourth Custom Surcharge"),
|
* @OA\Property(property="custom_surcharge4", type="number", format="float", example="10.00", description="Fourth Custom Surcharge"),
|
||||||
* @OA\Property(property="custom_surcharge_taxes", type="boolean", example=true, description="Toggles charging taxes on custom surcharge amounts"),
|
* @OA\Property(property="custom_surcharge_tax1", type="boolean", example=true, description="Toggles charging taxes on custom surcharge amounts"),
|
||||||
|
* @OA\Property(property="custom_surcharge_tax2", type="boolean", example=true, description="Toggles charging taxes on custom surcharge amounts"),
|
||||||
|
* @OA\Property(property="custom_surcharge_tax3", type="boolean", example=true, description="Toggles charging taxes on custom surcharge amounts"),
|
||||||
|
* @OA\Property(property="custom_surcharge_tax4", type="boolean", example=true, description="Toggles charging taxes on custom surcharge amounts"),
|
||||||
* )
|
* )
|
||||||
*/
|
*/
|
||||||
|
@ -48,6 +48,9 @@
|
|||||||
* @OA\Property(property="custom_surcharge2", type="number", format="float", example="10.00", description="Second Custom Surcharge"),
|
* @OA\Property(property="custom_surcharge2", type="number", format="float", example="10.00", description="Second Custom Surcharge"),
|
||||||
* @OA\Property(property="custom_surcharge3", type="number", format="float", example="10.00", description="Third Custom Surcharge"),
|
* @OA\Property(property="custom_surcharge3", type="number", format="float", example="10.00", description="Third Custom Surcharge"),
|
||||||
* @OA\Property(property="custom_surcharge4", type="number", format="float", example="10.00", description="Fourth Custom Surcharge"),
|
* @OA\Property(property="custom_surcharge4", type="number", format="float", example="10.00", description="Fourth Custom Surcharge"),
|
||||||
* @OA\Property(property="custom_surcharge_taxes", type="boolean", example=true, description="Toggles charging taxes on custom surcharge amounts"),
|
* @OA\Property(property="custom_surcharge_tax1", type="boolean", example=true, description="Toggles charging taxes on custom surcharge amounts"),
|
||||||
|
* @OA\Property(property="custom_surcharge_tax2", type="boolean", example=true, description="Toggles charging taxes on custom surcharge amounts"),
|
||||||
|
* @OA\Property(property="custom_surcharge_tax3", type="boolean", example=true, description="Toggles charging taxes on custom surcharge amounts"),
|
||||||
|
* @OA\Property(property="custom_surcharge_tax4", type="boolean", example=true, description="Toggles charging taxes on custom surcharge amounts"),
|
||||||
* )
|
* )
|
||||||
*/
|
*/
|
||||||
|
@ -22,12 +22,14 @@ use App\Http\Requests\Payment\RefundPaymentRequest;
|
|||||||
use App\Http\Requests\Payment\ShowPaymentRequest;
|
use App\Http\Requests\Payment\ShowPaymentRequest;
|
||||||
use App\Http\Requests\Payment\StorePaymentRequest;
|
use App\Http\Requests\Payment\StorePaymentRequest;
|
||||||
use App\Http\Requests\Payment\UpdatePaymentRequest;
|
use App\Http\Requests\Payment\UpdatePaymentRequest;
|
||||||
|
use App\Http\Requests\Payment\UploadPaymentRequest;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
use App\Models\Payment;
|
use App\Models\Payment;
|
||||||
use App\Repositories\PaymentRepository;
|
use App\Repositories\PaymentRepository;
|
||||||
use App\Transformers\PaymentTransformer;
|
use App\Transformers\PaymentTransformer;
|
||||||
use App\Utils\Ninja;
|
use App\Utils\Ninja;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use App\Utils\Traits\SavesDocuments;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
|
|
||||||
@ -37,6 +39,7 @@ use Illuminate\Http\Response;
|
|||||||
class PaymentController extends BaseController
|
class PaymentController extends BaseController
|
||||||
{
|
{
|
||||||
use MakesHash;
|
use MakesHash;
|
||||||
|
use SavesDocuments;
|
||||||
|
|
||||||
protected $entity_type = Payment::class;
|
protected $entity_type = Payment::class;
|
||||||
|
|
||||||
@ -671,4 +674,65 @@ class PaymentController extends BaseController
|
|||||||
|
|
||||||
return $this->itemResponse($payment);
|
return $this->itemResponse($payment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*
|
||||||
|
* @param UploadPaymentRequest $request
|
||||||
|
* @param Payment $payment
|
||||||
|
* @return Response
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @OA\Put(
|
||||||
|
* path="/api/v1/payments/{id}/upload",
|
||||||
|
* operationId="uploadPayment",
|
||||||
|
* tags={"payments"},
|
||||||
|
* summary="Uploads a document to a payment",
|
||||||
|
* description="Handles the uploading of a document to a payment",
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/include"),
|
||||||
|
* @OA\Parameter(
|
||||||
|
* name="id",
|
||||||
|
* in="path",
|
||||||
|
* description="The Payment Hashed ID",
|
||||||
|
* example="D2J234DFA",
|
||||||
|
* required=true,
|
||||||
|
* @OA\Schema(
|
||||||
|
* type="string",
|
||||||
|
* format="string",
|
||||||
|
* ),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Returns the Payment object",
|
||||||
|
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Payment"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=422,
|
||||||
|
* description="Validation error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
|
||||||
|
*
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="Unexpected Error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Error"),
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function upload(UploadPaymentRequest $request, Payment $payment)
|
||||||
|
{
|
||||||
|
|
||||||
|
if ($request->has('documents'))
|
||||||
|
$this->saveDocuments($request->file('documents'), $payment);
|
||||||
|
|
||||||
|
return $this->itemResponse($payment->fresh());
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
156
app/Http/Controllers/PostMarkController.php
Normal file
156
app/Http/Controllers/PostMarkController.php
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class PostMarkController.
|
||||||
|
*/
|
||||||
|
class PostMarkController extends BaseController
|
||||||
|
{
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process Postmark Webhook.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @OA\Post(
|
||||||
|
* path="/api/v1/postmark_webhook",
|
||||||
|
* operationId="postmarkWebhook",
|
||||||
|
* tags={"postmark"},
|
||||||
|
* summary="Processing webhooks from PostMark",
|
||||||
|
* description="Adds an credit to the system",
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/include"),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Returns the saved credit object",
|
||||||
|
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Credit"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=422,
|
||||||
|
* description="Validation error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
|
||||||
|
*
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="Unexpected Error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Error"),
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function webhook(Request $request)
|
||||||
|
{
|
||||||
|
|
||||||
|
if($request->header('X-API-SECURITY') && $request->header('X-API-SECURITY') == config('postmark.secret'))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// {
|
||||||
|
// "RecordType": "Delivery",
|
||||||
|
// "ServerID": 23,
|
||||||
|
// "MessageStream": "outbound",
|
||||||
|
// "MessageID": "00000000-0000-0000-0000-000000000000",
|
||||||
|
// "Recipient": "john@example.com",
|
||||||
|
// "Tag": "welcome-email",
|
||||||
|
// "DeliveredAt": "2021-02-21T16:34:52Z",
|
||||||
|
// "Details": "Test delivery webhook details",
|
||||||
|
// "Metadata": {
|
||||||
|
// "example": "value",
|
||||||
|
// "example_2": "value"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
private function processDelivery($request)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// {
|
||||||
|
// "Metadata": {
|
||||||
|
// "example": "value",
|
||||||
|
// "example_2": "value"
|
||||||
|
// },
|
||||||
|
// "RecordType": "Bounce",
|
||||||
|
// "ID": 42,
|
||||||
|
// "Type": "HardBounce",
|
||||||
|
// "TypeCode": 1,
|
||||||
|
// "Name": "Hard bounce",
|
||||||
|
// "Tag": "Test",
|
||||||
|
// "MessageID": "00000000-0000-0000-0000-000000000000",
|
||||||
|
// "ServerID": 1234,
|
||||||
|
// "MessageStream": "outbound",
|
||||||
|
// "Description": "The server was unable to deliver your message (ex: unknown user, mailbox not found).",
|
||||||
|
// "Details": "Test bounce details",
|
||||||
|
// "Email": "john@example.com",
|
||||||
|
// "From": "sender@example.com",
|
||||||
|
// "BouncedAt": "2021-02-21T16:34:52Z",
|
||||||
|
// "DumpAvailable": true,
|
||||||
|
// "Inactive": true,
|
||||||
|
// "CanActivate": true,
|
||||||
|
// "Subject": "Test subject",
|
||||||
|
// "Content": "Test content"
|
||||||
|
// }
|
||||||
|
|
||||||
|
private function processBounce($request)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// {
|
||||||
|
// "Metadata": {
|
||||||
|
// "example": "value",
|
||||||
|
// "example_2": "value"
|
||||||
|
// },
|
||||||
|
// "RecordType": "SpamComplaint",
|
||||||
|
// "ID": 42,
|
||||||
|
// "Type": "SpamComplaint",
|
||||||
|
// "TypeCode": 100001,
|
||||||
|
// "Name": "Spam complaint",
|
||||||
|
// "Tag": "Test",
|
||||||
|
// "MessageID": "00000000-0000-0000-0000-000000000000",
|
||||||
|
// "ServerID": 1234,
|
||||||
|
// "MessageStream": "outbound",
|
||||||
|
// "Description": "The subscriber explicitly marked this message as spam.",
|
||||||
|
// "Details": "Test spam complaint details",
|
||||||
|
// "Email": "john@example.com",
|
||||||
|
// "From": "sender@example.com",
|
||||||
|
// "BouncedAt": "2021-02-21T16:34:52Z",
|
||||||
|
// "DumpAvailable": true,
|
||||||
|
// "Inactive": true,
|
||||||
|
// "CanActivate": false,
|
||||||
|
// "Subject": "Test subject",
|
||||||
|
// "Content": "Test content"
|
||||||
|
// }
|
||||||
|
private function processSpamComplaint($request)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -19,16 +19,19 @@ use App\Http\Requests\Product\EditProductRequest;
|
|||||||
use App\Http\Requests\Product\ShowProductRequest;
|
use App\Http\Requests\Product\ShowProductRequest;
|
||||||
use App\Http\Requests\Product\StoreProductRequest;
|
use App\Http\Requests\Product\StoreProductRequest;
|
||||||
use App\Http\Requests\Product\UpdateProductRequest;
|
use App\Http\Requests\Product\UpdateProductRequest;
|
||||||
|
use App\Http\Requests\Product\UploadProductRequest;
|
||||||
use App\Models\Product;
|
use App\Models\Product;
|
||||||
use App\Repositories\ProductRepository;
|
use App\Repositories\ProductRepository;
|
||||||
use App\Transformers\ProductTransformer;
|
use App\Transformers\ProductTransformer;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use App\Utils\Traits\SavesDocuments;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
|
|
||||||
class ProductController extends BaseController
|
class ProductController extends BaseController
|
||||||
{
|
{
|
||||||
use MakesHash;
|
use MakesHash;
|
||||||
|
use SavesDocuments;
|
||||||
|
|
||||||
protected $entity_type = Product::class;
|
protected $entity_type = Product::class;
|
||||||
|
|
||||||
@ -476,4 +479,65 @@ class ProductController extends BaseController
|
|||||||
|
|
||||||
return $this->listResponse(Product::withTrashed()->whereIn('id', $this->transformKeys($ids)));
|
return $this->listResponse(Product::withTrashed()->whereIn('id', $this->transformKeys($ids)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*
|
||||||
|
* @param UploadProductRequest $request
|
||||||
|
* @param Product $product
|
||||||
|
* @return Response
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @OA\Put(
|
||||||
|
* path="/api/v1/products/{id}/upload",
|
||||||
|
* operationId="uploadProduct",
|
||||||
|
* tags={"products"},
|
||||||
|
* summary="Uploads a document to a product",
|
||||||
|
* description="Handles the uploading of a document to a product",
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/include"),
|
||||||
|
* @OA\Parameter(
|
||||||
|
* name="id",
|
||||||
|
* in="path",
|
||||||
|
* description="The Product Hashed ID",
|
||||||
|
* example="D2J234DFA",
|
||||||
|
* required=true,
|
||||||
|
* @OA\Schema(
|
||||||
|
* type="string",
|
||||||
|
* format="string",
|
||||||
|
* ),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Returns the Product object",
|
||||||
|
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Product"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=422,
|
||||||
|
* description="Validation error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
|
||||||
|
*
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="Unexpected Error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Error"),
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function upload(UploadProductRequest $request, Product $product)
|
||||||
|
{
|
||||||
|
|
||||||
|
if ($request->has('documents'))
|
||||||
|
$this->saveDocuments($request->file('documents'), $product);
|
||||||
|
|
||||||
|
return $this->itemResponse($product->fresh());
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ use App\Http\Requests\Project\EditProjectRequest;
|
|||||||
use App\Http\Requests\Project\ShowProjectRequest;
|
use App\Http\Requests\Project\ShowProjectRequest;
|
||||||
use App\Http\Requests\Project\StoreProjectRequest;
|
use App\Http\Requests\Project\StoreProjectRequest;
|
||||||
use App\Http\Requests\Project\UpdateProjectRequest;
|
use App\Http\Requests\Project\UpdateProjectRequest;
|
||||||
|
use App\Http\Requests\Project\UploadProjectRequest;
|
||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
use App\Repositories\ProjectRepository;
|
use App\Repositories\ProjectRepository;
|
||||||
use App\Transformers\ProjectTransformer;
|
use App\Transformers\ProjectTransformer;
|
||||||
@ -266,6 +267,10 @@ class ProjectController extends BaseController
|
|||||||
$project->number = empty($project->number) ? $this->getNextProjectNumber($project) : $project->number;
|
$project->number = empty($project->number) ? $this->getNextProjectNumber($project) : $project->number;
|
||||||
$project->save();
|
$project->save();
|
||||||
|
|
||||||
|
if ($request->has('documents')) {
|
||||||
|
$this->saveDocuments($request->input('documents'), $project);
|
||||||
|
}
|
||||||
|
|
||||||
return $this->itemResponse($project->fresh());
|
return $this->itemResponse($project->fresh());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -499,4 +504,65 @@ class ProjectController extends BaseController
|
|||||||
|
|
||||||
return $this->listResponse(Project::withTrashed()->whereIn('id', $this->transformKeys($ids)));
|
return $this->listResponse(Project::withTrashed()->whereIn('id', $this->transformKeys($ids)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*
|
||||||
|
* @param UploadProductRequest $request
|
||||||
|
* @param Product $project
|
||||||
|
* @return Response
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @OA\Put(
|
||||||
|
* path="/api/v1/projects/{id}/upload",
|
||||||
|
* operationId="uploadProject",
|
||||||
|
* tags={"projects"},
|
||||||
|
* summary="Uploads a document to a project",
|
||||||
|
* description="Handles the uploading of a document to a project",
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/include"),
|
||||||
|
* @OA\Parameter(
|
||||||
|
* name="id",
|
||||||
|
* in="path",
|
||||||
|
* description="The Project Hashed ID",
|
||||||
|
* example="D2J234DFA",
|
||||||
|
* required=true,
|
||||||
|
* @OA\Schema(
|
||||||
|
* type="string",
|
||||||
|
* format="string",
|
||||||
|
* ),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Returns the Project object",
|
||||||
|
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Project"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=422,
|
||||||
|
* description="Validation error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
|
||||||
|
*
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="Unexpected Error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Error"),
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function upload(UploadProjectRequest $request, Project $project)
|
||||||
|
{
|
||||||
|
|
||||||
|
if ($request->has('documents'))
|
||||||
|
$this->saveDocuments($request->file('documents'), $project);
|
||||||
|
|
||||||
|
return $this->itemResponse($project->fresh());
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ use App\Http\Requests\Quote\EditQuoteRequest;
|
|||||||
use App\Http\Requests\Quote\ShowQuoteRequest;
|
use App\Http\Requests\Quote\ShowQuoteRequest;
|
||||||
use App\Http\Requests\Quote\StoreQuoteRequest;
|
use App\Http\Requests\Quote\StoreQuoteRequest;
|
||||||
use App\Http\Requests\Quote\UpdateQuoteRequest;
|
use App\Http\Requests\Quote\UpdateQuoteRequest;
|
||||||
|
use App\Http\Requests\Quote\UploadQuoteRequest;
|
||||||
use App\Jobs\Invoice\ZipInvoices;
|
use App\Jobs\Invoice\ZipInvoices;
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
@ -34,6 +35,7 @@ use App\Transformers\QuoteTransformer;
|
|||||||
use App\Utils\Ninja;
|
use App\Utils\Ninja;
|
||||||
use App\Utils\TempFile;
|
use App\Utils\TempFile;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use App\Utils\Traits\SavesDocuments;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
|
|
||||||
@ -43,6 +45,7 @@ use Illuminate\Http\Response;
|
|||||||
class QuoteController extends BaseController
|
class QuoteController extends BaseController
|
||||||
{
|
{
|
||||||
use MakesHash;
|
use MakesHash;
|
||||||
|
use SavesDocuments;
|
||||||
|
|
||||||
protected $entity_type = Quote::class;
|
protected $entity_type = Quote::class;
|
||||||
|
|
||||||
@ -521,7 +524,7 @@ class QuoteController extends BaseController
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ZipInvoices::dispatch($quotes, $quotes->first()->company, auth()->user()->email);
|
ZipInvoices::dispatch($quotes, $quotes->first()->company, auth()->user());
|
||||||
|
|
||||||
return response()->json(['message' => ctrans('texts.sent_message')], 200);
|
return response()->json(['message' => ctrans('texts.sent_message')], 200);
|
||||||
}
|
}
|
||||||
@ -717,4 +720,65 @@ class QuoteController extends BaseController
|
|||||||
|
|
||||||
return response()->download($file_path);
|
return response()->download($file_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*
|
||||||
|
* @param UploadQuoteRequest $request
|
||||||
|
* @param Quote $quote
|
||||||
|
* @return Response
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @OA\Put(
|
||||||
|
* path="/api/v1/quotes/{id}/upload",
|
||||||
|
* operationId="uploadQuote",
|
||||||
|
* tags={"quotes"},
|
||||||
|
* summary="Uploads a document to a quote",
|
||||||
|
* description="Handles the uploading of a document to a quote",
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/include"),
|
||||||
|
* @OA\Parameter(
|
||||||
|
* name="id",
|
||||||
|
* in="path",
|
||||||
|
* description="The Quote Hashed ID",
|
||||||
|
* example="D2J234DFA",
|
||||||
|
* required=true,
|
||||||
|
* @OA\Schema(
|
||||||
|
* type="string",
|
||||||
|
* format="string",
|
||||||
|
* ),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Returns the Quote object",
|
||||||
|
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Quote"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=422,
|
||||||
|
* description="Validation error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
|
||||||
|
*
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="Unexpected Error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Error"),
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function upload(UploadQuoteRequest $request, Quote $quote)
|
||||||
|
{
|
||||||
|
|
||||||
|
if ($request->has('documents'))
|
||||||
|
$this->saveDocuments($request->file('documents'), $quote);
|
||||||
|
|
||||||
|
return $this->itemResponse($quote->fresh());
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,10 +20,12 @@ use App\Http\Requests\RecurringInvoice\EditRecurringInvoiceRequest;
|
|||||||
use App\Http\Requests\RecurringInvoice\ShowRecurringInvoiceRequest;
|
use App\Http\Requests\RecurringInvoice\ShowRecurringInvoiceRequest;
|
||||||
use App\Http\Requests\RecurringInvoice\StoreRecurringInvoiceRequest;
|
use App\Http\Requests\RecurringInvoice\StoreRecurringInvoiceRequest;
|
||||||
use App\Http\Requests\RecurringInvoice\UpdateRecurringInvoiceRequest;
|
use App\Http\Requests\RecurringInvoice\UpdateRecurringInvoiceRequest;
|
||||||
|
use App\Http\Requests\RecurringInvoice\UploadRecurringInvoiceRequest;
|
||||||
use App\Models\RecurringInvoice;
|
use App\Models\RecurringInvoice;
|
||||||
use App\Repositories\RecurringInvoiceRepository;
|
use App\Repositories\RecurringInvoiceRepository;
|
||||||
use App\Transformers\RecurringInvoiceTransformer;
|
use App\Transformers\RecurringInvoiceTransformer;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use App\Utils\Traits\SavesDocuments;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
|
|
||||||
@ -33,6 +35,7 @@ use Illuminate\Http\Response;
|
|||||||
class RecurringInvoiceController extends BaseController
|
class RecurringInvoiceController extends BaseController
|
||||||
{
|
{
|
||||||
use MakesHash;
|
use MakesHash;
|
||||||
|
use SavesDocuments;
|
||||||
|
|
||||||
protected $entity_type = RecurringInvoice::class;
|
protected $entity_type = RecurringInvoice::class;
|
||||||
|
|
||||||
@ -680,4 +683,65 @@ class RecurringInvoiceController extends BaseController
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*
|
||||||
|
* @param UploadRecurringInvoiceRequest $request
|
||||||
|
* @param RecurringInvoice $recurring_invoice
|
||||||
|
* @return Response
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @OA\Put(
|
||||||
|
* path="/api/v1/recurring_invoices/{id}/upload",
|
||||||
|
* operationId="uploadRecurringInvoice",
|
||||||
|
* tags={"recurring_invoices"},
|
||||||
|
* summary="Uploads a document to a recurring_invoice",
|
||||||
|
* description="Handles the uploading of a document to a recurring_invoice",
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/include"),
|
||||||
|
* @OA\Parameter(
|
||||||
|
* name="id",
|
||||||
|
* in="path",
|
||||||
|
* description="The RecurringInvoice Hashed ID",
|
||||||
|
* example="D2J234DFA",
|
||||||
|
* required=true,
|
||||||
|
* @OA\Schema(
|
||||||
|
* type="string",
|
||||||
|
* format="string",
|
||||||
|
* ),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Returns the RecurringInvoice object",
|
||||||
|
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/RecurringInvoice"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=422,
|
||||||
|
* description="Validation error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
|
||||||
|
*
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="Unexpected Error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Error"),
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function upload(UploadRecurringInvoiceRequest $request, RecurringInvoice $recurring_invoice)
|
||||||
|
{
|
||||||
|
|
||||||
|
if ($request->has('documents'))
|
||||||
|
$this->saveDocuments($request->file('documents'), $recurring_invoice);
|
||||||
|
|
||||||
|
return $this->itemResponse($recurring_invoice->fresh());
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,12 +21,14 @@ use App\Http\Requests\Task\EditTaskRequest;
|
|||||||
use App\Http\Requests\Task\ShowTaskRequest;
|
use App\Http\Requests\Task\ShowTaskRequest;
|
||||||
use App\Http\Requests\Task\StoreTaskRequest;
|
use App\Http\Requests\Task\StoreTaskRequest;
|
||||||
use App\Http\Requests\Task\UpdateTaskRequest;
|
use App\Http\Requests\Task\UpdateTaskRequest;
|
||||||
|
use App\Http\Requests\Task\UploadTaskRequest;
|
||||||
use App\Models\Task;
|
use App\Models\Task;
|
||||||
use App\Repositories\TaskRepository;
|
use App\Repositories\TaskRepository;
|
||||||
use App\Transformers\TaskTransformer;
|
use App\Transformers\TaskTransformer;
|
||||||
use App\Utils\Ninja;
|
use App\Utils\Ninja;
|
||||||
use App\Utils\Traits\BulkOptions;
|
use App\Utils\Traits\BulkOptions;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use App\Utils\Traits\SavesDocuments;
|
||||||
use App\Utils\Traits\Uploadable;
|
use App\Utils\Traits\Uploadable;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
@ -40,6 +42,7 @@ class TaskController extends BaseController
|
|||||||
use MakesHash;
|
use MakesHash;
|
||||||
use Uploadable;
|
use Uploadable;
|
||||||
use BulkOptions;
|
use BulkOptions;
|
||||||
|
use SavesDocuments;
|
||||||
|
|
||||||
protected $entity_type = Task::class;
|
protected $entity_type = Task::class;
|
||||||
|
|
||||||
@ -506,4 +509,65 @@ class TaskController extends BaseController
|
|||||||
{
|
{
|
||||||
//todo
|
//todo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*
|
||||||
|
* @param UploadTaskRequest $request
|
||||||
|
* @param Task $task
|
||||||
|
* @return Response
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @OA\Put(
|
||||||
|
* path="/api/v1/tasks/{id}/upload",
|
||||||
|
* operationId="uploadTask",
|
||||||
|
* tags={"tasks"},
|
||||||
|
* summary="Uploads a document to a task",
|
||||||
|
* description="Handles the uploading of a document to a task",
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/include"),
|
||||||
|
* @OA\Parameter(
|
||||||
|
* name="id",
|
||||||
|
* in="path",
|
||||||
|
* description="The Task Hashed ID",
|
||||||
|
* example="D2J234DFA",
|
||||||
|
* required=true,
|
||||||
|
* @OA\Schema(
|
||||||
|
* type="string",
|
||||||
|
* format="string",
|
||||||
|
* ),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Returns the Task object",
|
||||||
|
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Task"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=422,
|
||||||
|
* description="Validation error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
|
||||||
|
*
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="Unexpected Error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Error"),
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function upload(UploadTaskRequest $request, Task $task)
|
||||||
|
{
|
||||||
|
|
||||||
|
if ($request->has('documents'))
|
||||||
|
$this->saveDocuments($request->file('documents'), $task);
|
||||||
|
|
||||||
|
return $this->itemResponse($task->fresh());
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
63
app/Http/Controllers/TwoFactorController.php
Normal file
63
app/Http/Controllers/TwoFactorController.php
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use PragmaRX\Google2FA\Google2FA;
|
||||||
|
use Crypt;
|
||||||
|
|
||||||
|
class TwoFactorController extends BaseController
|
||||||
|
{
|
||||||
|
public function setupTwoFactor()
|
||||||
|
{
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
if ($user->google_2fa_secret)
|
||||||
|
return response()->json(['message' => '2FA already enabled'], 400);
|
||||||
|
elseif(! $user->phone)
|
||||||
|
return response()->json(['message' => ctrans('texts.set_phone_for_two_factor')], 400);
|
||||||
|
elseif(! $user->confirmed)
|
||||||
|
return response()->json(['message' => 'Please confirm your account first'], 400);
|
||||||
|
|
||||||
|
$google2fa = new Google2FA();
|
||||||
|
$secret = $google2fa->generateSecretKey();
|
||||||
|
|
||||||
|
$qr_code = $google2fa->getQRCodeGoogleUrl(
|
||||||
|
config('ninja.app_name')
|
||||||
|
$user->email,
|
||||||
|
$secret
|
||||||
|
);
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'secret' => $secret,
|
||||||
|
'qrCode' => $qrCode,
|
||||||
|
];
|
||||||
|
|
||||||
|
return response()->json(['data' => $data], 200);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function enableTwoFactor()
|
||||||
|
{
|
||||||
|
$user = auth()->user();
|
||||||
|
$secret = request()->input('secret');
|
||||||
|
$oneTimePassword = request()->input('one_time_password');
|
||||||
|
|
||||||
|
if (! $secret || ! \Google2FA::verifyKey($secret, $oneTimePassword)) {
|
||||||
|
return response()->json('message' > ctrans('texts.invalid_one_time_password'));
|
||||||
|
} elseif (! $user->google_2fa_secret && $user->phone && $user->confirmed) {
|
||||||
|
$user->google_2fa_secret = encrypt($secret);
|
||||||
|
$user->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json(['message' => ctrans('texts.enabled_two_factor')], 200);
|
||||||
|
}
|
||||||
|
}
|
@ -23,11 +23,16 @@ use App\Http\Requests\User\CreateUserRequest;
|
|||||||
use App\Http\Requests\User\DestroyUserRequest;
|
use App\Http\Requests\User\DestroyUserRequest;
|
||||||
use App\Http\Requests\User\DetachCompanyUserRequest;
|
use App\Http\Requests\User\DetachCompanyUserRequest;
|
||||||
use App\Http\Requests\User\EditUserRequest;
|
use App\Http\Requests\User\EditUserRequest;
|
||||||
|
use App\Http\Requests\User\ReconfirmUserRequest;
|
||||||
use App\Http\Requests\User\ShowUserRequest;
|
use App\Http\Requests\User\ShowUserRequest;
|
||||||
use App\Http\Requests\User\StoreUserRequest;
|
use App\Http\Requests\User\StoreUserRequest;
|
||||||
use App\Http\Requests\User\UpdateUserRequest;
|
use App\Http\Requests\User\UpdateUserRequest;
|
||||||
use App\Jobs\Company\CreateCompanyToken;
|
use App\Jobs\Company\CreateCompanyToken;
|
||||||
|
use App\Jobs\Mail\NinjaMailer;
|
||||||
|
use App\Jobs\Mail\NinjaMailerJob;
|
||||||
|
use App\Jobs\Mail\NinjaMailerObject;
|
||||||
use App\Jobs\User\UserEmailChanged;
|
use App\Jobs\User\UserEmailChanged;
|
||||||
|
use App\Mail\Admin\VerifyUserObject;
|
||||||
use App\Models\CompanyUser;
|
use App\Models\CompanyUser;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Repositories\UserRepository;
|
use App\Repositories\UserRepository;
|
||||||
@ -369,13 +374,28 @@ class UserController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function update(UpdateUserRequest $request, User $user)
|
public function update(UpdateUserRequest $request, User $user)
|
||||||
{
|
{
|
||||||
$old_email = $user->email;
|
|
||||||
|
$old_company_user = $user->company_user;
|
||||||
|
$old_user = json_encode($user);
|
||||||
|
$old_user_email = $user->getOriginal('email');
|
||||||
|
|
||||||
$new_email = $request->input('email');
|
$new_email = $request->input('email');
|
||||||
|
$new_user = $this->user_repo->save($request->all(), $user);
|
||||||
|
$new_user = $user->fresh();
|
||||||
|
|
||||||
$user = $this->user_repo->save($request->all(), $user);
|
/* When changing email address we store the former email in case we need to rollback */
|
||||||
|
if ($old_user_email != $new_email) {
|
||||||
|
$user->last_confirmed_email_address = $old_user_email;
|
||||||
|
$user->save();
|
||||||
|
UserEmailChanged::dispatch($new_user, json_decode($old_user), auth()->user()->company());
|
||||||
|
}
|
||||||
|
|
||||||
if ($old_email != $new_email) {
|
|
||||||
UserEmailChanged::dispatch($new_email, $old_email, auth()->user()->company());
|
if(
|
||||||
|
strcasecmp($old_company_user->permissions, $user->company_user->permissions) != 0 ||
|
||||||
|
$old_company_user->is_admin != $user->company_user->is_admin
|
||||||
|
){
|
||||||
|
$user->company_user()->update(["permissions_updated_at" => now()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
event(new UserWasUpdated($user, auth()->user(), auth()->user()->company, Ninja::eventVars()));
|
event(new UserWasUpdated($user, auth()->user(), auth()->user()->company, Ninja::eventVars()));
|
||||||
@ -670,4 +690,70 @@ class UserController extends BaseController
|
|||||||
|
|
||||||
return response()->json(['message' => ctrans('texts.user_detached')], 200);
|
return response()->json(['message' => ctrans('texts.user_detached')], 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detach an existing user to a company.
|
||||||
|
*
|
||||||
|
* @OA\Post(
|
||||||
|
* path="/api/v1/users/{user}/reconfirm",
|
||||||
|
* operationId="reconfirmUser",
|
||||||
|
* tags={"users"},
|
||||||
|
* summary="Reconfirm an existing user to a company",
|
||||||
|
* description="Reconfirm an existing user from a company",
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/include"),
|
||||||
|
* @OA\Parameter(
|
||||||
|
* name="user",
|
||||||
|
* in="path",
|
||||||
|
* description="The user hashed_id",
|
||||||
|
* example="FD767dfd7",
|
||||||
|
* required=true,
|
||||||
|
* @OA\Schema(
|
||||||
|
* type="string",
|
||||||
|
* format="string",
|
||||||
|
* ),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Success response",
|
||||||
|
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=422,
|
||||||
|
* description="Validation error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
|
||||||
|
*
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="Unexpected Error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Error"),
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
* @param ReconfirmUserRequest $request
|
||||||
|
* @param User $user
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
|
public function reconfirm(ReconfirmUserRequest $request, User $user)
|
||||||
|
{
|
||||||
|
$user->confirmation_code = $this->createDbHash($user->company()->db);
|
||||||
|
$user->save();
|
||||||
|
|
||||||
|
$nmo = new NinjaMailerObject;
|
||||||
|
$nmo->mailable = new NinjaMailer((new VerifyUserObject($user, $user->company()))->build());
|
||||||
|
$nmo->company = $user->company();
|
||||||
|
$nmo->to_user = $user;
|
||||||
|
$nmo->settings = $user->company->settings;
|
||||||
|
|
||||||
|
NinjaMailerJob::dispatch($nmo);
|
||||||
|
|
||||||
|
return response()->json(['message' => ctrans('texts.confirmation_resent')], 200);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -21,12 +21,14 @@ use App\Http\Requests\Vendor\EditVendorRequest;
|
|||||||
use App\Http\Requests\Vendor\ShowVendorRequest;
|
use App\Http\Requests\Vendor\ShowVendorRequest;
|
||||||
use App\Http\Requests\Vendor\StoreVendorRequest;
|
use App\Http\Requests\Vendor\StoreVendorRequest;
|
||||||
use App\Http\Requests\Vendor\UpdateVendorRequest;
|
use App\Http\Requests\Vendor\UpdateVendorRequest;
|
||||||
|
use App\Http\Requests\Vendor\UploadVendorRequest;
|
||||||
use App\Models\Vendor;
|
use App\Models\Vendor;
|
||||||
use App\Repositories\VendorRepository;
|
use App\Repositories\VendorRepository;
|
||||||
use App\Transformers\VendorTransformer;
|
use App\Transformers\VendorTransformer;
|
||||||
use App\Utils\Ninja;
|
use App\Utils\Ninja;
|
||||||
use App\Utils\Traits\BulkOptions;
|
use App\Utils\Traits\BulkOptions;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use App\Utils\Traits\SavesDocuments;
|
||||||
use App\Utils\Traits\Uploadable;
|
use App\Utils\Traits\Uploadable;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
@ -39,6 +41,7 @@ class VendorController extends BaseController
|
|||||||
use MakesHash;
|
use MakesHash;
|
||||||
use Uploadable;
|
use Uploadable;
|
||||||
use BulkOptions;
|
use BulkOptions;
|
||||||
|
use SavesDocuments;
|
||||||
|
|
||||||
protected $entity_type = Vendor::class;
|
protected $entity_type = Vendor::class;
|
||||||
|
|
||||||
@ -511,4 +514,65 @@ class VendorController extends BaseController
|
|||||||
{
|
{
|
||||||
//todo
|
//todo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*
|
||||||
|
* @param UploadVendorRequest $request
|
||||||
|
* @param Vendor $vendor
|
||||||
|
* @return Response
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @OA\Put(
|
||||||
|
* path="/api/v1/vendors/{id}/upload",
|
||||||
|
* operationId="uploadVendor",
|
||||||
|
* tags={"vendors"},
|
||||||
|
* summary="Uploads a document to a vendor",
|
||||||
|
* description="Handles the uploading of a document to a vendor",
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/include"),
|
||||||
|
* @OA\Parameter(
|
||||||
|
* name="id",
|
||||||
|
* in="path",
|
||||||
|
* description="The Vendor Hashed ID",
|
||||||
|
* example="D2J234DFA",
|
||||||
|
* required=true,
|
||||||
|
* @OA\Schema(
|
||||||
|
* type="string",
|
||||||
|
* format="string",
|
||||||
|
* ),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Returns the Vendor object",
|
||||||
|
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Vendor"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=422,
|
||||||
|
* description="Validation error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
|
||||||
|
*
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="Unexpected Error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Error"),
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function upload(UploadVendorRequest $request, Vendor $vendor)
|
||||||
|
{
|
||||||
|
|
||||||
|
if ($request->has('documents'))
|
||||||
|
$this->saveDocuments($request->file('documents'), $vendor);
|
||||||
|
|
||||||
|
return $this->itemResponse($vendor->fresh());
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ class CreditsTable extends Component
|
|||||||
{
|
{
|
||||||
$query = Credit::query()
|
$query = Credit::query()
|
||||||
->where('client_id', auth('contact')->user()->client->id)
|
->where('client_id', auth('contact')->user()->client->id)
|
||||||
|
->where('status_id', '<>', Credit::STATUS_DRAFT)
|
||||||
->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc')
|
->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc')
|
||||||
->paginate($this->per_page);
|
->paginate($this->per_page);
|
||||||
|
|
||||||
|
@ -25,38 +25,15 @@ class DocumentsTable extends Component
|
|||||||
|
|
||||||
public $per_page = 10;
|
public $per_page = 10;
|
||||||
|
|
||||||
public $status = [
|
|
||||||
'resources',
|
|
||||||
];
|
|
||||||
|
|
||||||
public function mount($client)
|
public function mount($client)
|
||||||
{
|
{
|
||||||
$this->client = $client;
|
$this->client = $client;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function statusChange($status)
|
|
||||||
{
|
|
||||||
if (in_array($status, $this->status)) {
|
|
||||||
return $this->status = array_diff($this->status, [$status]);
|
|
||||||
}
|
|
||||||
|
|
||||||
array_push($this->status, $status);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function render()
|
public function render()
|
||||||
{
|
{
|
||||||
$query = $this->client->documents();
|
$query = $this->client
|
||||||
|
->documents()
|
||||||
if (in_array('resources', $this->status) && ! in_array('client', $this->status)) {
|
|
||||||
$query = $query->where('documentable_type', '!=', Client::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (in_array('client', $this->status) && ! in_array('resources', $this->status)) {
|
|
||||||
$query = $query->where('documentable_type', Client::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
$query = $query
|
|
||||||
->where('is_public', true)
|
|
||||||
->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc')
|
->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc')
|
||||||
->paginate($this->per_page);
|
->paginate($this->per_page);
|
||||||
|
|
||||||
|
34
app/Http/Livewire/PayNowDropdown.php
Normal file
34
app/Http/Livewire/PayNowDropdown.php
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Livewire;
|
||||||
|
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class PayNowDropdown extends Component
|
||||||
|
{
|
||||||
|
public $total;
|
||||||
|
|
||||||
|
public $methods;
|
||||||
|
|
||||||
|
public function mount(int $total)
|
||||||
|
{
|
||||||
|
$this->total = $total;
|
||||||
|
|
||||||
|
$this->methods = auth()->user()->client->service()->getPaymentMethods($total);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return render('components.livewire.pay-now-dropdown');
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
namespace App\Http\Middleware;
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use App\Models\Account;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
|
use App\Utils\Ninja;
|
||||||
use Closure;
|
use Closure;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
@ -17,29 +19,39 @@ class ContactRegister
|
|||||||
*/
|
*/
|
||||||
public function handle($request, Closure $next)
|
public function handle($request, Closure $next)
|
||||||
{
|
{
|
||||||
/*
|
// Resolving based on subdomain. Used in version 5 hosted platform.
|
||||||
* Notes:
|
|
||||||
*
|
|
||||||
* 1. If request supports subdomain (for hosted) check domain and continue request.
|
|
||||||
* 2. If request doesn't support subdomain and doesn' have company_key, abort
|
|
||||||
* 3. firstOrFail() will abort with 404 if company with company_key wasn't found.
|
|
||||||
* 4. Abort if setting isn't enabled.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if ($request->subdomain) {
|
if ($request->subdomain) {
|
||||||
$company = Company::where('subdomain', $request->subdomain)->firstOrFail();
|
$company = Company::where('subdomain', $request->subdomain)->firstOrFail();
|
||||||
|
|
||||||
abort_unless($company->getSetting('enable_client_registration'), 404);
|
abort_unless($company->getSetting('enable_client_registration'), 404);
|
||||||
|
|
||||||
|
$request->merge(['key' => $company->company_key]);
|
||||||
|
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
|
|
||||||
abort_unless($request->company_key, 404);
|
// For self-hosted platforms with multiple companies, resolving is done using company key
|
||||||
|
// if it doesn't resolve using a domain.
|
||||||
|
if ($request->route()->parameter('company_key') && Ninja::isSelfHost()) {
|
||||||
$company = Company::where('company_key', $request->company_key)->firstOrFail();
|
$company = Company::where('company_key', $request->company_key)->firstOrFail();
|
||||||
|
|
||||||
abort_unless($company->client_can_register, 404);
|
abort_unless($company->client_can_register, 404);
|
||||||
|
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// As a fallback for self-hosted, it will use default company in the system
|
||||||
|
// if key isn't provided in the url.
|
||||||
|
if (!$request->route()->parameter('company_key') && Ninja::isSelfHost()) {
|
||||||
|
$company = Account::first()->default_company;
|
||||||
|
|
||||||
|
abort_unless($company->client_can_register, 404);
|
||||||
|
|
||||||
|
$request->merge(['key' => $company->company_key]);
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
return abort(404);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
39
app/Http/Requests/Client/UploadClientRequest.php
Normal file
39
app/Http/Requests/Client/UploadClientRequest.php
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Client;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
|
||||||
|
class UploadClientRequest extends Request
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize() : bool
|
||||||
|
{
|
||||||
|
return auth()->user()->can('edit', $this->client);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
|
||||||
|
$rules = [];
|
||||||
|
|
||||||
|
if($this->input('documents'))
|
||||||
|
$rules['documents'] = 'file|mimes:html,csv,png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:2000000';
|
||||||
|
|
||||||
|
return $rules;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -27,7 +27,8 @@ class ShowDocumentRequest extends FormRequest
|
|||||||
*/
|
*/
|
||||||
public function authorize()
|
public function authorize()
|
||||||
{
|
{
|
||||||
return auth()->user('contact')->client->id == $this->document->documentable_id;
|
return auth()->user('contact')->client->id == $this->document->documentable_id
|
||||||
|
|| $this->document->documentable->client_id == auth()->user('contact')->client->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
39
app/Http/Requests/Company/UploadCompanyRequest.php
Normal file
39
app/Http/Requests/Company/UploadCompanyRequest.php
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Company;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
|
||||||
|
class UploadCompanyRequest extends Request
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize() : bool
|
||||||
|
{
|
||||||
|
return auth()->user()->can('edit', $this->company);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
|
||||||
|
$rules = [];
|
||||||
|
|
||||||
|
if($this->input('documents'))
|
||||||
|
$rules['documents'] = 'file|mimes:png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:20000';
|
||||||
|
|
||||||
|
return $rules;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
39
app/Http/Requests/Credit/UploadCreditRequest.php
Normal file
39
app/Http/Requests/Credit/UploadCreditRequest.php
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Credit;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
|
||||||
|
class UploadCreditRequest extends Request
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize() : bool
|
||||||
|
{
|
||||||
|
return auth()->user()->can('edit', $this->credit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
|
||||||
|
$rules = [];
|
||||||
|
|
||||||
|
if($this->input('documents'))
|
||||||
|
$rules['documents'] = 'file|mimes:html,csv,png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:2000000';
|
||||||
|
|
||||||
|
return $rules;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
39
app/Http/Requests/Expense/UploadExpenseRequest.php
Normal file
39
app/Http/Requests/Expense/UploadExpenseRequest.php
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Expense;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
|
||||||
|
class UploadExpenseRequest extends Request
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize() : bool
|
||||||
|
{
|
||||||
|
return auth()->user()->can('edit', $this->expense);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
|
||||||
|
$rules = [];
|
||||||
|
|
||||||
|
if($this->input('documents'))
|
||||||
|
$rules['documents'] = 'file|mimes:html,csv,png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:2000000';
|
||||||
|
|
||||||
|
return $rules;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -28,10 +28,12 @@ class ImportRequest extends Request
|
|||||||
public function rules()
|
public function rules()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'hash' => 'required|string',
|
'import_type' => 'required',
|
||||||
'entity_type' => 'required|string',
|
'files' => 'required_without:hash|array|min:1|max:6',
|
||||||
'column_map' => 'required|array',
|
'hash' => 'nullable|string',
|
||||||
'skip_header' => 'required|boolean'
|
'column_map' => 'required_with:hash|array',
|
||||||
|
'skip_header' => 'required_with:hash|boolean',
|
||||||
|
'files.*' => 'file|mimes:csv,txt',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,8 +28,9 @@ class PreImportRequest extends Request
|
|||||||
public function rules()
|
public function rules()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'file' => 'required|file|mimes:csv,txt',
|
'files.*' => 'file|mimes:csv,txt',
|
||||||
'entity_type' => 'required',
|
'files' => 'required|array|min:1|max:6',
|
||||||
|
'import_type' => 'required',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
39
app/Http/Requests/Invoice/UploadInvoiceRequest.php
Normal file
39
app/Http/Requests/Invoice/UploadInvoiceRequest.php
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Invoice;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
|
||||||
|
class UploadInvoiceRequest extends Request
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize() : bool
|
||||||
|
{
|
||||||
|
return auth()->user()->can('edit', $this->invoice);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
|
||||||
|
$rules = [];
|
||||||
|
|
||||||
|
if($this->input('documents'))
|
||||||
|
$rules['documents'] = 'file|mimes:html,csv,png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:2000000';
|
||||||
|
|
||||||
|
return $rules;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
39
app/Http/Requests/Payment/UploadPaymentRequest.php
Normal file
39
app/Http/Requests/Payment/UploadPaymentRequest.php
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Payment Ninja (https://paymentninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/paymentninja/paymentninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Payment Ninja LLC (https://paymentninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Payment;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
|
||||||
|
class UploadPaymentRequest extends Request
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize() : bool
|
||||||
|
{
|
||||||
|
return auth()->user()->can('edit', $this->payment);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
|
||||||
|
$rules = [];
|
||||||
|
|
||||||
|
if($this->input('documents'))
|
||||||
|
$rules['documents'] = 'file|mimes:html,csv,png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:2000000';
|
||||||
|
|
||||||
|
return $rules;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
39
app/Http/Requests/Product/UploadProductRequest.php
Normal file
39
app/Http/Requests/Product/UploadProductRequest.php
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Product Ninja (https://paymentninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/paymentninja/paymentninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Product Ninja LLC (https://paymentninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Product;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
|
||||||
|
class UploadProductRequest extends Request
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize() : bool
|
||||||
|
{
|
||||||
|
return auth()->user()->can('edit', $this->product);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
|
||||||
|
$rules = [];
|
||||||
|
|
||||||
|
if($this->input('documents'))
|
||||||
|
$rules['documents'] = 'file|mimes:html,csv,png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:2000000';
|
||||||
|
|
||||||
|
return $rules;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
39
app/Http/Requests/Project/UploadProjectRequest.php
Normal file
39
app/Http/Requests/Project/UploadProjectRequest.php
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Project Ninja (https://paymentninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/paymentninja/paymentninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Project Ninja LLC (https://paymentninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Project;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
|
||||||
|
class UploadProjectRequest extends Request
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize() : bool
|
||||||
|
{
|
||||||
|
return auth()->user()->can('edit', $this->project);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
|
||||||
|
$rules = [];
|
||||||
|
|
||||||
|
if($this->input('documents'))
|
||||||
|
$rules['documents'] = 'file|mimes:html,csv,png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:2000000';
|
||||||
|
|
||||||
|
return $rules;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
39
app/Http/Requests/Quote/UploadQuoteRequest.php
Normal file
39
app/Http/Requests/Quote/UploadQuoteRequest.php
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Quote Ninja (https://paymentninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/paymentninja/paymentninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Quote Ninja LLC (https://paymentninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Quote;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
|
||||||
|
class UploadQuoteRequest extends Request
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize() : bool
|
||||||
|
{
|
||||||
|
return auth()->user()->can('edit', $this->quote);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
|
||||||
|
$rules = [];
|
||||||
|
|
||||||
|
if($this->input('documents'))
|
||||||
|
$rules['documents'] = 'file|mimes:html,csv,png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:2000000';
|
||||||
|
|
||||||
|
return $rules;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Quote Ninja (https://paymentninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/paymentninja/paymentninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Quote Ninja LLC (https://paymentninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Requests\RecurringInvoice;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
|
||||||
|
class UploadRecurringInvoiceRequest extends Request
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize() : bool
|
||||||
|
{
|
||||||
|
return auth()->user()->can('edit', $this->recurring_invoice);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
|
||||||
|
$rules = [];
|
||||||
|
|
||||||
|
if($this->input('documents'))
|
||||||
|
$rules['documents'] = 'file|mimes:html,csv,png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:2000000';
|
||||||
|
|
||||||
|
return $rules;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
39
app/Http/Requests/Task/UploadTaskRequest.php
Normal file
39
app/Http/Requests/Task/UploadTaskRequest.php
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Quote Ninja (https://paymentninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/paymentninja/paymentninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Quote Ninja LLC (https://paymentninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Task;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
|
||||||
|
class UploadTaskRequest extends Request
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize() : bool
|
||||||
|
{
|
||||||
|
return auth()->user()->can('edit', $this->task);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
|
||||||
|
$rules = [];
|
||||||
|
|
||||||
|
if($this->input('documents'))
|
||||||
|
$rules['documents'] = 'file|mimes:html,csv,png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:2000000';
|
||||||
|
|
||||||
|
return $rules;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
28
app/Http/Requests/User/ReconfirmUserRequest.php
Normal file
28
app/Http/Requests/User/ReconfirmUserRequest.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Requests\User;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
use App\Models\User;
|
||||||
|
|
||||||
|
class ReconfirmUserRequest extends Request
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize() : bool
|
||||||
|
{
|
||||||
|
return auth()->user()->Admin();
|
||||||
|
}
|
||||||
|
}
|
39
app/Http/Requests/Vendor/UploadVendorRequest.php
vendored
Normal file
39
app/Http/Requests/Vendor/UploadVendorRequest.php
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Quote Ninja (https://paymentninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/paymentninja/paymentninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Quote Ninja LLC (https://paymentninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Vendor;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
|
||||||
|
class UploadVendorRequest extends Request
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize() : bool
|
||||||
|
{
|
||||||
|
return auth()->user()->can('edit', $this->vendor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
|
||||||
|
$rules = [];
|
||||||
|
|
||||||
|
if($this->input('documents'))
|
||||||
|
$rules['documents'] = 'file|mimes:html,csv,png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:2000000';
|
||||||
|
|
||||||
|
return $rules;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -57,6 +57,7 @@ class PortalComposer
|
|||||||
$data['client'] = auth()->user()->client;
|
$data['client'] = auth()->user()->client;
|
||||||
$data['settings'] = $this->settings;
|
$data['settings'] = $this->settings;
|
||||||
$data['currencies'] = TranslationHelper::getCurrencies();
|
$data['currencies'] = TranslationHelper::getCurrencies();
|
||||||
|
$data['contact'] = auth('contact')->user();
|
||||||
|
|
||||||
$data['multiple_contacts'] = session()->get('multiple_contacts');
|
$data['multiple_contacts'] = session()->get('multiple_contacts');
|
||||||
|
|
||||||
@ -69,8 +70,8 @@ class PortalComposer
|
|||||||
|
|
||||||
//@todo wire this back in when we are happy with dashboard.
|
//@todo wire this back in when we are happy with dashboard.
|
||||||
// if($this->settings->enable_client_portal_dashboard == TRUE)
|
// if($this->settings->enable_client_portal_dashboard == TRUE)
|
||||||
// $data[] = [ 'title' => ctrans('texts.dashboard'), 'url' => 'client.dashboard', 'icon' => 'activity'];
|
|
||||||
|
|
||||||
|
// $data[] = [ 'title' => ctrans('texts.dashboard'), 'url' => 'client.dashboard', 'icon' => 'activity'];
|
||||||
$data[] = ['title' => ctrans('texts.invoices'), 'url' => 'client.invoices.index', 'icon' => 'file-text'];
|
$data[] = ['title' => ctrans('texts.invoices'), 'url' => 'client.invoices.index', 'icon' => 'file-text'];
|
||||||
$data[] = ['title' => ctrans('texts.recurring_invoices'), 'url' => 'client.recurring_invoices.index', 'icon' => 'file'];
|
$data[] = ['title' => ctrans('texts.recurring_invoices'), 'url' => 'client.recurring_invoices.index', 'icon' => 'file'];
|
||||||
$data[] = ['title' => ctrans('texts.payments'), 'url' => 'client.payments.index', 'icon' => 'credit-card'];
|
$data[] = ['title' => ctrans('texts.payments'), 'url' => 'client.payments.index', 'icon' => 'credit-card'];
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* client Ninja (https://clientninja.com).
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
*
|
*
|
||||||
* @link https://github.com/clientninja/clientninja source repository
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
*
|
*
|
||||||
* @copyright Copyright (c) 2021. client Ninja LLC (https://clientninja.com)
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
*
|
*
|
||||||
* @license https://opensource.org/licenses/AAL
|
* @license https://opensource.org/licenses/AAL
|
||||||
*/
|
*/
|
||||||
|
51
app/Import/Definitions/ExpenseMap.php
Normal file
51
app/Import/Definitions/ExpenseMap.php
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* client Ninja (https://clientninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/clientninja/clientninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. client Ninja LLC (https://clientninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Import\Definitions;
|
||||||
|
|
||||||
|
class ExpenseMap
|
||||||
|
{
|
||||||
|
public static function importable()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
0 => 'expense.vendor',
|
||||||
|
1 => 'expense.client',
|
||||||
|
2 => 'expense.project',
|
||||||
|
3 => 'expense.category',
|
||||||
|
4 => 'expense.amount',
|
||||||
|
5 => 'expense.currency',
|
||||||
|
6 => 'expense.date',
|
||||||
|
7 => 'expense.payment_type',
|
||||||
|
8 => 'expense.payment_date',
|
||||||
|
9 => 'expense.transaction_reference',
|
||||||
|
10 => 'expense.public_notes',
|
||||||
|
11 => 'expense.private_notes',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function import_keys()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
0 => 'texts.vendor',
|
||||||
|
1 => 'texts.client',
|
||||||
|
2 => 'texts.project',
|
||||||
|
3 => 'texts.category',
|
||||||
|
4 => 'texts.amount',
|
||||||
|
5 => 'texts.currency',
|
||||||
|
6 => 'texts.date',
|
||||||
|
7 => 'texts.payment_type',
|
||||||
|
8 => 'texts.payment_date',
|
||||||
|
9 => 'texts.transaction_reference',
|
||||||
|
10 => 'texts.public_notes',
|
||||||
|
11 => 'texts.private_notes',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -26,50 +26,51 @@ class InvoiceMap
|
|||||||
7 => 'invoice.date',
|
7 => 'invoice.date',
|
||||||
8 => 'invoice.due_date',
|
8 => 'invoice.due_date',
|
||||||
9 => 'invoice.terms',
|
9 => 'invoice.terms',
|
||||||
10 => 'invoice.public_notes',
|
10 => 'invoice.status',
|
||||||
11 => 'invoice.is_sent',
|
11 => 'invoice.public_notes',
|
||||||
12 => 'invoice.private_notes',
|
12 => 'invoice.is_sent',
|
||||||
13 => 'invoice.uses_inclusive_taxes',
|
13 => 'invoice.private_notes',
|
||||||
14 => 'invoice.tax_name1',
|
14 => 'invoice.uses_inclusive_taxes',
|
||||||
15 => 'invoice.tax_rate1',
|
15 => 'invoice.tax_name1',
|
||||||
16 => 'invoice.tax_name2',
|
16 => 'invoice.tax_rate1',
|
||||||
17 => 'invoice.tax_rate2',
|
17 => 'invoice.tax_name2',
|
||||||
18 => 'invoice.tax_name3',
|
18 => 'invoice.tax_rate2',
|
||||||
19 => 'invoice.tax_rate3',
|
19 => 'invoice.tax_name3',
|
||||||
20 => 'invoice.is_amount_discount',
|
20 => 'invoice.tax_rate3',
|
||||||
21 => 'invoice.footer',
|
21 => 'invoice.is_amount_discount',
|
||||||
22 => 'invoice.partial',
|
22 => 'invoice.footer',
|
||||||
23 => 'invoice.partial_due_date',
|
23 => 'invoice.partial',
|
||||||
24 => 'invoice.custom_value1',
|
24 => 'invoice.partial_due_date',
|
||||||
25 => 'invoice.custom_value2',
|
25 => 'invoice.custom_value1',
|
||||||
26 => 'invoice.custom_value3',
|
26 => 'invoice.custom_value2',
|
||||||
27 => 'invoice.custom_value4',
|
27 => 'invoice.custom_value3',
|
||||||
28 => 'invoice.custom_surcharge1',
|
28 => 'invoice.custom_value4',
|
||||||
29 => 'invoice.custom_surcharge2',
|
29 => 'invoice.custom_surcharge1',
|
||||||
30 => 'invoice.custom_surcharge3',
|
30 => 'invoice.custom_surcharge2',
|
||||||
31 => 'invoice.custom_surcharge4',
|
31 => 'invoice.custom_surcharge3',
|
||||||
32 => 'invoice.exchange_rate',
|
32 => 'invoice.custom_surcharge4',
|
||||||
33 => 'payment.date',
|
33 => 'invoice.exchange_rate',
|
||||||
34 => 'payment.amount',
|
34 => 'payment.date',
|
||||||
35 => 'payment.transaction_reference',
|
35 => 'payment.amount',
|
||||||
36 => 'item.quantity',
|
36 => 'payment.transaction_reference',
|
||||||
37 => 'item.cost',
|
37 => 'item.quantity',
|
||||||
38 => 'item.product_key',
|
38 => 'item.cost',
|
||||||
39 => 'item.notes',
|
39 => 'item.product_key',
|
||||||
40 => 'item.discount',
|
40 => 'item.notes',
|
||||||
41 => 'item.is_amount_discount',
|
41 => 'item.discount',
|
||||||
42 => 'item.tax_name1',
|
42 => 'item.is_amount_discount',
|
||||||
43 => 'item.tax_rate1',
|
43 => 'item.tax_name1',
|
||||||
44 => 'item.tax_name2',
|
44 => 'item.tax_rate1',
|
||||||
45 => 'item.tax_rate2',
|
45 => 'item.tax_name2',
|
||||||
46 => 'item.tax_name3',
|
46 => 'item.tax_rate2',
|
||||||
47 => 'item.tax_rate3',
|
47 => 'item.tax_name3',
|
||||||
48 => 'item.custom_value1',
|
48 => 'item.tax_rate3',
|
||||||
49 => 'item.custom_value2',
|
49 => 'item.custom_value1',
|
||||||
50 => 'item.custom_value3',
|
50 => 'item.custom_value2',
|
||||||
51 => 'item.custom_value4',
|
51 => 'item.custom_value3',
|
||||||
52 => 'item.type_id',
|
52 => 'item.custom_value4',
|
||||||
53 => 'client.email',
|
53 => 'item.type_id',
|
||||||
|
54 => 'client.email',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,50 +87,51 @@ class InvoiceMap
|
|||||||
7 => 'texts.date',
|
7 => 'texts.date',
|
||||||
8 => 'texts.due_date',
|
8 => 'texts.due_date',
|
||||||
9 => 'texts.terms',
|
9 => 'texts.terms',
|
||||||
10 => 'texts.public_notes',
|
10 => 'texts.status',
|
||||||
11 => 'texts.sent',
|
11 => 'texts.public_notes',
|
||||||
12 => 'texts.private_notes',
|
12 => 'texts.sent',
|
||||||
13 => 'texts.uses_inclusive_taxes',
|
13 => 'texts.private_notes',
|
||||||
14 => 'texts.tax_name',
|
14 => 'texts.uses_inclusive_taxes',
|
||||||
15 => 'texts.tax_rate',
|
15 => 'texts.tax_name',
|
||||||
16 => 'texts.tax_name',
|
16 => 'texts.tax_rate',
|
||||||
17 => 'texts.tax_rate',
|
17 => 'texts.tax_name',
|
||||||
18 => 'texts.tax_name',
|
18 => 'texts.tax_rate',
|
||||||
19 => 'texts.tax_rate',
|
19 => 'texts.tax_name',
|
||||||
20 => 'texts.is_amount_discount',
|
20 => 'texts.tax_rate',
|
||||||
21 => 'texts.footer',
|
21 => 'texts.is_amount_discount',
|
||||||
22 => 'texts.partial',
|
22 => 'texts.footer',
|
||||||
23 => 'texts.partial_due_date',
|
23 => 'texts.partial',
|
||||||
24 => 'texts.custom_value1',
|
24 => 'texts.partial_due_date',
|
||||||
25 => 'texts.custom_value2',
|
25 => 'texts.custom_value1',
|
||||||
26 => 'texts.custom_value3',
|
26 => 'texts.custom_value2',
|
||||||
27 => 'texts.custom_value4',
|
27 => 'texts.custom_value3',
|
||||||
28 => 'texts.surcharge',
|
28 => 'texts.custom_value4',
|
||||||
29 => 'texts.surcharge',
|
29 => 'texts.surcharge',
|
||||||
30 => 'texts.surcharge',
|
30 => 'texts.surcharge',
|
||||||
31 => 'texts.surcharge',
|
31 => 'texts.surcharge',
|
||||||
32 => 'texts.exchange_rate',
|
32 => 'texts.surcharge',
|
||||||
33 => 'texts.payment_date',
|
33 => 'texts.exchange_rate',
|
||||||
34 => 'texts.payment_amount',
|
34 => 'texts.payment_date',
|
||||||
35 => 'texts.transaction_reference',
|
35 => 'texts.payment_amount',
|
||||||
36 => 'texts.quantity',
|
36 => 'texts.transaction_reference',
|
||||||
37 => 'texts.cost',
|
37 => 'texts.quantity',
|
||||||
38 => 'texts.product_key',
|
38 => 'texts.cost',
|
||||||
39 => 'texts.notes',
|
39 => 'texts.product_key',
|
||||||
40 => 'texts.discount',
|
40 => 'texts.notes',
|
||||||
41 => 'texts.is_amount_discount',
|
41 => 'texts.discount',
|
||||||
42 => 'texts.tax_name',
|
42 => 'texts.is_amount_discount',
|
||||||
43 => 'texts.tax_rate',
|
43 => 'texts.tax_name',
|
||||||
44 => 'texts.tax_name',
|
44 => 'texts.tax_rate',
|
||||||
45 => 'texts.tax_rate',
|
45 => 'texts.tax_name',
|
||||||
46 => 'texts.tax_name',
|
46 => 'texts.tax_rate',
|
||||||
47 => 'texts.tax_rate',
|
47 => 'texts.tax_name',
|
||||||
48 => 'texts.custom_value',
|
48 => 'texts.tax_rate',
|
||||||
49 => 'texts.custom_value',
|
49 => 'texts.custom_value',
|
||||||
50 => 'texts.custom_value',
|
50 => 'texts.custom_value',
|
||||||
51 => 'texts.custom_value',
|
51 => 'texts.custom_value',
|
||||||
52 => 'texts.type',
|
52 => 'texts.custom_value',
|
||||||
53 => 'texts.email',
|
53 => 'texts.type',
|
||||||
|
54 => 'texts.email',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* client Ninja (https://clientninja.com).
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
*
|
*
|
||||||
* @link https://github.com/clientninja/clientninja source repository
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
*
|
*
|
||||||
* @copyright Copyright (c) 2021. client Ninja LLC (https://clientninja.com)
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
*
|
*
|
||||||
* @license https://opensource.org/licenses/AAL
|
* @license https://opensource.org/licenses/AAL
|
||||||
*/
|
*/
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* client Ninja (https://clientninja.com).
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
*
|
*
|
||||||
* @link https://github.com/clientninja/clientninja source repository
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
*
|
*
|
||||||
* @copyright Copyright (c) 2021. client Ninja LLC (https://clientninja.com)
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
*
|
*
|
||||||
* @license https://opensource.org/licenses/AAL
|
* @license https://opensource.org/licenses/AAL
|
||||||
*/
|
*/
|
||||||
|
61
app/Import/Definitions/VendorMap.php
Normal file
61
app/Import/Definitions/VendorMap.php
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* client Ninja (https://clientninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/clientninja/clientninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. client Ninja LLC (https://clientninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Import\Definitions;
|
||||||
|
|
||||||
|
class VendorMap
|
||||||
|
{
|
||||||
|
public static function importable()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
0 => 'vendor.name',
|
||||||
|
1 => 'vendor.phone',
|
||||||
|
2 => 'vendor.id_number',
|
||||||
|
3 => 'vendor.vat_number',
|
||||||
|
4 => 'vendor.website',
|
||||||
|
5 => 'vendor.first_name',
|
||||||
|
6 => 'vendor.last_name',
|
||||||
|
7 => 'vendor.email',
|
||||||
|
8 => 'vendor.currency_id',
|
||||||
|
9 => 'vendor.public_notes',
|
||||||
|
10 => 'vendor.private_notes',
|
||||||
|
11 => 'vendor.address1',
|
||||||
|
12 => 'vendor.address2',
|
||||||
|
13 => 'vendor.city',
|
||||||
|
14 => 'vendor.state',
|
||||||
|
15 => 'vendor.postal_code',
|
||||||
|
16 => 'vendor.country_id',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function import_keys()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
0 => 'texts.name',
|
||||||
|
1 => 'texts.phone',
|
||||||
|
2 => 'texts.id_number',
|
||||||
|
3 => 'texts.vat_number',
|
||||||
|
4 => 'texts.website',
|
||||||
|
5 => 'texts.first_name',
|
||||||
|
6 => 'texts.last_name',
|
||||||
|
7 => 'texts.email',
|
||||||
|
8 => 'texts.currency',
|
||||||
|
9 => 'texts.public_notes',
|
||||||
|
10 => 'texts.private_notes',
|
||||||
|
11 => 'texts.address1',
|
||||||
|
12 => 'texts.address2',
|
||||||
|
13 => 'texts.city',
|
||||||
|
14 => 'texts.state',
|
||||||
|
15 => 'texts.postal_code',
|
||||||
|
16 => 'texts.country',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
6
app/Import/ImportException.php
Normal file
6
app/Import/ImportException.php
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Import;
|
||||||
|
|
||||||
|
class ImportException extends \Exception{
|
||||||
|
|
||||||
|
}
|
@ -1,10 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* client Ninja (https://clientninja.com).
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
*
|
*
|
||||||
* @link https://github.com/clientninja/clientninja source repository
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
*
|
*
|
||||||
* @copyright Copyright (c) 2021. client Ninja LLC (https://clientninja.com)
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
*
|
*
|
||||||
* @license https://opensource.org/licenses/AAL
|
* @license https://opensource.org/licenses/AAL
|
||||||
*/
|
*/
|
||||||
@ -53,23 +53,13 @@ class BaseTransformer
|
|||||||
return (isset($data[$field]) && $data[$field]) ? $data[$field] : '1';
|
return (isset($data[$field]) && $data[$field]) ? $data[$field] : '1';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCurrencyByCode($data)
|
public function getCurrencyByCode( $data, $key = 'client.currency_id' ) {
|
||||||
{
|
$code = array_key_exists( $key, $data ) ? $data[ $key ] : false;
|
||||||
$code = array_key_exists('client.currency_id', $data) ? $data['client.currency_id'] : false;
|
|
||||||
|
|
||||||
if ($code) {
|
return $this->maps['currencies'][ $code ] ?? $this->maps['company']->settings->currency_id;
|
||||||
$currency = $this->maps['currencies']->where('code', $code)->first();
|
|
||||||
|
|
||||||
if ($currency) {
|
|
||||||
return $currency->id;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->maps['company']->settings->currency_id;
|
public function getClient($client_name, $client_email) {
|
||||||
}
|
|
||||||
|
|
||||||
public function getClient($client_name, $client_email)
|
|
||||||
{
|
|
||||||
$clients = $this->maps['company']->clients;
|
$clients = $this->maps['company']->clients;
|
||||||
|
|
||||||
$clients = $clients->where( 'name', $client_name );
|
$clients = $clients->where( 'name', $client_name );
|
||||||
@ -78,13 +68,14 @@ class BaseTransformer
|
|||||||
return $clients->first()->id;
|
return $clients->first()->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( ! empty( $client_email ) ) {
|
||||||
$contacts = ClientContact::where( 'company_id', $this->maps['company']->id )
|
$contacts = ClientContact::where( 'company_id', $this->maps['company']->id )
|
||||||
->where( 'email', $client_email );
|
->where( 'email', $client_email );
|
||||||
|
|
||||||
if ( $contacts->count() >= 1 ) {
|
if ( $contacts->count() >= 1 ) {
|
||||||
return $contacts->first()->client_id;
|
return $contacts->first()->client_id;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -101,7 +92,7 @@ class BaseTransformer
|
|||||||
{
|
{
|
||||||
$name = trim(strtolower($name));
|
$name = trim(strtolower($name));
|
||||||
|
|
||||||
return isset($this->maps[ENTITY_CLIENT][$name]);
|
return isset( $this->maps['client'][ $name ] );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -113,7 +104,7 @@ class BaseTransformer
|
|||||||
{
|
{
|
||||||
$name = trim(strtolower($name));
|
$name = trim(strtolower($name));
|
||||||
|
|
||||||
return isset($this->maps[ENTITY_VENDOR][$name]);
|
return isset( $this->maps['vendor'][ $name ] );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -126,7 +117,7 @@ class BaseTransformer
|
|||||||
{
|
{
|
||||||
$key = trim(strtolower($key));
|
$key = trim(strtolower($key));
|
||||||
|
|
||||||
return isset($this->maps[ENTITY_PRODUCT][$key]);
|
return isset( $this->maps['product'][ $key ] );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -167,7 +158,7 @@ class BaseTransformer
|
|||||||
{
|
{
|
||||||
$name = strtolower(trim($name));
|
$name = strtolower(trim($name));
|
||||||
|
|
||||||
return isset($this->maps[ENTITY_CLIENT][$name]) ? $this->maps[ENTITY_CLIENT][$name] : null;
|
return isset( $this->maps['client'][ $name ] ) ? $this->maps['client'][ $name ] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -322,7 +313,7 @@ class BaseTransformer
|
|||||||
*/
|
*/
|
||||||
public function getInvoiceNumber($number)
|
public function getInvoiceNumber($number)
|
||||||
{
|
{
|
||||||
return $number ? str_pad(trim($number), 4, '0', STR_PAD_LEFT) : null;
|
return $number ? ltrim( trim( $number ), '0' ) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -334,7 +325,8 @@ class BaseTransformer
|
|||||||
{
|
{
|
||||||
$invoiceNumber = $this->getInvoiceNumber($invoiceNumber);
|
$invoiceNumber = $this->getInvoiceNumber($invoiceNumber);
|
||||||
$invoiceNumber = strtolower($invoiceNumber);
|
$invoiceNumber = strtolower($invoiceNumber);
|
||||||
return isset($this->maps[ENTITY_INVOICE][$invoiceNumber]) ? $this->maps[ENTITY_INVOICE][$invoiceNumber] : null;
|
|
||||||
|
return isset( $this->maps['invoice'][ $invoiceNumber ] ) ? $this->maps['invoice'][ $invoiceNumber ] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -346,7 +338,8 @@ class BaseTransformer
|
|||||||
{
|
{
|
||||||
$invoiceNumber = $this->getInvoiceNumber($invoiceNumber);
|
$invoiceNumber = $this->getInvoiceNumber($invoiceNumber);
|
||||||
$invoiceNumber = strtolower($invoiceNumber);
|
$invoiceNumber = strtolower($invoiceNumber);
|
||||||
return isset($this->maps['invoices'][$invoiceNumber]) ? $this->maps['invoices'][$invoiceNumber]->public_id : null;
|
|
||||||
|
return isset( $this->maps['invoice'][ $invoiceNumber ] ) ? $this->maps['invoices'][ $invoiceNumber ]->public_id : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -359,7 +352,7 @@ class BaseTransformer
|
|||||||
$invoiceNumber = $this->getInvoiceNumber($invoiceNumber);
|
$invoiceNumber = $this->getInvoiceNumber($invoiceNumber);
|
||||||
$invoiceNumber = strtolower($invoiceNumber);
|
$invoiceNumber = strtolower($invoiceNumber);
|
||||||
|
|
||||||
return isset($this->maps[ENTITY_INVOICE][$invoiceNumber]);
|
return $this->maps['invoice'][ $invoiceNumber ] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -372,7 +365,7 @@ class BaseTransformer
|
|||||||
$invoiceNumber = $this->getInvoiceNumber($invoiceNumber);
|
$invoiceNumber = $this->getInvoiceNumber($invoiceNumber);
|
||||||
$invoiceNumber = strtolower($invoiceNumber);
|
$invoiceNumber = strtolower($invoiceNumber);
|
||||||
|
|
||||||
return isset($this->maps[ENTITY_INVOICE.'_'.ENTITY_CLIENT][$invoiceNumber]) ? $this->maps[ENTITY_INVOICE.'_'.ENTITY_CLIENT][$invoiceNumber] : null;
|
return $this->maps['invoice_client'][ $invoiceNumber ] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -384,7 +377,7 @@ class BaseTransformer
|
|||||||
{
|
{
|
||||||
$name = strtolower(trim($name));
|
$name = strtolower(trim($name));
|
||||||
|
|
||||||
return isset($this->maps[ENTITY_VENDOR][$name]) ? $this->maps[ENTITY_VENDOR][$name] : null;
|
return $this->maps['vendor'][ $name ] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -392,10 +385,31 @@ class BaseTransformer
|
|||||||
*
|
*
|
||||||
* @return null
|
* @return null
|
||||||
*/
|
*/
|
||||||
public function getExpenseCategoryId($name)
|
public function getExpenseCategoryId( $name ) {
|
||||||
{
|
|
||||||
$name = strtolower( trim( $name ) );
|
$name = strtolower( trim( $name ) );
|
||||||
|
|
||||||
return isset($this->maps[ENTITY_EXPENSE_CATEGORY][$name]) ? $this->maps[ENTITY_EXPENSE_CATEGORY][$name] : null;
|
return $this->maps['expense_category'][ $name ] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $name
|
||||||
|
*
|
||||||
|
* @return null
|
||||||
|
*/
|
||||||
|
public function getProjectId( $name ) {
|
||||||
|
$name = strtolower( trim( $name ) );
|
||||||
|
|
||||||
|
return $this->maps['project'][ $name ] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $name
|
||||||
|
*
|
||||||
|
* @return null
|
||||||
|
*/
|
||||||
|
public function getPaymentTypeId( $name ) {
|
||||||
|
$name = strtolower( trim( $name ) );
|
||||||
|
|
||||||
|
return $this->maps['payment_type'][ $name ] ?? null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* client Ninja (https://clientninja.com).
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
*
|
*
|
||||||
* @link https://github.com/clientninja/clientninja source repository
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
*
|
*
|
||||||
* @copyright Copyright (c) 2021. client Ninja LLC (https://clientninja.com)
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
*
|
*
|
||||||
* @license https://opensource.org/licenses/AAL
|
* @license https://opensource.org/licenses/AAL
|
||||||
*/
|
*/
|
||||||
|
79
app/Import/Transformers/Csv/ClientTransformer.php
Normal file
79
app/Import/Transformers/Csv/ClientTransformer.php
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* client Ninja (https://clientninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/clientninja/clientninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. client Ninja LLC (https://clientninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Import\Transformers\Csv;
|
||||||
|
use App\Import\ImportException;
|
||||||
|
use App\Import\Transformers\BaseTransformer;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class ClientTransformer.
|
||||||
|
*/
|
||||||
|
class ClientTransformer extends BaseTransformer
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param $data
|
||||||
|
*
|
||||||
|
* @return array|bool
|
||||||
|
*/
|
||||||
|
public function transform($data)
|
||||||
|
{
|
||||||
|
if (isset($data->name) && $this->hasClient($data->name)) {
|
||||||
|
throw new ImportException('Client already exists');
|
||||||
|
}
|
||||||
|
|
||||||
|
$settings = new \stdClass;
|
||||||
|
$settings->currency_id = (string)$this->getCurrencyByCode($data);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'company_id' => $this->maps['company']->id,
|
||||||
|
'name' => $this->getString( $data, 'client.name' ),
|
||||||
|
'work_phone' => $this->getString( $data, 'client.phone' ),
|
||||||
|
'address1' => $this->getString( $data, 'client.address1' ),
|
||||||
|
'address2' => $this->getString( $data, 'client.address2' ),
|
||||||
|
'city' => $this->getString( $data, 'client.city' ),
|
||||||
|
'state' => $this->getString( $data, 'client.state' ),
|
||||||
|
'shipping_address1' => $this->getString( $data, 'client.shipping_address1' ),
|
||||||
|
'shipping_address2' => $this->getString( $data, 'client.shipping_address2' ),
|
||||||
|
'shipping_city' => $this->getString( $data, 'client.shipping_city' ),
|
||||||
|
'shipping_state' => $this->getString( $data, 'client.shipping_state' ),
|
||||||
|
'shipping_postal_code' => $this->getString( $data, 'client.shipping_postal_code' ),
|
||||||
|
'public_notes' => $this->getString( $data, 'client.public_notes' ),
|
||||||
|
'private_notes' => $this->getString( $data, 'client.private_notes' ),
|
||||||
|
'website' => $this->getString( $data, 'client.website' ),
|
||||||
|
'vat_number' => $this->getString( $data, 'client.vat_number' ),
|
||||||
|
'id_number' => $this->getString( $data, 'client.id_number' ),
|
||||||
|
'custom_value1' => $this->getString( $data, 'client.custom1' ),
|
||||||
|
'custom_value2' => $this->getString( $data, 'client.custom2' ),
|
||||||
|
'custom_value3' => $this->getString( $data, 'client.custom3' ),
|
||||||
|
'custom_value4' => $this->getString( $data, 'client.custom4' ),
|
||||||
|
'balance' => preg_replace( '/[^0-9,.]+/', '', $this->getFloat( $data, 'client.balance' ) ),
|
||||||
|
'paid_to_date' => preg_replace( '/[^0-9,.]+/', '', $this->getFloat( $data, 'client.paid_to_date' ) ),
|
||||||
|
'credit_balance' => 0,
|
||||||
|
'settings' => $settings,
|
||||||
|
'client_hash' => Str::random( 40 ),
|
||||||
|
'contacts' => [
|
||||||
|
[
|
||||||
|
'first_name' => $this->getString( $data, 'contact.first_name' ),
|
||||||
|
'last_name' => $this->getString( $data, 'contact.last_name' ),
|
||||||
|
'email' => $this->getString( $data, 'contact.email' ),
|
||||||
|
'phone' => $this->getString( $data, 'contact.phone' ),
|
||||||
|
'custom_value1' => $this->getString( $data, 'contact.custom1' ),
|
||||||
|
'custom_value2' => $this->getString( $data, 'contact.custom2' ),
|
||||||
|
'custom_value3' => $this->getString( $data, 'contact.custom3' ),
|
||||||
|
'custom_value4' => $this->getString( $data, 'contact.custom4' ),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'country_id' => isset( $data['client.country'] ) ? $this->getCountryId( $data['client.country']) : null,
|
||||||
|
'shipping_country_id' => isset($data['client.shipping_country'] ) ? $this->getCountryId( $data['client.shipping_country'] ) : null,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
36
app/Import/Transformers/Csv/ExpenseTransformer.php
Normal file
36
app/Import/Transformers/Csv/ExpenseTransformer.php
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Import\Transformers\Csv;
|
||||||
|
|
||||||
|
use App\Import\Transformers\BaseTransformer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class InvoiceTransformer.
|
||||||
|
*/
|
||||||
|
class ExpenseTransformer extends BaseTransformer {
|
||||||
|
/**
|
||||||
|
* @param $data
|
||||||
|
*
|
||||||
|
* @return bool|array
|
||||||
|
*/
|
||||||
|
public function transform( $data ) {
|
||||||
|
$clientId = isset( $data['expense.client'] ) ? $this->getClientId( $data['expense.client'] ) : null;
|
||||||
|
|
||||||
|
return [
|
||||||
|
'company_id' => $this->maps['company']->id,
|
||||||
|
'amount' => $this->getFloat( $data, 'expense.amount' ),
|
||||||
|
'currency_id' => $this->getCurrencyByCode( $data, 'expense.currency_id' ),
|
||||||
|
'vendor_id' => isset( $data['expense.vendor'] ) ? $this->getVendorId( $data['expense.vendor'] ) : null,
|
||||||
|
'client_id' => isset( $data['expense.client'] ) ? $this->getClientId( $data['expense.client'] ) : null,
|
||||||
|
'expense_date' => isset( $data['expense.date'] ) ? date( 'Y-m-d', strtotime( $data['expense.date'] ) ) : null,
|
||||||
|
'public_notes' => $this->getString( $data, 'expense.public_notes' ),
|
||||||
|
'private_notes' => $this->getString( $data, 'expense.private_notes' ),
|
||||||
|
'expense_category_id' => isset( $data['expense.category'] ) ? $this->getExpenseCategoryId( $data['expense.category'] ) : null,
|
||||||
|
'project_id' => isset( $data['expense.project'] ) ? $this->getProjectId( $data['expense.project'] ) : null,
|
||||||
|
'payment_type_id' => isset( $data['expense.payment_type'] ) ? $this->getPaymentTypeId( $data['expense.payment_type'] ) : null,
|
||||||
|
'payment_date' => isset( $data['expense.payment_date'] ) ? date( 'Y-m-d', strtotime( $data['expense.payment_date'] ) ) : null,
|
||||||
|
'transaction_reference' => $this->getString( $data, 'expense.transaction_reference' ),
|
||||||
|
'should_be_invoiced' => $clientId ? true : false,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
131
app/Import/Transformers/Csv/InvoiceTransformer.php
Normal file
131
app/Import/Transformers/Csv/InvoiceTransformer.php
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* client Ninja (https://clientninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/clientninja/clientninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. client Ninja LLC (https://clientninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Import\Transformers\Csv;
|
||||||
|
|
||||||
|
use App\Import\ImportException;
|
||||||
|
use App\Import\Transformers\BaseTransformer;
|
||||||
|
use App\Models\Invoice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class InvoiceTransformer.
|
||||||
|
*/
|
||||||
|
class InvoiceTransformer extends BaseTransformer {
|
||||||
|
/**
|
||||||
|
* @param $data
|
||||||
|
*
|
||||||
|
* @return bool|array
|
||||||
|
*/
|
||||||
|
public function transform( $line_items_data ) {
|
||||||
|
$invoice_data = reset( $line_items_data );
|
||||||
|
|
||||||
|
if ( $this->hasInvoice( $invoice_data['invoice.number'] ) ) {
|
||||||
|
throw new ImportException( 'Invoice number already exists' );
|
||||||
|
}
|
||||||
|
|
||||||
|
$invoiceStatusMap = [
|
||||||
|
'sent' => Invoice::STATUS_SENT,
|
||||||
|
'draft' => Invoice::STATUS_DRAFT,
|
||||||
|
];
|
||||||
|
|
||||||
|
$transformed = [
|
||||||
|
'company_id' => $this->maps['company']->id,
|
||||||
|
'number' => $this->getString( $invoice_data, 'invoice.number' ),
|
||||||
|
'user_id' => $this->getString( $invoice_data, 'invoice.user_id' ),
|
||||||
|
'amount' => $amount = $this->getFloat( $invoice_data, 'invoice.amount' ),
|
||||||
|
'balance' => isset( $invoice_data['invoice.balance'] ) ? $this->getFloat( $invoice_data, 'invoice.balance' ) : $amount,
|
||||||
|
'client_id' => $this->getClient( $this->getString( $invoice_data, 'client.name' ), $this->getString( $invoice_data, 'client.email' ) ),
|
||||||
|
'discount' => $this->getFloat( $invoice_data, 'invoice.discount' ),
|
||||||
|
'po_number' => $this->getString( $invoice_data, 'invoice.po_number' ),
|
||||||
|
'date' => isset( $invoice_data['invoice.date'] ) ? date( 'Y-m-d', strtotime( $invoice_data['invoice.date'] ) ) : null,
|
||||||
|
'due_date' => isset( $invoice_data['invoice.due_date'] ) ? date( 'Y-m-d', strtotime( $invoice_data['invoice.due_date'] ) ) : null,
|
||||||
|
'terms' => $this->getString( $invoice_data, 'invoice.terms' ),
|
||||||
|
'public_notes' => $this->getString( $invoice_data, 'invoice.public_notes' ),
|
||||||
|
'is_sent' => $this->getString( $invoice_data, 'invoice.is_sent' ),
|
||||||
|
'private_notes' => $this->getString( $invoice_data, 'invoice.private_notes' ),
|
||||||
|
'tax_name1' => $this->getString( $invoice_data, 'invoice.tax_name1' ),
|
||||||
|
'tax_rate1' => $this->getFloat( $invoice_data, 'invoice.tax_rate1' ),
|
||||||
|
'tax_name2' => $this->getString( $invoice_data, 'invoice.tax_name2' ),
|
||||||
|
'tax_rate2' => $this->getFloat( $invoice_data, 'invoice.tax_rate2' ),
|
||||||
|
'tax_name3' => $this->getString( $invoice_data, 'invoice.tax_name3' ),
|
||||||
|
'tax_rate3' => $this->getFloat( $invoice_data, 'invoice.tax_rate3' ),
|
||||||
|
'custom_value1' => $this->getString( $invoice_data, 'invoice.custom_value1' ),
|
||||||
|
'custom_value2' => $this->getString( $invoice_data, 'invoice.custom_value2' ),
|
||||||
|
'custom_value3' => $this->getString( $invoice_data, 'invoice.custom_value3' ),
|
||||||
|
'custom_value4' => $this->getString( $invoice_data, 'invoice.custom_value4' ),
|
||||||
|
'footer' => $this->getString( $invoice_data, 'invoice.footer' ),
|
||||||
|
'partial' => $this->getFloat( $invoice_data, 'invoice.partial' ),
|
||||||
|
'partial_due_date' => $this->getString( $invoice_data, 'invoice.partial_due_date' ),
|
||||||
|
'custom_surcharge1' => $this->getString( $invoice_data, 'invoice.custom_surcharge1' ),
|
||||||
|
'custom_surcharge2' => $this->getString( $invoice_data, 'invoice.custom_surcharge2' ),
|
||||||
|
'custom_surcharge3' => $this->getString( $invoice_data, 'invoice.custom_surcharge3' ),
|
||||||
|
'custom_surcharge4' => $this->getString( $invoice_data, 'invoice.custom_surcharge4' ),
|
||||||
|
'exchange_rate' => $this->getString( $invoice_data, 'invoice.exchange_rate' ),
|
||||||
|
'status_id' => $invoiceStatusMap[ $status =
|
||||||
|
strtolower( $this->getString( $invoice_data, 'invoice.status' ) ) ] ??
|
||||||
|
Invoice::STATUS_SENT,
|
||||||
|
'viewed' => $status === 'viewed',
|
||||||
|
'archived' => $status === 'archived',
|
||||||
|
];
|
||||||
|
|
||||||
|
if ( isset( $invoice_data['payment.amount'] ) ) {
|
||||||
|
$transformed['payments'] = [
|
||||||
|
[
|
||||||
|
'date' => isset( $invoice_data['payment.date'] ) ? date( 'Y-m-d', strtotime( $invoice_data['payment.date'] ) ) : date( 'y-m-d' ),
|
||||||
|
'transaction_reference' => $this->getString( $invoice_data, 'payment.transaction_reference' ),
|
||||||
|
'amount' => $this->getFloat( $invoice_data, 'payment.amount' ),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
} elseif ( $status === 'paid' ) {
|
||||||
|
$transformed['payments'] = [
|
||||||
|
[
|
||||||
|
'date' => isset( $invoice_data['payment.date'] ) ? date( 'Y-m-d', strtotime( $invoice_data['payment.date'] ) ) : date( 'y-m-d' ),
|
||||||
|
'transaction_reference' => $this->getString( $invoice_data, 'payment.transaction_reference' ),
|
||||||
|
'amount' => $this->getFloat( $invoice_data, 'invoice.amount' ),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
} elseif ( isset( $transformed['amount'] ) && isset( $transformed['balance'] ) ) {
|
||||||
|
$transformed['payments'] = [
|
||||||
|
[
|
||||||
|
'date' => isset( $invoice_data['payment.date'] ) ? date( 'Y-m-d', strtotime( $invoice_data['payment.date'] ) ) : date( 'y-m-d' ),
|
||||||
|
'transaction_reference' => $this->getString( $invoice_data, 'payment.transaction_reference' ),
|
||||||
|
'amount' => $transformed['amount'] - $transformed['balance'],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$line_items = [];
|
||||||
|
foreach ( $line_items_data as $record ) {
|
||||||
|
$line_items[] = [
|
||||||
|
'quantity' => $this->getFloat( $record, 'item.quantity' ),
|
||||||
|
'cost' => $this->getFloat( $record, 'item.cost' ),
|
||||||
|
'product_key' => $this->getString( $record, 'item.product_key' ),
|
||||||
|
'notes' => $this->getString( $record, 'item.notes' ),
|
||||||
|
'discount' => $this->getFloat( $record, 'item.discount' ),
|
||||||
|
'is_amount_discount' => filter_var( $this->getString( $record, 'item.is_amount_discount' ), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE ),
|
||||||
|
'tax_name1' => $this->getString( $record, 'item.tax_name1' ),
|
||||||
|
'tax_rate1' => $this->getFloat( $record, 'item.tax_rate1' ),
|
||||||
|
'tax_name2' => $this->getString( $record, 'item.tax_name2' ),
|
||||||
|
'tax_rate2' => $this->getFloat( $record, 'item.tax_rate2' ),
|
||||||
|
'tax_name3' => $this->getString( $record, 'item.tax_name3' ),
|
||||||
|
'tax_rate3' => $this->getFloat( $record, 'item.tax_rate3' ),
|
||||||
|
'custom_value1' => $this->getString( $record, 'item.custom_value1' ),
|
||||||
|
'custom_value2' => $this->getString( $record, 'item.custom_value2' ),
|
||||||
|
'custom_value3' => $this->getString( $record, 'item.custom_value3' ),
|
||||||
|
'custom_value4' => $this->getString( $record, 'item.custom_value4' ),
|
||||||
|
'type_id' => $this->getInvoiceTypeId( $record, 'item.type_id' ),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$transformed['line_items'] = $line_items;
|
||||||
|
|
||||||
|
return $transformed;
|
||||||
|
}
|
||||||
|
}
|
64
app/Import/Transformers/Csv/PaymentTransformer.php
Normal file
64
app/Import/Transformers/Csv/PaymentTransformer.php
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* client Ninja (https://clientninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/clientninja/clientninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. client Ninja LLC (https://clientninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Import\Transformers\Csv;
|
||||||
|
|
||||||
|
use App\Import\ImportException;
|
||||||
|
use App\Import\Transformers\BaseTransformer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class PaymentTransformer.
|
||||||
|
*/
|
||||||
|
class PaymentTransformer extends BaseTransformer {
|
||||||
|
/**
|
||||||
|
* @param $data
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function transform( $data ) {
|
||||||
|
$client_id =
|
||||||
|
$this->getClient( $this->getString( $data, 'payment.client_id' ), $this->getString( $data, 'payment.client_id' ) );
|
||||||
|
|
||||||
|
if ( empty( $client_id ) ) {
|
||||||
|
throw new ImportException( 'Could not find client.' );
|
||||||
|
}
|
||||||
|
|
||||||
|
$transformed = [
|
||||||
|
'company_id' => $this->maps['company']->id,
|
||||||
|
'number' => $this->getString( $data, 'payment.number' ),
|
||||||
|
'user_id' => $this->getString( $data, 'payment.user_id' ),
|
||||||
|
'amount' => $this->getFloat( $data, 'payment.amount' ),
|
||||||
|
'refunded' => $this->getFloat( $data, 'payment.refunded' ),
|
||||||
|
'applied' => $this->getFloat( $data, 'payment.applied' ),
|
||||||
|
'transaction_reference' => $this->getString( $data, 'payment.transaction_reference ' ),
|
||||||
|
'date' => $this->getString( $data, 'payment.date' ),
|
||||||
|
'private_notes' => $this->getString( $data, 'payment.private_notes' ),
|
||||||
|
'custom_value1' => $this->getString( $data, 'payment.custom_value1' ),
|
||||||
|
'custom_value2' => $this->getString( $data, 'payment.custom_value2' ),
|
||||||
|
'custom_value3' => $this->getString( $data, 'payment.custom_value3' ),
|
||||||
|
'custom_value4' => $this->getString( $data, 'payment.custom_value4' ),
|
||||||
|
'client_id' => $client_id,
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
if ( isset( $data['payment.invoice_number'] ) &&
|
||||||
|
$invoice_id = $this->getInvoiceId( $data['payment.invoice_number'] ) ) {
|
||||||
|
$transformed['invoices'] = [
|
||||||
|
[
|
||||||
|
'invoice_id' => $invoice_id,
|
||||||
|
'amount' => $transformed['amount'] ?? null,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $transformed;
|
||||||
|
}
|
||||||
|
}
|
@ -1,16 +1,16 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* client Ninja (https://clientninja.com).
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
*
|
*
|
||||||
* @link https://github.com/clientninja/clientninja source repository
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
*
|
*
|
||||||
* @copyright Copyright (c) 2021. client Ninja LLC (https://clientninja.com)
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
*
|
*
|
||||||
* @license https://opensource.org/licenses/AAL
|
* @license https://opensource.org/licenses/AAL
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace App\Import\Transformers;
|
namespace App\Import\Transformers\Csv;
|
||||||
|
use App\Import\Transformers\BaseTransformer;
|
||||||
/**
|
/**
|
||||||
* Class ProductTransformer.
|
* Class ProductTransformer.
|
||||||
*/
|
*/
|
||||||
@ -19,7 +19,7 @@ class ProductTransformer extends BaseTransformer
|
|||||||
/**
|
/**
|
||||||
* @param $data
|
* @param $data
|
||||||
*
|
*
|
||||||
* @return bool|Item
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function transform($data)
|
public function transform($data)
|
||||||
{
|
{
|
47
app/Import/Transformers/Csv/VendorTransformer.php
Normal file
47
app/Import/Transformers/Csv/VendorTransformer.php
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Import\Transformers\Csv;
|
||||||
|
use App\Import\ImportException;
|
||||||
|
use App\Import\Transformers\BaseTransformer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class VendorTransformer.
|
||||||
|
*/
|
||||||
|
class VendorTransformer extends BaseTransformer {
|
||||||
|
/**
|
||||||
|
* @param $data
|
||||||
|
*
|
||||||
|
* @return array|bool
|
||||||
|
*/
|
||||||
|
public function transform( $data ) {
|
||||||
|
if ( isset( $data->name ) && $this->hasVendor( $data->name ) ) {
|
||||||
|
throw new ImportException('Vendor already exists');
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'company_id' => $this->maps['company']->id,
|
||||||
|
'name' => $this->getString( $data, 'vendor.name' ),
|
||||||
|
'phone' => $this->getString( $data, 'vendor.phone' ),
|
||||||
|
'id_number' => $this->getString( $data, 'vendor.id_number' ),
|
||||||
|
'vat_number' => $this->getString( $data, 'vendor.vat_number' ),
|
||||||
|
'website' => $this->getString( $data, 'vendor.website' ),
|
||||||
|
'currency_id' => $this->getCurrencyByCode( $data, 'vendor.currency_id' ),
|
||||||
|
'public_notes' => $this->getString( $data, 'vendor.public_notes' ),
|
||||||
|
'private_notes' => $this->getString( $data, 'vendor.private_notes' ),
|
||||||
|
'address1' => $this->getString( $data, 'vendor.address1' ),
|
||||||
|
'address2' => $this->getString( $data, 'vendor.address2' ),
|
||||||
|
'city' => $this->getString( $data, 'vendor.city' ),
|
||||||
|
'state' => $this->getString( $data, 'vendor.state' ),
|
||||||
|
'postal_code' => $this->getString( $data, 'vendor.postal_code' ),
|
||||||
|
'vendor_contacts' => [
|
||||||
|
[
|
||||||
|
'first_name' => $this->getString( $data, 'vendor.first_name' ),
|
||||||
|
'last_name' => $this->getString( $data, 'vendor.last_name' ),
|
||||||
|
'email' => $this->getString( $data, 'vendor.email' ),
|
||||||
|
'phone' => $this->getString( $data, 'vendor.phone' ),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'country_id' => isset( $data['vendor.country_id'] ) ? $this->getCountryId( $data['vendor.country_id'] ) : null,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
55
app/Import/Transformers/Freshbooks/ClientTransformer.php
Normal file
55
app/Import/Transformers/Freshbooks/ClientTransformer.php
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://clientninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/clientninja/clientninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. client Ninja LLC (https://clientninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Import\Transformers\Freshbooks;
|
||||||
|
|
||||||
|
use App\Import\ImportException;
|
||||||
|
use App\Import\Transformers\BaseTransformer;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class ClientTransformer.
|
||||||
|
*/
|
||||||
|
class ClientTransformer extends BaseTransformer {
|
||||||
|
/**
|
||||||
|
* @param $data
|
||||||
|
*
|
||||||
|
* @return array|bool
|
||||||
|
*/
|
||||||
|
public function transform( $data ) {
|
||||||
|
if ( isset( $data['Organization'] ) && $this->hasClient( $data['Organization'] ) ) {
|
||||||
|
throw new ImportException('Client already exists');
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'company_id' => $this->maps['company']->id,
|
||||||
|
'name' => $this->getString( $data, 'Organization' ),
|
||||||
|
'work_phone' => $this->getString( $data, 'Phone' ),
|
||||||
|
'address1' => $this->getString( $data, 'Street' ),
|
||||||
|
'city' => $this->getString( $data, 'City' ),
|
||||||
|
'state' => $this->getString( $data, 'Province/State' ),
|
||||||
|
'postal_code' => $this->getString( $data, 'Postal Code' ),
|
||||||
|
'country_id' => isset( $data['Country'] ) ? $this->getCountryId( $data['Country'] ) : null,
|
||||||
|
'private_notes' => $this->getString( $data, 'Notes' ),
|
||||||
|
'credit_balance' => 0,
|
||||||
|
'settings' => new \stdClass,
|
||||||
|
'client_hash' => Str::random( 40 ),
|
||||||
|
'contacts' => [
|
||||||
|
[
|
||||||
|
'first_name' => $this->getString( $data, 'First Name' ),
|
||||||
|
'last_name' => $this->getString( $data, 'Last Name' ),
|
||||||
|
'email' => $this->getString( $data, 'Email' ),
|
||||||
|
'phone' => $this->getString( $data, 'Phone' ),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
78
app/Import/Transformers/Freshbooks/InvoiceTransformer.php
Normal file
78
app/Import/Transformers/Freshbooks/InvoiceTransformer.php
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* client Ninja (https://clientninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/clientninja/clientninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. client Ninja LLC (https://clientninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Import\Transformers\Freshbooks;
|
||||||
|
|
||||||
|
use App\Import\ImportException;
|
||||||
|
use App\Import\Transformers\BaseTransformer;
|
||||||
|
use App\Models\Invoice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class InvoiceTransformer.
|
||||||
|
*/
|
||||||
|
class InvoiceTransformer extends BaseTransformer {
|
||||||
|
/**
|
||||||
|
* @param $line_items_data
|
||||||
|
*
|
||||||
|
* @return bool|array
|
||||||
|
*/
|
||||||
|
public function transform( $line_items_data ) {
|
||||||
|
$invoice_data = reset( $line_items_data );
|
||||||
|
|
||||||
|
if ( $this->hasInvoice( $invoice_data['Invoice #'] ) ) {
|
||||||
|
throw new ImportException( 'Invoice number already exists' );
|
||||||
|
}
|
||||||
|
|
||||||
|
$invoiceStatusMap = [
|
||||||
|
'sent' => Invoice::STATUS_SENT,
|
||||||
|
'draft' => Invoice::STATUS_DRAFT,
|
||||||
|
];
|
||||||
|
|
||||||
|
$transformed = [
|
||||||
|
'company_id' => $this->maps['company']->id,
|
||||||
|
'client_id' => $this->getClient( $this->getString( $invoice_data, 'Client Name' ), null ),
|
||||||
|
'number' => $this->getString( $invoice_data, 'Invoice #' ),
|
||||||
|
'date' => isset( $invoice_data['Date Issued'] ) ? date( 'Y-m-d', strtotime( $invoice_data['Date Issued'] ) ) : null,
|
||||||
|
'currency_id' => $this->getCurrencyByCode( $invoice_data, 'Currency' ),
|
||||||
|
'amount' => 0,
|
||||||
|
'status_id' => $invoiceStatusMap[ $status =
|
||||||
|
strtolower( $this->getString( $invoice_data, 'Invoice Status' ) ) ] ?? Invoice::STATUS_SENT,
|
||||||
|
'viewed' => $status === 'viewed',
|
||||||
|
];
|
||||||
|
|
||||||
|
$line_items = [];
|
||||||
|
foreach ( $line_items_data as $record ) {
|
||||||
|
$line_items[] = [
|
||||||
|
'product_key' => $this->getString( $record, 'Item Name' ),
|
||||||
|
'notes' => $this->getString( $record, 'Item Description' ),
|
||||||
|
'cost' => $this->getFloat( $record, 'Rate' ),
|
||||||
|
'quantity' => $this->getFloat( $record, 'Quantity' ),
|
||||||
|
'discount' => $this->getFloat( $record, 'Discount Percentage' ),
|
||||||
|
'is_amount_discount' => false,
|
||||||
|
'tax_name1' => $this->getString( $record, 'Tax 1 Type' ),
|
||||||
|
'tax_rate1' => $this->getFloat( $record, 'Tax 1 Amount' ),
|
||||||
|
'tax_name2' => $this->getString( $record, 'Tax 2 Type' ),
|
||||||
|
'tax_rate2' => $this->getFloat( $record, 'Tax 2 Amount' ),
|
||||||
|
];
|
||||||
|
$transformed['amount'] += $this->getFloat( $record, 'Line Total' );
|
||||||
|
}
|
||||||
|
$transformed['line_items'] = $line_items;
|
||||||
|
|
||||||
|
if ( ! empty( $invoice_data['Date Paid'] ) ) {
|
||||||
|
$transformed['payments'] = [[
|
||||||
|
'date' => date( 'Y-m-d', strtotime( $invoice_data['Date Paid'] ) ),
|
||||||
|
'amount' => $transformed['amount'],
|
||||||
|
]];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $transformed;
|
||||||
|
}
|
||||||
|
}
|
89
app/Import/Transformers/Invoice2Go/InvoiceTransformer.php
Normal file
89
app/Import/Transformers/Invoice2Go/InvoiceTransformer.php
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* client Ninja (https://clientninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/clientninja/clientninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. client Ninja LLC (https://clientninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Import\Transformers\Invoice2Go;
|
||||||
|
|
||||||
|
use App\Import\ImportException;
|
||||||
|
use App\Import\Transformers\BaseTransformer;
|
||||||
|
use App\Models\Invoice;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class InvoiceTransformer.
|
||||||
|
*/
|
||||||
|
class InvoiceTransformer extends BaseTransformer {
|
||||||
|
/**
|
||||||
|
* @param $line_items_data
|
||||||
|
*
|
||||||
|
* @return bool|array
|
||||||
|
*/
|
||||||
|
public function transform( $invoice_data ) {
|
||||||
|
if ( $this->hasInvoice( $invoice_data['DocumentNumber'] ) ) {
|
||||||
|
throw new ImportException( 'Invoice number already exists' );
|
||||||
|
}
|
||||||
|
|
||||||
|
$invoiceStatusMap = [
|
||||||
|
'unsent' => Invoice::STATUS_DRAFT,
|
||||||
|
'sent' => Invoice::STATUS_SENT,
|
||||||
|
];
|
||||||
|
|
||||||
|
$transformed = [
|
||||||
|
'company_id' => $this->maps['company']->id,
|
||||||
|
'number' => $this->getString( $invoice_data, 'DocumentNumber' ),
|
||||||
|
'notes' => $this->getString( $invoice_data, 'Comment' ),
|
||||||
|
'date' => isset( $invoice_data['DocumentDate'] ) ? date( 'Y-m-d', strtotime( $invoice_data['DocumentDate'] ) ) : null,
|
||||||
|
'currency_id' => $this->getCurrencyByCode( $invoice_data, 'Currency' ),
|
||||||
|
'amount' => 0,
|
||||||
|
'status_id' => $invoiceStatusMap[ $status =
|
||||||
|
strtolower( $this->getString( $invoice_data, 'DocumentStatus' ) ) ] ?? Invoice::STATUS_SENT,
|
||||||
|
'viewed' => $status === 'viewed',
|
||||||
|
'line_items' => [
|
||||||
|
[
|
||||||
|
'amount' => $amount = $this->getFloat( $invoice_data, 'TotalAmount' ),
|
||||||
|
'quantity' => 1,
|
||||||
|
'discount' => $this->getFloat( $invoice_data, 'DiscountValue' ),
|
||||||
|
'is_amount_discount' => false,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
$client_id =
|
||||||
|
$this->getClient( $this->getString( $invoice_data, 'Name' ), $this->getString( $invoice_data, 'EmailRecipient' ) );
|
||||||
|
|
||||||
|
if ( $client_id ) {
|
||||||
|
$transformed['client_id'] = $client_id;
|
||||||
|
} else {
|
||||||
|
$transformed['client'] = [
|
||||||
|
'name' => $this->getString( $invoice_data, 'Name' ),
|
||||||
|
'address1' => $this->getString( $invoice_data, 'DocumentRecipientAddress' ),
|
||||||
|
'shipping_address1' => $this->getString( $invoice_data, 'ShipAddress' ),
|
||||||
|
'credit_balance' => 0,
|
||||||
|
'settings' => new \stdClass,
|
||||||
|
'client_hash' => Str::random( 40 ),
|
||||||
|
'contacts' => [
|
||||||
|
[
|
||||||
|
'email' => $this->getString( $invoice_data, 'Email' ),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if ( ! empty( $invoice_data['Date Paid'] ) ) {
|
||||||
|
$transformed['payments'] = [
|
||||||
|
[
|
||||||
|
'date' => date( 'Y-m-d', strtotime( $invoice_data['DatePaid'] ) ),
|
||||||
|
'amount' => $this->getFloat( $invoice_data, 'Payments' ),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $transformed;
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* client Ninja (https://clientninja.com).
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
*
|
*
|
||||||
* @link https://github.com/clientninja/clientninja source repository
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
*
|
*
|
||||||
* @copyright Copyright (c) 2021. client Ninja LLC (https://clientninja.com)
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
*
|
*
|
||||||
* @license https://opensource.org/licenses/AAL
|
* @license https://opensource.org/licenses/AAL
|
||||||
*/
|
*/
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* client Ninja (https://clientninja.com).
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
*
|
*
|
||||||
* @link https://github.com/clientninja/clientninja source repository
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
*
|
*
|
||||||
* @copyright Copyright (c) 2021. client Ninja LLC (https://clientninja.com)
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
*
|
*
|
||||||
* @license https://opensource.org/licenses/AAL
|
* @license https://opensource.org/licenses/AAL
|
||||||
*/
|
*/
|
||||||
|
48
app/Import/Transformers/Invoicely/ClientTransformer.php
Normal file
48
app/Import/Transformers/Invoicely/ClientTransformer.php
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://clientninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/clientninja/clientninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. client Ninja LLC (https://clientninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Import\Transformers\Invoicely;
|
||||||
|
|
||||||
|
use App\Import\ImportException;
|
||||||
|
use App\Import\Transformers\BaseTransformer;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class ClientTransformer.
|
||||||
|
*/
|
||||||
|
class ClientTransformer extends BaseTransformer {
|
||||||
|
/**
|
||||||
|
* @param $data
|
||||||
|
*
|
||||||
|
* @return array|bool
|
||||||
|
*/
|
||||||
|
public function transform( $data ) {
|
||||||
|
if ( isset( $data['Client Name'] ) && $this->hasClient( $data['Client Name'] ) ) {
|
||||||
|
throw new ImportException('Client already exists');
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'company_id' => $this->maps['company']->id,
|
||||||
|
'name' => $this->getString( $data, 'Client Name' ),
|
||||||
|
'work_phone' => $this->getString( $data, 'Phone' ),
|
||||||
|
'country_id' => isset( $data['Country'] ) ? $this->getCountryIdBy2( $data['Country'] ) : null,
|
||||||
|
'credit_balance' => 0,
|
||||||
|
'settings' => new \stdClass,
|
||||||
|
'client_hash' => Str::random( 40 ),
|
||||||
|
'contacts' => [
|
||||||
|
[
|
||||||
|
'email' => $this->getString( $data, 'Email' ),
|
||||||
|
'phone' => $this->getString( $data, 'Phone' ),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
58
app/Import/Transformers/Invoicely/InvoiceTransformer.php
Normal file
58
app/Import/Transformers/Invoicely/InvoiceTransformer.php
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* client Ninja (https://clientninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/clientninja/clientninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. client Ninja LLC (https://clientninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Import\Transformers\Invoicely;
|
||||||
|
|
||||||
|
use App\Import\ImportException;
|
||||||
|
use App\Import\Transformers\BaseTransformer;
|
||||||
|
use App\Models\Invoice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class InvoiceTransformer.
|
||||||
|
*/
|
||||||
|
class InvoiceTransformer extends BaseTransformer {
|
||||||
|
/**
|
||||||
|
* @param $data
|
||||||
|
*
|
||||||
|
* @return bool|array
|
||||||
|
*/
|
||||||
|
public function transform( $data ) {
|
||||||
|
if ( $this->hasInvoice( $data['Details'] ) ) {
|
||||||
|
throw new ImportException( 'Invoice number already exists' );
|
||||||
|
}
|
||||||
|
|
||||||
|
$transformed = [
|
||||||
|
'company_id' => $this->maps['company']->id,
|
||||||
|
'client_id' => $this->getClient( $this->getString( $data, 'Client' ), null ),
|
||||||
|
'number' => $this->getString( $data, 'Details' ),
|
||||||
|
'date' => isset( $data['Date'] ) ? date( 'Y-m-d', strtotime( $data['Date'] ) ) : null,
|
||||||
|
'due_date' => isset( $data['Due'] ) ? date( 'Y-m-d', strtotime( $data['Due'] ) ) : null,
|
||||||
|
'status_id' => Invoice::STATUS_SENT,
|
||||||
|
'line_items' => [
|
||||||
|
[
|
||||||
|
'cost' => $amount = $this->getFloat( $data, 'Total' ),
|
||||||
|
'quantity' => 1,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
if ( strtolower( $data['Status'] ) === 'paid' ) {
|
||||||
|
$transformed['payments'] = [
|
||||||
|
[
|
||||||
|
'date' => date( 'Y-m-d' ),
|
||||||
|
'amount' => $amount,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $transformed;
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* client Ninja (https://clientninja.com).
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
*
|
*
|
||||||
* @link https://github.com/clientninja/clientninja source repository
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
*
|
*
|
||||||
* @copyright Copyright (c) 2021. client Ninja LLC (https://clientninja.com)
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
*
|
*
|
||||||
* @license https://opensource.org/licenses/AAL
|
* @license https://opensource.org/licenses/AAL
|
||||||
*/
|
*/
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user