mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-09-21 00:41:34 +02:00
Merge pull request #8173 from turbo124/v5-develop
Add company logo size to company settings object
This commit is contained in:
commit
2aea9eade3
68
.github/workflows/phpunit.yml
vendored
68
.github/workflows/phpunit.yml
vendored
@ -13,8 +13,12 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
operating-system: ['ubuntu-20.04', 'ubuntu-22.04']
|
||||
php-versions: ['8.1']
|
||||
php-versions: ['8.1','8.2']
|
||||
phpunit-versions: ['latest']
|
||||
ci_node_total: [ 8 ]
|
||||
ci_node_index: [ 0, 1, 2, 3, 4, 5, 6, 7]
|
||||
laravel: [9.*]
|
||||
dependency-version: [prefer-stable]
|
||||
|
||||
env:
|
||||
DB_DATABASE1: ninja
|
||||
@ -25,13 +29,14 @@ jobs:
|
||||
DB_USERNAME: root
|
||||
DB_PASSWORD: ninja
|
||||
DB_HOST: '127.0.0.1'
|
||||
REDIS_PORT: 6379
|
||||
BROADCAST_DRIVER: log
|
||||
CACHE_DRIVER: file
|
||||
QUEUE_CONNECTION: sync
|
||||
SESSION_DRIVER: file
|
||||
CACHE_DRIVER: redis
|
||||
QUEUE_CONNECTION: redis
|
||||
SESSION_DRIVER: redis
|
||||
NINJA_ENVIRONMENT: hosted
|
||||
MULTI_DB_ENABLED: false
|
||||
NINJA_LICENSE: 123456
|
||||
NINJA_LICENSE: ${{ secrets.ninja_license }}
|
||||
TRAVIS: true
|
||||
MAIL_MAILER: log
|
||||
|
||||
@ -47,13 +52,18 @@ jobs:
|
||||
MYSQL_DATABASE: ninja
|
||||
MYSQL_ROOT_PASSWORD: ninja
|
||||
options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3
|
||||
redis:
|
||||
image: redis
|
||||
ports:
|
||||
- 6379/tcp
|
||||
options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
|
||||
|
||||
steps:
|
||||
- name: Add hosts to /etc/hosts
|
||||
run: |
|
||||
sudo echo "127.0.0.1 ninja.test" | sudo tee -a /etc/hosts
|
||||
|
||||
- name: Start mysql service
|
||||
- name: Start MariaDB service
|
||||
run: |
|
||||
sudo systemctl start mysql.service
|
||||
- name: Verify MariaDB connection
|
||||
@ -65,11 +75,11 @@ jobs:
|
||||
while ! mysqladmin ping -h"127.0.0.1" -P"$DB_PORT" --silent; do
|
||||
sleep 1
|
||||
done
|
||||
- name: Setup PHP
|
||||
- name: Setup PHP shivammathur/setup-php@v2
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
extensions: mysql, mysqlnd, sqlite3, bcmath, gmp, gd, curl, zip, openssl, mbstring, xml
|
||||
extensions: mysql, mysqlnd, sqlite3, bcmath, gmp, gd, curl, zip, openssl, mbstring, xml, redis
|
||||
|
||||
- uses: actions/checkout@v1
|
||||
with:
|
||||
@ -79,32 +89,56 @@ jobs:
|
||||
- name: Copy .env
|
||||
run: |
|
||||
cp .env.ci .env
|
||||
|
||||
# - name: Get Composer Cache Directory
|
||||
# id: composer-cache
|
||||
# run: |
|
||||
# echo "::set-output name=dir::$(composer config cache-files-dir)"
|
||||
# - uses: actions/cache@v2
|
||||
# with:
|
||||
# path: ${{ steps.composer-cache.outputs.dir }}
|
||||
# key: ${{ runner.os }}-${{ matrix.php }}-composer-${{ hashFiles('**/composer.lock') }}
|
||||
# restore-keys: |
|
||||
# ${{ runner.os }}-${{ matrix.php }}-composer-
|
||||
|
||||
- name: Cache dependencies actions/cache@v3
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.composer/cache/files
|
||||
key: dependencies-${{ matrix.dependency-version }}-laravel-${{ matrix.laravel }}-php-${{ matrix.php-versions }}-composer-${{ hashFiles('composer.json') }}
|
||||
|
||||
- name: Install composer dependencies
|
||||
run: |
|
||||
composer config -g github-oauth.github.com ${{ secrets.GITHUB_TOKEN }}
|
||||
composer install
|
||||
|
||||
- name: Prepare Laravel Application
|
||||
env:
|
||||
REDIS_PORT: ${{ job.services.redis.ports['6379'] }}
|
||||
run: |
|
||||
php artisan key:generate
|
||||
php artisan optimize
|
||||
php artisan cache:clear
|
||||
php artisan config:cache
|
||||
- name: Create DB and schemas
|
||||
run: |
|
||||
mkdir -p database
|
||||
touch database/database.sqlite
|
||||
php artisan ninja:post-update
|
||||
|
||||
- name: Migrate Database
|
||||
run: |
|
||||
php artisan migrate:fresh --seed --force && php artisan db:seed --force
|
||||
- name: Prepare JS/CSS assets
|
||||
run: |
|
||||
npm i
|
||||
npm run production
|
||||
|
||||
# - name: Prepare JS/CSS assets
|
||||
# run: |
|
||||
# npm i
|
||||
# npm run production
|
||||
|
||||
- name: Run Testsuite
|
||||
run: |
|
||||
cat .env
|
||||
vendor/bin/snappdf download
|
||||
vendor/bin/phpunit --testdox
|
||||
tests/ci
|
||||
env:
|
||||
DB_PORT: ${{ job.services.mysql.ports[3306] }}
|
||||
PHP_CS_FIXER_IGNORE_ENV: true
|
||||
CI_NODE_TOTAL: ${{ matrix.ci_node_total }}
|
||||
# Use the index from matrix as an environment variable
|
||||
CI_NODE_INDEX: ${{ matrix.ci_node_index }}
|
@ -1 +1 @@
|
||||
5.5.56
|
||||
5.5.57
|
@ -80,10 +80,7 @@ class CreateSingleAccount extends Command
|
||||
public function handle()
|
||||
{
|
||||
|
||||
if(config('ninja.is_docker'))
|
||||
return;
|
||||
|
||||
if (!$this->confirm('Are you sure you want to inject dummy data?'))
|
||||
if (Ninja::isHosted() || config('ninja.is_docker') || !$this->confirm('Are you sure you want to inject dummy data?'))
|
||||
return;
|
||||
|
||||
$this->invoice_repo = new InvoiceRepository();
|
||||
@ -105,6 +102,11 @@ class CreateSingleAccount extends Command
|
||||
{
|
||||
$this->info('Creating Small Account and Company');
|
||||
|
||||
if($user = User::where('email','small@example.com')->first())
|
||||
{
|
||||
$user->account->delete();
|
||||
}
|
||||
|
||||
$account = Account::factory()->create();
|
||||
$company = Company::factory()->create([
|
||||
'account_id' => $account->id,
|
||||
|
@ -13,11 +13,14 @@ namespace App\Console\Commands;
|
||||
|
||||
use App\Jobs\Util\VersionCheck;
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\Traits\AppSetup;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
|
||||
class PostUpdate extends Command
|
||||
{
|
||||
use AppSetup;
|
||||
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
@ -83,6 +86,8 @@ class PostUpdate extends Command
|
||||
|
||||
info('queue restarted');
|
||||
|
||||
$this->buildCache(true);
|
||||
|
||||
VersionCheck::dispatch();
|
||||
|
||||
info('Sent for version check');
|
||||
|
@ -94,8 +94,6 @@ class Kernel extends ConsoleKernel
|
||||
/* Performs system maintenance such as pruning the backup table */
|
||||
$schedule->job(new SystemMaintenance)->sundays()->at('02:30')->withoutOverlapping()->name('system-maintenance-job')->onOneServer();
|
||||
|
||||
/* Pulls in bank transactions from third party services */
|
||||
$schedule->job(new BankTransactionSync)->dailyAt('04:10')->withoutOverlapping()->name('bank-trans-sync-job')->onOneServer();
|
||||
|
||||
if (Ninja::isSelfHost()) {
|
||||
|
||||
@ -110,6 +108,9 @@ class Kernel extends ConsoleKernel
|
||||
|
||||
$schedule->job(new AdjustEmailQuota)->dailyAt('23:30')->withoutOverlapping();
|
||||
|
||||
/* Pulls in bank transactions from third party services */
|
||||
$schedule->job(new BankTransactionSync)->dailyAt('04:10')->withoutOverlapping()->name('bank-trans-sync-job')->onOneServer();
|
||||
|
||||
//not used @deprecate
|
||||
// $schedule->job(new SendFailedEmails)->daily()->withoutOverlapping();
|
||||
|
||||
|
@ -453,8 +453,10 @@ class CompanySettings extends BaseSettings
|
||||
|
||||
public $show_email_footer = true;
|
||||
|
||||
public $company_logo_size = '65%';
|
||||
|
||||
public static $casts = [
|
||||
'company_logo_size' => 'string',
|
||||
'show_email_footer' => 'bool',
|
||||
'email_alignment' => 'string',
|
||||
'auto_bill_standard_invoices' => 'bool',
|
||||
|
@ -9,7 +9,7 @@
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\DataMapper;
|
||||
namespace App\DataMapper\Schedule;
|
||||
|
||||
use App\Models\Client;
|
||||
use stdClass;
|
||||
|
@ -11,11 +11,7 @@
|
||||
|
||||
namespace App\Filters;
|
||||
|
||||
use App\Models\BankIntegration;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
/**
|
||||
* BankIntegrationFilters.
|
||||
|
@ -12,10 +12,7 @@
|
||||
namespace App\Filters;
|
||||
|
||||
use App\Models\BankTransaction;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
/**
|
||||
* BankTransactionFilters.
|
||||
@ -77,87 +74,49 @@ class BankTransactionFilters extends QueryFilters
|
||||
|
||||
$status_parameters = explode(',', $value);
|
||||
|
||||
$status_array = [];
|
||||
|
||||
$debit_or_withdrawal_array = [];
|
||||
|
||||
if (in_array('all', $status_parameters)) {
|
||||
return $this->builder;
|
||||
}
|
||||
|
||||
if (in_array('unmatched', $status_parameters)) {
|
||||
$status_array[] = BankTransaction::STATUS_UNMATCHED;
|
||||
// $this->builder->orWhere('status_id', BankTransaction::STATUS_UNMATCHED);
|
||||
}
|
||||
$this->builder->where(function ($query) use ($status_parameters){
|
||||
|
||||
if (in_array('matched', $status_parameters)) {
|
||||
$status_array[] = BankTransaction::STATUS_MATCHED;
|
||||
// $this->builder->where('status_id', BankTransaction::STATUS_MATCHED);
|
||||
}
|
||||
$status_array = [];
|
||||
|
||||
$debit_or_withdrawal_array = [];
|
||||
|
||||
if (in_array('converted', $status_parameters)) {
|
||||
$status_array[] = BankTransaction::STATUS_CONVERTED;
|
||||
// $this->builder->where('status_id', BankTransaction::STATUS_CONVERTED);
|
||||
}
|
||||
if (in_array('unmatched', $status_parameters)) {
|
||||
$status_array[] = BankTransaction::STATUS_UNMATCHED;
|
||||
}
|
||||
|
||||
if (in_array('deposits', $status_parameters)) {
|
||||
$debit_or_withdrawal_array[] = 'CREDIT';
|
||||
// $this->builder->where('base_type', 'CREDIT');
|
||||
}
|
||||
if (in_array('matched', $status_parameters)) {
|
||||
$status_array[] = BankTransaction::STATUS_MATCHED;
|
||||
}
|
||||
|
||||
if (in_array('withdrawals', $status_parameters)) {
|
||||
$debit_or_withdrawal_array[] = 'DEBIT';
|
||||
// $this->builder->where('base_type', 'DEBIT');
|
||||
}
|
||||
if (in_array('converted', $status_parameters)) {
|
||||
$status_array[] = BankTransaction::STATUS_CONVERTED;
|
||||
}
|
||||
|
||||
if(count($status_array) >=1) {
|
||||
$this->builder->whereIn('status_id', $status_array);
|
||||
}
|
||||
if (in_array('deposits', $status_parameters)) {
|
||||
$debit_or_withdrawal_array[] = 'CREDIT';
|
||||
}
|
||||
|
||||
if(count($debit_or_withdrawal_array) >=1) {
|
||||
$this->builder->orWhereIn('base_type', $debit_or_withdrawal_array);
|
||||
}
|
||||
if (in_array('withdrawals', $status_parameters)) {
|
||||
$debit_or_withdrawal_array[] = 'DEBIT';
|
||||
}
|
||||
|
||||
if(count($status_array) >=1) {
|
||||
$query->whereIn('status_id', $status_array);
|
||||
}
|
||||
|
||||
if(count($debit_or_withdrawal_array) >=1) {
|
||||
$query->orWhereIn('base_type', $debit_or_withdrawal_array);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return $this->builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the list based on the status
|
||||
* archived, active, deleted.
|
||||
*
|
||||
* @param string filter
|
||||
* @return Builder
|
||||
*/
|
||||
public function status(string $filter = '') : Builder
|
||||
{
|
||||
if (strlen($filter) == 0) {
|
||||
return $this->builder;
|
||||
}
|
||||
|
||||
$filters = explode(',', $filter);
|
||||
|
||||
return $this->builder->where(function ($query) use ($filters) {
|
||||
|
||||
if (in_array(parent::STATUS_ACTIVE, $filters)) {
|
||||
$query->orWhereNull('deleted_at');
|
||||
}
|
||||
|
||||
if (in_array(parent::STATUS_ARCHIVED, $filters)) {
|
||||
$query->orWhere(function ($query) use ($table) {
|
||||
$query->whereNotNull($table.'.deleted_at');
|
||||
|
||||
if (! in_array($table, ['users'])) {
|
||||
$query->where($table.'.is_deleted', '=', 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (in_array(parent::STATUS_DELETED, $filters)) {
|
||||
$query->orWhere($table.'.is_deleted', '=', 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts the list based on $sort.
|
||||
*
|
||||
@ -186,19 +145,6 @@ class BankTransactionFilters extends QueryFilters
|
||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the base query.
|
||||
*
|
||||
* @param int company_id
|
||||
* @param User $user
|
||||
* @return Builder
|
||||
* @deprecated
|
||||
*/
|
||||
public function baseQuery(int $company_id, User $user) : Builder
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the query by the users company ID.
|
||||
*
|
||||
@ -206,7 +152,6 @@ class BankTransactionFilters extends QueryFilters
|
||||
*/
|
||||
public function entityFilter()
|
||||
{
|
||||
//return $this->builder->whereCompanyId(auth()->user()->company()->id);
|
||||
return $this->builder->company();
|
||||
}
|
||||
}
|
||||
|
@ -108,17 +108,17 @@ class ClientFilters extends QueryFilters
|
||||
}
|
||||
|
||||
return $this->builder->where(function ($query) use ($filter) {
|
||||
$query->where('clients.name', 'like', '%'.$filter.'%')
|
||||
->orWhere('clients.id_number', 'like', '%'.$filter.'%')
|
||||
$query->where('name', 'like', '%'.$filter.'%')
|
||||
->orWhere('id_number', 'like', '%'.$filter.'%')
|
||||
->orWhereHas('contacts', function ($query) use ($filter) {
|
||||
$query->where('first_name', 'like', '%'.$filter.'%');
|
||||
$query->orWhere('last_name', 'like', '%'.$filter.'%');
|
||||
$query->orWhere('email', 'like', '%'.$filter.'%');
|
||||
})
|
||||
->orWhere('clients.custom_value1', 'like', '%'.$filter.'%')
|
||||
->orWhere('clients.custom_value2', 'like', '%'.$filter.'%')
|
||||
->orWhere('clients.custom_value3', 'like', '%'.$filter.'%')
|
||||
->orWhere('clients.custom_value4', 'like', '%'.$filter.'%');
|
||||
->orWhere('custom_value1', 'like', '%'.$filter.'%')
|
||||
->orWhere('custom_value2', 'like', '%'.$filter.'%')
|
||||
->orWhere('custom_value3', 'like', '%'.$filter.'%')
|
||||
->orWhere('custom_value4', 'like', '%'.$filter.'%');
|
||||
});
|
||||
}
|
||||
|
||||
@ -147,4 +147,14 @@ class ClientFilters extends QueryFilters
|
||||
{
|
||||
return $this->builder->company();
|
||||
}
|
||||
|
||||
public function filter_details(string $filter = '')
|
||||
{
|
||||
|
||||
if($filter == 'true')
|
||||
return $this->builder->select('id', 'name', 'number', 'id_number');
|
||||
|
||||
return $this->builder;
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -13,9 +13,7 @@
|
||||
namespace App\Filters;
|
||||
|
||||
use App\Models\Credit;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
class CreditFilters extends QueryFilters
|
||||
{
|
||||
@ -44,20 +42,20 @@ class CreditFilters extends QueryFilters
|
||||
return $this->builder;
|
||||
}
|
||||
|
||||
if (in_array('draft', $status_parameters)) {
|
||||
$this->builder->where('status_id', Credit::STATUS_DRAFT);
|
||||
}
|
||||
|
||||
if (in_array('partial', $status_parameters)) {
|
||||
$this->builder->where('status_id', Credit::STATUS_PARTIAL);
|
||||
}
|
||||
$credit_filters = [];
|
||||
|
||||
if (in_array('applied', $status_parameters)) {
|
||||
$this->builder->where('status_id', Credit::STATUS_APPLIED);
|
||||
}
|
||||
if (in_array('draft', $status_parameters))
|
||||
$credit_filters[] = Credit::STATUS_DRAFT;
|
||||
|
||||
if (in_array('partial', $status_parameters))
|
||||
$credit_filters[] = Credit::STATUS_PARTIAL;
|
||||
|
||||
//->where('due_date', '>', Carbon::now())
|
||||
//->orWhere('partial_due_date', '>', Carbon::now());
|
||||
if (in_array('applied', $status_parameters))
|
||||
$credit_filters[] = Credit::STATUS_APPLIED;
|
||||
|
||||
if(count($credit_filters) >=1)
|
||||
$this->builder->whereIn('status_id', $credit_filters);
|
||||
|
||||
return $this->builder;
|
||||
}
|
||||
|
@ -11,11 +11,7 @@
|
||||
|
||||
namespace App\Filters;
|
||||
|
||||
use App\Models\Design;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
/**
|
||||
* DesignFilters.
|
||||
@ -27,9 +23,10 @@ class DesignFilters extends QueryFilters
|
||||
*
|
||||
* @param string query filter
|
||||
* @return Builder
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public function filter(string $filter = '') : Builder
|
||||
public function filter(string $filter = ''): Builder
|
||||
{
|
||||
if (strlen($filter) == 0) {
|
||||
return $this->builder;
|
||||
@ -44,48 +41,17 @@ class DesignFilters extends QueryFilters
|
||||
* Sorts the list based on $sort.
|
||||
*
|
||||
* @param string sort formatted as column|asc
|
||||
*
|
||||
* @return Builder
|
||||
*/
|
||||
public function sort(string $sort) : Builder
|
||||
public function sort(string $sort): Builder
|
||||
{
|
||||
$sort_col = explode('|', $sort);
|
||||
|
||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
||||
}
|
||||
if(is_array($sort_col))
|
||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
||||
|
||||
/**
|
||||
* Returns the base query.
|
||||
*
|
||||
* @param int company_id
|
||||
* @param User $user
|
||||
* @return Builder
|
||||
* @deprecated
|
||||
*/
|
||||
public function baseQuery(int $company_id, User $user) : Builder
|
||||
{
|
||||
$query = DB::table('designs')
|
||||
->join('companies', 'companies.id', '=', 'designs.company_id')
|
||||
->where('designs.company_id', '=', $company_id)
|
||||
->select(
|
||||
'designs.id',
|
||||
'designs.name',
|
||||
'designs.design',
|
||||
'designs.created_at',
|
||||
'designs.created_at as design_created_at',
|
||||
'designs.deleted_at',
|
||||
'designs.is_deleted',
|
||||
'designs.user_id',
|
||||
);
|
||||
|
||||
/*
|
||||
* If the user does not have permissions to view all invoices
|
||||
* limit the user to only the invoices they have created
|
||||
*/
|
||||
if (Gate::denies('view-list', Design::class)) {
|
||||
$query->where('designs.user_id', '=', $user->id);
|
||||
}
|
||||
|
||||
return $query;
|
||||
return $this->builder;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -93,7 +59,7 @@ class DesignFilters extends QueryFilters
|
||||
*
|
||||
* @return Illuminate\Database\Query\Builder
|
||||
*/
|
||||
public function entityFilter()
|
||||
public function entityFilter(): Builder
|
||||
{
|
||||
//return $this->builder->whereCompanyId(auth()->user()->company()->id);
|
||||
return $this->builder->where('company_id', auth()->user()->company()->id)->orWhere('company_id', null)->orderBy('id','asc');
|
||||
|
@ -12,7 +12,6 @@
|
||||
namespace App\Filters;
|
||||
|
||||
use App\Models\Company;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
/**
|
||||
@ -27,7 +26,7 @@ class DocumentFilters extends QueryFilters
|
||||
* @return Builder
|
||||
* @deprecated
|
||||
*/
|
||||
public function filter(string $filter = '') : Builder
|
||||
public function filter(string $filter = ''): Builder
|
||||
{
|
||||
if (strlen($filter) == 0) {
|
||||
return $this->builder;
|
||||
@ -36,8 +35,15 @@ class DocumentFilters extends QueryFilters
|
||||
return $this->builder;
|
||||
}
|
||||
|
||||
/* If client ID passed to this entity, simply return */
|
||||
public function client_id(string $client_id = '') :Builder
|
||||
/**
|
||||
* Overriding method as client_id does
|
||||
* not exist on this model, just pass
|
||||
* back the builder
|
||||
* @param string $client_id The client hashed id.
|
||||
*
|
||||
* @return Builder
|
||||
*/
|
||||
public function client_id(string $client_id = ''): Builder
|
||||
{
|
||||
return $this->builder;
|
||||
}
|
||||
@ -48,11 +54,14 @@ class DocumentFilters extends QueryFilters
|
||||
* @param string sort formatted as column|asc
|
||||
* @return Builder
|
||||
*/
|
||||
public function sort(string $sort) : Builder
|
||||
public function sort(string $sort = '') : Builder
|
||||
{
|
||||
$sort_col = explode('|', $sort);
|
||||
|
||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
||||
if(is_array($sort_col))
|
||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
||||
|
||||
return $this->builder;
|
||||
}
|
||||
|
||||
|
||||
|
@ -11,11 +11,7 @@
|
||||
|
||||
namespace App\Filters;
|
||||
|
||||
use App\Models\Expense;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
/**
|
||||
* ExpenseCategoryFilters.
|
||||
@ -49,9 +45,9 @@ class ExpenseCategoryFilters extends QueryFilters
|
||||
{
|
||||
$sort_col = explode('|', $sort);
|
||||
|
||||
if (is_array($sort_col) && in_array($sort_col[1], ['asc', 'desc']) && in_array($sort_col[0], ['name'])) {
|
||||
if (is_array($sort_col) && in_array($sort_col[1], ['asc', 'desc']) && in_array($sort_col[0], ['name']))
|
||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
||||
}
|
||||
|
||||
|
||||
return $this->builder;
|
||||
}
|
||||
@ -63,8 +59,6 @@ class ExpenseCategoryFilters extends QueryFilters
|
||||
*/
|
||||
public function entityFilter()
|
||||
{
|
||||
|
||||
//return $this->builder->whereCompanyId(auth()->user()->company()->id);
|
||||
return $this->builder->company();
|
||||
}
|
||||
}
|
||||
|
@ -11,11 +11,7 @@
|
||||
|
||||
namespace App\Filters;
|
||||
|
||||
use App\Models\Expense;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
/**
|
||||
* ExpenseFilters.
|
||||
@ -36,11 +32,11 @@ class ExpenseFilters extends QueryFilters
|
||||
}
|
||||
|
||||
return $this->builder->where(function ($query) use ($filter) {
|
||||
$query->where('expenses.public_notes', 'like', '%'.$filter.'%')
|
||||
->orWhere('expenses.custom_value1', 'like', '%'.$filter.'%')
|
||||
->orWhere('expenses.custom_value2', 'like', '%'.$filter.'%')
|
||||
->orWhere('expenses.custom_value3', 'like', '%'.$filter.'%')
|
||||
->orWhere('expenses.custom_value4', 'like', '%'.$filter.'%');
|
||||
$query->where('public_notes', 'like', '%'.$filter.'%')
|
||||
->orWhere('custom_value1', 'like', '%'.$filter.'%')
|
||||
->orWhere('custom_value2', 'like', '%'.$filter.'%')
|
||||
->orWhere('custom_value3', 'like', '%'.$filter.'%')
|
||||
->orWhere('custom_value4', 'like', '%'.$filter.'%');
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,6 @@
|
||||
namespace App\Filters;
|
||||
|
||||
use App\Models\Invoice;
|
||||
use App\Models\User;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Carbon;
|
||||
@ -80,6 +79,9 @@ class InvoiceFilters extends QueryFilters
|
||||
|
||||
public function number(string $number = '') :Builder
|
||||
{
|
||||
if(strlen($number) == 0)
|
||||
return $this->builder;
|
||||
|
||||
return $this->builder->where('number', $number);
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,6 @@
|
||||
|
||||
namespace App\Filters;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
/**
|
||||
@ -49,6 +48,7 @@ class PaymentFilters extends QueryFilters
|
||||
{
|
||||
|
||||
if($value == 'true'){
|
||||
|
||||
return $this->builder
|
||||
->where('is_deleted',0)
|
||||
->where(function ($query){
|
||||
@ -72,7 +72,10 @@ class PaymentFilters extends QueryFilters
|
||||
{
|
||||
$sort_col = explode('|', $sort);
|
||||
|
||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
||||
if(is_array($sort_col))
|
||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function number(string $number) : Builder
|
||||
|
@ -11,11 +11,7 @@
|
||||
|
||||
namespace App\Filters;
|
||||
|
||||
use App\Models\Design;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
/**
|
||||
* PaymentTermFilters.
|
||||
@ -29,7 +25,7 @@ class PaymentTermFilters extends QueryFilters
|
||||
* @return Builder
|
||||
* @deprecated
|
||||
*/
|
||||
public function filter(string $filter = '') : Builder
|
||||
public function filter(string $filter = ''): Builder
|
||||
{
|
||||
if (strlen($filter) == 0) {
|
||||
return $this->builder;
|
||||
@ -46,7 +42,7 @@ class PaymentTermFilters extends QueryFilters
|
||||
* @param string sort formatted as column|asc
|
||||
* @return Builder
|
||||
*/
|
||||
public function sort(string $sort) : Builder
|
||||
public function sort(string $sort): Builder
|
||||
{
|
||||
$sort_col = explode('|', $sort);
|
||||
|
||||
@ -56,12 +52,10 @@ class PaymentTermFilters extends QueryFilters
|
||||
/**
|
||||
* Filters the query by the users company ID.
|
||||
*
|
||||
* @return Illuminate\Database\Query\Builder
|
||||
* @return Builder
|
||||
*/
|
||||
public function entityFilter()
|
||||
public function entityFilter(): Builder
|
||||
{
|
||||
return $this->builder->company();
|
||||
//return $this->builder->whereCompanyId(auth()->user()->company()->id);
|
||||
// return $this->builder->whereCompanyId(auth()->user()->company()->id)->orWhere('company_id', null);
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,6 @@
|
||||
|
||||
namespace App\Filters;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
/**
|
||||
|
@ -11,11 +11,7 @@
|
||||
|
||||
namespace App\Filters;
|
||||
|
||||
use App\Models\Project;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
/**
|
||||
* ProjectFilters.
|
||||
@ -52,7 +48,8 @@ class ProjectFilters extends QueryFilters
|
||||
{
|
||||
$sort_col = explode('|', $sort);
|
||||
|
||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
||||
if(is_array($sort_col))
|
||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -12,7 +12,6 @@
|
||||
namespace App\Filters;
|
||||
|
||||
use App\Models\PurchaseOrder;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class PurchaseOrderFilters extends QueryFilters
|
||||
@ -70,7 +69,7 @@ class PurchaseOrderFilters extends QueryFilters
|
||||
if(count($status_parameters) >=1) {
|
||||
$query->whereIn('status_id', $status_parameters);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
return $this->builder;
|
||||
}
|
||||
|
@ -12,7 +12,6 @@
|
||||
namespace App\Filters;
|
||||
|
||||
use App\Models\Quote;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
/**
|
||||
|
@ -11,11 +11,7 @@
|
||||
|
||||
namespace App\Filters;
|
||||
|
||||
use App\Models\RecurringExpense;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
/**
|
||||
* RecurringExpenseFilters.
|
||||
@ -29,19 +25,18 @@ class RecurringExpenseFilters extends QueryFilters
|
||||
* @return Builder
|
||||
* @deprecated
|
||||
*/
|
||||
public function filter(string $filter = '') : Builder
|
||||
public function filter(string $filter = ''): Builder
|
||||
{
|
||||
if (strlen($filter) == 0) {
|
||||
return $this->builder;
|
||||
}
|
||||
|
||||
return $this->builder->where(function ($query) use ($filter) {
|
||||
$query->where('recurring_expenses.name', 'like', '%'.$filter.'%')
|
||||
->orWhere('recurring_expenses.id_number', 'like', '%'.$filter.'%')
|
||||
->orWhere('recurring_expenses.custom_value1', 'like', '%'.$filter.'%')
|
||||
->orWhere('recurring_expenses.custom_value2', 'like', '%'.$filter.'%')
|
||||
->orWhere('recurring_expenses.custom_value3', 'like', '%'.$filter.'%')
|
||||
->orWhere('recurring_expenses.custom_value4', 'like', '%'.$filter.'%');
|
||||
return $this->builder->where(function ($query) use ($filter) {
|
||||
$query->where('public_notes', 'like', '%'.$filter.'%')
|
||||
->orWhere('custom_value1', 'like', '%'.$filter.'%')
|
||||
->orWhere('custom_value2', 'like', '%'.$filter.'%')
|
||||
->orWhere('custom_value3', 'like', '%'.$filter.'%')
|
||||
->orWhere('custom_value4', 'like', '%'.$filter.'%');
|
||||
});
|
||||
}
|
||||
|
||||
@ -51,7 +46,7 @@ class RecurringExpenseFilters extends QueryFilters
|
||||
* @param string sort formatted as column|asc
|
||||
* @return Builder
|
||||
*/
|
||||
public function sort(string $sort) : Builder
|
||||
public function sort(string $sort): Builder
|
||||
{
|
||||
$sort_col = explode('|', $sort);
|
||||
|
||||
|
@ -12,7 +12,6 @@
|
||||
namespace App\Filters;
|
||||
|
||||
use App\Models\RecurringInvoice;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
/**
|
||||
@ -77,7 +76,10 @@ class RecurringInvoiceFilters extends QueryFilters
|
||||
if (in_array('completed', $status_parameters))
|
||||
$recurring_filters[] = RecurringInvoice::STATUS_COMPLETED;
|
||||
|
||||
return $this->builder->whereIn('status_id', $recurring_filters);
|
||||
if(count($recurring_filters) >= 1)
|
||||
return $this->builder->whereIn('status_id', $recurring_filters);
|
||||
|
||||
return $this->builder;
|
||||
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,6 @@
|
||||
|
||||
namespace App\Filters;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
/**
|
||||
@ -26,7 +25,7 @@ class RecurringQuoteFilters extends QueryFilters
|
||||
* @return Builder
|
||||
* @deprecated
|
||||
*/
|
||||
public function filter(string $filter = '') : Builder
|
||||
public function filter(string $filter = ''): Builder
|
||||
{
|
||||
if (strlen($filter) == 0) {
|
||||
return $this->builder;
|
||||
@ -46,7 +45,7 @@ class RecurringQuoteFilters extends QueryFilters
|
||||
* @param string sort formatted as column|asc
|
||||
* @return Builder
|
||||
*/
|
||||
public function sort(string $sort) : Builder
|
||||
public function sort(string $sort): Builder
|
||||
{
|
||||
$sort_col = explode('|', $sort);
|
||||
|
||||
@ -56,9 +55,9 @@ class RecurringQuoteFilters extends QueryFilters
|
||||
/**
|
||||
* Filters the query by the users company ID.
|
||||
*
|
||||
* @return Illuminate\Database\Query\Builder
|
||||
* @return Builder
|
||||
*/
|
||||
public function entityFilter()
|
||||
public function entityFilter(): Builder
|
||||
{
|
||||
return $this->builder->company();
|
||||
}
|
||||
|
@ -11,11 +11,7 @@
|
||||
|
||||
namespace App\Filters;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\Webhook;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
/**
|
||||
* SubscriptionFilters.
|
||||
@ -29,7 +25,7 @@ class SubscriptionFilters extends QueryFilters
|
||||
* @return Builder
|
||||
* @deprecated
|
||||
*/
|
||||
public function filter(string $filter = '') : Builder
|
||||
public function filter(string $filter = ''): Builder
|
||||
{
|
||||
if (strlen($filter) == 0) {
|
||||
return $this->builder;
|
||||
@ -46,7 +42,7 @@ class SubscriptionFilters extends QueryFilters
|
||||
* @param string sort formatted as column|asc
|
||||
* @return Builder
|
||||
*/
|
||||
public function sort(string $sort) : Builder
|
||||
public function sort(string $sort): Builder
|
||||
{
|
||||
$sort_col = explode('|', $sort);
|
||||
|
||||
@ -56,9 +52,9 @@ class SubscriptionFilters extends QueryFilters
|
||||
/**
|
||||
* Filters the query by the users company ID.
|
||||
*
|
||||
* @return Illuminate\Database\Query\Builder
|
||||
* @return Builder
|
||||
*/
|
||||
public function entityFilter()
|
||||
public function entityFilter(): Builder
|
||||
{
|
||||
return $this->builder->company();
|
||||
}
|
||||
|
@ -11,7 +11,6 @@
|
||||
|
||||
namespace App\Filters;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
/**
|
||||
@ -66,9 +65,9 @@ class SystemLogFilters extends QueryFilters
|
||||
/**
|
||||
* Filters the query by the users company ID.
|
||||
*
|
||||
* @return Illuminate\Database\Query\Builder
|
||||
* @return Builder
|
||||
*/
|
||||
public function entityFilter()
|
||||
public function entityFilter(): Builder
|
||||
{
|
||||
return $this->builder->company();
|
||||
}
|
||||
|
@ -11,7 +11,6 @@
|
||||
|
||||
namespace App\Filters;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
@ -29,7 +28,7 @@ class TaskFilters extends QueryFilters
|
||||
* @return Builder
|
||||
* @deprecated
|
||||
*/
|
||||
public function filter(string $filter = '') : Builder
|
||||
public function filter(string $filter = ''): Builder
|
||||
{
|
||||
if (strlen($filter) == 0) {
|
||||
return $this->builder;
|
||||
@ -55,7 +54,7 @@ class TaskFilters extends QueryFilters
|
||||
* @param string client_status The invoice status as seen by the client
|
||||
* @return Builder
|
||||
*/
|
||||
public function client_status(string $value = '') :Builder
|
||||
public function client_status(string $value = ''): Builder
|
||||
{
|
||||
if (strlen($value) == 0) {
|
||||
return $this->builder;
|
||||
@ -90,7 +89,7 @@ class TaskFilters extends QueryFilters
|
||||
* @param string sort formatted as column|asc
|
||||
* @return Builder
|
||||
*/
|
||||
public function sort(string $sort) : Builder
|
||||
public function sort(string $sort): Builder
|
||||
{
|
||||
$sort_col = explode('|', $sort);
|
||||
|
||||
@ -100,9 +99,9 @@ class TaskFilters extends QueryFilters
|
||||
/**
|
||||
* Filters the query by the users company ID.
|
||||
*
|
||||
* @return Illuminate\Database\Query\Builder
|
||||
* @return Builder
|
||||
*/
|
||||
public function entityFilter()
|
||||
public function entityFilter(): Builder
|
||||
{
|
||||
return $this->builder->company();
|
||||
}
|
||||
|
@ -11,7 +11,6 @@
|
||||
|
||||
namespace App\Filters;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
/**
|
||||
@ -26,7 +25,7 @@ class TaskStatusFilters extends QueryFilters
|
||||
* @return Builder
|
||||
* @deprecated
|
||||
*/
|
||||
public function filter(string $filter = '') : Builder
|
||||
public function filter(string $filter = ''): Builder
|
||||
{
|
||||
if (strlen($filter) == 0) {
|
||||
return $this->builder;
|
||||
@ -53,9 +52,9 @@ class TaskStatusFilters extends QueryFilters
|
||||
/**
|
||||
* Filters the query by the users company ID.
|
||||
*
|
||||
* @return Illuminate\Database\Query\Builder
|
||||
* @return Builder
|
||||
*/
|
||||
public function entityFilter()
|
||||
public function entityFilter(): Builder
|
||||
{
|
||||
return $this->builder->company();
|
||||
}
|
||||
|
@ -11,7 +11,6 @@
|
||||
|
||||
namespace App\Filters;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
/**
|
||||
@ -53,9 +52,9 @@ class TaxRateFilters extends QueryFilters
|
||||
/**
|
||||
* Filters the query by the users company ID.
|
||||
*
|
||||
* @return Illuminate\Database\Query\Builder
|
||||
* @return Builder
|
||||
*/
|
||||
public function entityFilter()
|
||||
public function entityFilter(): Builder
|
||||
{
|
||||
return $this->builder->company();
|
||||
}
|
||||
|
@ -11,10 +11,7 @@
|
||||
|
||||
namespace App\Filters;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
/**
|
||||
* TokenFilters.
|
||||
@ -55,9 +52,9 @@ class TokenFilters extends QueryFilters
|
||||
/**
|
||||
* Filters the query by the users company ID.
|
||||
*
|
||||
* @return Illuminate\Database\Query\Builder
|
||||
* @return Builder
|
||||
*/
|
||||
public function entityFilter()
|
||||
public function entityFilter(): Builder
|
||||
{
|
||||
return $this->builder->company();
|
||||
}
|
||||
|
@ -11,7 +11,6 @@
|
||||
|
||||
namespace App\Filters;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
/**
|
||||
@ -61,10 +60,29 @@ class UserFilters extends QueryFilters
|
||||
*/
|
||||
public function entityFilter()
|
||||
{
|
||||
//return $this->builder->user_companies()->whereCompanyId(auth()->user()->company()->id);
|
||||
//return $this->builder->whereCompanyId(auth()->user()->company()->id);
|
||||
return $this->builder->whereHas('company_users', function ($q) {
|
||||
$q->where('company_id', '=', auth()->user()->company()->id);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the base with() function as no company ID
|
||||
* exists on the user table
|
||||
*
|
||||
* @param string $value Hashed ID of the user to return back in the dataset
|
||||
*
|
||||
* @return Builder
|
||||
*/
|
||||
public function with(string $value = ''): Builder
|
||||
{
|
||||
|
||||
if(strlen($value) == 0)
|
||||
return $this->builder;
|
||||
|
||||
return $this->builder
|
||||
->orWhere($this->with_property, $value)
|
||||
->orderByRaw("{$this->with_property} = ? DESC", [$value])
|
||||
->where('account_id', auth()->user()->account_id);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -11,11 +11,7 @@
|
||||
|
||||
namespace App\Filters;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\Vendor;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
/**
|
||||
* VendorFilters.
|
||||
@ -29,7 +25,7 @@ class VendorFilters extends QueryFilters
|
||||
* @return Builder
|
||||
* @deprecated
|
||||
*/
|
||||
public function filter(string $filter = '') : Builder
|
||||
public function filter(string $filter = ''): Builder
|
||||
{
|
||||
if (strlen($filter) == 0) {
|
||||
return $this->builder;
|
||||
@ -56,7 +52,7 @@ class VendorFilters extends QueryFilters
|
||||
* @param string sort formatted as column|asc
|
||||
* @return Builder
|
||||
*/
|
||||
public function sort(string $sort) : Builder
|
||||
public function sort(string $sort): Builder
|
||||
{
|
||||
$sort_col = explode('|', $sort);
|
||||
|
||||
@ -66,12 +62,10 @@ class VendorFilters extends QueryFilters
|
||||
/**
|
||||
* Filters the query by the users company ID.
|
||||
*
|
||||
* @return Illuminate\Database\Query\Builder
|
||||
* @return Builder
|
||||
*/
|
||||
public function entityFilter()
|
||||
public function entityFilter(): Builder
|
||||
{
|
||||
|
||||
//return $this->builder->whereCompanyId(auth()->user()->company()->id);
|
||||
return $this->builder->company();
|
||||
}
|
||||
}
|
||||
|
@ -11,11 +11,7 @@
|
||||
|
||||
namespace App\Filters;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\Webhook;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
/**
|
||||
* TokenFilters.
|
||||
@ -29,14 +25,14 @@ class WebhookFilters extends QueryFilters
|
||||
* @return Builder
|
||||
* @deprecated
|
||||
*/
|
||||
public function filter(string $filter = '') : Builder
|
||||
public function filter(string $filter = ''): Builder
|
||||
{
|
||||
if (strlen($filter) == 0) {
|
||||
return $this->builder;
|
||||
}
|
||||
|
||||
return $this->builder->where(function ($query) use ($filter) {
|
||||
$query->where('webhooks.target_url', 'like', '%'.$filter.'%');
|
||||
$query->where('target_url', 'like', '%'.$filter.'%');
|
||||
});
|
||||
}
|
||||
|
||||
@ -46,7 +42,7 @@ class WebhookFilters extends QueryFilters
|
||||
* @param string sort formatted as column|asc
|
||||
* @return Builder
|
||||
*/
|
||||
public function sort(string $sort) : Builder
|
||||
public function sort(string $sort): Builder
|
||||
{
|
||||
$sort_col = explode('|', $sort);
|
||||
|
||||
@ -56,9 +52,9 @@ class WebhookFilters extends QueryFilters
|
||||
/**
|
||||
* Filters the query by the users company ID.
|
||||
*
|
||||
* @return Illuminate\Database\Query\Builder
|
||||
* @return Builder
|
||||
*/
|
||||
public function entityFilter()
|
||||
public function entityFilter(): Builder
|
||||
{
|
||||
return $this->builder->company();
|
||||
}
|
||||
|
@ -24,6 +24,9 @@ use Illuminate\View\View;
|
||||
function isActive($page, bool $boolean = false)
|
||||
{
|
||||
$current_page = Route::currentRouteName();
|
||||
$action = Route::currentRouteAction(); // string
|
||||
|
||||
$show = str_replace(['.show','payment_methodss','documentss','subscriptionss','paymentss'],['s.index','payment_methods','documents','subscriptions','payments'], $current_page);
|
||||
|
||||
if ($page == $current_page && $boolean) {
|
||||
return true;
|
||||
@ -33,6 +36,12 @@ function isActive($page, bool $boolean = false)
|
||||
return 'bg-gray-200';
|
||||
}
|
||||
|
||||
if(($page == $show) && $boolean){
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,7 @@ class LoginController extends BaseController
|
||||
* description="Authentication",
|
||||
* @OA\ExternalDocumentation(
|
||||
* description="Find out more",
|
||||
* url="http://docs.invoiceninja.com"
|
||||
* url="https://invoiceninja.github.io"
|
||||
* )
|
||||
* )
|
||||
*/
|
||||
|
@ -335,7 +335,7 @@ class BankTransactionRuleController extends BaseController
|
||||
*
|
||||
* @OA\Post(
|
||||
* path="/api/v1/bank_transaction_rules",
|
||||
* operationId="storeBankTransaction",
|
||||
* operationId="storeBankTransactionRule",
|
||||
* tags={"bank_transaction_rules"},
|
||||
* summary="Adds a bank_transaction rule",
|
||||
* description="Adds an bank_transaction to a company",
|
||||
|
@ -160,7 +160,7 @@ class PaymentController extends Controller
|
||||
}
|
||||
|
||||
if (property_exists($payment_hash->data, 'billing_context')) {
|
||||
$billing_subscription = \App\Models\Subscription::find($payment_hash->data->billing_context->subscription_id);
|
||||
$billing_subscription = \App\Models\Subscription::find($this->decodePrimaryKey($payment_hash->data->billing_context->subscription_id));
|
||||
|
||||
return (new SubscriptionService($billing_subscription))->completePurchase($payment_hash);
|
||||
}
|
||||
|
@ -19,8 +19,8 @@
|
||||
* url="https://ninja.test",
|
||||
* ),
|
||||
* @OA\ExternalDocumentation(
|
||||
* description="http://docs.invoiceninja.com",
|
||||
* url="http://docs.invoiceninja.com"
|
||||
* description="https://invoiceninja.github.io",
|
||||
* url="https://invoiceninja.github.io"
|
||||
* ),
|
||||
* ),
|
||||
*/
|
||||
|
@ -108,6 +108,8 @@ class SelfUpdateController extends BaseController
|
||||
$zipFile->openFile($file);
|
||||
|
||||
$zipFile->deleteFromName(".htaccess");
|
||||
|
||||
$zipFile->rewrite();
|
||||
|
||||
$zipFile->extractTo(base_path());
|
||||
|
||||
|
@ -323,7 +323,7 @@ class TaskSchedulerController extends BaseController
|
||||
* @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/TaskScheduleSchema"),
|
||||
* @OA\JsonContent(ref="#/components/schemas/TaskSchedulerSchema"),
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response=422,
|
||||
|
@ -403,10 +403,10 @@ class BillingPortalPurchase extends Component
|
||||
->save();
|
||||
|
||||
Cache::put($this->hash, [
|
||||
'subscription_id' => $this->subscription->id,
|
||||
'subscription_id' => $this->subscription->hashed_id,
|
||||
'email' => $this->email ?? $this->contact->email,
|
||||
'client_id' => $this->contact->client->id,
|
||||
'invoice_id' => $this->invoice->id,
|
||||
'client_id' => $this->contact->client->hashed_id,
|
||||
'invoice_id' => $this->invoice->hashed_id,
|
||||
'context' => 'purchase',
|
||||
'campaign' => $this->campaign,
|
||||
], now()->addMinutes(60));
|
||||
|
@ -483,7 +483,12 @@ class BillingPortalPurchasev2 extends Component
|
||||
*/
|
||||
protected function getPaymentMethods() :self
|
||||
{
|
||||
if($this->contact)
|
||||
nlog("total amount = {$this->float_amount_total}");
|
||||
|
||||
if($this->float_amount_total == 0)
|
||||
$this->methods = [];
|
||||
|
||||
if($this->contact && $this->float_amount_total >= 1)
|
||||
$this->methods = $this->contact->client->service()->getPaymentMethods($this->float_amount_total);
|
||||
|
||||
return $this;
|
||||
@ -526,7 +531,7 @@ class BillingPortalPurchasev2 extends Component
|
||||
}
|
||||
|
||||
$data = [
|
||||
'client_id' => $this->contact->client->id,
|
||||
'client_id' => $this->contact->client->hashed_id,
|
||||
'date' => now()->format('Y-m-d'),
|
||||
'invitations' => [[
|
||||
'key' => '',
|
||||
@ -547,10 +552,10 @@ class BillingPortalPurchasev2 extends Component
|
||||
->save();
|
||||
|
||||
Cache::put($this->hash, [
|
||||
'subscription_id' => $this->subscription->id,
|
||||
'subscription_id' => $this->subscription->hashed_id,
|
||||
'email' => $this->email ?? $this->contact->email,
|
||||
'client_id' => $this->contact->client->id,
|
||||
'invoice_id' => $this->invoice->id,
|
||||
'client_id' => $this->contact->client->hashed_id,
|
||||
'invoice_id' => $this->invoice->hashed_id,
|
||||
'context' => 'purchase',
|
||||
'campaign' => $this->campaign,
|
||||
'bundle' => $this->bundle,
|
||||
@ -562,17 +567,62 @@ class BillingPortalPurchasev2 extends Component
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Starts the trial
|
||||
*
|
||||
* @return \Illuminate\Routing\Redirector|\Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function handleTrial()
|
||||
{
|
||||
return $this->subscription->service()->startTrial([
|
||||
'email' => $this->email ?? $this->contact->email,
|
||||
'quantity' => $this->quantity,
|
||||
'contact_id' => $this->contact->id,
|
||||
'client_id' => $this->contact->client->id,
|
||||
'contact_id' => $this->contact->hashed_id,
|
||||
'client_id' => $this->contact->client->hashed_id,
|
||||
'bundle' => $this->bundle,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* When the subscription total comes to $0 we
|
||||
* pass back a $0 Invoice.
|
||||
*
|
||||
* @return \Illuminate\Routing\Redirector|\Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function handlePaymentNotRequired()
|
||||
{
|
||||
|
||||
$eligibility_check = $this->subscription->service()->isEligible($this->contact);
|
||||
|
||||
if(is_array($eligibility_check) && $eligibility_check['message'] != 'Success'){
|
||||
|
||||
$this->is_eligible = false;
|
||||
$this->not_eligible_message = $eligibility_check['message'];
|
||||
return $this;
|
||||
|
||||
}
|
||||
|
||||
$invoice = $this->subscription
|
||||
->service()
|
||||
->createInvoiceV2($this->bundle, $this->contact->client_id, $this->valid_coupon)
|
||||
->service()
|
||||
->fillDefaults()
|
||||
->adjustInventory()
|
||||
->save();
|
||||
|
||||
$invoice->number = null;
|
||||
|
||||
$invoice->service()
|
||||
->markPaid()
|
||||
->save();
|
||||
|
||||
return $this->subscription
|
||||
->service()
|
||||
->handleNoPaymentFlow($invoice, $this->bundle, $this->contact);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@ -607,43 +657,6 @@ class BillingPortalPurchasev2 extends Component
|
||||
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Handle user authentication
|
||||
// *
|
||||
// * @return $this|bool|void
|
||||
// */
|
||||
// public function authenticate()
|
||||
// {
|
||||
// $this->validate();
|
||||
|
||||
// $contact = ClientContact::where('email', $this->email)
|
||||
// ->where('company_id', $this->subscription->company_id)
|
||||
// ->first();
|
||||
|
||||
// if ($contact && $this->steps['existing_user'] === false) {
|
||||
// return $this->steps['existing_user'] = true;
|
||||
// }
|
||||
|
||||
// if ($contact && $this->steps['existing_user']) {
|
||||
// $attempt = Auth::guard('contact')->attempt(['email' => $this->email, 'password' => $this->password, 'company_id' => $this->subscription->company_id]);
|
||||
|
||||
// return $attempt
|
||||
// ? $this->getPaymentMethods($contact)
|
||||
// : session()->flash('message', 'These credentials do not match our records.');
|
||||
// }
|
||||
|
||||
// $this->steps['existing_user'] = false;
|
||||
|
||||
// $contact = $this->createBlankClient();
|
||||
|
||||
// if ($contact && $contact instanceof ClientContact) {
|
||||
// $this->getPaymentMethods($contact);
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create a blank client. Used for new customers purchasing.
|
||||
*
|
||||
|
@ -42,7 +42,7 @@ class PaymentsTable extends Component
|
||||
public function render()
|
||||
{
|
||||
$query = Payment::query()
|
||||
->with('type', 'client')
|
||||
->with('type', 'client', 'invoices')
|
||||
->where('company_id', $this->company->id)
|
||||
->where('client_id', auth()->guard('contact')->user()->client_id)
|
||||
->whereIn('status_id', [Payment::STATUS_FAILED, Payment::STATUS_COMPLETED, Payment::STATUS_PENDING, Payment::STATUS_REFUNDED, Payment::STATUS_PARTIALLY_REFUNDED])
|
||||
|
@ -106,11 +106,11 @@ class SubscriptionPlanSwitch extends Component
|
||||
]);
|
||||
|
||||
Cache::put($this->hash, [
|
||||
'subscription_id' => $this->target->id,
|
||||
'target_id' => $this->target->id,
|
||||
'recurring_invoice' => $this->recurring_invoice->id,
|
||||
'client_id' => $this->recurring_invoice->client->id,
|
||||
'invoice_id' => $this->state['invoice']->id,
|
||||
'subscription_id' => $this->target->hashed_id,
|
||||
'target_id' => $this->target->hashed_id,
|
||||
'recurring_invoice' => $this->recurring_invoice->hashed_id,
|
||||
'client_id' => $this->recurring_invoice->client->hashed_id,
|
||||
'invoice_id' => $this->state['invoice']->hashed_id,
|
||||
'context' => 'change_plan',
|
||||
now()->addMinutes(60), ]
|
||||
);
|
||||
|
@ -78,8 +78,6 @@ class StoreShopClientRequest extends Request
|
||||
|
||||
$input = $this->all();
|
||||
|
||||
//@todo implement feature permissions for > 100 clients
|
||||
//
|
||||
$settings = ClientSettings::defaults();
|
||||
|
||||
if (array_key_exists('settings', $input) && ! empty($input['settings'])) {
|
||||
|
@ -9,7 +9,7 @@
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Http\Requests\Task;
|
||||
namespace App\Http\Requests\TaskScheduler;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
|
||||
|
@ -63,8 +63,6 @@ class StoreUserRequest extends Request
|
||||
{
|
||||
$input = $this->all();
|
||||
|
||||
//unique user rule - check company_user table for user_id / company_id / account_id if none exist we can add the user. ELSE return false
|
||||
|
||||
if (array_key_exists('email', $input)) {
|
||||
$input['email'] = trim($input['email']);
|
||||
}
|
||||
@ -79,12 +77,10 @@ class StoreUserRequest extends Request
|
||||
}
|
||||
|
||||
if (! isset($input['company_user']['settings'])) {
|
||||
//$input['company_user']['settings'] = DefaultSettings::userSettings();
|
||||
$input['company_user']['settings'] = null;
|
||||
}
|
||||
} else {
|
||||
$input['company_user'] = [
|
||||
//'settings' => DefaultSettings::userSettings(),
|
||||
'settings' => null,
|
||||
'permissions' => '',
|
||||
];
|
||||
|
@ -319,7 +319,7 @@ class MatchBankTransactions implements ShouldQueue
|
||||
|
||||
});
|
||||
|
||||
}, 1);
|
||||
}, 2);
|
||||
|
||||
if(!$this->invoice)
|
||||
return;
|
||||
|
@ -45,6 +45,7 @@ class SubscriptionCron
|
||||
$invoices = Invoice::where('is_deleted', 0)
|
||||
->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL])
|
||||
->where('balance', '>', 0)
|
||||
->where('is_proforma',0)
|
||||
->whereDate('due_date', '<=', now()->addDay()->startOfDay())
|
||||
->whereNull('deleted_at')
|
||||
->whereNotNull('subscription_id')
|
||||
@ -74,6 +75,7 @@ class SubscriptionCron
|
||||
$invoices = Invoice::where('is_deleted', 0)
|
||||
->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL])
|
||||
->where('balance', '>', 0)
|
||||
->where('is_proforma',0)
|
||||
->whereDate('due_date', '<=', now()->addDay()->startOfDay())
|
||||
->whereNull('deleted_at')
|
||||
->whereNotNull('subscription_id')
|
||||
|
@ -56,12 +56,5 @@ class InvoiceWorkflowSettings implements ShouldQueue
|
||||
/* Throws: Payment amount xxx does not match invoice totals. */
|
||||
$this->base_repository->archive($this->invoice);
|
||||
}
|
||||
|
||||
//@TODO this setting should only fire for recurring invoices
|
||||
// if ($this->client->getSetting('auto_email_invoice')) {
|
||||
// $this->invoice->invitations->each(function ($invitation, $key) {
|
||||
// $this->invoice->service()->sendEmail($invitation->contact);
|
||||
// });
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ class BankTransactionSync implements ShouldQueue
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
|
||||
//multiDB environment, need to
|
||||
foreach (MultiDB::$dbs as $db)
|
||||
{
|
||||
|
@ -29,6 +29,8 @@ class UpdateOrCreateProduct implements ShouldQueue
|
||||
|
||||
public $company;
|
||||
|
||||
public $deleteWhenMissingModels = true;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
|
@ -212,6 +212,11 @@ class Payment extends BaseModel
|
||||
return Number::formatMoney($this->amount, $this->client);
|
||||
}
|
||||
|
||||
public function formatAmount(float $amount): string
|
||||
{
|
||||
return Number::formatMoney($amount, $this->client);
|
||||
}
|
||||
|
||||
public function clientPaymentDate()
|
||||
{
|
||||
if (! $this->date) {
|
||||
|
@ -43,4 +43,5 @@ class Paymentable extends Pivot
|
||||
{
|
||||
return $this->belongsTo(Payment::class);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -27,7 +27,6 @@ class ClientPresenter extends EntityPresenter
|
||||
return $this->entity->name;
|
||||
}
|
||||
|
||||
//$contact = $this->entity->primary_contact->first();
|
||||
$contact = $this->entity->contacts->whereNotNull('email')->first();
|
||||
|
||||
$contact_name = 'No Contact Set';
|
||||
|
@ -370,11 +370,6 @@ class User extends Authenticatable implements MustVerifyEmail
|
||||
(is_int(stripos($this->token()->cu->permissions, $all_permission))) ||
|
||||
(is_int(stripos($this->token()->cu->permissions, $permission)));
|
||||
|
||||
//23-03-2021 - stripos return an int if true and bool false, but 0 is also interpreted as false, so we simply use is_int() to verify state
|
||||
// return $this->isOwner() ||
|
||||
// $this->isAdmin() ||
|
||||
// (stripos($this->company_user->permissions, $all_permission) !== false) ||
|
||||
// (stripos($this->company_user->permissions, $permission) !== false);
|
||||
}
|
||||
|
||||
public function documents()
|
||||
|
@ -289,7 +289,7 @@ class BaseDriver extends AbstractPaymentDriver
|
||||
event(new PaymentWasCreated($payment, $payment->company, Ninja::eventVars()));
|
||||
|
||||
if (property_exists($this->payment_hash->data, 'billing_context') && $status == Payment::STATUS_COMPLETED) {
|
||||
$billing_subscription = \App\Models\Subscription::find($this->payment_hash->data->billing_context->subscription_id);
|
||||
$billing_subscription = \App\Models\Subscription::find($this->decodePrimaryKey($this->payment_hash->data->billing_context->subscription_id));
|
||||
|
||||
// To access campaign hash => $this->payment_hash->data->billing_context->campaign;
|
||||
// To access campaign data => Cache::get(CAMPAIGN_HASH)
|
||||
|
@ -18,18 +18,16 @@ use App\Models\Invoice;
|
||||
use App\Models\Proposal;
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\TruthSource;
|
||||
use Illuminate\Cache\RateLimiting\Limit;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\Relation;
|
||||
use Illuminate\Mail\Mailer;
|
||||
use Illuminate\Queue\Events\JobProcessing;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
use Illuminate\Support\Facades\Blade;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\ParallelTesting;
|
||||
use Illuminate\Support\Facades\Queue;
|
||||
use Illuminate\Support\Facades\RateLimiter;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Livewire\Livewire;
|
||||
@ -111,13 +109,4 @@ class AppServiceProvider extends ServiceProvider
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Register any application services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -52,7 +52,6 @@ class ClientRepository extends BaseRepository
|
||||
* @return Client|Client|null Client Object
|
||||
*
|
||||
* @throws \Laracasts\Presenter\Exceptions\PresenterException
|
||||
* @todo Write tests to make sure that custom client numbers work as expected.
|
||||
*/
|
||||
public function save(array $data, Client $client) : ?Client
|
||||
{
|
||||
|
@ -42,7 +42,7 @@ class ClientService
|
||||
$this->client->balance += $amount;
|
||||
$this->client->save();
|
||||
|
||||
}, 1);
|
||||
}, 2);
|
||||
}
|
||||
catch (\Throwable $throwable) {
|
||||
nlog("DB ERROR " . $throwable->getMessage());
|
||||
@ -63,7 +63,7 @@ class ClientService
|
||||
$this->client->paid_to_date += $paid_to_date;
|
||||
$this->client->save();
|
||||
|
||||
}, 1);
|
||||
}, 2);
|
||||
}
|
||||
catch (\Throwable $throwable) {
|
||||
nlog("DB ERROR " . $throwable->getMessage());
|
||||
@ -82,7 +82,7 @@ class ClientService
|
||||
$this->client->paid_to_date += $amount;
|
||||
$this->client->save();
|
||||
|
||||
}, 1);
|
||||
}, 2);
|
||||
|
||||
return $this;
|
||||
|
||||
|
@ -230,6 +230,14 @@ class InstantPayment
|
||||
elseif($this->request->hash){
|
||||
$hash_data['billing_context'] = Cache::get($this->request->hash);
|
||||
}
|
||||
elseif($old_hash = PaymentHash::where('fee_invoice_id', $first_invoice->id)->whereNull('payment_id')->first()) {
|
||||
|
||||
if(isset($old_hash->data->billing_context))
|
||||
{
|
||||
$hash_data['billing_context'] = $old_hash->data->billing_context;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$payment_hash = new PaymentHash;
|
||||
$payment_hash->hash = Str::random(32);
|
||||
|
@ -51,7 +51,7 @@ class DeletePayment
|
||||
|
||||
}
|
||||
|
||||
}, 1);
|
||||
}, 2);
|
||||
|
||||
return $this->payment;
|
||||
|
||||
|
@ -37,7 +37,7 @@ class SendEmail
|
||||
$contact = $this->payment->client->contacts()->first();
|
||||
|
||||
if ($contact?->email)
|
||||
EmailPayment::dispatch($this->payment, $this->payment->company, $contact)->delay(now()->addSeconds(3));
|
||||
EmailPayment::dispatch($this->payment, $this->payment->company, $contact)->delay(now()->addSeconds(8));
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ class SchedulerService
|
||||
|
||||
//Email only the selected clients
|
||||
if(count($this->scheduler->parameters['clients']) >= 1)
|
||||
$query->where('id', $this->transformKeys($this->scheduler->parameters['clients']));
|
||||
$query->whereIn('id', $this->transformKeys($this->scheduler->parameters['clients']));
|
||||
|
||||
$query->cursor()
|
||||
->each(function ($_client){
|
||||
@ -119,40 +119,40 @@ class SchedulerService
|
||||
|
||||
switch ($this->scheduler->frequency_id) {
|
||||
case RecurringInvoice::FREQUENCY_DAILY:
|
||||
$next_run = Carbon::parse($this->scheduler->next_run)->startOfDay()->addDay();
|
||||
$next_run = now()->startOfDay()->addDay();
|
||||
break;
|
||||
case RecurringInvoice::FREQUENCY_WEEKLY:
|
||||
$next_run = Carbon::parse($this->scheduler->next_run)->startOfDay()->addWeek();
|
||||
$next_run = now()->startOfDay()->addWeek();
|
||||
break;
|
||||
case RecurringInvoice::FREQUENCY_TWO_WEEKS:
|
||||
$next_run = Carbon::parse($this->scheduler->next_run)->startOfDay()->addWeeks(2);
|
||||
$next_run = now()->startOfDay()->addWeeks(2);
|
||||
break;
|
||||
case RecurringInvoice::FREQUENCY_FOUR_WEEKS:
|
||||
$next_run = Carbon::parse($this->scheduler->next_run)->startOfDay()->addWeeks(4);
|
||||
$next_run = now()->startOfDay()->addWeeks(4);
|
||||
break;
|
||||
case RecurringInvoice::FREQUENCY_MONTHLY:
|
||||
$next_run = Carbon::parse($this->scheduler->next_run)->startOfDay()->addMonthNoOverflow();
|
||||
$next_run = now()->startOfDay()->addMonthNoOverflow();
|
||||
break;
|
||||
case RecurringInvoice::FREQUENCY_TWO_MONTHS:
|
||||
$next_run = Carbon::parse($this->scheduler->next_run)->startOfDay()->addMonthsNoOverflow(2);
|
||||
$next_run = now()->startOfDay()->addMonthsNoOverflow(2);
|
||||
break;
|
||||
case RecurringInvoice::FREQUENCY_THREE_MONTHS:
|
||||
$next_run = Carbon::parse($this->scheduler->next_run)->startOfDay()->addMonthsNoOverflow(3);
|
||||
$next_run = now()->startOfDay()->addMonthsNoOverflow(3);
|
||||
break;
|
||||
case RecurringInvoice::FREQUENCY_FOUR_MONTHS:
|
||||
$next_run = Carbon::parse($this->scheduler->next_run)->startOfDay()->addMonthsNoOverflow(4);
|
||||
$next_run = now()->startOfDay()->addMonthsNoOverflow(4);
|
||||
break;
|
||||
case RecurringInvoice::FREQUENCY_SIX_MONTHS:
|
||||
$next_run = Carbon::parse($this->scheduler->next_run)->startOfDay()->addMonthsNoOverflow(6);
|
||||
$next_run = now()->startOfDay()->addMonthsNoOverflow(6);
|
||||
break;
|
||||
case RecurringInvoice::FREQUENCY_ANNUALLY:
|
||||
$next_run = Carbon::parse($this->scheduler->next_run)->startOfDay()->addYear();
|
||||
$next_run = now()->startOfDay()->addYear();
|
||||
break;
|
||||
case RecurringInvoice::FREQUENCY_TWO_YEARS:
|
||||
$next_run = Carbon::parse($this->scheduler->next_run)->startOfDay()->addYears(2);
|
||||
$next_run = now()->startOfDay()->addYears(2);
|
||||
break;
|
||||
case RecurringInvoice::FREQUENCY_THREE_YEARS:
|
||||
$next_run = Carbon::parse($this->scheduler->next_run)->startOfDay()->addYears(3);
|
||||
$next_run = now()->startOfDay()->addYears(3);
|
||||
break;
|
||||
default:
|
||||
$next_run = null;
|
||||
|
@ -167,7 +167,7 @@ class SubscriptionService
|
||||
public function startTrial(array $data)
|
||||
{
|
||||
// Redirects from here work just fine. Livewire will respect it.
|
||||
$client_contact = ClientContact::find($data['contact_id']);
|
||||
$client_contact = ClientContact::find($this->decodePrimaryKey($data['contact_id']));
|
||||
|
||||
if(!$this->subscription->trial_enabled)
|
||||
return new \Exception("Trials are disabled for this product");
|
||||
@ -331,6 +331,7 @@ class SubscriptionService
|
||||
* We refund unused days left.
|
||||
*
|
||||
* @param Invoice $invoice
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
private function calculateProRataRefundForSubscription($invoice) :float
|
||||
@ -338,6 +339,20 @@ class SubscriptionService
|
||||
if(!$invoice || !$invoice->date || $invoice->status_id != Invoice::STATUS_PAID)
|
||||
return 0;
|
||||
|
||||
/*Remove previous refunds from the calculation of the amount*/
|
||||
$invoice->line_items = collect($invoice->line_items)->filter(function($item){
|
||||
|
||||
if($item->product_key == ctrans("texts.refund"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
})->toArray();
|
||||
|
||||
$amount = $invoice->calc()->getTotal();
|
||||
|
||||
$start_date = Carbon::parse($invoice->date);
|
||||
|
||||
$current_date = now();
|
||||
@ -346,7 +361,7 @@ class SubscriptionService
|
||||
|
||||
$days_in_frequency = $this->getDaysInFrequency();
|
||||
|
||||
$pro_rata_refund = round((($days_in_frequency - $days_of_subscription_used)/$days_in_frequency) * $invoice->amount ,2);
|
||||
$pro_rata_refund = round((($days_in_frequency - $days_of_subscription_used)/$days_in_frequency) * $amount ,2);
|
||||
|
||||
return max(0, $pro_rata_refund);
|
||||
|
||||
@ -670,6 +685,8 @@ class SubscriptionService
|
||||
nlog("pro rata refund = {$pro_rata_refund_amount}");
|
||||
}
|
||||
|
||||
nlog("{$pro_rata_refund_amount} + {$pro_rata_charge_amount} + {$this->subscription->price}");
|
||||
|
||||
$total_payable = $pro_rata_refund_amount + $pro_rata_charge_amount + $this->subscription->price;
|
||||
|
||||
if($total_payable > 0)
|
||||
@ -734,7 +751,7 @@ class SubscriptionService
|
||||
{
|
||||
nlog("handle plan change");
|
||||
|
||||
$old_recurring_invoice = RecurringInvoice::find($payment_hash->data->billing_context->recurring_invoice);
|
||||
$old_recurring_invoice = RecurringInvoice::find($this->decodePrimaryKey($payment_hash->data->billing_context->recurring_invoice));
|
||||
|
||||
if(!$old_recurring_invoice)
|
||||
return $this->handleRedirect('/client/recurring_invoices/');
|
||||
@ -1291,7 +1308,12 @@ class SubscriptionService
|
||||
|
||||
}
|
||||
|
||||
private function getDaysInFrequency()
|
||||
/**
|
||||
* Get the number of days in the currency frequency
|
||||
*
|
||||
* @return int Number of days
|
||||
*/
|
||||
private function getDaysInFrequency() :int
|
||||
{
|
||||
|
||||
switch ($this->subscription->frequency_id) {
|
||||
@ -1325,7 +1347,15 @@ class SubscriptionService
|
||||
|
||||
}
|
||||
|
||||
public function getNextDateForFrequency($date, $frequency)
|
||||
/**
|
||||
* Get the next date by frequency_id
|
||||
*
|
||||
* @param Carbon $date The current carbon date
|
||||
* @param int $frequency The frequncy_id of the subscription
|
||||
*
|
||||
* @return ?Carbon The next date carbon object
|
||||
*/
|
||||
public function getNextDateForFrequency($date, $frequency) :?Carbon
|
||||
{
|
||||
switch ($frequency) {
|
||||
case RecurringInvoice::FREQUENCY_DAILY:
|
||||
@ -1353,11 +1383,56 @@ class SubscriptionService
|
||||
case RecurringInvoice::FREQUENCY_THREE_YEARS:
|
||||
return $date->addYears(3);
|
||||
default:
|
||||
return 0;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle case where no payment is required
|
||||
* @param Invoice $invoice The Invoice
|
||||
* @param array $bundle The bundle array
|
||||
* @param ClientContact $contact The Client Contact
|
||||
*
|
||||
* @return \Illuminate\Routing\Redirector|\Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function handleNoPaymentFlow(Invoice $invoice, $bundle, ClientContact $contact)
|
||||
{
|
||||
|
||||
if (strlen($this->subscription->recurring_product_ids) >= 1) {
|
||||
|
||||
$recurring_invoice = $this->convertInvoiceToRecurringBundle($contact->client_id, collect($bundle)->map(function ($bund){ return (object) $bund;}));
|
||||
|
||||
/* Start the recurring service */
|
||||
$recurring_invoice->service()
|
||||
->start()
|
||||
->save();
|
||||
|
||||
$invoice->recurring_id = $recurring_invoice->id;
|
||||
$invoice->save();
|
||||
|
||||
$context = [
|
||||
'context' => 'recurring_purchase',
|
||||
'recurring_invoice' => $recurring_invoice->hashed_id,
|
||||
'invoice' => $invoice->hashed_id,
|
||||
'client' => $recurring_invoice->client->hashed_id,
|
||||
'subscription' => $this->subscription->hashed_id,
|
||||
'contact' => $contact->hashed_id,
|
||||
'redirect_url' => "/client/recurring_invoices/{$recurring_invoice->hashed_id}",
|
||||
];
|
||||
|
||||
$this->triggerWebhook($context);
|
||||
|
||||
return $this->handleRedirect($context['redirect_url']);
|
||||
|
||||
}
|
||||
|
||||
$redirect_url = "/client/invoices/{$invoice->hashed_id}";
|
||||
|
||||
return $this->handleRedirect($redirect_url);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 'email' => $this->email ?? $this->contact->email,
|
||||
* 'quantity' => $this->quantity,
|
||||
|
@ -27,6 +27,9 @@ trait SubscriptionHooker
|
||||
'X-Requested-With' => 'XMLHttpRequest',
|
||||
];
|
||||
|
||||
if(!isset($subscription->webhook_configuration['post_purchase_url']) && !isset($subscription->webhook_configuration['post_purchase_rest_method']))
|
||||
return [];
|
||||
|
||||
if (count($subscription->webhook_configuration['post_purchase_headers']) >= 1) {
|
||||
$headers = array_merge($headers, $subscription->webhook_configuration['post_purchase_headers']);
|
||||
}
|
||||
|
@ -14,8 +14,8 @@ return [
|
||||
'require_https' => env('REQUIRE_HTTPS', true),
|
||||
'app_url' => rtrim(env('APP_URL', ''), '/'),
|
||||
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
|
||||
'app_version' => '5.5.56',
|
||||
'app_tag' => '5.5.56',
|
||||
'app_version' => '5.5.57',
|
||||
'app_tag' => '5.5.57',
|
||||
'minimum_client_version' => '5.0.16',
|
||||
'terms_version' => '1.0.1',
|
||||
'api_secret' => env('API_SECRET', ''),
|
||||
|
@ -32,7 +32,7 @@ class SchedulerFactory extends Factory
|
||||
'frequency_id' => RecurringInvoice::FREQUENCY_MONTHLY,
|
||||
'next_run' => now()->addSeconds(rand(86400,8640000)),
|
||||
'next_run_client' => now()->addSeconds(rand(86400,8640000)),
|
||||
'template' => 'statement_task',
|
||||
'template' => 'client_statement',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -48,6 +48,7 @@ CREATE TABLE `accounts` (
|
||||
`account_sms_verification_number` text DEFAULT NULL,
|
||||
`account_sms_verified` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`bank_integration_account_id` text DEFAULT NULL,
|
||||
`is_trial` tinyint(1) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `accounts_payment_id_index` (`payment_id`),
|
||||
KEY `accounts_key_index` (`key`)
|
||||
@ -255,6 +256,7 @@ CREATE TABLE `bank_transactions` (
|
||||
`updated_at` timestamp(6) NULL DEFAULT NULL,
|
||||
`deleted_at` timestamp(6) NULL DEFAULT NULL,
|
||||
`bank_transaction_rule_id` bigint(20) DEFAULT NULL,
|
||||
`payment_id` int(10) unsigned DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `bank_transactions_bank_integration_id_foreign` (`bank_integration_id`),
|
||||
KEY `bank_transactions_user_id_foreign` (`user_id`),
|
||||
@ -519,7 +521,12 @@ CREATE TABLE `companies` (
|
||||
`invoice_task_project` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`report_include_deleted` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`invoice_task_lock` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`use_vendor_currency` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`matomo_url` varchar(191) DEFAULT NULL,
|
||||
`matomo_id` bigint(20) DEFAULT NULL,
|
||||
`convert_payment_currency` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`convert_expense_currency` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`notify_vendor_when_paid` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`invoice_task_hours` tinyint(1) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `companies_company_key_unique` (`company_key`),
|
||||
KEY `companies_industry_id_foreign` (`industry_id`),
|
||||
@ -1139,6 +1146,7 @@ CREATE TABLE `invoices` (
|
||||
`paid_to_date` decimal(20,6) NOT NULL DEFAULT 0.000000,
|
||||
`subscription_id` int(10) unsigned DEFAULT NULL,
|
||||
`auto_bill_tries` smallint(6) NOT NULL DEFAULT 0,
|
||||
`is_proforma` tinyint(1) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `invoices_company_id_number_unique` (`company_id`,`number`),
|
||||
KEY `invoices_user_id_foreign` (`user_id`),
|
||||
@ -1948,20 +1956,23 @@ DROP TABLE IF EXISTS `schedulers`;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `schedulers` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`paused` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`is_deleted` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`repeat_every` varchar(191) NOT NULL,
|
||||
`start_from` timestamp NULL DEFAULT NULL,
|
||||
`scheduled_run` timestamp NULL DEFAULT NULL,
|
||||
`company_id` bigint(20) unsigned NOT NULL,
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
`deleted_at` timestamp NULL DEFAULT NULL,
|
||||
`action_name` varchar(191) NOT NULL,
|
||||
`action_class` varchar(191) NOT NULL,
|
||||
`parameters` mediumtext DEFAULT NULL,
|
||||
`company_id` int(10) unsigned NOT NULL,
|
||||
`is_paused` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`frequency_id` int(10) unsigned DEFAULT NULL,
|
||||
`next_run` datetime DEFAULT NULL,
|
||||
`next_run_client` datetime DEFAULT NULL,
|
||||
`user_id` int(10) unsigned NOT NULL,
|
||||
`name` varchar(191) NOT NULL,
|
||||
`template` varchar(191) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `schedulers_action_name_index` (`action_name`)
|
||||
UNIQUE KEY `schedulers_company_id_name_unique` (`company_id`,`name`),
|
||||
KEY `schedulers_company_id_deleted_at_index` (`company_id`,`deleted_at`),
|
||||
CONSTRAINT `schedulers_company_id_foreign` FOREIGN KEY (`company_id`) REFERENCES `companies` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `sizes`;
|
||||
@ -2522,3 +2533,10 @@ INSERT INTO `migrations` VALUES (171,'2022_11_06_215526_drop_html_backups_column
|
||||
INSERT INTO `migrations` VALUES (172,'2022_11_13_034143_bank_transaction_rules_table',1);
|
||||
INSERT INTO `migrations` VALUES (173,'2022_11_16_093535_calmness_design',1);
|
||||
INSERT INTO `migrations` VALUES (174,'2022_11_22_215618_lock_tasks_when_invoiced',1);
|
||||
INSERT INTO `migrations` VALUES (175,'2022_05_12_56879_add_stripe_klarna',2);
|
||||
INSERT INTO `migrations` VALUES (176,'2022_07_12_45766_add_matomo',2);
|
||||
INSERT INTO `migrations` VALUES (177,'2022_11_30_063229_add_payment_id_to_bank_transaction_table',2);
|
||||
INSERT INTO `migrations` VALUES (178,'2022_12_07_024625_add_properties_to_companies_table',2);
|
||||
INSERT INTO `migrations` VALUES (179,'2022_12_14_004639_vendor_currency_update',2);
|
||||
INSERT INTO `migrations` VALUES (180,'2022_12_20_063038_set_proforma_invoice_type',2);
|
||||
INSERT INTO `migrations` VALUES (181,'2023_01_12_125540_set_auto_bill_on_regular_invoice_setting',2);
|
108
phpunit.yml
108
phpunit.yml
@ -1,108 +0,0 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- v5-develop
|
||||
pull_request:
|
||||
branches:
|
||||
- v5-develop
|
||||
|
||||
name: phpunit
|
||||
jobs:
|
||||
run:
|
||||
runs-on: ${{ matrix.operating-system }}
|
||||
strategy:
|
||||
matrix:
|
||||
operating-system: ['ubuntu-18.04', 'ubuntu-20.04']
|
||||
php-versions: ['7.3','7.4','8.0']
|
||||
phpunit-versions: ['latest']
|
||||
|
||||
env:
|
||||
DB_DATABASE1: ninja
|
||||
DB_USERNAME1: root
|
||||
DB_PASSWORD1: ninja
|
||||
DB_HOST1: '127.0.0.1'
|
||||
DB_DATABASE: ninja
|
||||
DB_USERNAME: root
|
||||
DB_PASSWORD: ninja
|
||||
DB_HOST: '127.0.0.1'
|
||||
BROADCAST_DRIVER: log
|
||||
CACHE_DRIVER: file
|
||||
QUEUE_CONNECTION: sync
|
||||
SESSION_DRIVER: file
|
||||
NINJA_ENVIRONMENT: hosted
|
||||
MULTI_DB_ENABLED: false
|
||||
NINJA_LICENSE: 123456
|
||||
TRAVIS: true
|
||||
MAIL_MAILER: log
|
||||
|
||||
services:
|
||||
mariadb:
|
||||
image: mariadb:latest
|
||||
ports:
|
||||
- 32768:3306
|
||||
env:
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: yes
|
||||
MYSQL_USER: ninja
|
||||
MYSQL_PASSWORD: ninja
|
||||
MYSQL_DATABASE: ninja
|
||||
MYSQL_ROOT_PASSWORD: ninja
|
||||
options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3
|
||||
|
||||
steps:
|
||||
- name: Start mysql service
|
||||
run: |
|
||||
sudo systemctl start mysql.service
|
||||
- name: Verify MariaDB connection
|
||||
env:
|
||||
DB_PORT: ${{ job.services.mariadb.ports[3306] }}
|
||||
DB_PORT1: ${{ job.services.mariadb.ports[3306] }}
|
||||
|
||||
run: |
|
||||
while ! mysqladmin ping -h"127.0.0.1" -P"$DB_PORT" --silent; do
|
||||
sleep 1
|
||||
done
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
extensions: mysql, mysqlnd, sqlite3, bcmath, gmp, gd, curl, zip, openssl, mbstring, xml
|
||||
|
||||
- uses: actions/checkout@v1
|
||||
with:
|
||||
ref: v5-develop
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Copy .env
|
||||
run: |
|
||||
cp .env.ci .env
|
||||
- name: Install composer dependencies
|
||||
run: |
|
||||
composer config -g github-oauth.github.com ${{ secrets.GITHUB_TOKEN }}
|
||||
composer install
|
||||
- name: Prepare Laravel Application
|
||||
run: |
|
||||
php artisan key:generate
|
||||
php artisan optimize
|
||||
php artisan cache:clear
|
||||
php artisan config:cache
|
||||
- name: Create DB and schemas
|
||||
run: |
|
||||
mkdir -p database
|
||||
touch database/database.sqlite
|
||||
- name: Migrate Database
|
||||
run: |
|
||||
php artisan migrate:fresh --seed --force && php artisan db:seed --force
|
||||
- name: Prepare JS/CSS assets
|
||||
run: |
|
||||
npm i
|
||||
npm run production
|
||||
- name: Run Testsuite
|
||||
run: |
|
||||
cat .env
|
||||
vendor/bin/phpunit --testdox
|
||||
env:
|
||||
DB_PORT: ${{ job.services.mysql.ports[3306] }}
|
||||
|
||||
- name: Run php-cs-fixer
|
||||
run: |
|
||||
vendor/bin/php-cs-fixer fix
|
@ -51,18 +51,34 @@
|
||||
</div>
|
||||
<p class="mt-1 text-sm text-gray-500"></p>
|
||||
</div>
|
||||
<div class="flex content-end text-sm mt-1">
|
||||
<div class="flex justify-between text-sm mt-1">
|
||||
@if($subscription->per_seat_enabled)
|
||||
<p class="text-gray-500 w-full"></p>
|
||||
<p class="text-gray-500 w-3/4"></p>
|
||||
<div class="flex place-content-end">
|
||||
@if($subscription->use_inventory_management && $product->in_stock_quantity == 0)
|
||||
<p class="text-sm font-light text-red-500 text-right mr-2 mt-2">Out of stock</p>
|
||||
@else
|
||||
<p class="text-sm font-light text-gray-700 text-right mr-2 mt-2">{{ ctrans('texts.qty') }}</p>
|
||||
@endif
|
||||
<select wire:model.debounce.300ms="data.{{ $index }}.recurring_qty" class="rounded-md border-gray-300 shadow-sm sm:text-sm"
|
||||
@if($subscription->use_inventory_management && $product->in_stock_quantity == 0)
|
||||
disabled
|
||||
@endif
|
||||
>
|
||||
<option value="1" selected="selected">1</option>
|
||||
|
||||
<select wire:model.debounce.300ms="data.{{ $index }}.recurring_qty" class="rounded-md border-gray-300 shadow-sm sm:text-sm">
|
||||
<option value="1" selected="selected">1</option>
|
||||
@for ($i = 2; $i <= $subscription->max_seats_limit; $i++)
|
||||
@if($subscription->max_seats_limit > 1)
|
||||
{
|
||||
@for ($i = 2; $i <= ($subscription->use_inventory_management ? min($subscription->max_seats_limit,$product->in_stock_quantity) : $subscription->max_seats_limit); $i++)
|
||||
<option value="{{$i}}">{{$i}}</option>
|
||||
@endfor
|
||||
</select>
|
||||
}
|
||||
@else
|
||||
@for ($i = 2; $i <= ($subscription->use_inventory_management ? min($product->in_stock_quantity, max(100,$product->custom_value2)) : max(100,$product->custom_value2)); $i++)
|
||||
<option value="{{$i}}">{{$i}}</option>
|
||||
@endfor
|
||||
@endif
|
||||
</select>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
@ -60,7 +60,7 @@
|
||||
{{ $payment->translatedType() }}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm leading-5 text-gray-500">
|
||||
{!! \App\Utils\Number::formatMoney($payment->amount, $payment->client) !!}
|
||||
{!! \App\Utils\Number::formatMoney($payment->amount > 0 ? $payment->amount : $payment->credits->sum('pivot.amount'), $payment->client) !!}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm leading-5 text-gray-500">
|
||||
{{ \Illuminate\Support\Str::limit($payment->transaction_reference, 35) }}
|
||||
|
@ -66,7 +66,7 @@
|
||||
{{ ctrans('texts.amount') }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
||||
{{ $payment->formattedAmount() }}
|
||||
{{ $payment->formatAmount($payment->amount > 0 ? $payment->amount : $payment?->invoices->sum('pivot.amount')) }}
|
||||
</dd>
|
||||
</div>
|
||||
@endif
|
||||
@ -116,6 +116,7 @@
|
||||
href="{{ route('client.invoice.show', ['invoice' => $invoice->hashed_id])}}">
|
||||
{{ $invoice->number }}
|
||||
</a>
|
||||
- {{ \App\Utils\Number::formatMoney($payment->invoices->where('id', $invoice->id)->sum('pivot.amount') - $payment->invoices->where('id', $invoice->id)->sum('pivot.refunded'), $payment->client) }}
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
|
@ -12,18 +12,11 @@
|
||||
|
||||
namespace Tests\Feature\Account;
|
||||
|
||||
use App\DataMapper\ClientSettings;
|
||||
use App\DataMapper\ClientRegistrationFields;
|
||||
use App\DataMapper\CompanySettings;
|
||||
use App\Http\Livewire\CreditsTable;
|
||||
use App\Models\Account;
|
||||
use App\Models\Client;
|
||||
use App\Models\ClientContact;
|
||||
use App\Models\Company;
|
||||
use App\Models\Credit;
|
||||
use App\Models\User;
|
||||
use App\Utils\Traits\AppSetup;
|
||||
use Faker\Factory;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use App\Utils\Ninja;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Livewire\Livewire;
|
||||
use Tests\MockAccountData;
|
||||
@ -31,30 +24,123 @@ use Tests\TestCase;
|
||||
|
||||
class AccountEmailQuotaTest extends TestCase
|
||||
{
|
||||
use DatabaseTransactions;
|
||||
use AppSetup;
|
||||
use MockAccountData;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
|
||||
public function testIfQuotaBreached()
|
||||
{
|
||||
|
||||
config([
|
||||
'ninja.production' => true
|
||||
]);
|
||||
|
||||
$account = Account::factory()->create([
|
||||
'hosted_client_count' => 1000,
|
||||
'hosted_company_count' => 1000,
|
||||
'is_flagged' => false,
|
||||
'key' => '123ifyouknowwhatimean',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
$account->num_users = 3;
|
||||
$account->save();
|
||||
|
||||
$company = Company::factory()->create([
|
||||
'account_id' => $account->id,
|
||||
]);
|
||||
|
||||
$company->client_registration_fields = ClientRegistrationFields::generate();
|
||||
|
||||
$settings = CompanySettings::defaults();
|
||||
|
||||
$settings->company_logo = 'https://pdf.invoicing.co/favicon-v2.png';
|
||||
$settings->website = 'www.invoiceninja.com';
|
||||
$settings->address1 = 'Address 1';
|
||||
$settings->address2 = 'Address 2';
|
||||
$settings->city = 'City';
|
||||
$settings->state = 'State';
|
||||
$settings->postal_code = 'Postal Code';
|
||||
$settings->phone = '555-343-2323';
|
||||
$settings->email = 'nothingtoofancy@acme.com';
|
||||
$settings->country_id = '840';
|
||||
$settings->vat_number = 'vat number';
|
||||
$settings->id_number = 'id number';
|
||||
$settings->use_credits_payment = 'always';
|
||||
$settings->timezone_id = '1';
|
||||
$settings->entity_send_time = 0;
|
||||
|
||||
$company->track_inventory = true;
|
||||
$company->settings = $settings;
|
||||
$company->save();
|
||||
|
||||
$account->default_company_id = $company->id;
|
||||
$account->save();
|
||||
|
||||
|
||||
Cache::put($account->key, 3000);
|
||||
|
||||
$this->assertFalse($account->isPaid());
|
||||
$this->assertTrue(Ninja::isNinja());
|
||||
$this->assertEquals(20, $account->getDailyEmailLimit());
|
||||
|
||||
$this->assertEquals(3000, Cache::get($account->key));
|
||||
$this->assertTrue($account->emailQuotaExceeded());
|
||||
|
||||
Cache::forget('123ifyouknowwhatimean');
|
||||
|
||||
$this->faker = Factory::create();
|
||||
$this->buildCache(true);
|
||||
$this->makeTestData();
|
||||
}
|
||||
|
||||
public function testQuotaValidRule()
|
||||
{
|
||||
Cache::increment($this->account->key);
|
||||
|
||||
$this->assertFalse($this->account->emailQuotaExceeded());
|
||||
$account = Account::factory()->create([
|
||||
'hosted_client_count' => 1000,
|
||||
'hosted_company_count' => 1000,
|
||||
'is_flagged' => false,
|
||||
'key' => '123ifyouknowwhatimean',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
$account->num_users = 3;
|
||||
$account->save();
|
||||
|
||||
Cache::increment($account->key);
|
||||
|
||||
$this->assertFalse($account->emailQuotaExceeded());
|
||||
|
||||
Cache::forget('123ifyouknowwhatimean');
|
||||
|
||||
}
|
||||
|
||||
public function testQuotaInValidRule()
|
||||
public function testEmailSentCount()
|
||||
{
|
||||
Cache::increment($this->account->key, 3000);
|
||||
$account = Account::factory()->create([
|
||||
'hosted_client_count' => 1000,
|
||||
'hosted_company_count' => 1000,
|
||||
'is_flagged' => false,
|
||||
'key' => '123ifyouknowwhatimean',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
$account->num_users = 3;
|
||||
$account->save();
|
||||
|
||||
|
||||
Cache::put($account->key, 3000);
|
||||
|
||||
$count = $account->emailsSent();
|
||||
|
||||
$this->assertEquals(3000, $count);
|
||||
|
||||
Cache::forget('123ifyouknowwhatimean');
|
||||
|
||||
$this->assertTrue($this->account->emailQuotaExceeded());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -15,7 +15,6 @@ use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Tests\MockAccountData;
|
||||
use Tests\TestCase;
|
||||
|
||||
@ -42,6 +41,17 @@ class BankTransactionApiTest extends TestCase
|
||||
Model::reguard();
|
||||
}
|
||||
|
||||
|
||||
public function testBankTransactionGetClientStatus()
|
||||
{
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->get('/api/v1/bank_transactions?client_status=unmatched'.$this->encodePrimaryKey($this->bank_transaction->id));
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
|
||||
public function testBankTransactionGet()
|
||||
{
|
||||
$response = $this->withHeaders([
|
||||
|
@ -48,6 +48,19 @@ class CompanyTokenApiTest extends TestCase
|
||||
);
|
||||
}
|
||||
|
||||
public function testCompanyTokenListFilter()
|
||||
{
|
||||
$this->withoutMiddleware(PasswordProtection::class);
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
'X-API-PASSWORD' => 'ALongAndBriliantPassword',
|
||||
])->get('/api/v1/tokens?filter=xx');
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
|
||||
public function testCompanyTokenList()
|
||||
{
|
||||
$this->withoutMiddleware(PasswordProtection::class);
|
||||
|
@ -40,6 +40,16 @@ class CreditTest extends TestCase
|
||||
$this->makeTestData();
|
||||
}
|
||||
|
||||
public function testCreditGetClientStatus()
|
||||
{
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->get('/api/v1/credits?client_status=draft'.$this->encodePrimaryKey($this->bank_transaction->id));
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
|
||||
public function testCreditsList()
|
||||
{
|
||||
Client::factory()->count(3)->create(['user_id' => $this->user->id, 'company_id' => $this->company->id])->each(function ($c) {
|
||||
|
212
tests/Feature/Email/EmailServiceTest.php
Normal file
212
tests/Feature/Email/EmailServiceTest.php
Normal file
@ -0,0 +1,212 @@
|
||||
<?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://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace Tests\Feature\Email;
|
||||
|
||||
use App\Services\Email\EmailObject;
|
||||
use App\Services\Email\EmailService;
|
||||
use App\Utils\Traits\GeneratesCounter;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||
use Tests\MockAccountData;
|
||||
use Tests\TestCase;
|
||||
use Illuminate\Mail\Mailables\Address;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @covers App\Services\Email\EmailService
|
||||
*/
|
||||
class EmailServiceTest extends TestCase
|
||||
{
|
||||
use MakesHash;
|
||||
use GeneratesCounter;
|
||||
use MockAccountData;
|
||||
|
||||
public EmailService $email_service;
|
||||
|
||||
public EmailObject $email_object;
|
||||
|
||||
protected function setUp() :void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
if(!class_exists(\Modules\Admin\Jobs\Account\EmailFilter::class))
|
||||
$this->markTestSkipped('Skipped :: test not needed in this environment');
|
||||
|
||||
$this->makeTestData();
|
||||
|
||||
$this->email_object = new EmailObject();
|
||||
$this->email_object->to = [new Address("testing@gmail.com", "Cool Name")];
|
||||
$this->email_object->attachments = [];
|
||||
$this->email_object->settings = $this->client->getMergedSettings();
|
||||
$this->email_object->company = $this->client->company;
|
||||
$this->email_object->client = $this->client;
|
||||
$this->email_object->email_template_subject = 'email_subject_statement';
|
||||
$this->email_object->email_template_body = 'email_template_statement';
|
||||
$this->email_object->variables = [
|
||||
'$client' => $this->client->present()->name(),
|
||||
'$start_date' => '2022-01-01',
|
||||
'$end_date' => '2023-01-01',
|
||||
];
|
||||
|
||||
$this->email_service = new EmailService($this->email_object, $this->company);
|
||||
|
||||
}
|
||||
|
||||
public function testScanEmailsAttemptedFromVerifiedAccounts()
|
||||
{
|
||||
$email_filter = new \Modules\Admin\Jobs\Account\EmailFilter($this->email_object, $this->client->company);
|
||||
|
||||
Cache::put($this->account->key, 1);
|
||||
|
||||
config(['ninja.environment' => 'hosted']);
|
||||
|
||||
$this->account->account_sms_verified = true;
|
||||
$this->account->is_verified_account = false;
|
||||
$this->account->save();
|
||||
|
||||
$this->assertFalse($this->email_service->preFlightChecksFail());
|
||||
|
||||
collect($email_filter->getSpamKeywords())->each(function ($spam_subject){
|
||||
|
||||
$this->email_object->subject = $spam_subject;
|
||||
|
||||
$this->assertTrue($this->email_service->preFlightChecksFail());
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function scanEmailsAttemptedFromUnverifiedAccounts()
|
||||
{
|
||||
|
||||
config(['ninja.environment' => 'hosted']);
|
||||
|
||||
Cache::put($this->account->key, 1);
|
||||
|
||||
$this->account->account_sms_verified = false;
|
||||
$this->account->save();
|
||||
|
||||
$this->assertTrue($this->email_service->preFlightChecksFail());
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function testVerifiedAccountsSkipFilters()
|
||||
{
|
||||
config(['ninja.environment' => 'hosted']);
|
||||
|
||||
Cache::put($this->account->key, 1);
|
||||
|
||||
$this->account->is_verified_account = true;
|
||||
$this->account->save();
|
||||
|
||||
$this->assertFalse($this->email_service->preFlightChecksFail());
|
||||
|
||||
}
|
||||
|
||||
public function testClientMailersAreUnCapped()
|
||||
{
|
||||
|
||||
config(['ninja.environment' => 'hosted']);
|
||||
|
||||
Cache::put($this->account->key, 1000000);
|
||||
|
||||
collect([
|
||||
'gmail',
|
||||
'office365',
|
||||
'client_postmark',
|
||||
'client_mailgun'])
|
||||
->each(function ($mailer){
|
||||
|
||||
$this->email_object->settings->email_sending_method = $mailer;
|
||||
|
||||
$this->assertFalse($this->email_service->preFlightChecksFail());
|
||||
|
||||
});
|
||||
|
||||
$this->email_object->settings->email_sending_method = 'postmark';
|
||||
|
||||
$this->assertTrue($this->email_service->preFlightChecksFail());
|
||||
|
||||
}
|
||||
|
||||
public function testFlaggedInvalidEmailsPrevented()
|
||||
{
|
||||
|
||||
config(['ninja.environment' => 'hosted']);
|
||||
|
||||
Cache::put($this->account->key, 1);
|
||||
|
||||
$this->email_object->to = [new Address("user@example.com", "Cool Name")];
|
||||
|
||||
$this->assertTrue($this->email_service->preFlightChecksFail());
|
||||
|
||||
|
||||
collect([
|
||||
'user@example.com',
|
||||
'',
|
||||
'bademail',
|
||||
'domain.com',
|
||||
])->each(function ($email){
|
||||
|
||||
|
||||
$this->email_object->to = [new Address($email, "Cool Name")];
|
||||
|
||||
$this->assertTrue($this->email_service->preFlightChecksFail());
|
||||
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
public function testFlaggedAccountsPrevented()
|
||||
{
|
||||
|
||||
Cache::put($this->account->key, 1);
|
||||
|
||||
config(['ninja.environment' => 'hosted']);
|
||||
|
||||
$this->account->is_flagged = true;
|
||||
$this->account->save();
|
||||
|
||||
$this->assertTrue($this->email_service->preFlightChecksFail());
|
||||
|
||||
}
|
||||
|
||||
public function testPreFlightChecksHosted()
|
||||
{
|
||||
|
||||
Cache::put($this->account->key, 1);
|
||||
|
||||
config(['ninja.environment' => 'hosted']);
|
||||
|
||||
$this->assertFalse($this->email_service->preFlightChecksFail());
|
||||
|
||||
}
|
||||
|
||||
public function testPreFlightChecksSelfHost()
|
||||
{
|
||||
|
||||
Cache::put($this->account->key, 1);
|
||||
|
||||
config(['ninja.environment' => 'selfhost']);
|
||||
|
||||
$this->assertFalse($this->email_service->preFlightChecksFail());
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
<?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://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Services\Email\EmailObject;
|
||||
use App\Services\Email\EmailService;
|
||||
use App\Utils\Traits\GeneratesCounter;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||
use Tests\MockAccountData;
|
||||
use Tests\TestCase;
|
||||
use Illuminate\Mail\Mailables\Address;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @covers App\Services\Email\EmailService
|
||||
*/
|
||||
class EmailTest extends TestCase
|
||||
{
|
||||
use MakesHash;
|
||||
use GeneratesCounter;
|
||||
use MockAccountData;
|
||||
|
||||
public EmailService $email_service;
|
||||
|
||||
public EmailObject $email_object;
|
||||
|
||||
protected function setUp() :void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
if(!class_exists(\Modules\Admin\Jobs\Account\EmailFilter::class))
|
||||
$this->markTestSkipped('Skip test not needed in this environment');
|
||||
|
||||
$this->makeTestData();
|
||||
|
||||
$this->email_object = new EmailObject();
|
||||
$this->email_object->to = [new Address("testing@gmail.com", "Cool Name")];
|
||||
$this->email_object->attachments = [];
|
||||
$this->email_object->settings = $this->client->getMergedSettings();
|
||||
$this->email_object->company = $this->client->company;
|
||||
$this->email_object->client = $this->client;
|
||||
$this->email_object->email_template_subject = 'email_subject_statement';
|
||||
$this->email_object->email_template_body = 'email_template_statement';
|
||||
$this->email_object->variables = [
|
||||
'$client' => $this->client->present()->name(),
|
||||
'$start_date' => '2022-01-01',
|
||||
'$end_date' => '2023-01-01',
|
||||
];
|
||||
|
||||
$this->email_service = new EmailService($this->email_object, $this->company);
|
||||
|
||||
}
|
||||
|
||||
public function testPreFlightChecksHosted()
|
||||
{
|
||||
|
||||
config(['ninja.environment' => 'hosted']);
|
||||
|
||||
$this->assertFalse($this->email_service->preFlightChecksFail());
|
||||
|
||||
}
|
||||
|
||||
public function testPreFlightChecksSelfHost()
|
||||
{
|
||||
|
||||
config(['ninja.environment' => 'selfhost']);
|
||||
|
||||
$this->assertFalse($this->email_service->preFlightChecksFail());
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -41,6 +41,18 @@ class ExpenseApiTest extends TestCase
|
||||
Model::reguard();
|
||||
}
|
||||
|
||||
public function testExpenseGetClientStatus()
|
||||
{
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->get('/api/v1/expenses?client_status=paid');
|
||||
|
||||
$response->assertStatus(200);
|
||||
|
||||
}
|
||||
|
||||
public function testExpensePost()
|
||||
{
|
||||
$data = [
|
||||
|
@ -66,6 +66,8 @@ class ProductSalesReportTest extends TestCase
|
||||
|
||||
public $account;
|
||||
|
||||
public $client;
|
||||
|
||||
/**
|
||||
* start_date - Y-m-d
|
||||
end_date - Y-m-d
|
||||
@ -108,6 +110,9 @@ class ProductSalesReportTest extends TestCase
|
||||
'settings' => $settings,
|
||||
]);
|
||||
|
||||
$this->company->settings = $settings;
|
||||
$this->company->save();
|
||||
|
||||
$this->payload = [
|
||||
'start_date' => '2000-01-01',
|
||||
'end_date' => '2030-01-11',
|
||||
@ -115,6 +120,13 @@ class ProductSalesReportTest extends TestCase
|
||||
'is_income_billed' => true,
|
||||
'include_tax' => false,
|
||||
];
|
||||
|
||||
$this->client = Client::factory()->create([
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $this->company->id,
|
||||
'is_deleted' => 0,
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
public function testProductSalesInstance()
|
||||
@ -133,22 +145,16 @@ class ProductSalesReportTest extends TestCase
|
||||
$this->buildData();
|
||||
|
||||
|
||||
$client = Client::factory()->create([
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $this->company->id,
|
||||
'is_deleted' => 0,
|
||||
]);
|
||||
|
||||
$this->payload = [
|
||||
'start_date' => '2000-01-01',
|
||||
'end_date' => '2030-01-11',
|
||||
'date_range' => 'custom',
|
||||
'client_id' => $client->id,
|
||||
'client_id' => $this->client->id,
|
||||
'report_keys' => []
|
||||
];
|
||||
|
||||
$i = Invoice::factory()->create([
|
||||
'client_id' => $client->id,
|
||||
'client_id' => $this->client->id,
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $this->company->id,
|
||||
'amount' => 0,
|
||||
@ -174,7 +180,6 @@ class ProductSalesReportTest extends TestCase
|
||||
$response = $pl->run();
|
||||
|
||||
$this->assertIsString($response);
|
||||
// nlog($response);
|
||||
|
||||
$this->account->delete();
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ use App\Models\Product;
|
||||
use App\Models\TaxRate;
|
||||
use App\Models\Vendor;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use App\Utils\TruthSource;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Str;
|
||||
@ -50,6 +51,9 @@ class CsvImportTest extends TestCase
|
||||
$this->makeTestData();
|
||||
|
||||
$this->withoutExceptionHandling();
|
||||
|
||||
auth()->login($this->user);
|
||||
|
||||
}
|
||||
|
||||
public function testExpenseCsvImport()
|
||||
@ -274,6 +278,11 @@ class CsvImportTest extends TestCase
|
||||
|
||||
Cache::put($hash.'-invoice', base64_encode($csv), 360);
|
||||
|
||||
$truth = app()->make(TruthSource::class);
|
||||
$truth->setCompanyUser($this->cu);
|
||||
$truth->setUser($this->user);
|
||||
$truth->setCompany($this->company);
|
||||
|
||||
$csv_importer = new Csv($data, $this->company);
|
||||
|
||||
$csv_importer->import('invoice');
|
||||
|
@ -40,6 +40,9 @@ class InvitationTest extends TestCase
|
||||
protected function setUp() :void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->faker = \Faker\Factory::create();
|
||||
|
||||
}
|
||||
|
||||
public function testInvoiceCreationAfterInvoiceMarkedSent()
|
||||
@ -52,10 +55,13 @@ class InvitationTest extends TestCase
|
||||
$account->default_company_id = $company->id;
|
||||
$account->save();
|
||||
|
||||
$user = User::where('email', 'user@example.com')->first();
|
||||
$fake_email = $this->faker->email();
|
||||
|
||||
$user = User::where('email', $fake_email)->first();
|
||||
|
||||
if (! $user) {
|
||||
$user = User::factory()->create([
|
||||
'email' => $fake_email,
|
||||
'account_id' => $account->id,
|
||||
'confirmation_code' => $this->createDbHash(config('database.default')),
|
||||
]);
|
||||
|
@ -47,6 +47,16 @@ class InvoiceTest extends TestCase
|
||||
}
|
||||
|
||||
|
||||
public function testInvoiceGetPaidInvoices()
|
||||
{
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->get('/api/v1/invoices?client_status=paid',)
|
||||
->assertStatus(200);
|
||||
}
|
||||
|
||||
public function testInvoiceArchiveAction()
|
||||
{
|
||||
|
||||
|
@ -48,6 +48,17 @@ class PaymentTermsApiTest extends TestCase
|
||||
);
|
||||
}
|
||||
|
||||
public function testPaymentTermsGetWithFilter()
|
||||
{
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->get('/api/v1/payment_terms?filter=hey');
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
|
||||
|
||||
public function testPaymentTermsGet()
|
||||
{
|
||||
$response = $this->withHeaders([
|
||||
|
@ -62,6 +62,18 @@ class PaymentTest extends TestCase
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetPaymentMatchList()
|
||||
{
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->get('/api/v1/payments?match_transactions=true')
|
||||
->assertStatus(200);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public function testStorePaymentIdempotencyKeyIllegalLength()
|
||||
{
|
||||
$client = ClientFactory::create($this->company->id, $this->user->id);
|
||||
|
@ -47,6 +47,15 @@ class ProductTest extends TestCase
|
||||
$this->makeTestData();
|
||||
}
|
||||
|
||||
public function testProductGetProductKeyFilter()
|
||||
{
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->get('/api/v1/products?product_key=xx')
|
||||
->assertStatus(200);
|
||||
}
|
||||
|
||||
public function testProductList()
|
||||
{
|
||||
$response = $this->withHeaders([
|
||||
|
@ -42,6 +42,16 @@ class ProjectApiTest extends TestCase
|
||||
Model::reguard();
|
||||
}
|
||||
|
||||
public function testProjectGetFilter()
|
||||
{
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->get('/api/v1/projects?filter=xx');
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
|
||||
public function testProjectGet()
|
||||
{
|
||||
$response = $this->withHeaders([
|
||||
|
@ -40,6 +40,16 @@ class PurchaseOrderTest extends TestCase
|
||||
$this->makeTestData();
|
||||
}
|
||||
|
||||
public function testPurchaseOrderGetWithClientStatus()
|
||||
{
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->get('/api/v1/purchase_orders?client_status=sent'.$this->encodePrimaryKey($this->purchase_order->id));
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
|
||||
public function testPostNewPurchaseOrderPdf()
|
||||
{
|
||||
$purchase_order = [
|
||||
|
@ -50,6 +50,15 @@ class QuoteTest extends TestCase
|
||||
);
|
||||
}
|
||||
|
||||
public function testQuoteListApproved()
|
||||
{
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->get('/api/v1/quotes?client_status=approved');
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
|
||||
|
||||
public function testQuoteConvertToProject()
|
||||
|
@ -43,6 +43,16 @@ class RecurringExpenseApiTest extends TestCase
|
||||
Model::reguard();
|
||||
}
|
||||
|
||||
public function testRecurringExpenseGetFiltered()
|
||||
{
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->get('/api/v1/recurring_expenses?filter=xx');
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
|
||||
public function testRecurringExpenseGet()
|
||||
{
|
||||
$response = $this->withHeaders([
|
||||
|
@ -52,6 +52,17 @@ class RecurringInvoiceTest extends TestCase
|
||||
$this->makeTestData();
|
||||
}
|
||||
|
||||
public function testRecurringGetStatus()
|
||||
{
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->get('/api/v1/recurring_invoices?client_status=active')
|
||||
->assertStatus(200);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function testPostRecurringInvoiceWithPlaceholderVariables()
|
||||
{
|
||||
$line_items = [];
|
||||
|
@ -47,6 +47,17 @@ class RecurringQuoteTest extends TestCase
|
||||
$this->makeTestData();
|
||||
}
|
||||
|
||||
public function testRecurringQuoteListFilter()
|
||||
{
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->get('/api/v1/recurring_quotes?filter=xx');
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
|
||||
public function testRecurringQuoteList()
|
||||
{
|
||||
RecurringQuote::factory()->create(['user_id' => $this->user->id, 'company_id' => $this->company->id, 'client_id' => $this->client->id]);
|
||||
|
@ -14,6 +14,7 @@ namespace Tests\Feature\Scheduler;
|
||||
use App\Factory\SchedulerFactory;
|
||||
use App\Models\Client;
|
||||
use App\Models\RecurringInvoice;
|
||||
use App\Models\Scheduler;
|
||||
use App\Services\Scheduler\SchedulerService;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Carbon\Carbon;
|
||||
@ -53,6 +54,72 @@ class SchedulerTest extends TestCase
|
||||
|
||||
}
|
||||
|
||||
public function testClientCountResolution()
|
||||
{
|
||||
|
||||
$c = Client::factory()->create([
|
||||
'company_id' => $this->company->id,
|
||||
'user_id' => $this->user->id,
|
||||
'number' => rand(1000,100000),
|
||||
'name' => 'A fancy client'
|
||||
]);
|
||||
|
||||
$c2 = Client::factory()->create([
|
||||
'company_id' => $this->company->id,
|
||||
'user_id' => $this->user->id,
|
||||
'number' => rand(1000,100000),
|
||||
'name' => 'A fancy client'
|
||||
]);
|
||||
|
||||
$data = [
|
||||
'name' => 'A test statement scheduler',
|
||||
'frequency_id' => RecurringInvoice::FREQUENCY_MONTHLY,
|
||||
'next_run' => now()->format('Y-m-d'),
|
||||
'template' => 'client_statement',
|
||||
'parameters' => [
|
||||
'date_range' => 'previous_month',
|
||||
'show_payments_table' => true,
|
||||
'show_aging_table' => true,
|
||||
'status' => 'paid',
|
||||
'clients' => [
|
||||
$c2->hashed_id,
|
||||
$c->hashed_id
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$response = false;
|
||||
|
||||
try{
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->postJson('/api/v1/task_schedulers', $data);
|
||||
|
||||
} catch (ValidationException $e) {
|
||||
$message = json_decode($e->validator->getMessageBag(), 1);
|
||||
nlog($message);
|
||||
}
|
||||
|
||||
$response->assertStatus(200);
|
||||
|
||||
$data = $response->json();
|
||||
|
||||
$scheduler = Scheduler::find($this->decodePrimaryKey($data['data']['id']));
|
||||
|
||||
$this->assertInstanceOf(Scheduler::class, $scheduler);
|
||||
|
||||
$this->assertCount(2, $scheduler->parameters['clients']);
|
||||
|
||||
$q = Client::query()
|
||||
->where('company_id', $scheduler->company_id)
|
||||
->whereIn('id', $this->transformKeys($scheduler->parameters['clients']))
|
||||
->cursor();
|
||||
|
||||
$this->assertCount(2, $q);
|
||||
|
||||
}
|
||||
|
||||
public function testClientsValidationInScheduledTask()
|
||||
{
|
||||
|
||||
@ -162,7 +229,7 @@ class SchedulerTest extends TestCase
|
||||
$data = [
|
||||
'name' => 'A test statement scheduler',
|
||||
'frequency_id' => RecurringInvoice::FREQUENCY_MONTHLY,
|
||||
'next_run' => "2023-01-01",
|
||||
'next_run' => now()->format('Y-m-d'),
|
||||
'template' => 'client_statement',
|
||||
'parameters' => [
|
||||
'date_range' => 'previous_month',
|
||||
@ -184,7 +251,7 @@ class SchedulerTest extends TestCase
|
||||
|
||||
$scheduler->fresh();
|
||||
|
||||
$this->assertEquals("2023-02-01", $scheduler->next_run->format('Y-m-d'));
|
||||
$this->assertEquals(now()->addMonth()->format('Y-m-d'), $scheduler->next_run->format('Y-m-d'));
|
||||
|
||||
}
|
||||
|
||||
|
@ -50,6 +50,17 @@ class SubscriptionApiTest extends TestCase
|
||||
Model::reguard();
|
||||
}
|
||||
|
||||
public function testSubscriptionFilter()
|
||||
{
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->get('/api/v1/subscriptions?filter=xx')
|
||||
->assertStatus(200);
|
||||
|
||||
}
|
||||
|
||||
public function testSubscriptionsGet()
|
||||
{
|
||||
$product = Product::factory()->create([
|
||||
|
@ -34,6 +34,18 @@ class SystemLogApiTest extends TestCase
|
||||
$this->makeTestData();
|
||||
}
|
||||
|
||||
|
||||
public function testFilters()
|
||||
{
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->get('/api/v1/system_logs?type_id=3')
|
||||
->assertStatus(200);;
|
||||
|
||||
}
|
||||
|
||||
public function testSystemLogRoutes()
|
||||
{
|
||||
$sl = [
|
||||
|
@ -44,6 +44,17 @@ class TaskApiTest extends TestCase
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function testTaskListClientStatus()
|
||||
{
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->get('/api/v1/tasks?client_status=invoiced')
|
||||
->assertStatus(200);
|
||||
|
||||
}
|
||||
|
||||
public function testTaskLockingGate()
|
||||
{
|
||||
$data = [
|
||||
|
@ -41,6 +41,16 @@ class TaskStatusApiTest extends TestCase
|
||||
Model::reguard();
|
||||
}
|
||||
|
||||
public function testTaskStatusGetFilter()
|
||||
{
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->get('/api/v1/task_statuses?filter=xx');
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
|
||||
public function testTaskStatusPost()
|
||||
{
|
||||
$data = [
|
||||
|
@ -42,6 +42,16 @@ class TaxRateApiTest extends TestCase
|
||||
Model::reguard();
|
||||
}
|
||||
|
||||
public function testTaxRatesGetFilter()
|
||||
{
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->get('/api/v1/tax_rates?filter=gst');
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
|
||||
public function testTaxRatePost()
|
||||
{
|
||||
$rate_name = $this->faker->firstName();
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user