Merge branch 'v5-develop' into v5-stable

This commit is contained in:
David Bomba 2023-07-22 11:41:14 +10:00
commit 1c8a248828
938 changed files with 735320 additions and 450528 deletions

View File

@ -21,3 +21,6 @@ COMPOSER_AUTH='{"github-oauth": {"github.com": "${{ secrets.GITHUB_TOKEN }}"}}'
TRAVIS=true
API_SECRET=superdoopersecrethere
PHANTOMJS_PDF_GENERATION=false
CACHE_DRIVER=redis
QUEUE_CONNECTION=redis
SESSION_DRIVER=redis

View File

@ -4,6 +4,7 @@ APP_KEY=base64:RR++yx2rJ9kdxbdh3+AmbHLDQu+Q76i++co9Y8ybbno=
APP_DEBUG=false
APP_URL=http://localhost
REACT_URL=http://localhost:3001
DB_CONNECTION=mysql
MULTI_DB_ENABLED=false
@ -33,8 +34,8 @@ MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS='user@example.com'
MAIL_FROM_NAME='Self Hosted User'
MAIL_FROM_ADDRESS="user@example.com"
MAIL_FROM_NAME="Self Hosted User"
POSTMARK_API_TOKEN=
REQUIRE_HTTPS=false
@ -67,4 +68,4 @@ MICROSOFT_REDIRECT_URI=
APPLE_CLIENT_ID=
APPLE_CLIENT_SECRET=
APPLE_REDIRECT_URI=
APPLE_REDIRECT_URI=

View File

@ -22,6 +22,7 @@ jobs:
dependency-version: [prefer-stable]
env:
DB_CONNECTION: mysql
DB_DATABASE1: ninja
DB_USERNAME1: root
DB_PASSWORD1: ninja
@ -43,7 +44,7 @@ jobs:
services:
mariadb:
image: mariadb:latest
image: mariadb:10.6
ports:
- 32768:3306
env:
@ -112,11 +113,10 @@ jobs:
REDIS_PORT: ${{ job.services.redis.ports['6379'] }}
run: |
php artisan key:generate
php artisan optimize
php artisan cache:clear
php artisan config:cache
php artisan config:clear
php artisan ninja:post-update
php artisan optimize
- name: Migrate Database
run: |
php artisan migrate:fresh --seed --force && php artisan db:seed --force

View File

@ -23,7 +23,7 @@ jobs:
- name: Copy .env file
run: |
cp .env.example .env
- name: Install composer dependencies
run: |
composer config -g github-oauth.github.com ${{ secrets.GITHUB_TOKEN }}
@ -46,7 +46,9 @@ jobs:
git checkout main
npm i
npm run build
cp -r dist/react/* ../public/react
cp -r dist/react/* ../public/react
mkdir -p ../public/tinymce_6.4.2/tinymce/js/
cp -r node_modules/tinymce ../public/tinymce_6.4.2/tinymce/js/
cd ..
rm -rf ui
php artisan ninja:react
@ -65,8 +67,9 @@ jobs:
- name: Build project
run: |
zip -r ./invoiceninja.zip .* -x "../*"
zip -r /home/runner/work/invoiceninja/invoiceninja.zip .* -x "../*"
shopt -s dotglob
tar --exclude='public/storage' --exclude='.htaccess' --exclude='invoiceninja.zip' -zcvf /home/runner/work/invoiceninja/invoiceninja.tar *
- name: Release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
@ -74,4 +77,5 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
files: |
invoiceninja.zip
/home/runner/work/invoiceninja/invoiceninja.tar
/home/runner/work/invoiceninja/invoiceninja.zip

4
.gitignore vendored
View File

@ -37,4 +37,6 @@ public/test.pdf
public/storage/test.pdf
/Modules
_ide_helper_models.php
_ide_helper.php
_ide_helper.php
/composer.phar
.tx/

View File

@ -1 +1 @@
5.5.102
5.6.20

View File

@ -0,0 +1,27 @@
<?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 App\Casts;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
class EncryptedCast implements CastsAttributes
{
public function get($model, string $key, $value, array $attributes)
{
return is_string($value) && strlen($value) > 1 ? decrypt($value) : null;
}
public function set($model, string $key, $value, array $attributes)
{
return [$key => ! is_null($value) ? encrypt($value) : null];
}
}

View File

@ -11,11 +11,12 @@
namespace App\Console\Commands;
use App\Libraries\MultiDB;
use App\Utils\Ninja;
use App\Models\Backup;
use App\Models\Client;
use App\Models\Company;
use App\Models\Document;
use App\Libraries\MultiDB;
use App\Models\GroupSetting;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Storage;
@ -55,6 +56,9 @@ class BackupUpdate extends Command
{
//always return state to first DB
if(Ninja::isSelfHost())
return;
$current_db = config('database.default');
if (! config('ninja.db.multi_db_enabled')) {

View File

@ -12,36 +12,37 @@
namespace App\Console\Commands;
use App;
use Exception;
use App\Models\User;
use App\Utils\Ninja;
use App\Models\Quote;
use App\Models\Client;
use App\Models\Credit;
use App\Models\Vendor;
use App\Models\Account;
use App\Models\Company;
use App\Models\Contact;
use App\Models\Invoice;
use App\Models\Payment;
use App\Models\CompanyUser;
use Illuminate\Support\Str;
use App\Models\CompanyToken;
use App\Models\ClientContact;
use App\Models\CompanyLedger;
use App\Models\PurchaseOrder;
use App\Models\VendorContact;
use App\Models\BankTransaction;
use App\Models\QuoteInvitation;
use Illuminate\Console\Command;
use App\Models\CreditInvitation;
use App\Models\InvoiceInvitation;
use App\DataMapper\ClientSettings;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Mail;
use App\Factory\ClientContactFactory;
use App\Factory\VendorContactFactory;
use App\Jobs\Company\CreateCompanyToken;
use App\Models\Account;
use App\Models\Client;
use App\Models\ClientContact;
use App\Models\Company;
use App\Models\CompanyLedger;
use App\Models\CompanyToken;
use App\Models\CompanyUser;
use App\Models\Contact;
use App\Models\Credit;
use App\Models\CreditInvitation;
use App\Models\Invoice;
use App\Models\InvoiceInvitation;
use App\Models\Payment;
use App\Models\PurchaseOrder;
use App\Models\Quote;
use App\Models\QuoteInvitation;
use App\Models\RecurringInvoiceInvitation;
use App\Models\User;
use App\Models\Vendor;
use App\Models\VendorContact;
use App\Utils\Ninja;
use Exception;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Str;
use Symfony\Component\Console\Input\InputOption;
/*
@ -81,7 +82,7 @@ class CheckData extends Command
/**
* @var string
*/
protected $signature = 'ninja:check-data {--database=} {--fix=} {--portal_url=} {--client_id=} {--vendor_id=} {--paid_to_date=} {--client_balance=} {--ledger_balance=} {--balance_status=}';
protected $signature = 'ninja:check-data {--database=} {--fix=} {--portal_url=} {--client_id=} {--vendor_id=} {--paid_to_date=} {--client_balance=} {--ledger_balance=} {--balance_status=} {--bank_transaction=}';
/**
* @var string
@ -126,7 +127,8 @@ class CheckData extends Command
$this->checkClientSettings();
$this->checkCompanyTokens();
$this->checkUserState();
$this->checkContactEmailAndSendEmailStatus();
if (Ninja::isHosted()) {
$this->checkAccountStatuses();
$this->checkNinjaPortalUrls();
@ -136,6 +138,10 @@ class CheckData extends Command
$this->checkOAuth();
}
if($this->option('bank_transaction')) {
$this->fixBankTransactions();
}
$this->logMessage('Done: '.strtoupper($this->isValid ? Account::RESULT_SUCCESS : Account::RESULT_FAILURE));
$this->logMessage('Total execution time in seconds: ' . (microtime(true) - $time_start));
@ -148,7 +154,7 @@ class CheckData extends Command
->subject('Check-Data: '.strtoupper($this->isValid ? Account::RESULT_SUCCESS : Account::RESULT_FAILURE)." [{$database}]");
});
} elseif (! $this->isValid) {
new Exception("Check data failed!!\n".$this->log);
new \Exception("Check data failed!!".$this->log);
}
}
@ -410,8 +416,8 @@ class CheckData extends Command
$invitation->company_id = $invoice->company_id;
$invitation->user_id = $invoice->user_id;
$invitation->invoice_id = $invoice->id;
$invitation->contact_id = ClientContact::whereClientId($invoice->client_id)->first()->id;
$invitation->invitation_key = Str::random(config('ninja.key_length'));
$invitation->client_contact_id = ClientContact::whereClientId($invoice->client_id)->first()->id;
$invitation->key = Str::random(config('ninja.key_length'));
$invitation->save();
}
}
@ -429,11 +435,38 @@ class CheckData extends Command
private function checkEntityInvitations()
{
RecurringInvoiceInvitation::where('deleted_at', "0000-00-00 00:00:00.000000")->withTrashed()->update(['deleted_at' => null]);
InvoiceInvitation::where('deleted_at', "0000-00-00 00:00:00.000000")->withTrashed()->update(['deleted_at' => null]);
QuoteInvitation::where('deleted_at', "0000-00-00 00:00:00.000000")->withTrashed()->update(['deleted_at' => null]);
CreditInvitation::where('deleted_at', "0000-00-00 00:00:00.000000")->withTrashed()->update(['deleted_at' => null]);
InvoiceInvitation::where('sent_date', '0000-00-00 00:00:00')->cursor()->each(function ($ii){
$ii->sent_date = null;
$ii->saveQuietly();
});
InvoiceInvitation::where('viewed_date', '0000-00-00 00:00:00')->cursor()->each(function ($ii) {
$ii->viewed_date = null;
$ii->saveQuietly();
});
QuoteInvitation::where('sent_date', '0000-00-00 00:00:00')->cursor()->each(function ($ii) {
$ii->sent_date = null;
$ii->saveQuietly();
});
QuoteInvitation::where('viewed_date', '0000-00-00 00:00:00')->cursor()->each(function ($ii) {
$ii->viewed_date = null;
$ii->saveQuietly();
});
CreditInvitation::where('sent_date', '0000-00-00 00:00:00')->cursor()->each(function ($ii) {
$ii->sent_date = null;
$ii->saveQuietly();
});
CreditInvitation::where('viewed_date', '0000-00-00 00:00:00')->cursor()->each(function ($ii) {
$ii->viewed_date = null;
$ii->saveQuietly();
});
collect([Invoice::class, Quote::class, Credit::class, PurchaseOrder::class])->each(function ($entity) {
if ($entity::doesntHave('invitations')->count() > 0) {
@ -442,7 +475,7 @@ class CheckData extends Command
$contact_id = 'client_contact_id';
$contact_class = ClientContact::class;
$entity_key = \Illuminate\Support\Str::of(class_basename($entity))->snake()->append('_id')->value;
$entity_key = \Illuminate\Support\Str::of(class_basename($entity))->snake()->append('_id')->toString();
$entity_obj = get_class($entity).'Invitation';
if ($entity instanceof PurchaseOrder) {
@ -1090,4 +1123,42 @@ class CheckData extends Command
}
});
}
public function fixBankTransactions()
{
$this->logMessage("checking bank transactions");
BankTransaction::with('payment')->withTrashed()->where('invoice_ids', ',,,,,,,,')->cursor()->each(function ($bt){
if($bt->payment->exists()) {
$bt->invoice_ids = collect($bt->payment->invoices)->pluck('hashed_id')->implode(',');
$bt->save();
$this->logMessage("Fixing - {$bt->id}");
}
});
}
public function checkContactEmailAndSendEmailStatus()
{
$q = ClientContact::whereNull('email')
->where('send_email', true);
$this->logMessage($q->count() . " Contacts with Send Email = true but no email address");
if ($this->option('fix') == 'true') {
$q->cursor()->each(function ($c){
$c->send_email = false;
$c->saveQuietly();
$this->logMessage("Fixing - {$c->id}");
});
}
}
}

View File

@ -42,11 +42,6 @@ class CreateAccount extends Command
*/
protected $signature = 'ninja:create-account {--email=} {--password=}';
/**
* Create a new command instance.
*
* @param InvoiceRepository $invoice_repo
*/
public function __construct()
{
parent::__construct();

View File

@ -60,7 +60,7 @@ class DesignUpdate extends Command
foreach (MultiDB::$dbs as $db) {
MultiDB::setDB($db);
$this->handleOnDb($db);
$this->handleOnDb();
}
MultiDB::setDB($current_db);

View File

@ -105,7 +105,7 @@ class HostedMigrations extends Command
Import::dispatch($import_file, $user->companies()->first(), $user);
} catch (NonExistingMigrationFile | ProcessingMigrationArchiveFailed | ResourceNotAvailableForMigration | MigrationValidatorFailed | ResourceDependencyMissing $e) {
\Mail::to($this->user)->send(new MigrationFailed($e, $e->getMessage()));
\Mail::to($user)->send(new MigrationFailed($e, $company));
if (app()->environment() !== 'production') {
info($e->getMessage());

View File

@ -44,7 +44,6 @@ class HostedUsers extends Command
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{

View File

@ -64,8 +64,6 @@ class ImportMigrations extends Command
*/
public function __construct()
{
$this->faker = Factory::create();
parent::__construct();
}
@ -76,6 +74,8 @@ class ImportMigrations extends Command
*/
public function handle()
{
$this->faker = Factory::create();
$this->buildCache();
$path = $this->option('path') ?? public_path('storage/migrations/import');
@ -105,9 +105,9 @@ class ImportMigrations extends Command
$import_file = public_path("storage/migrations/$filename/migration.json");
Import::dispatch($import_file, $this->getUser()->companies()->first(), $this->getUser());
// StartMigration::dispatch($file->getRealPath(), $this->getUser(), $this->getUser()->companies()->first());
} catch (NonExistingMigrationFile | ProcessingMigrationArchiveFailed | ResourceNotAvailableForMigration | MigrationValidatorFailed | ResourceDependencyMissing $e) {
\Mail::to($this->user)->send(new MigrationFailed($e, $e->getMessage()));
\Mail::to($user)->send(new MigrationFailed($e, $company));
if (app()->environment() !== 'production') {
info($e->getMessage());

View File

@ -12,7 +12,6 @@
namespace App\Console\Commands;
use DirectoryIterator;
use Faker\Factory;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Storage;
@ -44,8 +43,6 @@ class OpenApiYaml extends Command
*/
public function __construct()
{
$this->faker = Factory::create();
parent::__construct();
}
@ -82,6 +79,7 @@ class OpenApiYaml extends Command
Storage::disk('base')->append('/openapi/api-docs.yaml', file_get_contents($path.'/components.yaml'));
Storage::disk('base')->append('/openapi/api-docs.yaml', file_get_contents($path.'/components/responses.yaml'));
Storage::disk('base')->append('/openapi/api-docs.yaml', file_get_contents($path.'/components/examples.yaml'));
$directory = new DirectoryIterator($path . '/components/responses/');

View File

@ -62,12 +62,13 @@ class PostUpdate extends Command
info('finished running composer install ');
try {
Artisan::call('optimize');
// Artisan::call('optimize');
Artisan::call('config:clear');
} catch (\Exception $e) {
info("I wasn't able to optimize.");
info("I wasn't able to clear config.");
}
info('optimized');
info('cleared config');
try {
Artisan::call('view:clear');

View File

@ -47,7 +47,6 @@ class S3Cleanup extends Command
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{

View File

@ -57,7 +57,6 @@ class SendRemindersCron extends Command
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
@ -175,6 +174,9 @@ class SendRemindersCron extends Command
$invoice->calc()->getInvoice()->save();
$invoice->fresh();
$invoice->service()->deletePdf()->save();
if ($invoice->client->getSetting('enable_e_invoice')){
$invoice->service()->deleteEInvoice()->save();
}
/* Refresh the client here to ensure the balance is fresh */
$client = $invoice->client;

View File

@ -51,10 +51,13 @@ class TranslationsExport extends Command
'fi',
'fr',
'fr_CA',
'fr_CH',
'he',
'hr',
'hu',
'it',
'ja',
'km_KH',
'lt',
'lv_LV',
'mk_MK',
@ -134,7 +137,6 @@ class TranslationsExport extends Command
Storage::disk('local')->makeDirectory("lang/{$lang}");
$translations = Lang::getLoader()->load($lang, 'texts');
Storage::disk('local')->put("lang/{$lang}/{$lang}.json", json_encode(Arr::dot($translations), JSON_UNESCAPED_UNICODE));
}
}

View File

@ -15,6 +15,7 @@ use App\Jobs\Cron\AutoBillCron;
use App\Jobs\Cron\RecurringExpensesCron;
use App\Jobs\Cron\RecurringInvoicesCron;
use App\Jobs\Cron\SubscriptionCron;
use App\Jobs\Cron\UpdateCalculatedFields;
use App\Jobs\Invoice\InvoiceCheckLateWebhook;
use App\Jobs\Ninja\AdjustEmailQuota;
use App\Jobs\Ninja\BankTransactionSync;
@ -47,14 +48,23 @@ class Kernel extends ConsoleKernel
/* Check for the latest version of Invoice Ninja */
$schedule->job(new VersionCheck)->daily();
/* Checks and cleans redundant files */
$schedule->job(new DiskCleanup)->dailyAt('02:10')->withoutOverlapping()->name('disk-cleanup-job')->onOneServer();
/* Returns the number of jobs in the queue */
$schedule->job(new QueueSize)->everyFiveMinutes()->withoutOverlapping()->name('queue-size-job')->onOneServer();
/* Send reminders */
$schedule->job(new ReminderJob)->hourly()->withoutOverlapping()->name('reminder-job')->onOneServer();
/* Returns the number of jobs in the queue */
$schedule->job(new QueueSize)->everyFiveMinutes()->withoutOverlapping()->name('queue-size-job')->onOneServer();
/* Sends recurring invoices*/
$schedule->job(new RecurringInvoicesCron)->hourly()->withoutOverlapping()->name('recurring-invoice-job')->onOneServer();
/* Checks for scheduled tasks */
$schedule->job(new TaskScheduler())->hourlyAt(10)->withoutOverlapping()->name('task-scheduler-job')->onOneServer();
/* Stale Invoice Cleanup*/
$schedule->job(new CleanStaleInvoiceOrder)->hourlyAt(30)->withoutOverlapping()->name('stale-invoice-job')->onOneServer();
/* Stale Invoice Cleanup*/
$schedule->job(new UpdateCalculatedFields)->hourlyAt(40)->withoutOverlapping()->name('update-calculated-fields-job')->onOneServer();
/* Checks for large companies and marked them as is_large */
$schedule->job(new CompanySizeCheck)->dailyAt('23:20')->withoutOverlapping()->name('company-size-job')->onOneServer();
@ -65,33 +75,26 @@ class Kernel extends ConsoleKernel
/* Runs cleanup code for subscriptions */
$schedule->job(new SubscriptionCron)->dailyAt('00:01')->withoutOverlapping()->name('subscription-job')->onOneServer();
/* Sends recurring invoices*/
$schedule->job(new RecurringInvoicesCron)->hourly()->withoutOverlapping()->name('recurring-invoice-job')->onOneServer();
/* Stale Invoice Cleanup*/
$schedule->job(new CleanStaleInvoiceOrder)->hourlyAt(30)->withoutOverlapping()->name('stale-invoice-job')->onOneServer();
/* Sends recurring invoices*/
$schedule->job(new RecurringExpensesCron)->dailyAt('00:10')->withoutOverlapping()->name('recurring-expense-job')->onOneServer();
/* Fires notifications for expired Quotes */
$schedule->job(new QuoteCheckExpired)->dailyAt('05:10')->withoutOverlapping()->name('quote-expired-job')->onOneServer();
/* Fires webhooks for overdue Invoice */
$schedule->job(new InvoiceCheckLateWebhook)->dailyAt('07:00')->withoutOverlapping()->name('invoice-overdue-job')->onOneServer();
/* Performs auto billing */
$schedule->job(new AutoBillCron)->dailyAt('06:20')->withoutOverlapping()->name('auto-bill-job')->onOneServer();
/* Checks the status of the scheduler */
$schedule->job(new SchedulerCheck)->dailyAt('01:10')->withoutOverlapping();
/* Checks for scheduled tasks */
$schedule->job(new TaskScheduler())->hourlyAt(10)->withoutOverlapping()->name('task-scheduler-job')->onOneServer();
/* Checks and cleans redundant files */
$schedule->job(new DiskCleanup)->dailyAt('02:10')->withoutOverlapping()->name('disk-cleanup-job')->onOneServer();
/* Performs system maintenance such as pruning the backup table */
$schedule->job(new SystemMaintenance)->sundays()->at('02:30')->withoutOverlapping()->name('system-maintenance-job')->onOneServer();
/* Fires notifications for expired Quotes */
$schedule->job(new QuoteCheckExpired)->dailyAt('05:10')->withoutOverlapping()->name('quote-expired-job')->onOneServer();
/* Performs auto billing */
$schedule->job(new AutoBillCron)->dailyAt('06:20')->withoutOverlapping()->name('auto-bill-job')->onOneServer();
/* Fires webhooks for overdue Invoice */
$schedule->job(new InvoiceCheckLateWebhook)->dailyAt('07:00')->withoutOverlapping()->name('invoice-overdue-job')->onOneServer();
if (Ninja::isSelfHost()) {
$schedule->call(function () {
@ -106,9 +109,6 @@ class Kernel extends ConsoleKernel
/* 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();
$schedule->command('ninja:check-data --database=db-ninja-01')->dailyAt('02:10')->withoutOverlapping()->name('check-data-db-1-job')->onOneServer();
$schedule->command('ninja:check-data --database=db-ninja-02')->dailyAt('02:20')->withoutOverlapping()->name('check-data-db-2-job')->onOneServer();

View File

@ -37,7 +37,7 @@ class AccountCreated extends GenericCounter
*
* date("Y-m-d H:i:s")
*
* @var DateTime
* @var \DateTime
*/
public $datetime;

View File

@ -37,7 +37,7 @@ class AccountDeleted extends GenericCounter
*
* date("Y-m-d H:i:s")
*
* @var DateTime
* @var \DateTime
*/
public $datetime;

View File

@ -37,7 +37,7 @@ class AccountPlatform extends GenericMixedMetric
*
* date("Y-m-d H:i:s")
*
* @var DateTime
* @var \DateTime
*/
public $datetime;

View File

@ -37,7 +37,7 @@ class AccountSignup extends GenericMixedMetric
*
* date("Y-m-d H:i:s")
*
* @var DateTime
* @var \DateTime
*/
public $datetime;

View File

@ -37,7 +37,7 @@ class BankAccountsCreated extends GenericMixedMetric
*
* date("Y-m-d H:i:s")
*
* @var DateTime
* @var \DateTime
*/
public $datetime;

View File

@ -37,7 +37,7 @@ class DbQuery extends GenericMixedMetric
*
* date("Y-m-d H:i:s")
*
* @var DateTime
* @var \DateTime
*/
public $datetime;

View File

@ -37,7 +37,7 @@ class EmailCount extends GenericMixedMetric
*
* date("Y-m-d H:i:s")
*
* @var DateTime
* @var \DateTime
*/
public $datetime;

View File

@ -37,7 +37,7 @@ class EmailFailure extends GenericMixedMetric
*
* date("Y-m-d H:i:s")
*
* @var DateTime
* @var \DateTime
*/
public $datetime;

View File

@ -37,7 +37,7 @@ class EmailInvoiceFailure extends GenericMixedMetric
*
* date("Y-m-d H:i:s")
*
* @var DateTime
* @var \DateTime
*/
public $datetime;

View File

@ -37,7 +37,7 @@ class EmailSuccess extends GenericMixedMetric
*
* date("Y-m-d H:i:s")
*
* @var DateTime
* @var \DateTime
*/
public $datetime;

View File

@ -37,7 +37,7 @@ class LivePreview extends GenericCounter
*
* date("Y-m-d H:i:s")
*
* @var DateTime
* @var \DateTime
*/
public $datetime;

View File

@ -37,7 +37,7 @@ class LoginFailure extends GenericCounter
*
* date("Y-m-d H:i:s")
*
* @var DateTime
* @var \DateTime
*/
public $datetime;

View File

@ -37,7 +37,7 @@ class LoginSuccess extends GenericCounter
*
* date("Y-m-d H:i:s")
*
* @var DateTime
* @var \DateTime
*/
public $datetime;

View File

@ -37,7 +37,7 @@ class EmailBounce extends GenericMixedMetric
*
* date("Y-m-d H:i:s")
*
* @var DateTime
* @var \DateTime
*/
public $datetime;

View File

@ -37,7 +37,7 @@ class EmailSpam extends GenericMixedMetric
*
* date("Y-m-d H:i:s")
*
* @var DateTime
* @var \DateTime
*/
public $datetime;

View File

@ -37,7 +37,7 @@ class MigrationFailure extends GenericMixedMetric
*
* date("Y-m-d H:i:s")
*
* @var DateTime
* @var \DateTime
*/
public $datetime;

View File

@ -37,7 +37,7 @@ class QueueSize extends GenericMixedMetric
*
* date("Y-m-d H:i:s")
*
* @var DateTime
* @var \DateTime
*/
public $datetime;

View File

@ -37,7 +37,7 @@ class SendRecurringFailure extends GenericMixedMetric
*
* date("Y-m-d H:i:s")
*
* @var DateTime
* @var \DateTime
*/
public $datetime;

View File

@ -37,7 +37,7 @@ class TrialFinished extends GenericCounter
*
* date("Y-m-d H:i:s")
*
* @var DateTime
* @var \DateTime
*/
public $datetime;

View File

@ -37,7 +37,7 @@ class TrialStarted extends GenericCounter
*
* date("Y-m-d H:i:s")
*
* @var DateTime
* @var \DateTime
*/
public $datetime;

View File

@ -475,7 +475,16 @@ class CompanySettings extends BaseSettings
public $sync_invoice_quote_columns = true;
public $e_invoice_type = 'EN16931';
public $default_expense_payment_type_id = '0';
public $enable_e_invoice = false;
public static $casts = [
'enable_e_invoice' => 'bool',
'default_expense_payment_type_id' => 'string',
'e_invoice_type' => 'string',
'mailgun_endpoint' => 'string',
'client_initiated_payments' => 'bool',
'client_initiated_payments_minimum' => 'float',
@ -962,6 +971,12 @@ class CompanySettings extends BaseSettings
'$method',
'$statement_amount',
],
'statement_credit_columns' => [
'$credit.number',
'$credit.date',
'$total',
'$credit.balance',
],
];
return json_decode(json_encode($variables));

View File

@ -0,0 +1,73 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\DataMapper\Schedule;
class EmailReport
{
/**
* Defines the template name
*
* @var string
*/
public string $template = 'email_report';
/**
* An array of clients hashed_ids
*
* Leave blank if this action should apply to all clients
*
* @var array
*/
public array $clients = [];
/**
* The consts to be used to define the date_range variable of the statement
*/
public const LAST7 = "last7_days";
public const LAST30 = "last30_days";
public const LAST365 = "last365_days";
public const THIS_MONTH = "this_month";
public const LAST_MONTH = "last_month";
public const THIS_QUARTER = "this_quarter";
public const LAST_QUARTER = "last_quarter";
public const THIS_YEAR = "this_year";
public const LAST_YEAR = "last_year";
public const CUSTOM_RANGE = "custom";
/**
* The date range the statement should include
*
* @var string
*/
public string $date_range = 'this_month';
/**
* If a custom range is select for the date range then
* the start_date should be supplied in Y-m-d format
*
* @var string
*/
public string $start_date = '';
/**
* If a custom range is select for the date range then
* the end_date should be supplied in Y-m-d format
*
* @var string
*/
public string $end_date = '';
/** @var string $report_name */
public string $report_name = '';
}

View File

@ -41,6 +41,7 @@ class EmailStatement
public const LAST_QUARTER = "last_quarter";
public const THIS_YEAR = "this_year";
public const LAST_YEAR = "last_year";
public const ALL_TIME = "all_time";
public const CUSTOM_RANGE = "custom";

View File

@ -0,0 +1,44 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\DataMapper\Tax\AT;
use App\DataMapper\Tax\DE\Rule as DERule;
class Rule extends DERule
{
/** @var string $seller_region */
public string $seller_region = 'EU';
/** @var bool $consumer_tax_exempt */
public bool $consumer_tax_exempt = false;
/** @var bool $business_tax_exempt */
public bool $business_tax_exempt = false;
/** @var bool $eu_business_tax_exempt */
public bool $eu_business_tax_exempt = true;
/** @var bool $foreign_business_tax_exempt */
public bool $foreign_business_tax_exempt = false;
/** @var bool $foreign_consumer_tax_exempt */
public bool $foreign_consumer_tax_exempt = false;
/** @var float $tax_rate */
public float $tax_rate = 0;
/** @var float $reduced_tax_rate */
public float $reduced_tax_rate = 0;
public string $tax_name1 = 'USt';
}

View File

@ -0,0 +1,260 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\DataMapper\Tax\AU;
use App\DataMapper\Tax\BaseRule;
use App\DataMapper\Tax\RuleInterface;
use App\Models\Product;
class Rule extends BaseRule implements RuleInterface
{
/** @var string $seller_region */
public string $seller_region = 'AU';
/** @var bool $consumer_tax_exempt */
public bool $consumer_tax_exempt = false;
/** @var bool $business_tax_exempt */
public bool $business_tax_exempt = false;
/** @var bool $eu_business_tax_exempt */
public bool $eu_business_tax_exempt = true;
/** @var bool $foreign_business_tax_exempt */
public bool $foreign_business_tax_exempt = false;
/** @var bool $foreign_consumer_tax_exempt */
public bool $foreign_consumer_tax_exempt = false;
/** @var float $tax_rate */
public float $tax_rate = 0;
/** @var float $reduced_tax_rate */
public float $reduced_tax_rate = 0;
/**
* Initializes the rules and builds any required data.
*
* @return self
*/
public function init(): self
{
$this->calculateRates();
return $this;
}
/**
* Sets the correct tax rate based on the product type.
*
* @param mixed $item
* @return self
*/
public function taxByType($item): self
{
if ($this->client->is_tax_exempt) {
return $this->taxExempt($item);
}
match(intval($item->tax_id)) {
Product::PRODUCT_TYPE_EXEMPT => $this->taxExempt($item),
Product::PRODUCT_TYPE_DIGITAL => $this->taxDigital($item),
Product::PRODUCT_TYPE_SERVICE => $this->taxService($item),
Product::PRODUCT_TYPE_SHIPPING => $this->taxShipping($item),
Product::PRODUCT_TYPE_PHYSICAL => $this->taxPhysical($item),
Product::PRODUCT_TYPE_REDUCED_TAX => $this->taxReduced($item),
Product::PRODUCT_TYPE_OVERRIDE_TAX => $this->override($item),
Product::PRODUCT_TYPE_ZERO_RATED => $this->zeroRated($item),
Product::PRODUCT_TYPE_REVERSE_TAX => $this->reverseTax($item),
default => $this->default($item),
};
return $this;
}
/**
* Calculates the tax rate for a reduced tax product
*
* @return self
*/
public function reverseTax($item): self
{
$this->tax_rate1 = 10;
$this->tax_name1 = 'GST';
return $this;
}
/**
* Calculates the tax rate for a reduced tax product
*
* @return self
*/
public function taxReduced($item): self
{
$this->tax_rate1 = $this->reduced_tax_rate;
$this->tax_name1 = 'GST';
return $this;
}
/**
* Calculates the tax rate for a zero rated tax product
*
* @return self
*/
public function zeroRated($item): self
{
$this->tax_rate1 = 0;
$this->tax_name1 = 'GST';
return $this;
}
/**
* Calculates the tax rate for a tax exempt product
*
* @return self
*/
public function taxExempt($item): self
{
$this->tax_name1 = '';
$this->tax_rate1 = 0;
return $this;
}
/**
* Calculates the tax rate for a digital product
*
* @return self
*/
public function taxDigital($item): self
{
$this->tax_rate1 = $this->tax_rate;
$this->tax_name1 = 'GST';
return $this;
}
/**
* Calculates the tax rate for a service product
*
* @return self
*/
public function taxService($item): self
{
$this->tax_rate1 = $this->tax_rate;
$this->tax_name1 = 'GST';
return $this;
}
/**
* Calculates the tax rate for a shipping product
*
* @return self
*/
public function taxShipping($item): self
{
$this->tax_rate1 = $this->tax_rate;
$this->tax_name1 = 'GST';
return $this;
}
/**
* Calculates the tax rate for a physical product
*
* @return self
*/
public function taxPhysical($item): self
{
$this->tax_rate1 = $this->tax_rate;
$this->tax_name1 = 'GST';
return $this;
}
/**
* Calculates the tax rate for a default product
*
* @return self
*/
public function default($item): self
{
$this->tax_name1 = '';
$this->tax_rate1 = 0;
return $this;
}
/**
* Calculates the tax rate for an override product
*
* @return self
*/
public function override($item): self
{
return $this;
}
/**
* Calculates the tax rates based on the client's location.
*
* @return self
*/
public function calculateRates(): self
{
if ($this->client->is_tax_exempt) {
$this->tax_rate = 0;
$this->reduced_tax_rate = 0;
return $this;
}
// } elseif($this->client_subregion != $this->client->company->tax_data->seller_subregion && in_array($this->client_subregion, $this->eu_country_codes) && $this->client->has_valid_vat_number && $this->eu_business_tax_exempt) {
// nlog("euro zone and tax exempt");
// $this->tax_rate = 0;
// $this->reduced_tax_rate = 0;
// } elseif(!in_array($this->client_subregion, $this->eu_country_codes) && ($this->foreign_consumer_tax_exempt || $this->foreign_business_tax_exempt)) { //foreign + tax exempt
// nlog("foreign and tax exempt");
// $this->tax_rate = 0;
// $this->reduced_tax_rate = 0;
// } elseif(!in_array($this->client_subregion, $this->eu_country_codes)) {
// $this->defaultForeign();
// } elseif(in_array($this->client_subregion, $this->eu_country_codes) && !$this->client->has_valid_vat_number) { //eu country / no valid vat
// if(($this->client->company->tax_data->seller_subregion != $this->client_subregion) && $this->client->company->tax_data->regions->EU->has_sales_above_threshold) {
// nlog("eu zone with sales above threshold");
// $this->tax_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->country->iso_3166_2}->tax_rate;
// $this->reduced_tax_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->country->iso_3166_2}->reduced_tax_rate;
// } else {
// nlog("EU with intra-community supply ie DE to DE");
// $this->tax_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->company->country()->iso_3166_2}->tax_rate;
// $this->reduced_tax_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->company->country()->iso_3166_2}->reduced_tax_rate;
// }
$this->tax_rate = $this->client->company->tax_data->regions->AU->subregions->{$this->client->company->country()->iso_3166_2}->tax_rate;
$this->reduced_tax_rate = $this->client->company->tax_data->regions->AU->subregions->{$this->client->company->country()->iso_3166_2}->reduced_tax_rate;
return $this;
}
}

View File

@ -0,0 +1,44 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\DataMapper\Tax\BE;
use App\DataMapper\Tax\DE\Rule as DERule;
class Rule extends DERule
{
/** @var string $seller_region */
public string $seller_region = 'EU';
/** @var bool $consumer_tax_exempt */
public bool $consumer_tax_exempt = false;
/** @var bool $business_tax_exempt */
public bool $business_tax_exempt = false;
/** @var bool $eu_business_tax_exempt */
public bool $eu_business_tax_exempt = true;
/** @var bool $foreign_business_tax_exempt */
public bool $foreign_business_tax_exempt = false;
/** @var bool $foreign_consumer_tax_exempt */
public bool $foreign_consumer_tax_exempt = false;
/** @var float $tax_rate */
public float $tax_rate = 0;
/** @var float $reduced_tax_rate */
public float $reduced_tax_rate = 0;
public string $tax_name1 = 'BTW';
}

View File

@ -0,0 +1,44 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\DataMapper\Tax\BG;
use App\DataMapper\Tax\DE\Rule as DERule;
class Rule extends DERule
{
/** @var string $seller_region */
public string $seller_region = 'EU';
/** @var bool $consumer_tax_exempt */
public bool $consumer_tax_exempt = false;
/** @var bool $business_tax_exempt */
public bool $business_tax_exempt = false;
/** @var bool $eu_business_tax_exempt */
public bool $eu_business_tax_exempt = true;
/** @var bool $foreign_business_tax_exempt */
public bool $foreign_business_tax_exempt = false;
/** @var bool $foreign_consumer_tax_exempt */
public bool $foreign_consumer_tax_exempt = false;
/** @var float $tax_rate */
public float $tax_rate = 0;
/** @var float $reduced_tax_rate */
public float $reduced_tax_rate = 0;
public string $tax_name1 = 'НДС';
}

View File

@ -11,8 +11,11 @@
namespace App\DataMapper\Tax;
use App\DataMapper\Tax\ZipTax\Response;
use App\Models\Client;
use App\Models\Invoice;
use App\Models\Product;
use App\DataProviders\USStates;
use App\DataMapper\Tax\ZipTax\Response;
class BaseRule implements RuleInterface
{
@ -27,42 +30,79 @@ class BaseRule implements RuleInterface
public bool $foreign_consumer_tax_exempt = true;
public string $seller_region = '';
public string $client_region = '';
public string $client_subregion = '';
public array $eu_country_codes = [
'AT', // Austria
'BE', // Belgium
'BG', // Bulgaria
'CY', // Cyprus
'CZ', // Czech Republic
'DE', // Germany
'DK', // Denmark
'EE', // Estonia
'ES', // Spain
'FI', // Finland
'FR', // France
'GR', // Greece
'HR', // Croatia
'HU', // Hungary
'IE', // Ireland
'IT', // Italy
'LT', // Lithuania
'LU', // Luxembourg
'LV', // Latvia
'MT', // Malta
'NL', // Netherlands
'PL', // Poland
'PT', // Portugal
'RO', // Romania
'SE', // Sweden
'SI', // Slovenia
'SK', // Slovakia
'AT', // Austria
'BE', // Belgium
'BG', // Bulgaria
'CY', // Cyprus
'CZ', // Czech Republic
'DE', // Germany
'DK', // Denmark
'EE', // Estonia
'ES', // Spain
'FI', // Finland
'FR', // France
'GR', // Greece
'HR', // Croatia
'HU', // Hungary
'IE', // Ireland
'IT', // Italy
'LT', // Lithuania
'LU', // Luxembourg
'LV', // Latvia
'MT', // Malta
'NL', // Netherlands
'PL', // Poland
'PT', // Portugal
'RO', // Romania
'SE', // Sweden
'SI', // Slovenia
'SK', // Slovakia
];
public array $region_codes = [
'AT' => 'EU', // Austria
'BE' => 'EU', // Belgium
'BG' => 'EU', // Bulgaria
'CY' => 'EU', // Cyprus
'CZ' => 'EU', // Czech Republic
'DE' => 'EU', // Germany
'DK' => 'EU', // Denmark
'EE' => 'EU', // Estonia
'ES' => 'EU', // Spain
'FI' => 'EU', // Finland
'FR' => 'EU', // France
'GR' => 'EU', // Greece
'HR' => 'EU', // Croatia
'HU' => 'EU', // Hungary
'IE' => 'EU', // Ireland
'IT' => 'EU', // Italy
'LT' => 'EU', // Lithuania
'LU' => 'EU', // Luxembourg
'LV' => 'EU', // Latvia
'MT' => 'EU', // Malta
'NL' => 'EU', // Netherlands
'PL' => 'EU', // Poland
'PT' => 'EU', // Portugal
'RO' => 'EU', // Romania
'SE' => 'EU', // Sweden
'SI' => 'EU', // Slovenia
'SK' => 'EU', // Slovakia
'US' => 'US', // United States
'AU' => 'AU', // Australia
];
/** EU TAXES */
/** US TAXES */
/** US TAXES */
public string $tax_name1 = '';
public float $tax_rate1 = 0;
@ -74,7 +114,11 @@ class BaseRule implements RuleInterface
protected ?Client $client;
protected ?Response $tax_data;
public ?Response $tax_data;
public mixed $invoice;
private bool $should_calc_tax = true;
public function __construct()
{
@ -84,67 +128,240 @@ class BaseRule implements RuleInterface
{
return $this;
}
public function setClient(Client $client): self
public function shouldCalcTax(): bool
{
$this->client = $client;
return $this->should_calc_tax;
}
/**
* Initializes the tax rule for the entity.
*
* @param mixed $invoice
* @return self
*/
public function setEntity(mixed $invoice): self
{
$this->invoice = $invoice;
$this->client = $invoice->client;
$this->resolveRegions();
if(!$this->isTaxableRegion())
return $this;
$this->configTaxData();
$this->tax_data = new Response($this->invoice->tax_data);
return $this;
}
public function setTaxData(Response $tax_data): self
/**
* Configigures the Tax Data for the entity
*
* @return self
*/
private function configTaxData(): self
{
$this->tax_data = $tax_data;
/* We should only apply taxes for configured states */
if(!array_key_exists($this->client->country->iso_3166_2, $this->region_codes)) {
nlog('Automatic tax calculations not supported for this country - defaulting to company country');
nlog("With new logic, we should never see this");
}
/** Harvest the client_region */
/** If the tax data is already set and the invoice is marked as sent, do not adjust the rates */
if($this->invoice->tax_data && $this->invoice->status_id > 1)
return $this;
/**
* Origin - Company Tax Data
* Destination - Client Tax Data
*
*/
$tax_data = false;
if($this->seller_region == 'US' && $this->client_region == 'US'){
$company = $this->invoice->company;
/** If no company tax data has been configured, lets do that now. */
/** We should never encounter this scenario */
if(!$company->origin_tax_data)
{
$this->should_calc_tax = false;
return $this;
}
/** If we are in a Origin based state, force the company tax here */
if($company->origin_tax_data?->originDestination == 'O' && ($company->tax_data?->seller_subregion == $this->client_subregion)) {
$tax_data = $company->origin_tax_data;
}
elseif($this->client->tax_data){
$tax_data = $this->client->tax_data;
}
}
/** Applies the tax data to the invoice */
if($this->invoice instanceof Invoice && $tax_data) {
$this->invoice->tax_data = $tax_data;
if(\DB::transactionLevel() == 0)
$this->invoice->saveQuietly();
}
return $this;
}
/**
* Resolve Regions & Subregions
*
* @return self
*/
private function resolveRegions(): self
{
$this->client_region = $this->region_codes[$this->client->country->iso_3166_2];
match($this->client_region){
'US' => $this->client_subregion = isset($this->invoice?->client?->tax_data?->geoState) ? $this->invoice->client->tax_data->geoState : $this->getUSState(),
'EU' => $this->client_subregion = $this->client->country->iso_3166_2,
'AU' => $this->client_subregion = 'AU',
default => $this->client_subregion = $this->client->country->iso_3166_2,
};
return $this;
}
private function getUSState(): string
{
try {
$states = USStates::$states;
if(isset($states[$this->client->state]))
return $this->client->state;
return USStates::getState(strlen($this->client->postal_code) > 1 ? $this->client->postal_code : $this->client->shipping_postal_code);
} catch (\Exception $e) {
return $this->client->company->country()->iso_3166_2 == 'US' ? $this->client->company->tax_data->seller_subregion : 'CA';
}
}
public function isTaxableRegion(): bool
{
return $this->client->company->tax_data->regions->{$this->client_region}->tax_all_subregions ||
(property_exists($this->client->company->tax_data->regions->{$this->client_region}->subregions, $this->client_subregion) && $this->client->company->tax_data->regions->{$this->client_region}->subregions->{$this->client_subregion}->apply_tax);
}
public function defaultForeign(): self
{
if($this->client_region == 'US' && isset($this->tax_data?->taxSales)) {
$this->tax_rate1 = $this->tax_data->taxSales * 100;
$this->tax_name1 = "{$this->tax_data->geoState} Sales Tax";
return $this;
}
elseif($this->client_region == 'AU'){ //these are defaults and are only stubbed out for now, for AU we can actually remove these
$this->tax_rate1 = $this->client->company->tax_data->regions->AU->subregions->AU->tax_rate;
$this->tax_name1 = $this->client->company->tax_data->regions->AU->subregions->AU->tax_name;
return $this;
}
if(isset($this->client->company->tax_data->regions->{$this->client_region}->subregions->{$this->client_subregion})) {
$this->tax_rate1 = $this->client->company->tax_data->regions->{$this->client_region}->subregions->{$this->client_subregion}->tax_rate;
$this->tax_name1 = $this->client->company->tax_data->regions->{$this->client_region}->subregions->{$this->client_subregion}->tax_name;
}
return $this;
}
public function tax($product_tax_type): self
public function tax($item = null): self
{
if ($this->client->is_tax_exempt) {
return $this->taxExempt($item);
} elseif($this->client_region == $this->seller_region && $this->isTaxableRegion()) {
$this->taxByType($item);
return $this;
} elseif($this->isTaxableRegion()) { //other regions outside of US
match(intval($item->tax_id)) {
Product::PRODUCT_TYPE_EXEMPT => $this->taxExempt($item),
Product::PRODUCT_TYPE_REDUCED_TAX => $this->taxReduced($item),
Product::PRODUCT_TYPE_OVERRIDE_TAX => $this->override($item),
default => $this->defaultForeign(),
};
}
return $this;
}
public function taxByType(mixed $type): self
{
return $this;
}
public function taxByType($product_tax_type): self
public function taxReduced($item): self
{
return $this;
}
public function taxReduced(): self
public function taxExempt($item): self
{
return $this;
}
public function taxExempt(): self
public function taxDigital($item): self
{
return $this;
}
public function taxDigital(): self
public function taxService($item): self
{
return $this;
}
public function taxService(): self
public function taxShipping($item): self
{
return $this;
}
public function taxShipping(): self
public function taxPhysical($item): self
{
return $this;
}
public function taxPhysical(): self
public function default($item): self
{
return $this;
}
public function default(): self
{
return $this;
}
public function override(): self
public function override($item): self
{
return $this;
}
@ -153,4 +370,10 @@ class BaseRule implements RuleInterface
{
return $this;
}
public function regionWithNoTaxCoverage(string $iso_3166_2): bool
{
return ! in_array($iso_3166_2, array_merge($this->eu_country_codes, array_keys($this->region_codes)));
}
}

View File

@ -0,0 +1,44 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\DataMapper\Tax\CY;
use App\DataMapper\Tax\DE\Rule as DERule;
class Rule extends DERule
{
/** @var string $seller_region */
public string $seller_region = 'EU';
/** @var bool $consumer_tax_exempt */
public bool $consumer_tax_exempt = false;
/** @var bool $business_tax_exempt */
public bool $business_tax_exempt = false;
/** @var bool $eu_business_tax_exempt */
public bool $eu_business_tax_exempt = true;
/** @var bool $foreign_business_tax_exempt */
public bool $foreign_business_tax_exempt = false;
/** @var bool $foreign_consumer_tax_exempt */
public bool $foreign_consumer_tax_exempt = false;
/** @var float $tax_rate */
public float $tax_rate = 0;
/** @var float $reduced_tax_rate */
public float $reduced_tax_rate = 0;
public string $tax_name1 = 'ΦΠΑ';
}

View File

@ -0,0 +1,44 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\DataMapper\Tax\CZ;
use App\DataMapper\Tax\DE\Rule as DERule;
class Rule extends DERule
{
/** @var string $seller_region */
public string $seller_region = 'EU';
/** @var bool $consumer_tax_exempt */
public bool $consumer_tax_exempt = false;
/** @var bool $business_tax_exempt */
public bool $business_tax_exempt = false;
/** @var bool $eu_business_tax_exempt */
public bool $eu_business_tax_exempt = true;
/** @var bool $foreign_business_tax_exempt */
public bool $foreign_business_tax_exempt = false;
/** @var bool $foreign_consumer_tax_exempt */
public bool $foreign_consumer_tax_exempt = false;
/** @var float $tax_rate */
public float $tax_rate = 0;
/** @var float $reduced_tax_rate */
public float $reduced_tax_rate = 0;
public string $tax_name1 = 'DPH';
}

View File

@ -11,168 +11,186 @@
namespace App\DataMapper\Tax\DE;
use App\Models\Client;
use App\Models\Product;
use Illuminate\Support\Str;
use App\DataMapper\Tax\BaseRule;
use App\DataMapper\Tax\RuleInterface;
use App\DataMapper\Tax\ZipTax\Response;
class Rule extends BaseRule implements RuleInterface
{
public string $vendor_country_code = 'DE';
public string $client_country_code = 'DE';
{
/** @var string $seller_region */
public string $seller_region = 'EU';
/** @var bool $consumer_tax_exempt */
public bool $consumer_tax_exempt = false;
/** @var bool $business_tax_exempt */
public bool $business_tax_exempt = false;
/** @var bool $eu_business_tax_exempt */
public bool $eu_business_tax_exempt = true;
public bool $foreign_business_tax_exempt = true;
public bool $foreign_consumer_tax_exempt = true;
public string $tax_name1 = '';
public float $tax_rate1 = 0;
public string $tax_name2 = '';
public float $tax_rate2 = 0;
/** @var bool $foreign_business_tax_exempt */
public bool $foreign_business_tax_exempt = false;
public string $tax_name3 = '';
/** @var bool $foreign_consumer_tax_exempt */
public bool $foreign_consumer_tax_exempt = false;
public float $tax_rate3 = 0;
public float $vat_rate = 0;
public float $reduced_vat_rate = 0;
protected ?Client $client;
protected ?Response $tax_data;
public function __construct()
{
}
/** @var float $tax_rate */
public float $tax_rate = 0;
/** @var float $reduced_tax_rate */
public float $reduced_tax_rate = 0;
public string $tax_name1 = 'MwSt.';
/**
* Initializes the rules and builds any required data.
*
* @return self
*/
public function init(): self
{
$this->client_country_code = $this->client->shipping_country ? $this->client->shipping_country->iso_3166_2 : $this->client->country->iso_3166_2;
$this->calculateRates();
return $this;
}
public function setClient(Client $client): self
{
$this->client = $client;
return $this;
}
public function setTaxData(Response $tax_data): self
{
$this->tax_data = $tax_data;
return $this;
}
//need to add logic here to capture if
public function tax($type): self
{
if ($this->client->is_tax_exempt) {
return $this->taxExempt();
} elseif ($this->client->company->tax_data->regions->EU->tax_all) {
$this->tax_rate1 = $this->vat_rate;
$this->tax_name1 = "MwSt.";
return $this;
}
if ($type)
return $this->taxByType($type);
return $this;
}
public function taxByType($product_tax_type): self
/**
* Sets the correct tax rate based on the product type.
*
* @param mixed $item
* @return self
*/
public function taxByType($item): self
{
if ($this->client->is_tax_exempt) {
return $this->taxExempt();
return $this->taxExempt($item);
}
if(!$product_tax_type)
return $this;
match($product_tax_type){
Product::PRODUCT_TYPE_EXEMPT => $this->taxExempt(),
Product::PRODUCT_TYPE_DIGITAL => $this->taxDigital(),
Product::PRODUCT_TYPE_SERVICE => $this->taxService(),
Product::PRODUCT_TYPE_SHIPPING => $this->taxShipping(),
Product::PRODUCT_TYPE_PHYSICAL => $this->taxPhysical(),
Product::PRODUCT_TYPE_REDUCED_TAX => $this->taxReduced(),
Product::PRODUCT_TYPE_OVERRIDE_TAX => $this->override(),
default => $this->default(),
match(intval($item->tax_id)){
Product::PRODUCT_TYPE_EXEMPT => $this->taxExempt($item),
Product::PRODUCT_TYPE_DIGITAL => $this->taxDigital($item),
Product::PRODUCT_TYPE_SERVICE => $this->taxService($item),
Product::PRODUCT_TYPE_SHIPPING => $this->taxShipping($item),
Product::PRODUCT_TYPE_PHYSICAL => $this->taxPhysical($item),
Product::PRODUCT_TYPE_REDUCED_TAX => $this->taxReduced($item),
Product::PRODUCT_TYPE_OVERRIDE_TAX => $this->override($item),
Product::PRODUCT_TYPE_ZERO_RATED => $this->zeroRated($item),
Product::PRODUCT_TYPE_REVERSE_TAX => $this->reverseTax($item),
default => $this->default($item),
};
return $this;
}
public function taxReduced(): self
/**
* Calculates the tax rate for a reduced tax product
*
* @return self
*/
public function reverseTax($item): self
{
$this->tax_rate1 = $this->reduced_vat_rate;
$this->tax_name1 = 'ermäßigte MwSt.';
$this->tax_rate1 = 0;
return $this;
}
public function taxExempt(): self
/**
* Calculates the tax rate for a reduced tax product
*
* @return self
*/
public function taxReduced($item): self
{
$this->tax_rate1 = $this->reduced_tax_rate;
return $this;
}
/**
* Calculates the tax rate for a zero rated tax product
*
* @return self
*/
public function zeroRated($item): self
{
$this->tax_rate1 = 0;
return $this;
}
/**
* Calculates the tax rate for a tax exempt product
*
* @return self
*/
public function taxExempt($item): self
{
$this->tax_name1 = '';
$this->tax_rate1 = 0;
return $this;
}
public function taxDigital(): self
/**
* Calculates the tax rate for a digital product
*
* @return self
*/
public function taxDigital($item): self
{
$this->tax();
$this->tax_rate1 = $this->tax_rate;
return $this;
}
public function taxService(): self
/**
* Calculates the tax rate for a service product
*
* @return self
*/
public function taxService($item): self
{
$this->tax();
$this->tax_rate1 = $this->tax_rate;
return $this;
}
public function taxShipping(): self
/**
* Calculates the tax rate for a shipping product
*
* @return self
*/
public function taxShipping($item): self
{
$this->tax();
$this->tax_rate1 = $this->tax_rate;
return $this;
}
public function taxPhysical(): self
/**
* Calculates the tax rate for a physical product
*
* @return self
*/
public function taxPhysical($item): self
{
$this->tax();
$this->tax_rate1 = $this->tax_rate;
return $this;
}
public function default(): self
/**
* Calculates the tax rate for a default product
*
* @return self
*/
public function default($item): self
{
$this->tax_name1 = '';
@ -180,54 +198,68 @@ class Rule extends BaseRule implements RuleInterface
return $this;
}
public function override(): self
/**
* Calculates the tax rate for an override product
*
* @return self
*/
public function override($item): self
{
return $this;
}
/**
* Calculates the tax rates based on the client's location.
*
* @return self
*/
public function calculateRates(): self
{
if ($this->client->is_tax_exempt) {
$this->vat_rate = 0;
$this->reduced_vat_rate = 0;
// nlog("tax exempt");
$this->tax_rate = 0;
$this->reduced_tax_rate = 0;
}
elseif($this->client_country_code != $this->vendor_country_code && in_array($this->client_country_code, $this->eu_country_codes) && $this->client->has_valid_vat_number && $this->eu_business_tax_exempt)
elseif($this->client_subregion != $this->client->company->tax_data->seller_subregion && in_array($this->client_subregion, $this->eu_country_codes) && $this->client->vat_number && $this->eu_business_tax_exempt)
// elseif($this->client_subregion != $this->client->company->tax_data->seller_subregion && in_array($this->client_subregion, $this->eu_country_codes) && $this->client->has_valid_vat_number && $this->eu_business_tax_exempt)
{
$this->vat_rate = 0;
$this->reduced_vat_rate = 0;
// nlog("euro zone and tax exempt");
$this->tax_rate = 0;
$this->reduced_tax_rate = 0;
}
elseif(!in_array(strtoupper($this->client_country_code), $this->eu_country_codes) && ($this->foreign_consumer_tax_exempt || $this->foreign_business_tax_exempt)) //foreign + tax exempt
elseif(!in_array($this->client_subregion, $this->eu_country_codes) && ($this->foreign_consumer_tax_exempt || $this->foreign_business_tax_exempt)) //foreign + tax exempt
{
$this->vat_rate = 0;
$this->reduced_vat_rate = 0;
// nlog("foreign and tax exempt");
$this->tax_rate = 0;
$this->reduced_tax_rate = 0;
}
elseif(in_array(strtoupper($this->client_country_code), $this->eu_country_codes) && !$this->client->has_valid_vat_number) //eu country / no valid vat
elseif(!in_array($this->client_subregion, $this->eu_country_codes))
{
$this->defaultForeign();
}
elseif(in_array($this->client_subregion, $this->eu_country_codes) && !$this->client->vat_number) //eu country / no valid vat
{
if(($this->vendor_country_code != $this->client_country_code) && $this->client->company->tax_data->regions->EU->has_sales_above_threshold)
if(($this->client->company->tax_data->seller_subregion != $this->client_subregion) && $this->client->company->tax_data->regions->EU->has_sales_above_threshold)
{
$this->vat_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->country->iso_3166_2}->vat_rate;
$this->reduced_vat_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->country->iso_3166_2}->reduced_vat_rate;
// nlog("eu zone with sales above threshold");
$this->tax_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->country->iso_3166_2}->tax_rate;
$this->reduced_tax_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->country->iso_3166_2}->reduced_tax_rate;
}
else {
$this->vat_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->company->country()->iso_3166_2}->vat_rate;
$this->reduced_vat_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->company->country()->iso_3166_2}->reduced_vat_rate;
// nlog("same eu country with");
// nlog("EU with intra-community supply ie DE to DE");
$this->tax_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->company->country()->iso_3166_2}->tax_rate;
$this->reduced_tax_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->company->country()->iso_3166_2}->reduced_tax_rate;
}
}
else {
$this->vat_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->company->country()->iso_3166_2}->vat_rate;
$this->reduced_vat_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->company->country()->iso_3166_2}->reduced_vat_rate;
// nlog("default tax");
$this->tax_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->company->country()->iso_3166_2}->tax_rate;
$this->reduced_tax_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->company->country()->iso_3166_2}->reduced_tax_rate;
}
return $this;
}
}
}

View File

@ -0,0 +1,44 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\DataMapper\Tax\DK;
use App\DataMapper\Tax\DE\Rule as DERule;
class Rule extends DERule
{
/** @var string $seller_region */
public string $seller_region = 'EU';
/** @var bool $consumer_tax_exempt */
public bool $consumer_tax_exempt = false;
/** @var bool $business_tax_exempt */
public bool $business_tax_exempt = false;
/** @var bool $eu_business_tax_exempt */
public bool $eu_business_tax_exempt = true;
/** @var bool $foreign_business_tax_exempt */
public bool $foreign_business_tax_exempt = false;
/** @var bool $foreign_consumer_tax_exempt */
public bool $foreign_consumer_tax_exempt = false;
/** @var float $tax_rate */
public float $tax_rate = 0;
/** @var float $reduced_tax_rate */
public float $reduced_tax_rate = 0;
public string $tax_name1 = 'Moms';
}

View File

@ -0,0 +1,44 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\DataMapper\Tax\EE;
use App\DataMapper\Tax\DE\Rule as DERule;
class Rule extends DERule
{
/** @var string $seller_region */
public string $seller_region = 'EU';
/** @var bool $consumer_tax_exempt */
public bool $consumer_tax_exempt = false;
/** @var bool $business_tax_exempt */
public bool $business_tax_exempt = false;
/** @var bool $eu_business_tax_exempt */
public bool $eu_business_tax_exempt = true;
/** @var bool $foreign_business_tax_exempt */
public bool $foreign_business_tax_exempt = false;
/** @var bool $foreign_consumer_tax_exempt */
public bool $foreign_consumer_tax_exempt = false;
/** @var float $tax_rate */
public float $tax_rate = 0;
/** @var float $reduced_tax_rate */
public float $reduced_tax_rate = 0;
public string $tax_name1 = 'KM';
}

View File

@ -0,0 +1,44 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\DataMapper\Tax\ES;
use App\DataMapper\Tax\DE\Rule as DERule;
class Rule extends DERule
{
/** @var string $seller_region */
public string $seller_region = 'EU';
/** @var bool $consumer_tax_exempt */
public bool $consumer_tax_exempt = false;
/** @var bool $business_tax_exempt */
public bool $business_tax_exempt = false;
/** @var bool $eu_business_tax_exempt */
public bool $eu_business_tax_exempt = true;
/** @var bool $foreign_business_tax_exempt */
public bool $foreign_business_tax_exempt = false;
/** @var bool $foreign_consumer_tax_exempt */
public bool $foreign_consumer_tax_exempt = false;
/** @var float $tax_rate */
public float $tax_rate = 0;
/** @var float $reduced_tax_rate */
public float $reduced_tax_rate = 0;
public string $tax_name1 = 'IVA';
}

View File

@ -0,0 +1,44 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\DataMapper\Tax\FI;
use App\DataMapper\Tax\DE\Rule as DERule;
class Rule extends DERule
{
/** @var string $seller_region */
public string $seller_region = 'EU';
/** @var bool $consumer_tax_exempt */
public bool $consumer_tax_exempt = false;
/** @var bool $business_tax_exempt */
public bool $business_tax_exempt = false;
/** @var bool $eu_business_tax_exempt */
public bool $eu_business_tax_exempt = true;
/** @var bool $foreign_business_tax_exempt */
public bool $foreign_business_tax_exempt = false;
/** @var bool $foreign_consumer_tax_exempt */
public bool $foreign_consumer_tax_exempt = false;
/** @var float $tax_rate */
public float $tax_rate = 0;
/** @var float $reduced_tax_rate */
public float $reduced_tax_rate = 0;
public string $tax_name1 = 'ALV';
}

View File

@ -0,0 +1,44 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\DataMapper\Tax\FR;
use App\DataMapper\Tax\DE\Rule as DERule;
class Rule extends DERule
{
/** @var string $seller_region */
public string $seller_region = 'EU';
/** @var bool $consumer_tax_exempt */
public bool $consumer_tax_exempt = false;
/** @var bool $business_tax_exempt */
public bool $business_tax_exempt = false;
/** @var bool $eu_business_tax_exempt */
public bool $eu_business_tax_exempt = true;
/** @var bool $foreign_business_tax_exempt */
public bool $foreign_business_tax_exempt = false;
/** @var bool $foreign_consumer_tax_exempt */
public bool $foreign_consumer_tax_exempt = false;
/** @var float $tax_rate */
public float $tax_rate = 0;
/** @var float $reduced_tax_rate */
public float $reduced_tax_rate = 0;
public string $tax_name1 = 'TVA';
}

View File

@ -0,0 +1,44 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\DataMapper\Tax\GR;
use App\DataMapper\Tax\DE\Rule as DERule;
class Rule extends DERule
{
/** @var string $seller_region */
public string $seller_region = 'EU';
/** @var bool $consumer_tax_exempt */
public bool $consumer_tax_exempt = false;
/** @var bool $business_tax_exempt */
public bool $business_tax_exempt = false;
/** @var bool $eu_business_tax_exempt */
public bool $eu_business_tax_exempt = true;
/** @var bool $foreign_business_tax_exempt */
public bool $foreign_business_tax_exempt = false;
/** @var bool $foreign_consumer_tax_exempt */
public bool $foreign_consumer_tax_exempt = false;
/** @var float $tax_rate */
public float $tax_rate = 0;
/** @var float $reduced_tax_rate */
public float $reduced_tax_rate = 0;
public string $tax_name1 = 'IVA';
}

View File

@ -0,0 +1,44 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\DataMapper\Tax\HR;
use App\DataMapper\Tax\DE\Rule as DERule;
class Rule extends DERule
{
/** @var string $seller_region */
public string $seller_region = 'EU';
/** @var bool $consumer_tax_exempt */
public bool $consumer_tax_exempt = false;
/** @var bool $business_tax_exempt */
public bool $business_tax_exempt = false;
/** @var bool $eu_business_tax_exempt */
public bool $eu_business_tax_exempt = true;
/** @var bool $foreign_business_tax_exempt */
public bool $foreign_business_tax_exempt = false;
/** @var bool $foreign_consumer_tax_exempt */
public bool $foreign_consumer_tax_exempt = false;
/** @var float $tax_rate */
public float $tax_rate = 0;
/** @var float $reduced_tax_rate */
public float $reduced_tax_rate = 0;
public string $tax_name1 = 'PDV';
}

View File

@ -0,0 +1,44 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\DataMapper\Tax\HU;
use App\DataMapper\Tax\DE\Rule as DERule;
class Rule extends DERule
{
/** @var string $seller_region */
public string $seller_region = 'EU';
/** @var bool $consumer_tax_exempt */
public bool $consumer_tax_exempt = false;
/** @var bool $business_tax_exempt */
public bool $business_tax_exempt = false;
/** @var bool $eu_business_tax_exempt */
public bool $eu_business_tax_exempt = true;
/** @var bool $foreign_business_tax_exempt */
public bool $foreign_business_tax_exempt = false;
/** @var bool $foreign_consumer_tax_exempt */
public bool $foreign_consumer_tax_exempt = false;
/** @var float $tax_rate */
public float $tax_rate = 0;
/** @var float $reduced_tax_rate */
public float $reduced_tax_rate = 0;
public string $tax_name1 = 'ÁFA';
}

View File

@ -0,0 +1,44 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\DataMapper\Tax\IE;
use App\DataMapper\Tax\DE\Rule as DERule;
class Rule extends DERule
{
/** @var string $seller_region */
public string $seller_region = 'EU';
/** @var bool $consumer_tax_exempt */
public bool $consumer_tax_exempt = false;
/** @var bool $business_tax_exempt */
public bool $business_tax_exempt = false;
/** @var bool $eu_business_tax_exempt */
public bool $eu_business_tax_exempt = true;
/** @var bool $foreign_business_tax_exempt */
public bool $foreign_business_tax_exempt = false;
/** @var bool $foreign_consumer_tax_exempt */
public bool $foreign_consumer_tax_exempt = false;
/** @var float $tax_rate */
public float $tax_rate = 0;
/** @var float $reduced_tax_rate */
public float $reduced_tax_rate = 0;
public string $tax_name1 = 'VAT';
}

View File

@ -0,0 +1,44 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\DataMapper\Tax\IT;
use App\DataMapper\Tax\DE\Rule as DERule;
class Rule extends DERule
{
/** @var string $seller_region */
public string $seller_region = 'EU';
/** @var bool $consumer_tax_exempt */
public bool $consumer_tax_exempt = false;
/** @var bool $business_tax_exempt */
public bool $business_tax_exempt = false;
/** @var bool $eu_business_tax_exempt */
public bool $eu_business_tax_exempt = true;
/** @var bool $foreign_business_tax_exempt */
public bool $foreign_business_tax_exempt = false;
/** @var bool $foreign_consumer_tax_exempt */
public bool $foreign_consumer_tax_exempt = false;
/** @var float $tax_rate */
public float $tax_rate = 0;
/** @var float $reduced_tax_rate */
public float $reduced_tax_rate = 0;
public string $tax_name1 = 'IVA';
}

View File

@ -0,0 +1,44 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\DataMapper\Tax\LT;
use App\DataMapper\Tax\DE\Rule as DERule;
class Rule extends DERule
{
/** @var string $seller_region */
public string $seller_region = 'EU';
/** @var bool $consumer_tax_exempt */
public bool $consumer_tax_exempt = false;
/** @var bool $business_tax_exempt */
public bool $business_tax_exempt = false;
/** @var bool $eu_business_tax_exempt */
public bool $eu_business_tax_exempt = true;
/** @var bool $foreign_business_tax_exempt */
public bool $foreign_business_tax_exempt = false;
/** @var bool $foreign_consumer_tax_exempt */
public bool $foreign_consumer_tax_exempt = false;
/** @var float $tax_rate */
public float $tax_rate = 0;
/** @var float $reduced_tax_rate */
public float $reduced_tax_rate = 0;
public string $tax_name1 = 'PVM';
}

View File

@ -0,0 +1,44 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\DataMapper\Tax\LU;
use App\DataMapper\Tax\DE\Rule as DERule;
class Rule extends DERule
{
/** @var string $seller_region */
public string $seller_region = 'EU';
/** @var bool $consumer_tax_exempt */
public bool $consumer_tax_exempt = false;
/** @var bool $business_tax_exempt */
public bool $business_tax_exempt = false;
/** @var bool $eu_business_tax_exempt */
public bool $eu_business_tax_exempt = true;
/** @var bool $foreign_business_tax_exempt */
public bool $foreign_business_tax_exempt = false;
/** @var bool $foreign_consumer_tax_exempt */
public bool $foreign_consumer_tax_exempt = false;
/** @var float $tax_rate */
public float $tax_rate = 0;
/** @var float $reduced_tax_rate */
public float $reduced_tax_rate = 0;
public string $tax_name1 = 'TVA';
}

View File

@ -0,0 +1,44 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\DataMapper\Tax\LV;
use App\DataMapper\Tax\DE\Rule as DERule;
class Rule extends DERule
{
/** @var string $seller_region */
public string $seller_region = 'EU';
/** @var bool $consumer_tax_exempt */
public bool $consumer_tax_exempt = false;
/** @var bool $business_tax_exempt */
public bool $business_tax_exempt = false;
/** @var bool $eu_business_tax_exempt */
public bool $eu_business_tax_exempt = true;
/** @var bool $foreign_business_tax_exempt */
public bool $foreign_business_tax_exempt = false;
/** @var bool $foreign_consumer_tax_exempt */
public bool $foreign_consumer_tax_exempt = false;
/** @var float $tax_rate */
public float $tax_rate = 0;
/** @var float $reduced_tax_rate */
public float $reduced_tax_rate = 0;
public string $tax_name1 = 'PVN';
}

View File

@ -0,0 +1,44 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\DataMapper\Tax\MT;
use App\DataMapper\Tax\DE\Rule as DERule;
class Rule extends DERule
{
/** @var string $seller_region */
public string $seller_region = 'EU';
/** @var bool $consumer_tax_exempt */
public bool $consumer_tax_exempt = false;
/** @var bool $business_tax_exempt */
public bool $business_tax_exempt = false;
/** @var bool $eu_business_tax_exempt */
public bool $eu_business_tax_exempt = true;
/** @var bool $foreign_business_tax_exempt */
public bool $foreign_business_tax_exempt = false;
/** @var bool $foreign_consumer_tax_exempt */
public bool $foreign_consumer_tax_exempt = false;
/** @var float $tax_rate */
public float $tax_rate = 0;
/** @var float $reduced_tax_rate */
public float $reduced_tax_rate = 0;
public string $tax_name1 = 'VAT';
}

View File

@ -0,0 +1,44 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\DataMapper\Tax\NL;
use App\DataMapper\Tax\DE\Rule as DERule;
class Rule extends DERule
{
/** @var string $seller_region */
public string $seller_region = 'EU';
/** @var bool $consumer_tax_exempt */
public bool $consumer_tax_exempt = false;
/** @var bool $business_tax_exempt */
public bool $business_tax_exempt = false;
/** @var bool $eu_business_tax_exempt */
public bool $eu_business_tax_exempt = true;
/** @var bool $foreign_business_tax_exempt */
public bool $foreign_business_tax_exempt = false;
/** @var bool $foreign_consumer_tax_exempt */
public bool $foreign_consumer_tax_exempt = false;
/** @var float $tax_rate */
public float $tax_rate = 0;
/** @var float $reduced_tax_rate */
public float $reduced_tax_rate = 0;
public string $tax_name1 = 'BTW';
}

View File

@ -0,0 +1,44 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\DataMapper\Tax\PT;
use App\DataMapper\Tax\DE\Rule as DERule;
class Rule extends DERule
{
/** @var string $seller_region */
public string $seller_region = 'EU';
/** @var bool $consumer_tax_exempt */
public bool $consumer_tax_exempt = false;
/** @var bool $business_tax_exempt */
public bool $business_tax_exempt = false;
/** @var bool $eu_business_tax_exempt */
public bool $eu_business_tax_exempt = true;
/** @var bool $foreign_business_tax_exempt */
public bool $foreign_business_tax_exempt = false;
/** @var bool $foreign_consumer_tax_exempt */
public bool $foreign_consumer_tax_exempt = false;
/** @var float $tax_rate */
public float $tax_rate = 0;
/** @var float $reduced_tax_rate */
public float $reduced_tax_rate = 0;
public string $tax_name1 = 'IVA';
}

View File

@ -0,0 +1,44 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\DataMapper\Tax\RO;
use App\DataMapper\Tax\DE\Rule as DERule;
class Rule extends DERule
{
/** @var string $seller_region */
public string $seller_region = 'EU';
/** @var bool $consumer_tax_exempt */
public bool $consumer_tax_exempt = false;
/** @var bool $business_tax_exempt */
public bool $business_tax_exempt = false;
/** @var bool $eu_business_tax_exempt */
public bool $eu_business_tax_exempt = true;
/** @var bool $foreign_business_tax_exempt */
public bool $foreign_business_tax_exempt = false;
/** @var bool $foreign_consumer_tax_exempt */
public bool $foreign_consumer_tax_exempt = false;
/** @var float $tax_rate */
public float $tax_rate = 0;
/** @var float $reduced_tax_rate */
public float $reduced_tax_rate = 0;
public string $tax_name1 = 'TVA';
}

View File

@ -11,36 +11,29 @@
namespace App\DataMapper\Tax;
use App\Models\Client;
use App\DataMapper\Tax\ZipTax\Response;
interface RuleInterface
{
public function init();
public function tax(mixed $type);
public function tax($item);
public function taxByType($type);
public function taxExempt();
public function taxExempt($item);
public function taxDigital();
public function taxDigital($item);
public function taxService();
public function taxService($item);
public function taxShipping();
public function taxShipping($item);
public function taxPhysical();
public function taxPhysical($item);
public function taxReduced();
public function taxReduced($item);
public function default();
public function default($item);
public function override();
public function setClient(Client $client);
public function setTaxData(Response $tax_data);
public function override($item);
public function calculateRates();
}

View File

@ -0,0 +1,44 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\DataMapper\Tax\SE;
use App\DataMapper\Tax\DE\Rule as DERule;
class Rule extends DERule
{
/** @var string $seller_region */
public string $seller_region = 'EU';
/** @var bool $consumer_tax_exempt */
public bool $consumer_tax_exempt = false;
/** @var bool $business_tax_exempt */
public bool $business_tax_exempt = false;
/** @var bool $eu_business_tax_exempt */
public bool $eu_business_tax_exempt = true;
/** @var bool $foreign_business_tax_exempt */
public bool $foreign_business_tax_exempt = false;
/** @var bool $foreign_consumer_tax_exempt */
public bool $foreign_consumer_tax_exempt = false;
/** @var float $tax_rate */
public float $tax_rate = 0;
/** @var float $reduced_tax_rate */
public float $reduced_tax_rate = 0;
public string $tax_name1 = 'Moms';
}

View File

@ -0,0 +1,44 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\DataMapper\Tax\SI;
use App\DataMapper\Tax\DE\Rule as DERule;
class Rule extends DERule
{
/** @var string $seller_region */
public string $seller_region = 'EU';
/** @var bool $consumer_tax_exempt */
public bool $consumer_tax_exempt = false;
/** @var bool $business_tax_exempt */
public bool $business_tax_exempt = false;
/** @var bool $eu_business_tax_exempt */
public bool $eu_business_tax_exempt = true;
/** @var bool $foreign_business_tax_exempt */
public bool $foreign_business_tax_exempt = false;
/** @var bool $foreign_consumer_tax_exempt */
public bool $foreign_consumer_tax_exempt = false;
/** @var float $tax_rate */
public float $tax_rate = 0;
/** @var float $reduced_tax_rate */
public float $reduced_tax_rate = 0;
public string $tax_name1 = 'DDV';
}

View File

@ -0,0 +1,44 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\DataMapper\Tax\SK;
use App\DataMapper\Tax\DE\Rule as DERule;
class Rule extends DERule
{
/** @var string $seller_region */
public string $seller_region = 'EU';
/** @var bool $consumer_tax_exempt */
public bool $consumer_tax_exempt = false;
/** @var bool $business_tax_exempt */
public bool $business_tax_exempt = false;
/** @var bool $eu_business_tax_exempt */
public bool $eu_business_tax_exempt = true;
/** @var bool $foreign_business_tax_exempt */
public bool $foreign_business_tax_exempt = false;
/** @var bool $foreign_consumer_tax_exempt */
public bool $foreign_consumer_tax_exempt = false;
/** @var float $tax_rate */
public float $tax_rate = 0;
/** @var float $reduced_tax_rate */
public float $reduced_tax_rate = 0;
public string $tax_name1 = 'DPH';
}

View File

@ -13,12 +13,22 @@ namespace App\DataMapper\Tax;
class TaxModel
{
// public string $seller_region = 'US';
/** @var string $seller_subregion */
public string $seller_subregion = 'CA';
/** @var string $version */
public string $version = 'alpha';
/** @var object $regions */
public object $regions;
/**
* __construct
*
* @param TaxModel $model
* @return void
*/
public function __construct(public ?TaxModel $model = null)
{
@ -28,20 +38,64 @@ class TaxModel
$this->regions = $model;
}
public function init()
/**
* Initializes the rules and builds any required data.
*
* @return object
*/
public function init(): object
{
$this->regions = new \stdClass();
$this->regions->US = new \stdClass();
$this->regions->EU = new \stdClass();
$this->usRegion()
->euRegion();
->euRegion()
->auRegion();
return $this->regions;
}
/**
* Builds the model for Australian Taxes
*
* @return self
*/
private function auRegion(): self
{
$this->regions->AU = new \stdClass();
$this->regions->AU->has_sales_above_threshold = false;
$this->regions->AU->tax_all_subregions = false;
$this->regions->AU->tax_threshold = 75000;
$this->auSubRegions();
return $this;
}
/**
* Builds the model for Australian Subregions
*
* @return self
*/
private function auSubRegions(): self
{
$this->regions->AU->subregions = new \stdClass();
$this->regions->AU->subregions->AU = new \stdClass();
$this->regions->AU->subregions->AU->apply_tax = false;
$this->regions->AU->subregions->AU->tax_rate = 10;
$this->regions->AU->subregions->AU->tax_name = 'GST';
return $this;
}
/**
* Builds the model for US Taxes
*
* @return self
*/
private function usRegion(): self
{
$this->regions->US->has_sales_above_threshold = false;
@ -50,263 +104,404 @@ class TaxModel
return $this;
}
/**
* Builds the model for EU Taxes
*
* @return self
*/
private function euRegion(): self
{
$this->regions->EU->has_sales_above_threshold = false;
$this->regions->EU->tax_all_subregions = false;
$this->regions->EU->vat_threshold = 10000;
$this->regions->EU->tax_threshold = 10000;
$this->euSubRegions();
return $this;
}
/**
* Builds the model for US States
*
* @return self
*/
private function usSubRegions(): self
{
$this->regions->US->subregions = new \stdClass();
$this->regions->US->subregions->AL = new \stdClass();
$this->regions->US->subregions->AL->apply_tax = false;
$this->regions->US->subregions->AL->tax_rate = 4;
$this->regions->US->subregions->AL->tax_name = 'Sales Tax';
$this->regions->US->subregions->AK = new \stdClass();
$this->regions->US->subregions->AK->apply_tax = false;
$this->regions->US->subregions->AK->tax_rate = 0;
$this->regions->US->subregions->AK->tax_name = 'Sales Tax';
$this->regions->US->subregions->AZ = new \stdClass();
$this->regions->US->subregions->AZ->apply_tax = false;
$this->regions->US->subregions->AZ->tax_rate = 5.6;
$this->regions->US->subregions->AZ->tax_name = 'Sales Tax';
$this->regions->US->subregions->AR = new \stdClass();
$this->regions->US->subregions->AR->apply_tax = false;
$this->regions->US->subregions->AR->tax_rate = 6.5;
$this->regions->US->subregions->AR->tax_name = 'Sales Tax';
$this->regions->US->subregions->CA = new \stdClass();
$this->regions->US->subregions->CA->apply_tax = false;
$this->regions->US->subregions->CA->tax_rate = 7.25;
$this->regions->US->subregions->CA->tax_name = 'Sales Tax';
$this->regions->US->subregions->CO = new \stdClass();
$this->regions->US->subregions->CO->apply_tax = false;
$this->regions->US->subregions->CO->tax_rate = 2.9;
$this->regions->US->subregions->CO->tax_name = 'Sales Tax';
$this->regions->US->subregions->CT = new \stdClass();
$this->regions->US->subregions->CT->apply_tax = false;
$this->regions->US->subregions->CT->tax_rate = 6.35;
$this->regions->US->subregions->CT->tax_name = 'Sales Tax';
$this->regions->US->subregions->DE = new \stdClass();
$this->regions->US->subregions->DE->apply_tax = false;
$this->regions->US->subregions->DE->tax_rate = 0;
$this->regions->US->subregions->DE->tax_name = 'Sales Tax';
$this->regions->US->subregions->FL = new \stdClass();
$this->regions->US->subregions->FL->apply_tax = false;
$this->regions->US->subregions->FL->tax_rate = 6;
$this->regions->US->subregions->FL->tax_name = 'Sales Tax';
$this->regions->US->subregions->GA = new \stdClass();
$this->regions->US->subregions->GA->apply_tax = false;
$this->regions->US->subregions->GA->tax_rate = 4;
$this->regions->US->subregions->GA->tax_name = 'Sales Tax';
$this->regions->US->subregions->HI = new \stdClass();
$this->regions->US->subregions->HI->apply_tax = false;
$this->regions->US->subregions->HI->tax_rate = 4;
$this->regions->US->subregions->HI->tax_name = 'Sales Tax';
$this->regions->US->subregions->ID = new \stdClass();
$this->regions->US->subregions->ID->apply_tax = false;
$this->regions->US->subregions->ID->tax_rate = 6;
$this->regions->US->subregions->ID->tax_name = 'Sales Tax';
$this->regions->US->subregions->IL = new \stdClass();
$this->regions->US->subregions->IL->apply_tax = false;
$this->regions->US->subregions->IL->tax_rate = 6.25;
$this->regions->US->subregions->IL->tax_name = 'Sales Tax';
$this->regions->US->subregions->IN = new \stdClass();
$this->regions->US->subregions->IN->apply_tax = false;
$this->regions->US->subregions->IN->tax_rate = 7;
$this->regions->US->subregions->IN->tax_name = 'Sales Tax';
$this->regions->US->subregions->IA = new \stdClass();
$this->regions->US->subregions->IA->apply_tax = false;
$this->regions->US->subregions->IA->tax_rate = 6;
$this->regions->US->subregions->IA->tax_name = 'Sales Tax';
$this->regions->US->subregions->KS = new \stdClass();
$this->regions->US->subregions->KS->apply_tax = false;
$this->regions->US->subregions->KS->tax_rate = 6.5;
$this->regions->US->subregions->KS->tax_name = 'Sales Tax';
$this->regions->US->subregions->KY = new \stdClass();
$this->regions->US->subregions->KY->apply_tax = false;
$this->regions->US->subregions->KY->tax_rate = 6;
$this->regions->US->subregions->KY->tax_name = 'Sales Tax';
$this->regions->US->subregions->LA = new \stdClass();
$this->regions->US->subregions->LA->apply_tax = false;
$this->regions->US->subregions->LA->tax_rate = 4.45;
$this->regions->US->subregions->LA->tax_name = 'Sales Tax';
$this->regions->US->subregions->ME = new \stdClass();
$this->regions->US->subregions->ME->apply_tax = false;
$this->regions->US->subregions->ME->tax_rate = 5.5;
$this->regions->US->subregions->ME->tax_name = 'Sales Tax';
$this->regions->US->subregions->MD = new \stdClass();
$this->regions->US->subregions->MD->apply_tax = false;
$this->regions->US->subregions->MD->tax_rate = 6;
$this->regions->US->subregions->MD->tax_name = 'Sales Tax';
$this->regions->US->subregions->MA = new \stdClass();
$this->regions->US->subregions->MA->apply_tax = false;
$this->regions->US->subregions->MA->tax_rate = 6.25;
$this->regions->US->subregions->MA->tax_name = 'Sales Tax';
$this->regions->US->subregions->MI = new \stdClass();
$this->regions->US->subregions->MI->apply_tax = false;
$this->regions->US->subregions->MI->tax_rate = 6;
$this->regions->US->subregions->MI->tax_name = 'Sales Tax';
$this->regions->US->subregions->MN = new \stdClass();
$this->regions->US->subregions->MN->apply_tax = false;
$this->regions->US->subregions->MN->tax_rate = 6.875;
$this->regions->US->subregions->MN->tax_name = 'Sales Tax';
$this->regions->US->subregions->MS = new \stdClass();
$this->regions->US->subregions->MS->apply_tax = false;
$this->regions->US->subregions->MS->tax_rate = 7;
$this->regions->US->subregions->MS->tax_name = 'Sales Tax';
$this->regions->US->subregions->MO = new \stdClass();
$this->regions->US->subregions->MO->apply_tax = false;
$this->regions->US->subregions->MO->tax_rate = 4.225;
$this->regions->US->subregions->MO->tax_name = 'Sales Tax';
$this->regions->US->subregions->MT = new \stdClass();
$this->regions->US->subregions->MT->apply_tax = false;
$this->regions->US->subregions->MT->tax_rate = 0;
$this->regions->US->subregions->MT->tax_name = 'Sales Tax';
$this->regions->US->subregions->NE = new \stdClass();
$this->regions->US->subregions->NE->apply_tax = false;
$this->regions->US->subregions->NE->tax_rate = 5.5;
$this->regions->US->subregions->NE->tax_name = 'Sales Tax';
$this->regions->US->subregions->NV = new \stdClass();
$this->regions->US->subregions->NV->apply_tax = false;
$this->regions->US->subregions->NV->tax_rate = 6.85;
$this->regions->US->subregions->NV->tax_name = 'Sales Tax';
$this->regions->US->subregions->NH = new \stdClass();
$this->regions->US->subregions->NH->apply_tax = false;
$this->regions->US->subregions->NH->tax_rate = 0;
$this->regions->US->subregions->NH->tax_name = 'Sales Tax';
$this->regions->US->subregions->NJ = new \stdClass();
$this->regions->US->subregions->NJ->apply_tax = false;
$this->regions->US->subregions->NJ->tax_rate = 6.625;
$this->regions->US->subregions->NJ->tax_name = 'Sales Tax';
$this->regions->US->subregions->NM = new \stdClass();
$this->regions->US->subregions->NM->apply_tax = false;
$this->regions->US->subregions->NM->tax_rate = 5.125;
$this->regions->US->subregions->NM->tax_name = 'Sales Tax';
$this->regions->US->subregions->NY = new \stdClass();
$this->regions->US->subregions->NY->apply_tax = false;
$this->regions->US->subregions->NY->tax_rate = 4;
$this->regions->US->subregions->NY->tax_name = 'Sales Tax';
$this->regions->US->subregions->NC = new \stdClass();
$this->regions->US->subregions->NC->apply_tax = false;
$this->regions->US->subregions->NC->tax_rate = 4.75;
$this->regions->US->subregions->NC->tax_name = 'Sales Tax';
$this->regions->US->subregions->ND = new \stdClass();
$this->regions->US->subregions->ND->apply_tax = false;
$this->regions->US->subregions->ND->tax_rate = 5;
$this->regions->US->subregions->ND->tax_name = 'Sales Tax';
$this->regions->US->subregions->OH = new \stdClass();
$this->regions->US->subregions->OH->apply_tax = false;
$this->regions->US->subregions->OH->tax_rate = 5.75;
$this->regions->US->subregions->OH->tax_name = 'Sales Tax';
$this->regions->US->subregions->OK = new \stdClass();
$this->regions->US->subregions->OK->apply_tax = false;
$this->regions->US->subregions->OK->tax_rate = 4.5;
$this->regions->US->subregions->OK->tax_name = 'Sales Tax';
$this->regions->US->subregions->OR = new \stdClass();
$this->regions->US->subregions->OR->apply_tax = false;
$this->regions->US->subregions->OR->tax_rate = 0;
$this->regions->US->subregions->OR->tax_name = 'Sales Tax';
$this->regions->US->subregions->PA = new \stdClass();
$this->regions->US->subregions->PA->apply_tax = false;
$this->regions->US->subregions->PA->tax_rate = 6;
$this->regions->US->subregions->PA->tax_name = 'Sales Tax';
$this->regions->US->subregions->RI = new \stdClass();
$this->regions->US->subregions->RI->apply_tax = false;
$this->regions->US->subregions->RI->tax_rate = 7;
$this->regions->US->subregions->RI->tax_name = 'Sales Tax';
$this->regions->US->subregions->SC = new \stdClass();
$this->regions->US->subregions->SC->apply_tax = false;
$this->regions->US->subregions->SC->tax_rate = 6;
$this->regions->US->subregions->SC->tax_name = 'Sales Tax';
$this->regions->US->subregions->SD = new \stdClass();
$this->regions->US->subregions->SD->apply_tax = false;
$this->regions->US->subregions->SD->tax_rate = 4.5;
$this->regions->US->subregions->SD->tax_name = 'Sales Tax';
$this->regions->US->subregions->TN = new \stdClass();
$this->regions->US->subregions->TN->apply_tax = false;
$this->regions->US->subregions->TN->tax_rate = 7;
$this->regions->US->subregions->TN->tax_name = 'Sales Tax';
$this->regions->US->subregions->TX = new \stdClass();
$this->regions->US->subregions->TX->apply_tax = false;
$this->regions->US->subregions->TX->tax_rate = 6.25;
$this->regions->US->subregions->TX->tax_name = 'Sales Tax';
$this->regions->US->subregions->UT = new \stdClass();
$this->regions->US->subregions->UT->apply_tax = false;
$this->regions->US->subregions->UT->tax_rate = 5.95;
$this->regions->US->subregions->UT->tax_name = 'Sales Tax';
$this->regions->US->subregions->VT = new \stdClass();
$this->regions->US->subregions->VT->apply_tax = false;
$this->regions->US->subregions->VT->tax_rate = 6;
$this->regions->US->subregions->VT->tax_name = 'Sales Tax';
$this->regions->US->subregions->VA = new \stdClass();
$this->regions->US->subregions->VA->apply_tax = false;
$this->regions->US->subregions->VA->tax_rate = 5.3;
$this->regions->US->subregions->VA->tax_name = 'Sales Tax';
$this->regions->US->subregions->WA = new \stdClass();
$this->regions->US->subregions->WA->apply_tax = false;
$this->regions->US->subregions->WA->tax_rate = 6.5;
$this->regions->US->subregions->WA->tax_name = 'Sales Tax';
$this->regions->US->subregions->WV = new \stdClass();
$this->regions->US->subregions->WV->apply_tax = false;
$this->regions->US->subregions->WV->tax_rate = 6;
$this->regions->US->subregions->WV->tax_name = 'Sales Tax';
$this->regions->US->subregions->WI = new \stdClass();
$this->regions->US->subregions->WI->apply_tax = false;
$this->regions->US->subregions->WI->tax_rate = 5;
$this->regions->US->subregions->WI->tax_name = 'Sales Tax';
$this->regions->US->subregions->WY = new \stdClass();
$this->regions->US->subregions->WY->apply_tax = false;
$this->regions->US->subregions->WY->tax_rate = 4;
$this->regions->US->subregions->WY->tax_name = 'Sales Tax';
return $this;
}
/**
* Create the EU member countries
*
* @return self
*/
private function euSubRegions(): self
{
$this->regions->EU->subregions = new \stdClass();
$this->regions->EU->subregions->AT = new \stdClass();
$this->regions->EU->subregions->AT->vat_rate = 21;
$this->regions->EU->subregions->AT->reduced_vat_rate = 11;
$this->regions->EU->subregions->AT->tax_rate = 20;
$this->regions->EU->subregions->AT->tax_name = 'USt';
$this->regions->EU->subregions->AT->reduced_tax_rate = 10;
$this->regions->EU->subregions->AT->apply_tax = false;
$this->regions->EU->subregions->BE = new \stdClass();
$this->regions->EU->subregions->BE->vat_rate = 21;
$this->regions->EU->subregions->BE->reduced_vat_rate = 6;
$this->regions->EU->subregions->BE->tax_rate = 21;
$this->regions->EU->subregions->BE->tax_name = 'BTW';
$this->regions->EU->subregions->BE->reduced_tax_rate = 6;
$this->regions->EU->subregions->BE->apply_tax = false;
$this->regions->EU->subregions->BG = new \stdClass();
$this->regions->EU->subregions->BG->vat_rate = 20;
$this->regions->EU->subregions->BG->reduced_vat_rate = 9;
$this->regions->EU->subregions->BG->tax_rate = 20;
$this->regions->EU->subregions->BG->tax_name = 'НДС';
$this->regions->EU->subregions->BG->reduced_tax_rate = 9;
$this->regions->EU->subregions->BG->apply_tax = false;
$this->regions->EU->subregions->CY = new \stdClass();
$this->regions->EU->subregions->CY->vat_rate = 19;
$this->regions->EU->subregions->CY->reduced_vat_rate = 9;
$this->regions->EU->subregions->CY->tax_rate = 19;
$this->regions->EU->subregions->CY->tax_name = 'ΦΠΑ';
$this->regions->EU->subregions->CY->reduced_tax_rate = 9;
$this->regions->EU->subregions->CY->apply_tax = false;
$this->regions->EU->subregions->CZ = new \stdClass();
$this->regions->EU->subregions->CZ->vat_rate = 21;
$this->regions->EU->subregions->CZ->reduced_vat_rate = 15;
$this->regions->EU->subregions->CZ->tax_rate = 21;
$this->regions->EU->subregions->CZ->tax_name = 'DPH';
$this->regions->EU->subregions->CZ->reduced_tax_rate = 15;
$this->regions->EU->subregions->CZ->apply_tax = false;
$this->regions->EU->subregions->DE = new \stdClass();
$this->regions->EU->subregions->DE->vat_rate = 19;
$this->regions->EU->subregions->DE->reduced_vat_rate = 7;
$this->regions->EU->subregions->DE->tax_rate = 19;
$this->regions->EU->subregions->DE->tax_name = 'MwSt';
$this->regions->EU->subregions->DE->reduced_tax_rate = 7;
$this->regions->EU->subregions->DE->apply_tax = false;
$this->regions->EU->subregions->DK = new \stdClass();
$this->regions->EU->subregions->DK->vat_rate = 25;
$this->regions->EU->subregions->DK->reduced_vat_rate = 0;
$this->regions->EU->subregions->DK->tax_rate = 25;
$this->regions->EU->subregions->DK->tax_name = 'Moms';
$this->regions->EU->subregions->DK->reduced_tax_rate = 0;
$this->regions->EU->subregions->DK->apply_tax = false;
$this->regions->EU->subregions->EE = new \stdClass();
$this->regions->EU->subregions->EE->vat_rate = 20;
$this->regions->EU->subregions->EE->reduced_vat_rate = 9;
$this->regions->EU->subregions->EE->tax_rate = 20;
$this->regions->EU->subregions->EE->tax_name = 'KM';
$this->regions->EU->subregions->EE->reduced_tax_rate = 9;
$this->regions->EU->subregions->EE->apply_tax = false;
$this->regions->EU->subregions->ES = new \stdClass();
$this->regions->EU->subregions->ES->vat_rate = 21;
$this->regions->EU->subregions->ES->reduced_vat_rate = 10;
$this->regions->EU->subregions->ES->tax_rate = 21;
$this->regions->EU->subregions->ES->tax_name = 'IVA';
$this->regions->EU->subregions->ES->reduced_tax_rate = 10;
$this->regions->EU->subregions->ES->apply_tax = false;
$this->regions->EU->subregions->FI = new \stdClass();
$this->regions->EU->subregions->FI->vat_rate = 24;
$this->regions->EU->subregions->FI->reduced_vat_rate = 14;
$this->regions->EU->subregions->FI->tax_rate = 24;
$this->regions->EU->subregions->FI->tax_name = 'ALV';
$this->regions->EU->subregions->FI->reduced_tax_rate = 14;
$this->regions->EU->subregions->FI->apply_tax = false;
$this->regions->EU->subregions->FR = new \stdClass();
$this->regions->EU->subregions->FR->vat_rate = 20;
$this->regions->EU->subregions->FR->reduced_vat_rate = 5.5;
$this->regions->EU->subregions->FR->tax_rate = 20;
$this->regions->EU->subregions->FR->tax_name = 'TVA';
$this->regions->EU->subregions->FR->reduced_tax_rate = 5.5;
$this->regions->EU->subregions->FR->apply_tax = false;
// $this->regions->EU->subregions->GB = new \stdClass();
// $this->regions->EU->subregions->GB->vat_rate = 20;
// $this->regions->EU->subregions->GB->reduced_vat_rate = 0;
// $this->regions->EU->subregions->GB->tax_rate = 20;
// $this->regions->EU->subregions->GB->reduced_tax_rate = 0;
// $this->regions->EU->subregions->GB->apply_tax = false;
$this->regions->EU->subregions->GR = new \stdClass();
$this->regions->EU->subregions->GR->vat_rate = 24;
$this->regions->EU->subregions->GR->reduced_vat_rate = 13;
$this->regions->EU->subregions->GR->tax_rate = 24;
$this->regions->EU->subregions->GR->tax_name = 'ΦΠΑ';
$this->regions->EU->subregions->GR->reduced_tax_rate = 13;
$this->regions->EU->subregions->GR->apply_tax = false;
$this->regions->EU->subregions->HR = new \stdClass();
$this->regions->EU->subregions->HR->vat_rate = 25;
$this->regions->EU->subregions->HR->reduced_vat_rate = 5;
$this->regions->EU->subregions->HR->tax_rate = 25;
$this->regions->EU->subregions->HR->tax_name = 'PDV';
$this->regions->EU->subregions->HR->reduced_tax_rate = 5;
$this->regions->EU->subregions->HR->apply_tax = false;
$this->regions->EU->subregions->HU = new \stdClass();
$this->regions->EU->subregions->HU->vat_rate = 27;
$this->regions->EU->subregions->HU->reduced_vat_rate = 5;
$this->regions->EU->subregions->HU->tax_rate = 27;
$this->regions->EU->subregions->HU->tax_name = 'ÁFA';
$this->regions->EU->subregions->HU->reduced_tax_rate = 5;
$this->regions->EU->subregions->HU->apply_tax = false;
$this->regions->EU->subregions->IE = new \stdClass();
$this->regions->EU->subregions->IE->vat_rate = 23;
$this->regions->EU->subregions->IE->reduced_vat_rate = 0;
$this->regions->EU->subregions->IE->tax_rate = 23;
$this->regions->EU->subregions->IE->tax_name = 'VAT';
$this->regions->EU->subregions->IE->reduced_tax_rate = 0;
$this->regions->EU->subregions->IE->apply_tax = false;
$this->regions->EU->subregions->IT = new \stdClass();
$this->regions->EU->subregions->IT->vat_rate = 22;
$this->regions->EU->subregions->IT->reduced_vat_rate = 10;
$this->regions->EU->subregions->IT->tax_rate = 22;
$this->regions->EU->subregions->IT->tax_name = 'IVA';
$this->regions->EU->subregions->IT->reduced_tax_rate = 10;
$this->regions->EU->subregions->IT->apply_tax = false;
$this->regions->EU->subregions->LT = new \stdClass();
$this->regions->EU->subregions->LT->vat_rate = 21;
$this->regions->EU->subregions->LT->reduced_vat_rate = 9;
$this->regions->EU->subregions->LT->tax_rate = 21;
$this->regions->EU->subregions->LT->tax_name = 'PVM';
$this->regions->EU->subregions->LT->reduced_tax_rate = 9;
$this->regions->EU->subregions->LT->apply_tax = false;
$this->regions->EU->subregions->LU = new \stdClass();
$this->regions->EU->subregions->LU->vat_rate = 17;
$this->regions->EU->subregions->LU->reduced_vat_rate = 3;
$this->regions->EU->subregions->LU->tax_rate = 17;
$this->regions->EU->subregions->LU->tax_name = 'TVA';
$this->regions->EU->subregions->LU->reduced_tax_rate = 3;
$this->regions->EU->subregions->LU->apply_tax = false;
$this->regions->EU->subregions->LV = new \stdClass();
$this->regions->EU->subregions->LV->vat_rate = 21;
$this->regions->EU->subregions->LV->reduced_vat_rate = 12;
$this->regions->EU->subregions->LV->tax_rate = 21;
$this->regions->EU->subregions->LV->tax_name = 'PVN';
$this->regions->EU->subregions->LV->reduced_tax_rate = 12;
$this->regions->EU->subregions->LV->apply_tax = false;
$this->regions->EU->subregions->MT = new \stdClass();
$this->regions->EU->subregions->MT->vat_rate = 18;
$this->regions->EU->subregions->MT->reduced_vat_rate = 5;
$this->regions->EU->subregions->MT->tax_rate = 18;
$this->regions->EU->subregions->MT->tax_name = 'VAT';
$this->regions->EU->subregions->MT->reduced_tax_rate = 5;
$this->regions->EU->subregions->MT->apply_tax = false;
$this->regions->EU->subregions->NL = new \stdClass();
$this->regions->EU->subregions->NL->vat_rate = 21;
$this->regions->EU->subregions->NL->reduced_vat_rate = 9;
$this->regions->EU->subregions->NL->tax_rate = 21;
$this->regions->EU->subregions->NL->tax_name = 'BTW';
$this->regions->EU->subregions->NL->reduced_tax_rate = 9;
$this->regions->EU->subregions->NL->apply_tax = false;
$this->regions->EU->subregions->PT = new \stdClass();
$this->regions->EU->subregions->PT->vat_rate = 23;
$this->regions->EU->subregions->PT->reduced_vat_rate = 6;
$this->regions->EU->subregions->PT->tax_rate = 23;
$this->regions->EU->subregions->PT->tax_name = 'IVA';
$this->regions->EU->subregions->PT->reduced_tax_rate = 6;
$this->regions->EU->subregions->PT->apply_tax = false;
$this->regions->EU->subregions->RO = new \stdClass();
$this->regions->EU->subregions->RO->vat_rate = 19;
$this->regions->EU->subregions->RO->reduced_vat_rate = 5;
$this->regions->EU->subregions->RO->tax_rate = 19;
$this->regions->EU->subregions->RO->tax_name = 'TVA';
$this->regions->EU->subregions->RO->reduced_tax_rate = 5;
$this->regions->EU->subregions->RO->apply_tax = false;
$this->regions->EU->subregions->SE = new \stdClass();
$this->regions->EU->subregions->SE->vat_rate = 25;
$this->regions->EU->subregions->SE->reduced_vat_rate = 12;
$this->regions->EU->subregions->SE->tax_rate = 25;
$this->regions->EU->subregions->SE->tax_name = 'Moms';
$this->regions->EU->subregions->SE->reduced_tax_rate = 12;
$this->regions->EU->subregions->SE->apply_tax = false;
$this->regions->EU->subregions->SI = new \stdClass();
$this->regions->EU->subregions->SI->vat_rate = 22;
$this->regions->EU->subregions->SI->reduced_vat_rate = 9.5;
$this->regions->EU->subregions->SI->tax_rate = 22;
$this->regions->EU->subregions->SI->tax_name = 'DDV';
$this->regions->EU->subregions->SI->reduced_tax_rate = 9.5;
$this->regions->EU->subregions->SI->apply_tax = false;
$this->regions->EU->subregions->SK = new \stdClass();
$this->regions->EU->subregions->SK->vat_rate = 20;
$this->regions->EU->subregions->SK->reduced_vat_rate = 10;
$this->regions->EU->subregions->SK->tax_rate = 20;
$this->regions->EU->subregions->SK->tax_name = 'DPH';
$this->regions->EU->subregions->SK->reduced_tax_rate = 10;
$this->regions->EU->subregions->SK->apply_tax = false;
return $this;

View File

@ -11,151 +11,213 @@
namespace App\DataMapper\Tax\US;
use App\Models\Client;
use App\Models\Product;
use App\DataMapper\Tax\BaseRule;
use App\DataMapper\Tax\RuleInterface;
use App\DataMapper\Tax\ZipTax\Response;
use App\Models\Product;
class Rule implements RuleInterface
/**
* The rules apply US => US taxes using the tax calculator.
*
* US => Foreign taxes we check the product types still for exemptions, and we all back to the client country tax rate.
*/
class Rule extends BaseRule implements RuleInterface
{
public string $tax_name1 = '';
public float $tax_rate1 = 0;
public string $tax_name2 = '';
public float $tax_rate2 = 0;
/** @var string $seller_region */
public string $seller_region = 'US';
public string $tax_name3 = '';
public float $tax_rate3 = 0;
/**
* Initializes the rules and builds any required data.
*
* @return self
*/
public function init(): self
{
$this->calculateRates();
return $this;
}
public ?Client $client;
public ?Response $tax_data;
public function __construct()
{
}
public function override()
{
return $this;
}
public function setTaxData(Response $tax_data): self
{
$this->tax_data = $tax_data;
return $this;
}
public function setClient(Client $client):self
{
$this->client = $client;
return $this;
}
public function tax($type): self
/**
* Override tax class, we use this when we do not modify the input taxes
*
* @param mixed $item
* @return self
*/
public function override($item): self
{
if ($this->client->is_tax_exempt) {
return $this->taxExempt();
}
else if($this->client->company->tax_data->regions->US->tax_all){
$this->tax_rate1 = $this->tax_data->taxSales * 100;
$this->tax_name1 = "{$this->tax_data->geoState} Sales Tax";
return $this;
}
if($type)
return $this->taxByType($type);
$this->tax_rate1 = $item->tax_rate1;
$this->tax_name1 = $item->tax_name1;
return $this;
}
public function taxByType($product_tax_type): self
/**
* Sets the correct tax rate based on the product type.
*
* @param mixed $item
* @return self
*/
public function taxByType($item): self
{
if(!$product_tax_type)
return $this;
match($product_tax_type){
Product::PRODUCT_TYPE_EXEMPT => $this->taxExempt(),
Product::PRODUCT_TYPE_DIGITAL => $this->taxDigital(),
Product::PRODUCT_TYPE_SERVICE => $this->taxService(),
Product::PRODUCT_TYPE_SHIPPING => $this->taxShipping(),
Product::PRODUCT_TYPE_PHYSICAL => $this->taxPhysical(),
Product::PRODUCT_TYPE_REDUCED_TAX => $this->taxReduced(),
Product::PRODUCT_TYPE_OVERRIDE_TAX => $this->override(),
default => $this->default(),
match(intval($item->tax_id)) {
Product::PRODUCT_TYPE_EXEMPT => $this->taxExempt($item),
Product::PRODUCT_TYPE_DIGITAL => $this->taxDigital($item),
Product::PRODUCT_TYPE_SERVICE => $this->taxService($item),
Product::PRODUCT_TYPE_SHIPPING => $this->taxShipping($item),
Product::PRODUCT_TYPE_PHYSICAL => $this->taxPhysical($item),
Product::PRODUCT_TYPE_REDUCED_TAX => $this->taxReduced($item),
Product::PRODUCT_TYPE_OVERRIDE_TAX => $this->override($item),
Product::PRODUCT_TYPE_ZERO_RATED => $this->zeroRated($item),
default => $this->default($item),
};
return $this;
}
public function taxExempt(): self
/**
* Sets the tax as exempt (0)
* @param mixed $item
*
* @return self
*/
public function taxExempt($item): self
{
$this->tax_name1 = '';
$this->tax_rate1 = 0;
return $this;
}
public function taxDigital(): self
/**
* Calculates the tax rate for a digital product
* @param mixed $item
*
* @return self
*/
public function taxDigital($item): self
{
$this->default();
$this->default($item);
return $this;
}
public function taxService(): self
/**
* Calculates the tax rate for a service product
* @param mixed $item
*
* @return self
*/
public function taxService($item): self
{
if($this->tax_data->txbService == 'Y')
$this->default();
if(in_array($this->tax_data?->txbService,['Y','L'])) {
$this->default($item);
}
else {
$this->taxExempt($item);
}
return $this;
}
public function taxShipping(): self
/**
* Calculates the tax rate for a shipping product
* @param mixed $item
*
* @return self
*/
public function taxShipping($item): self
{
if($this->tax_data->txbFreight == 'Y')
$this->default();
if($this->tax_data?->txbFreight == 'Y') {
return $this->default($item);
}
$this->tax_rate1 = 0;
$this->tax_name1 = '';
return $this;
}
/**
* Calculates the tax rate for a physical product
* @param mixed $item
*
* @return self
*/
public function taxPhysical($item): self
{
$this->default($item);
return $this;
}
public function taxPhysical(): self
/**
* Calculates the tax rate for an undefined product uses the default tax rate for the client county
*
* @return self
*/
public function default($item): self
{
$this->default();
if($this->tax_data?->stateSalesTax == 0) {
return $this;
}
$this->tax_rate1 = 0;
$this->tax_name1 = '';
return $this;
}
public function default(): self
{
$this->tax_rate1 = $this->tax_data->taxSales * 100;
$this->tax_name1 = "{$this->tax_data->geoState} Sales Tax";
$this->tax_name1 = "Sales Tax";
return $this;
}
public function taxReduced(): self
public function zeroRated($item): self
{
$this->default();
$this->tax_rate1 = 0;
$this->tax_name1 = "{$this->tax_data->geoState} Zero Rated Tax";
return $this;
}
public function init(): self
/**
* Calculates the tax rate for a reduced tax product
*
* @return self
*/
public function taxReduced($item): self
{
$this->default($item);
return $this;
}
/**
* Calculates the tax rate for a reverse tax product
*
* @return self
*/
public function reverseTax($item): self
{
$this->default($item);
return $this;
}
/**
* Calculates the tax rates to be applied
*
* @return self
*/
public function calculateRates(): self
{
return $this;
}
}
}

View File

@ -57,7 +57,7 @@ class Response
* ];
*
*/
public string $seller_region = "";
public string $seller_subregion = "";
//US
public string $geoPostalCode = "";
@ -65,14 +65,17 @@ class Response
public string $geoCounty = "";
public string $geoState = "";
public float $taxSales = 0;
public string $taxName = "";
public float $taxUse = 0;
public string $txbService = ""; // N = No, Y = Yes
public string $txbFreight = ""; // N = No, Y = Yes
public string $txbService = "Y"; // N = No, Y = Yes
public string $txbFreight = "Y"; // N = No, Y = Yes
public float $stateSalesTax = 0;
public float $stateUseTax = 0;
public float $citySalesTax = 0;
public float $cityUseTax = 0;
public string $cityTaxCode = "";
/* US SPECIFIC TAX CODES */
public float $countySalesTax = 0;
public float $countyUseTax = 0;
public string $countyTaxCode = "";
@ -93,13 +96,19 @@ class Response
public string $district5Code = "";
public float $district5SalesTax = 0;
public float $district5UseTax = 0;
public string $originDestination = "";
/* US SPECIFIC TAX CODES */
public function __construct($data)
public string $originDestination = "D"; // defines if the client origin is the locale where the tax is remitted to
public function __construct($data = null)
{
foreach($data as $key => $value){
$this->{$key} = $value;
if($data) {
foreach($data as $key => $value) {
$this->{$key} = $value;
}
}
}

View File

@ -106,9 +106,8 @@ region:
apply_tax: false
EU:
tax_all: false
vat_threshold: 10000
tax_threshold: 10000
has_sales_above_threshold: false
seller_region: DE
subregions:
AT:
vat: 21

View File

@ -0,0 +1,24 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\DataProviders;
class DesignBlocks
{
public function __construct(
public string $includes = '',
public string $header = '',
public string $body = '',
public string $footer = ''
) {
}
}

File diff suppressed because it is too large Load Diff

View File

@ -24,9 +24,6 @@ class AccountCreated
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* @var
*/
public $user;
public $company;
@ -47,13 +44,14 @@ class AccountCreated
$this->event_vars = $event_vars;
}
/**
* Get the channels the event should broadcast on.
*
* @return Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
// /**
// * Get the channels the event should broadcast on.
// *
// * @return Channel|array
// */
public function broadcastOn()
{
return [];
// return new PrivateChannel('channel-name');
}
}

View File

@ -49,13 +49,13 @@ class ClientWasArchived
$this->event_vars = $event_vars;
}
/**
* Get the channels the event should broadcast on.
*
* @return Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
// /**
// * Get the channels the event should broadcast on.
// *
// * @return Channel|array
// */
public function broadcastOn()
{
return [];
}
}

View File

@ -42,8 +42,8 @@ class CompanyDocumentsDeleted
*
* @return Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
public function broadcastOn()
{
return [];
}
}

View File

@ -25,9 +25,6 @@ class ContactLoggedIn
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* @var
*/
public $client_contact;
public $company;
@ -53,8 +50,8 @@ class ContactLoggedIn
*
* @return Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
public function broadcastOn()
{
return [];
}
}

View File

@ -32,7 +32,7 @@ class CreditWasEmailed
/**
* Create a new event instance.
*
* @param Credit $credit
* @param CreditInvitation $invitation
* @param Company $company
* @param array $event_vars
*/

View File

@ -23,7 +23,7 @@ class CreditWasRestored
use SerializesModels;
/**
* @var Client
* @var Credit
*/
public $credit;

View File

@ -26,29 +26,8 @@ class DesignWasArchived
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* @var Design
*/
public $design;
public $company;
public $event_vars;
/**
* Create a new event instance.
*
* @param Design $design
* @param Company $company
* @param array $event_vars
*/
public function __construct(Design $design, Company $company, array $event_vars)
public function __construct(public Design $design, public Company $company, public array $event_vars)
{
$this->design = $design;
$this->company = $company;
$this->event_vars = $event_vars;
}
/**
@ -56,8 +35,8 @@ class DesignWasArchived
*
* @return Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
public function broadcastOn()
{
return [];
}
}

View File

@ -11,9 +11,10 @@
namespace App\Events\Design;
use App\Models\Company;
use App\Models\Design;
use App\Models\Company;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
/**
* Class DesignWasCreated.
@ -22,29 +23,8 @@ class DesignWasCreated
{
use SerializesModels;
/**
* @var Design
*/
public $design;
public $company;
public $event_vars;
/**
* Create a new event instance.
*
* @param Design $design
* @param Company $company
* @param array $event_vars
*/
public function __construct(Design $design, Company $company, array $event_vars)
public function __construct(public Design $design, public Company $company, public array $event_vars)
{
$this->design = $design;
$this->company = $company;
$this->event_vars = $event_vars;
}
/**
@ -52,8 +32,8 @@ class DesignWasCreated
*
* @return PrivateChannel
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
public function broadcastOn()
{
return [];
}
}

View File

@ -11,9 +11,10 @@
namespace App\Events\Design;
use App\Models\Company;
use App\Models\Design;
use App\Models\Company;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
/**
* Class DesignWasDeleted.
@ -22,38 +23,17 @@ class DesignWasDeleted
{
use SerializesModels;
/**
* @var Design
*/
public $design;
public $company;
public $event_vars;
/**
* Create a new event instance.
*
* @param Design $design
* @param Company $company
* @param array $event_vars
*/
public function __construct(Design $design, Company $company, array $event_vars)
public function __construct(public Design $design, public Company $company, public array $event_vars)
{
$this->design = $design;
$this->company = $company;
$this->event_vars = $event_vars;
}
/**
* Get the channels the event should broadcast on.
*
* @return PrivateChannel
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
*/
public function broadcastOn()
{
return [];
}
}

View File

@ -11,9 +11,10 @@
namespace App\Events\Design;
use App\Models\Company;
use App\Models\Design;
use App\Models\Company;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
/**
* Class DesignWasRestored.
@ -22,33 +23,8 @@ class DesignWasRestored
{
use SerializesModels;
/**
* @var Design
*/
public $design;
public $company;
public $event_vars;
public $fromDeleted;
/**
* Create a new event instance.
*
* @param Design $design
* @param Company $company
* @param array $event_vars
*/
public function __construct(Design $design, $fromDeleted, Company $company, array $event_vars)
public function __construct(public Design $design, public bool $fromDeleted, public Company $company, public array $event_vars)
{
$this->design = $design;
$this->fromDeleted = $fromDeleted;
$this->company = $company;
$this->event_vars = $event_vars;
}
/**
@ -56,8 +32,8 @@ class DesignWasRestored
*
* @return PrivateChannel
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
public function broadcastOn()
{
return [];
}
}

View File

@ -11,9 +11,10 @@
namespace App\Events\Design;
use App\Models\Company;
use App\Models\Design;
use App\Models\Company;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
/**
* Class DesignWasUpdated.
@ -22,29 +23,8 @@ class DesignWasUpdated
{
use SerializesModels;
/**
* @var Design
*/
public $design;
public $company;
public $event_vars;
/**
* Create a new event instance.
*
* @param Design $design
* @param Company $company
* @param array $event_vars
*/
public function __construct(Design $design, Company $company, array $event_vars)
public function __construct(public Design $design, public Company $company, public array $event_vars)
{
$this->design = $design;
$this->company = $company;
$this->event_vars = $event_vars;
}
/**
@ -52,8 +32,8 @@ class DesignWasUpdated
*
* @return PrivateChannel
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
public function broadcastOn()
{
return [];
}
}

View File

@ -56,6 +56,6 @@ class DocumentWasArchived
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
return [];
}
}

View File

@ -22,29 +22,7 @@ class InvoiceReminderWasEmailed
{
use SerializesModels;
/**
* @var Invoice
*/
public $invitation;
public $reminder;
public $company;
public $event_vars;
/**
* Create a new event instance.
*
* @param InvoiceInvitation $invitation
* @param Company $company
* @param array $event_vars
*/
public function __construct(InvoiceInvitation $invitation, Company $company, array $event_vars, string $reminder)
public function __construct(public InvoiceInvitation $invitation, public Company $company, public array $event_vars, public string $template)
{
$this->invitation = $invitation;
$this->company = $company;
$this->event_vars = $event_vars;
$this->reminder = $reminder;
}
}

View File

@ -56,17 +56,17 @@ class InvoiceWasCreated implements ShouldBroadcast
*/
public function broadcastOn()
{
return ['simple-channel'];
return [];
}
/**
* Get the data to broadcast.
*
* @return array<string, mixed>
*/
public function broadcastWith(): array
{
return ['id' => 'value'];
}
// /**
// * Get the data to broadcast.
// *
// * @return array<string, mixed>
// */
// public function broadcastWith(): array
// {
// return ['id' => 'value'];
// }
}

View File

@ -23,7 +23,7 @@ class InvoiceWasEmailed
use SerializesModels;
/**
* @var Invoice
* @var InvoiceInvitation
*/
public $invitation;

View File

@ -21,34 +21,7 @@ class InvoiceWasEmailedAndFailed
{
use SerializesModels;
public $invitation;
public $message;
public $company;
public $event_vars;
public $template;
/**
* Create a new event instance.
*
* @param $invitation
* @param Company $company
* @param string $errors
* @param array $event_vars
*/
public function __construct($invitation, Company $company, string $message, string $template, array $event_vars)
public function __construct(public mixed $invitation, public Company $company, public string $message, public string $template, public array $event_vars)
{
$this->invitation = $invitation;
$this->company = $company;
$this->message = $message;
$this->event_vars = $event_vars;
$this->template = $template;
}
}

View File

@ -22,14 +22,6 @@ class InvoiceWasViewed
{
use SerializesModels;
/**
* @var Invoice
*/
public $invitation;
public $company;
public $event_vars;
/**
* Create a new event instance.
@ -38,10 +30,7 @@ class InvoiceWasViewed
* @param Company $company
* @param array $event_vars
*/
public function __construct(InvoiceInvitation $invitation, Company $company, array $event_vars)
public function __construct(public InvoiceInvitation $invitation, public Company $company, public array $event_vars)
{
$this->invitation = $invitation;
$this->company = $company;
$this->event_vars = $event_vars;
}
}

View File

@ -26,7 +26,7 @@ class MethodDeleted
/**
* @var ClientGatewayToken
*/
private $payment_method;
public $payment_method;
public $company;
@ -51,8 +51,8 @@ class MethodDeleted
*
* @return Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
public function broadcastOn()
{
return [];
}
}

View File

@ -13,9 +13,10 @@ namespace App\Events\Payment;
use App\Models\Company;
use App\Models\Payment;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use App\Models\ClientContact;
use Illuminate\Queue\SerializesModels;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
/**
* Class PaymentWasEmailed.
@ -24,26 +25,15 @@ class PaymentWasEmailed
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* @var Payment
*/
public $payment;
public $company;
public $event_vars;
/**
* Create a new event instance.
*
* @param Payment $payment
* @param Company $company
* @param ClientContact $contact
* @param array $event_vars
*/
public function __construct(Payment $payment, Company $company, array $event_vars)
public function __construct(public Payment $payment, public Company $company, public ClientContact $contact, public array $event_vars)
{
$this->payment = $payment;
$this->company = $company;
$this->event_vars = $event_vars;
}
}

View File

@ -19,26 +19,7 @@ class ProductWasArchived
{
use SerializesModels;
/**
* @var Product
*/
public $product;
public $company;
public $event_vars;
/**
* Create a new event instance.
*
* @param Product $product
* @param Company $company
* @param array $event_vars
*/
public function __construct(Product $product, Company $company, array $event_vars)
public function __construct(public Product $product, public Company $company, public array $event_vars)
{
$this->product = $product;
$this->company = $company;
$this->event_vars = $event_vars;
}
}

View File

@ -19,30 +19,7 @@ class ProductWasCreated
{
use SerializesModels;
/**
* @var Product
*/
public $product;
public $input;
public $company;
public $event_vars;
/**
* Create a new event instance.
*
* @param Product $product
* @param $input
* @param Company $company
* @param array $event_vars
*/
public function __construct(Product $product, $input, Company $company, array $event_vars)
public function __construct(public Product $product, public mixed $input, public Company $company, public array $event_vars)
{
$this->product = $product;
$this->input = $input;
$this->company = $company;
$this->event_vars = $event_vars;
}
}

View File

@ -19,26 +19,7 @@ class ProductWasDeleted
{
use SerializesModels;
/**
* @var Product
*/
public $product;
public $company;
public $event_vars;
/**
* Create a new event instance.
*
* @param Product $product
* @param Company $company
* @param array $event_vars
*/
public function __construct(Product $product, Company $company, array $event_vars)
public function __construct(public Product $product, public Company $company, public array $event_vars)
{
$this->product = $product;
$this->company = $company;
$this->event_vars = $event_vars;
}
}

Some files were not shown because too many files have changed in this diff Show More