mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-05-24 02:14:21 -04:00
Merge branch 'v5-develop' of https://github.com/invoiceninja/invoiceninja into v5-develop
This commit is contained in:
commit
9dd6ead39e
3
.env.ci
3
.env.ci
@ -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
|
@ -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=
|
5
.github/ISSUE_TEMPLATE/bug_report.md
vendored
5
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -14,6 +14,11 @@ https://invoiceninja.github.io/docs/self-host-troubleshooting/ -->
|
||||
- Version: <!-- i.e. v4.5.25 / v5.0.30 -->
|
||||
- Environment: <!-- Docker/Shared Hosting/ZIP/Other -->
|
||||
|
||||
## Interface
|
||||
- Flutter: []
|
||||
- React: []
|
||||
- Both: []
|
||||
|
||||
## Checklist
|
||||
- Can you replicate the issue on our v5 demo site https://demo.invoiceninja.com or https://react.invoicing.co/demo?
|
||||
- Have you searched existing issues?
|
||||
|
23
.github/workflows/phpunit.yml
vendored
23
.github/workflows/phpunit.yml
vendored
@ -2,6 +2,7 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- v5-develop
|
||||
- v5-stable
|
||||
pull_request:
|
||||
branches:
|
||||
- v5-develop
|
||||
@ -21,6 +22,7 @@ jobs:
|
||||
dependency-version: [prefer-stable]
|
||||
|
||||
env:
|
||||
DB_CONNECTION: mysql
|
||||
DB_DATABASE1: ninja
|
||||
DB_USERNAME1: root
|
||||
DB_PASSWORD1: ninja
|
||||
@ -42,7 +44,7 @@ jobs:
|
||||
|
||||
services:
|
||||
mariadb:
|
||||
image: mariadb:latest
|
||||
image: mariadb:10.6
|
||||
ports:
|
||||
- 32768:3306
|
||||
env:
|
||||
@ -79,9 +81,9 @@ jobs:
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
extensions: mysql, mysqlnd, sqlite3, bcmath, gmp, gd, curl, zip, openssl, mbstring, xml, redis
|
||||
extensions: mysql, mysqlnd, sqlite3, bcmath, gmp, gd, curl, zip, openssl, mbstring, xml, redis, :psr
|
||||
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: v5-develop
|
||||
fetch-depth: 1
|
||||
@ -94,19 +96,13 @@ jobs:
|
||||
id: composer-cache
|
||||
run: |
|
||||
echo "::set-output name=dir::$(composer config cache-files-dir)"
|
||||
- uses: actions/cache@v2
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
key: ${{ runner.os }}-${{ matrix.php }}-composer-${{ hashFiles('**/composer.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-${{ matrix.php }}-composer-
|
||||
|
||||
# - name: Cache dependencies actions/cache@v3
|
||||
# uses: actions/cache@v3
|
||||
# with:
|
||||
# path: ~/.composer/cache/files
|
||||
# key: dependencies-${{ matrix.dependency-version }}-laravel-${{ matrix.laravel }}-php-${{ matrix.php-versions }}-composer-${{ hashFiles('composer.json') }}
|
||||
|
||||
- name: Install composer dependencies
|
||||
run: |
|
||||
composer config -g github-oauth.github.com ${{ secrets.GITHUB_TOKEN }}
|
||||
@ -117,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
|
||||
|
26
.github/workflows/release.yml
vendored
26
.github/workflows/release.yml
vendored
@ -18,12 +18,12 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v1
|
||||
with:
|
||||
ref: v5-stable
|
||||
|
||||
ref: v5-develop
|
||||
|
||||
- name: Copy .env file
|
||||
run: |
|
||||
cp .env.example .env
|
||||
|
||||
|
||||
- name: Install composer dependencies
|
||||
run: |
|
||||
composer config -g github-oauth.github.com ${{ secrets.GITHUB_TOKEN }}
|
||||
@ -32,9 +32,9 @@ jobs:
|
||||
- name: Prepare Laravel Application
|
||||
run: |
|
||||
cp .env.example .env
|
||||
php artisan key:generate
|
||||
php artisan key:generate --force
|
||||
php artisan optimize
|
||||
php artisan storage:link
|
||||
php artisan storage:link --force
|
||||
sudo php artisan cache:clear
|
||||
sudo find ./vendor/bin/ -type f -exec chmod +x {} \;
|
||||
sudo find ./ -type d -exec chmod 755 {} \;
|
||||
@ -46,7 +46,13 @@ jobs:
|
||||
git checkout main
|
||||
npm i
|
||||
npm run build
|
||||
cp -r dist/react/* ../public/react
|
||||
|
||||
mkdir -p ../public/react/${{ github.event.release.tag_name }}/
|
||||
cp -r dist/react/* ../public/react/${{ github.event.release.tag_name }}/
|
||||
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 +71,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 +81,5 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
files: |
|
||||
invoiceninja.zip
|
||||
/home/runner/work/invoiceninja/invoiceninja.tar
|
||||
/home/runner/work/invoiceninja/invoiceninja.zip
|
8
.gitignore
vendored
8
.gitignore
vendored
@ -5,7 +5,9 @@
|
||||
/storage/*.key
|
||||
/storage/debugbar
|
||||
/storage/*
|
||||
/tests/bootstrap/
|
||||
/vendor
|
||||
/app/Console/Commands/vendor/
|
||||
/.idea
|
||||
/.vscode
|
||||
/.vagrant
|
||||
@ -17,10 +19,12 @@ yarn-error.log
|
||||
local_version.txt
|
||||
.env
|
||||
.phpunit.result.cache
|
||||
_ide_helper.php
|
||||
|
||||
/resources/assets/bower
|
||||
/public/logo
|
||||
.env.dusk.local
|
||||
.env.cypress
|
||||
/public/vendors/*
|
||||
*.log
|
||||
|
||||
@ -32,3 +36,7 @@ nbproject
|
||||
public/test.pdf
|
||||
public/storage/test.pdf
|
||||
/Modules
|
||||
_ide_helper_models.php
|
||||
_ide_helper.php
|
||||
/composer.phar
|
||||
.tx/
|
19
.php_cs
19
.php_cs
@ -1,19 +0,0 @@
|
||||
<?php
|
||||
|
||||
$finder = Symfony\Component\Finder\Finder::create()
|
||||
->notPath('vendor')
|
||||
->notPath('bootstrap')
|
||||
->notPath('storage')
|
||||
->notPath('node_modules')
|
||||
->in(__DIR__)
|
||||
->name('*.php')
|
||||
->notName('*.blade.php');
|
||||
|
||||
return PhpCsFixer\Config::create()
|
||||
->setRules([
|
||||
'@PSR2' => true,
|
||||
'array_syntax' => ['syntax' => 'short'],
|
||||
'ordered_imports' => ['sortAlgorithm' => 'alpha'],
|
||||
'no_unused_imports' => true,
|
||||
])
|
||||
->setFinder($finder);
|
73
README.md
73
README.md
@ -10,9 +10,7 @@
|
||||
|
||||
## [Hosted](https://www.invoiceninja.com) | [Self-Hosted](https://www.invoiceninja.org)
|
||||
|
||||
Join us on [Slack](http://slack.invoiceninja.com), [Discourse](https://forum.invoiceninja.com) -
|
||||
or [StackOverflow](https://stackoverflow.com/tags/invoice-ninja/) if you like,
|
||||
just make sure to add the `invoice-ninja` tag to your question.
|
||||
Join us on [Slack](http://slack.invoiceninja.com), [Discord](https://discord.gg/ZwEdtfCwXA), [Support Forum](https://forum.invoiceninja.com)
|
||||
|
||||
## Introduction
|
||||
|
||||
@ -24,16 +22,16 @@ All Pro and Enterprise features from the hosted app are included in the open cod
|
||||
We offer a $30 per year white-label license to remove the Invoice Ninja branding from client facing parts of the app.
|
||||
|
||||
* [Videos](https://www.youtube.com/@appinvoiceninja)
|
||||
* [API Documentation](https://app.swaggerhub.com/apis/invoiceninja/invoiceninja)
|
||||
* [API Documentation](https://api-docs.invoicing.co/)
|
||||
* [APP Documentation](https://invoiceninja.github.io/)
|
||||
* [Support Forum](https://forum.invoiceninja.com)
|
||||
* [StackOverflow](https://stackoverflow.com/tags/invoice-ninja/)
|
||||
|
||||
## Setup
|
||||
|
||||
### Mobile Apps
|
||||
* [iPhone](https://apps.apple.com/app/id1503970375?platform=iphone)
|
||||
* [Android](https://play.google.com/store/apps/details?id=com.invoiceninja.app)
|
||||
* [F-Droid](https://f-droid.org/en/packages/com.invoiceninja.app)
|
||||
|
||||
### Desktop Apps
|
||||
* [macOS](https://apps.apple.com/app/id1503970375?platform=mac)
|
||||
@ -52,10 +50,9 @@ We offer a $30 per year white-label license to remove the Invoice Ninja branding
|
||||
## Quick Hosting Setup
|
||||
|
||||
```sh
|
||||
git clone https://github.com/invoiceninja/invoiceninja.git
|
||||
git checkout v5-stable
|
||||
git clone --single-branch --branch v5-stable https://github.com/invoiceninja/invoiceninja.git
|
||||
cp .env.example .env
|
||||
composer update
|
||||
composer i -o --no-dev
|
||||
php artisan key:generate
|
||||
```
|
||||
|
||||
@ -85,6 +82,66 @@ http://localhost:8000/client/login - For Client Portal
|
||||
user: user@example.com
|
||||
pass: password
|
||||
```
|
||||
## Developers Guide
|
||||
|
||||
|
||||
### App Design
|
||||
|
||||
The API and client portal have been developed using [Laravel](https://laravel.com) if you wish to contribute to this project familiarity with Laravel is essential.
|
||||
|
||||
When inspecting functionality of the API, the best place to start would be in the routes/api.php file which describes all of the availabe API endpoints. The controller methods then describe all the entry points into each domain of the application, ie InvoiceController / QuoteController
|
||||
|
||||
The average API request follows this path into the application.
|
||||
|
||||
* Middleware processes the request initially inspecting the domain being requested + provides the authentication layer.
|
||||
* The request then passes into a Form Request (Type hinted in the controller methods) which is used to provide authorization and also validation of the request. If successful, the request is then passed into the controller method where it is digested, here is an example:
|
||||
|
||||
```php
|
||||
public function store(StoreInvoiceRequest $request)
|
||||
{
|
||||
|
||||
$invoice = $this->invoice_repo->save($request->all(), InvoiceFactory::create(auth()->user()->company()->id, auth()->user()->id));
|
||||
|
||||
$invoice = $invoice->service()
|
||||
->fillDefaults()
|
||||
->triggeredActions($request)
|
||||
->adjustInventory()
|
||||
->save();
|
||||
|
||||
event(new InvoiceWasCreated($invoice, $invoice->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
|
||||
|
||||
return $this->itemResponse($invoice);
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
Here for example we are storing a new invoice, we pass the validated request along with a factory into the invoice repository where it is processed and saved.
|
||||
|
||||
The returned invoice then passes through its service class (app/Services/Invoice) where various actions are performed.
|
||||
|
||||
A event is then fired which notifies listeners in the application (app/Providers/EventServiceProvider) which perform non blocking sub tasks
|
||||
|
||||
Finally the invoice is transformed (app/Transformers/) and returned as a response via Fractal.
|
||||
|
||||
### Developer environment
|
||||
|
||||
Using the Quick Hosting Setup describe above you can quickly get started building out your development environment. Instead of using
|
||||
|
||||
```
|
||||
composer i -o --no-dev
|
||||
```
|
||||
|
||||
use
|
||||
|
||||
```
|
||||
composer i -o
|
||||
```
|
||||
|
||||
This provides the developer tools including phpunit which allows the test suite to be run.
|
||||
|
||||
If you are considering contributing back to the main repository, please add in any tests for new functionality / modifications. This will greatly increase the chances of your PR being accepted
|
||||
|
||||
Also, if you plan any additions for the main repository, you may want to discuss this with us first on Slack where we can assist with any technical information and provide advice.
|
||||
|
||||
## Credits
|
||||
* [Hillel Coren](https://hillelcoren.com/)
|
||||
|
@ -1 +1 @@
|
||||
5.5.65
|
||||
5.7.59
|
17
_ide_helper_custom.php
Normal file
17
_ide_helper_custom.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Contracts\Mail
|
||||
{
|
||||
class Mailer
|
||||
{
|
||||
public function postmark_config(string $key)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function mailgun_config(string $key)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
27
app/Casts/EncryptedCast.php
Normal file
27
app/Casts/EncryptedCast.php
Normal 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];
|
||||
}
|
||||
}
|
@ -13,12 +13,13 @@ namespace App\Console\Commands;
|
||||
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\Backup;
|
||||
use App\Models\Client;
|
||||
use App\Models\Company;
|
||||
use App\Models\Design;
|
||||
use App\Models\Document;
|
||||
use App\Models\GroupSetting;
|
||||
use App\Utils\Ninja;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use stdClass;
|
||||
|
||||
class BackupUpdate extends Command
|
||||
{
|
||||
@ -55,12 +56,15 @@ 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')) {
|
||||
$this->handleOnDb();
|
||||
} else {
|
||||
|
||||
//multiDB environment, need to
|
||||
foreach (MultiDB::$dbs as $db) {
|
||||
MultiDB::setDB($db);
|
||||
@ -78,50 +82,126 @@ class BackupUpdate extends Command
|
||||
|
||||
//logos
|
||||
Company::cursor()
|
||||
->each(function ($company){
|
||||
->each(function ($company) {
|
||||
$company_logo_path = $company->settings->company_logo;
|
||||
|
||||
$company_logo = $company->present()->logo();
|
||||
if ($company_logo_path == config('ninja.app_logo') || $company_logo_path == '') {
|
||||
return;
|
||||
}
|
||||
|
||||
if($company_logo == 'https://invoicing.co/images/new_logo.png')
|
||||
return;
|
||||
$logo = @file_get_contents($company_logo_path);
|
||||
$extension = @pathinfo($company->settings->company_logo, PATHINFO_EXTENSION);
|
||||
|
||||
if ($logo && $extension) {
|
||||
$path = "{$company->company_key}/{$company->company_key}.{$extension}";
|
||||
|
||||
$logo = @file_get_contents($company_logo);
|
||||
Storage::disk($this->option('disk'))->put($path, $logo);
|
||||
|
||||
if($logo){
|
||||
$url = Storage::disk($this->option('disk'))->url($path);
|
||||
|
||||
$path = str_replace("https://objects.invoicing.co/", "", $company->present()->logo());
|
||||
$path = str_replace("https://v5-at-backup.us-southeast-1.linodeobjects.com/", "", $path);
|
||||
|
||||
Storage::disk($this->option('disk'))->put($path, $logo);
|
||||
}
|
||||
nlog("Company - Moving {$company_logo_path} logo to {$this->option('disk')} final URL = {$url}}");
|
||||
|
||||
$settings = $company->settings;
|
||||
$settings->company_logo = $url;
|
||||
$company->settings = $settings;
|
||||
;
|
||||
$company->save();
|
||||
}
|
||||
});
|
||||
|
||||
Client::withTrashed()
|
||||
->whereNotNull('settings->company_logo')
|
||||
->cursor()
|
||||
->each(function ($client) {
|
||||
$company_logo_path = $client->settings->company_logo;
|
||||
|
||||
$logo = @file_get_contents($company_logo_path);
|
||||
$extension = @pathinfo($company_logo_path, PATHINFO_EXTENSION);
|
||||
|
||||
if ($logo && $extension) {
|
||||
$path = "{$client->company->company_key}/{$client->client_hash}.{$extension}";
|
||||
|
||||
Storage::disk($this->option('disk'))->put($path, $logo);
|
||||
|
||||
$url = Storage::disk($this->option('disk'))->url($path);
|
||||
|
||||
nlog("Client - Moving {$company_logo_path} logo to {$this->option('disk')} final URL = {$url}}");
|
||||
|
||||
$settings = $client->settings;
|
||||
$settings->company_logo = $url;
|
||||
$client->settings = $settings;
|
||||
;
|
||||
$client->saveQuietly();
|
||||
}
|
||||
});
|
||||
|
||||
GroupSetting::withTrashed()
|
||||
->whereNotNull('settings->company_logo')
|
||||
->orWhere('settings->company_logo', '!=', '')
|
||||
->cursor()
|
||||
->each(function ($group) {
|
||||
$company_logo_path = $group->settings->company_logo;
|
||||
|
||||
if (!$company_logo_path) {
|
||||
return;
|
||||
}
|
||||
|
||||
$logo = @file_get_contents($company_logo_path);
|
||||
$extension = @pathinfo($company_logo_path, PATHINFO_EXTENSION);
|
||||
|
||||
if ($logo && $extension) {
|
||||
$path = "{$group->company->company_key}/{$group->hashed_id}.{$extension}";
|
||||
|
||||
Storage::disk($this->option('disk'))->put($path, $logo);
|
||||
|
||||
$url = Storage::disk($this->option('disk'))->url($path);
|
||||
|
||||
nlog("Group - Moving {$company_logo_path} logo to {$this->option('disk')} final URL = {$url}}");
|
||||
|
||||
$settings = $group->settings;
|
||||
$settings->company_logo = $url;
|
||||
$group->settings = $settings;
|
||||
;
|
||||
$group->saveQuietly();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
//documents
|
||||
Document::cursor()
|
||||
->each(function ($document){
|
||||
->each(function (Document $document) {
|
||||
$doc_bin = false;
|
||||
|
||||
$doc_bin = $document->getFile();
|
||||
try {
|
||||
$doc_bin = $document->getFile();
|
||||
} catch(\Exception $e) {
|
||||
nlog($e->getMessage());
|
||||
}
|
||||
|
||||
if($doc_bin)
|
||||
if ($doc_bin) {
|
||||
Storage::disk($this->option('disk'))->put($document->url, $doc_bin);
|
||||
|
||||
$document->disk = $this->option('disk');
|
||||
$document->saveQuietly();
|
||||
|
||||
nlog("Documents - Moving {$document->url} to {$this->option('disk')}");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
//backups
|
||||
Backup::cursor()
|
||||
->each(function ($backup){
|
||||
//backups
|
||||
Backup::whereNotNull('filename')
|
||||
->where('filename', '!=', '')
|
||||
->cursor()
|
||||
->each(function ($backup) {
|
||||
$backup_bin = Storage::disk('s3')->get($backup->filename);
|
||||
|
||||
$backup_bin = Storage::disk('s3')->get($backup->filename);
|
||||
|
||||
if($backup_bin)
|
||||
if ($backup_bin) {
|
||||
Storage::disk($this->option('disk'))->put($backup->filename, $backup_bin);
|
||||
|
||||
nlog("Backups - Moving {$backup->filename} to {$this->option('disk')}");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -11,8 +11,6 @@
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App;
|
||||
use App\Factory\ClientContactFactory;
|
||||
use App\Models\Account;
|
||||
use App\Models\Activity;
|
||||
use App\Models\Backup;
|
||||
@ -24,7 +22,6 @@ use App\Models\CompanyGateway;
|
||||
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\Design;
|
||||
@ -53,13 +50,7 @@ use App\Models\User;
|
||||
use App\Models\Vendor;
|
||||
use App\Models\VendorContact;
|
||||
use App\Models\Webhook;
|
||||
use App\Utils\Ninja;
|
||||
use DB;
|
||||
use Exception;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Str;
|
||||
use Mail;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
/**
|
||||
* Class CheckDb.
|
||||
|
@ -11,41 +11,20 @@
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\DataMapper\ClientRegistrationFields;
|
||||
use App\DataMapper\CompanySettings;
|
||||
use App\DataMapper\FeesAndLimits;
|
||||
use App\Events\Invoice\InvoiceWasCreated;
|
||||
use App\Factory\InvoiceFactory;
|
||||
use App\Factory\InvoiceItemFactory;
|
||||
use App\Helpers\Invoice\InvoiceSum;
|
||||
use App\Jobs\Company\CreateCompanyPaymentTerms;
|
||||
use App\Jobs\Company\CreateCompanyTaskStatuses;
|
||||
use App\Jobs\Util\VersionCheck;
|
||||
use App\Models\Account;
|
||||
use App\Models\Client;
|
||||
use App\Models\ClientContact;
|
||||
use App\Models\Company;
|
||||
use App\Models\CompanyGateway;
|
||||
use App\Models\CompanyToken;
|
||||
use App\Models\Country;
|
||||
use App\Models\Credit;
|
||||
use App\Models\Expense;
|
||||
use App\Models\Product;
|
||||
use App\Models\Project;
|
||||
use App\Models\Quote;
|
||||
use App\Models\Task;
|
||||
use App\Models\User;
|
||||
use App\Models\Vendor;
|
||||
use App\Models\VendorContact;
|
||||
use App\Repositories\InvoiceRepository;
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\Traits\GeneratesCounter;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Carbon\Carbon;
|
||||
use Faker\Factory;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class CreateAccount extends Command
|
||||
@ -62,11 +41,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();
|
||||
@ -88,14 +62,25 @@ class CreateAccount extends Command
|
||||
|
||||
private function createAccount()
|
||||
{
|
||||
$settings = CompanySettings::defaults();
|
||||
|
||||
$settings->name = "Untitled Company";
|
||||
$settings->currency_id = '1';
|
||||
$settings->language_id = '1';
|
||||
|
||||
$account = Account::factory()->create();
|
||||
$company = Company::factory()->create([
|
||||
'account_id' => $account->id,
|
||||
'portal_domain' => config('ninja.app_url'),
|
||||
'portal_mode' => 'domain',
|
||||
'settings' => $settings,
|
||||
]);
|
||||
|
||||
|
||||
$company->client_registration_fields = ClientRegistrationFields::generate();
|
||||
$company->save();
|
||||
|
||||
$account->default_company_id = $company->id;
|
||||
$account->set_react_as_default_ap = true;
|
||||
$account->save();
|
||||
|
||||
$email = $this->option('email') ?? 'admin@example.com';
|
||||
@ -136,7 +121,6 @@ class CreateAccount extends Command
|
||||
(new VersionCheck())->handle();
|
||||
|
||||
$this->warmCache();
|
||||
|
||||
}
|
||||
|
||||
private function warmCache()
|
||||
@ -158,7 +142,6 @@ class CreateAccount extends Command
|
||||
if ($tableData->count()) {
|
||||
Cache::forever($name, $tableData);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -36,11 +36,13 @@ use App\Models\CompanyToken;
|
||||
use App\Models\Country;
|
||||
use App\Models\Credit;
|
||||
use App\Models\Expense;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Product;
|
||||
use App\Models\Project;
|
||||
use App\Models\Quote;
|
||||
use App\Models\RecurringInvoice;
|
||||
use App\Models\Task;
|
||||
use App\Models\TaskStatus;
|
||||
use App\Models\TaxRate;
|
||||
use App\Models\User;
|
||||
use App\Models\Vendor;
|
||||
@ -50,13 +52,11 @@ use App\Utils\Ninja;
|
||||
use App\Utils\Traits\GeneratesCounter;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Carbon\Carbon;
|
||||
use Database\Factories\BankTransactionRuleFactory;
|
||||
use Faker\Factory;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\Str;
|
||||
use stdClass;
|
||||
|
||||
class CreateSingleAccount extends Command
|
||||
@ -73,6 +73,7 @@ class CreateSingleAccount extends Command
|
||||
|
||||
protected $gateway;
|
||||
|
||||
public $faker;
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
@ -80,9 +81,11 @@ class CreateSingleAccount extends Command
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$this->faker = Factory::create();
|
||||
|
||||
if (Ninja::isHosted() || config('ninja.is_docker') || !$this->confirm('Are you sure you want to inject dummy data?'))
|
||||
if (Ninja::isHosted() || config('ninja.is_docker') || !$this->confirm('Are you sure you want to inject dummy data?')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->invoice_repo = new InvoiceRepository();
|
||||
|
||||
@ -103,8 +106,7 @@ class CreateSingleAccount extends Command
|
||||
{
|
||||
$this->info('Creating Small Account and Company');
|
||||
|
||||
if($user = User::where('email','small@example.com')->first())
|
||||
{
|
||||
if ($user = User::where('email', 'small@example.com')->first()) {
|
||||
$user->account->delete();
|
||||
}
|
||||
|
||||
@ -117,12 +119,33 @@ class CreateSingleAccount extends Command
|
||||
'portal_domain' => 'http://ninja.test:8000',
|
||||
'track_inventory' => true
|
||||
]);
|
||||
$faker = \Faker\Factory::create();
|
||||
|
||||
$settings = $company->settings;
|
||||
$settings->invoice_terms = 'Default company invoice terms';
|
||||
$settings->quote_terms = 'Default company quote terms';
|
||||
$settings->invoice_footer = 'Default invoice footer';
|
||||
|
||||
$settings->company_logo = 'https://pdf.invoicing.co/favicon-v2.png';
|
||||
$settings->name = $faker->name();
|
||||
$settings->email = $faker->safeEmail();
|
||||
$settings->phone = $faker->phoneNumber();
|
||||
$settings->website = $faker->url();
|
||||
|
||||
$settings->address1 = $faker->streetName();
|
||||
$settings->address2 = $faker->streetAddress();
|
||||
$settings->city = $faker->city();
|
||||
$settings->state = $faker->state();
|
||||
$settings->postal_code = $faker->postcode();
|
||||
|
||||
$settings->country_id = '840';
|
||||
$settings->vat_number = 'vat number';
|
||||
$settings->id_number = 'id number';
|
||||
$settings->use_credits_payment = 'always';
|
||||
$settings->timezone_id = '1';
|
||||
$settings->entity_send_time = 0;
|
||||
$settings->name = $faker->name();
|
||||
|
||||
$company->settings = $settings;
|
||||
$company->client_registration_fields = ClientRegistrationFields::generate();
|
||||
$company->save();
|
||||
@ -201,7 +224,7 @@ class CreateSingleAccount extends Command
|
||||
$btr = BankTransactionRule::factory()->create([
|
||||
'user_id' => $user->id,
|
||||
'company_id' => $company->id,
|
||||
'applies_to' => (bool)rand(0,1) ? 'CREDIT' : 'DEBIT',
|
||||
'applies_to' => (bool)rand(0, 1) ? 'CREDIT' : 'DEBIT',
|
||||
]);
|
||||
|
||||
$client = Client::factory()->create([
|
||||
@ -285,6 +308,62 @@ class CreateSingleAccount extends Command
|
||||
$this->createGateways($company, $user);
|
||||
|
||||
$this->createSubsData($company, $user);
|
||||
|
||||
|
||||
$repo = new \App\Repositories\TaskRepository();
|
||||
|
||||
Task::query()->cursor()->each(function ($t) use ($repo) {
|
||||
$repo->save([], $t);
|
||||
});
|
||||
|
||||
$repo = new \App\Repositories\ExpenseRepository();
|
||||
|
||||
Expense::query()->cursor()->each(function ($t) use ($repo) {
|
||||
$repo->save([], $t);
|
||||
});
|
||||
|
||||
$repo = new \App\Repositories\VendorRepository(new \App\Repositories\VendorContactRepository());
|
||||
Vendor::query()->cursor()->each(function ($t) use ($repo) {
|
||||
$repo->save([], $t);
|
||||
});
|
||||
|
||||
$repo = new \App\Repositories\ClientRepository(new \App\Repositories\ClientContactRepository());
|
||||
Client::query()->cursor()->each(function ($t) use ($repo) {
|
||||
$repo->save([], $t);
|
||||
});
|
||||
|
||||
$repo = new \App\Repositories\RecurringInvoiceRepository();
|
||||
RecurringInvoice::query()->cursor()->each(function ($t) use ($repo) {
|
||||
$repo->save([], $t);
|
||||
});
|
||||
|
||||
$repo = new \App\Repositories\InvoiceRepository();
|
||||
Invoice::query()->cursor()->each(function ($t) use ($repo) {
|
||||
$repo->save([], $t);
|
||||
});
|
||||
|
||||
$repo = new \App\Repositories\QuoteRepository();
|
||||
Quote::query()->cursor()->each(function ($t) use ($repo) {
|
||||
$repo->save([], $t);
|
||||
});
|
||||
|
||||
$repo = new \App\Repositories\CreditRepository();
|
||||
Credit::query()->cursor()->each(function ($t) use ($repo) {
|
||||
$repo->save([], $t);
|
||||
});
|
||||
|
||||
|
||||
Project::query()->with('client')->whereNotNull('client_id')->cursor()->each(function ($p) {
|
||||
|
||||
if($p && $p->client && !isset($p->number)) {
|
||||
$p->number = $this->getNextProjectNumber($p);
|
||||
$p->save();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
$this->info("finished");
|
||||
|
||||
}
|
||||
|
||||
private function createSubsData($company, $user)
|
||||
@ -359,7 +438,6 @@ class CreateSingleAccount extends Command
|
||||
|
||||
private function createClient($company, $user)
|
||||
{
|
||||
|
||||
// dispatch(function () use ($company, $user) {
|
||||
|
||||
// });
|
||||
@ -386,7 +464,7 @@ class CreateSingleAccount extends Command
|
||||
|
||||
$settings = $client->settings;
|
||||
$settings->currency_id = "1";
|
||||
// $settings->use_credits_payment = "always";
|
||||
// $settings->use_credits_payment = "always";
|
||||
|
||||
$client->settings = $settings;
|
||||
|
||||
@ -429,19 +507,61 @@ class CreateSingleAccount extends Command
|
||||
|
||||
private function createTask($client)
|
||||
{
|
||||
$vendor = Task::factory()->create([
|
||||
$time_log = $this->createTimeLog(rand(1, 20));
|
||||
$status = TaskStatus::where('company_id', $client->company_id)->get()->random();
|
||||
|
||||
return Task::factory()->create([
|
||||
'user_id' => $client->user->id,
|
||||
'company_id' => $client->company->id,
|
||||
'time_log' => $time_log,
|
||||
'description' => $this->faker->paragraph,
|
||||
'status_id' => $status->id ?? null,
|
||||
'number' => rand(10000, 100000000),
|
||||
'rate' => rand(1, 150),
|
||||
'client_id' => $client->id
|
||||
]);
|
||||
}
|
||||
|
||||
private function createTimeLog(int $count)
|
||||
{
|
||||
$time_log = [];
|
||||
|
||||
$min = 0;
|
||||
|
||||
for ($x = 0; $x < $count; $x++) {
|
||||
|
||||
$rando = rand(300, 87000);
|
||||
|
||||
$time_log[] = [
|
||||
Carbon::now()->addSeconds($min)->timestamp,
|
||||
Carbon::now()->addSeconds($min += $rando)->timestamp,
|
||||
$this->faker->sentence,
|
||||
rand(0, 1) === 0 ? false : true
|
||||
];
|
||||
|
||||
$min += 300;
|
||||
}
|
||||
|
||||
return json_encode($time_log);
|
||||
}
|
||||
|
||||
private function createProject($client)
|
||||
{
|
||||
$vendor = Project::factory()->create([
|
||||
$project = Project::factory()->create([
|
||||
'user_id' => $client->user->id,
|
||||
'company_id' => $client->company->id,
|
||||
'client_id' => $client->id,
|
||||
'due_date' => now()->addSeconds(rand(100000, 1000000))->format('Y-m-d'),
|
||||
'budgeted_hours' => rand(100, 1000),
|
||||
'task_rate' => rand(1, 200),
|
||||
]);
|
||||
|
||||
for($x=0; $x < rand(2, 5); $x++) {
|
||||
$task = $this->createTask($client);
|
||||
$task->project_id = $project->id;
|
||||
$task->save();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function createInvoice($client)
|
||||
@ -485,6 +605,7 @@ class CreateSingleAccount extends Command
|
||||
$invoice->amount = 100; // Braintree sandbox only allows payments under 2,000 to complete successfully.
|
||||
}
|
||||
|
||||
/** @var \App\Models\Invoice $invoice */
|
||||
$invoice->save();
|
||||
$invoice->service()->createInvitations()->markSent();
|
||||
|
||||
@ -512,6 +633,7 @@ class CreateSingleAccount extends Command
|
||||
|
||||
$credit = $invoice_calc->getCredit();
|
||||
|
||||
/** @var \App\Models\Credit $credit */
|
||||
$credit->save();
|
||||
$credit->service()->markSent()->save();
|
||||
$credit->service()->createInvitations();
|
||||
@ -554,6 +676,7 @@ class CreateSingleAccount extends Command
|
||||
|
||||
$quote->save();
|
||||
|
||||
/** @var \App\Models\Quote $quote */
|
||||
$quote->service()->markSent()->save();
|
||||
$quote->service()->createInvitations();
|
||||
}
|
||||
@ -630,30 +753,29 @@ class CreateSingleAccount extends Command
|
||||
$cached_tables = config('ninja.cached_tables');
|
||||
|
||||
foreach ($cached_tables as $name => $class) {
|
||||
// check that the table exists in case the migration is pending
|
||||
if (! Schema::hasTable((new $class())->getTable())) {
|
||||
continue;
|
||||
}
|
||||
if ($name == 'payment_terms') {
|
||||
$orderBy = 'num_days';
|
||||
} elseif ($name == 'fonts') {
|
||||
$orderBy = 'sort_order';
|
||||
} elseif (in_array($name, ['currencies', 'industries', 'languages', 'countries', 'banks'])) {
|
||||
$orderBy = 'name';
|
||||
} else {
|
||||
$orderBy = 'id';
|
||||
}
|
||||
$tableData = $class::orderBy($orderBy)->get();
|
||||
if ($tableData->count()) {
|
||||
Cache::forever($name, $tableData);
|
||||
}
|
||||
// check that the table exists in case the migration is pending
|
||||
if (! Schema::hasTable((new $class())->getTable())) {
|
||||
continue;
|
||||
}
|
||||
if ($name == 'payment_terms') {
|
||||
$orderBy = 'num_days';
|
||||
} elseif ($name == 'fonts') {
|
||||
$orderBy = 'sort_order';
|
||||
} elseif (in_array($name, ['currencies', 'industries', 'languages', 'countries', 'banks'])) {
|
||||
$orderBy = 'name';
|
||||
} else {
|
||||
$orderBy = 'id';
|
||||
}
|
||||
$tableData = $class::orderBy($orderBy)->get();
|
||||
if ($tableData->count()) {
|
||||
Cache::forever($name, $tableData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function createGateways($company, $user)
|
||||
{
|
||||
if (config('ninja.testvars.stripe') && ($this->gateway == 'all' || $this->gateway == 'stripe')) {
|
||||
|
||||
$cg = new CompanyGateway;
|
||||
$cg->company_id = $company->id;
|
||||
$cg->user_id = $user->id;
|
||||
@ -672,8 +794,6 @@ class CreateSingleAccount extends Command
|
||||
|
||||
$cg->fees_and_limits = $fees_and_limits;
|
||||
$cg->save();
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (config('ninja.testvars.paypal') && ($this->gateway == 'all' || $this->gateway == 'paypal')) {
|
||||
@ -697,6 +817,29 @@ class CreateSingleAccount extends Command
|
||||
$cg->save();
|
||||
}
|
||||
|
||||
if (config('ninja.testvars.paypal_rest') && ($this->gateway == 'all' || $this->gateway == 'paypal_rest')) {
|
||||
$cg = new CompanyGateway;
|
||||
$cg->company_id = $company->id;
|
||||
$cg->user_id = $user->id;
|
||||
$cg->gateway_key = '80af24a6a691230bbec33e930ab40665';
|
||||
$cg->require_cvv = true;
|
||||
$cg->require_billing_address = true;
|
||||
$cg->require_shipping_address = true;
|
||||
$cg->update_details = true;
|
||||
$cg->config = encrypt(config('ninja.testvars.paypal_rest'));
|
||||
$cg->save();
|
||||
|
||||
// $gateway_types = $cg->driver()->gatewayTypes();
|
||||
|
||||
$fees_and_limits = new stdClass;
|
||||
$fees_and_limits->{3} = new FeesAndLimits;
|
||||
|
||||
$cg->fees_and_limits = $fees_and_limits;
|
||||
$cg->save();
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (config('ninja.testvars.checkout') && ($this->gateway == 'all' || $this->gateway == 'checkout')) {
|
||||
$cg = new CompanyGateway;
|
||||
$cg->company_id = $company->id;
|
||||
@ -848,11 +991,11 @@ class CreateSingleAccount extends Command
|
||||
}
|
||||
}
|
||||
|
||||
private function createRecurringInvoice($client)
|
||||
private function createRecurringInvoice(Client $client)
|
||||
{
|
||||
$faker = Factory::create();
|
||||
|
||||
$invoice = RecurringInvoiceFactory::create($client->company->id, $client->user->id); //stub the company and user_id
|
||||
$invoice = RecurringInvoiceFactory::create($client->company_id, $client->user_id); //stub the company and user_id
|
||||
$invoice->client_id = $client->id;
|
||||
$dateable = Carbon::now()->subDays(rand(0, 90));
|
||||
$invoice->date = $dateable;
|
||||
|
@ -61,6 +61,8 @@ class CreateTestData extends Command
|
||||
|
||||
protected $invoice_repo;
|
||||
|
||||
protected $count;
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
@ -380,7 +382,6 @@ class CreateTestData extends Command
|
||||
|
||||
private function createClient($company, $user)
|
||||
{
|
||||
|
||||
// dispatch(function () use ($company, $user) {
|
||||
|
||||
// });
|
||||
@ -495,7 +496,7 @@ class CreateTestData extends Command
|
||||
|
||||
$invoice = InvoiceFactory::create($client->company->id, $client->user->id); //stub the company and user_id
|
||||
$invoice->client_id = $client->id;
|
||||
// $invoice->date = $faker->date();
|
||||
// $invoice->date = $faker->date();
|
||||
$dateable = Carbon::now()->subDays(rand(0, 90));
|
||||
$invoice->date = $dateable;
|
||||
|
||||
|
@ -188,6 +188,7 @@ class DemoMode extends Command
|
||||
$company_token->account_id = $account->id;
|
||||
$company_token->name = 'test token';
|
||||
$company_token->token = 'TOKEN';
|
||||
$company_token->is_system = true;
|
||||
$company_token->save();
|
||||
|
||||
$u2->companies()->attach($company->id, [
|
||||
@ -257,7 +258,6 @@ class DemoMode extends Command
|
||||
|
||||
private function createClient($company, $user, $assigned_user_id = null)
|
||||
{
|
||||
|
||||
// dispatch(function () use ($company, $user) {
|
||||
|
||||
// });
|
||||
|
@ -56,12 +56,11 @@ class DesignUpdate extends Command
|
||||
if (! config('ninja.db.multi_db_enabled')) {
|
||||
$this->handleOnDb();
|
||||
} else {
|
||||
|
||||
//multiDB environment, need to
|
||||
foreach (MultiDB::$dbs as $db) {
|
||||
MultiDB::setDB($db);
|
||||
|
||||
$this->handleOnDb($db);
|
||||
$this->handleOnDb();
|
||||
}
|
||||
|
||||
MultiDB::setDB($current_db);
|
||||
|
@ -11,27 +11,19 @@
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\DataMapper\CompanySettings;
|
||||
use App\Exceptions\MigrationValidatorFailed;
|
||||
use App\Exceptions\NonExistingMigrationFile;
|
||||
use App\Exceptions\ProcessingMigrationArchiveFailed;
|
||||
use App\Exceptions\ResourceDependencyMissing;
|
||||
use App\Exceptions\ResourceNotAvailableForMigration;
|
||||
use App\Jobs\Util\Import;
|
||||
use App\Jobs\Util\StartMigration;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Mail\MigrationFailed;
|
||||
use App\Models\Account;
|
||||
use App\Models\Company;
|
||||
use App\Models\CompanyToken;
|
||||
use App\Models\User;
|
||||
use App\Utils\Traits\AppSetup;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use DirectoryIterator;
|
||||
use Faker\Factory;
|
||||
use Faker\Generator;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Str;
|
||||
use ZipArchive;
|
||||
|
||||
class HostedMigrations extends Command
|
||||
@ -113,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());
|
||||
|
@ -11,9 +11,7 @@
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\ClientContact;
|
||||
use App\Models\Company;
|
||||
use App\Models\User;
|
||||
use App\Utils\Ninja;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
@ -46,7 +44,6 @@ class HostedUsers extends Command
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
|
@ -18,7 +18,6 @@ use App\Exceptions\ProcessingMigrationArchiveFailed;
|
||||
use App\Exceptions\ResourceDependencyMissing;
|
||||
use App\Exceptions\ResourceNotAvailableForMigration;
|
||||
use App\Jobs\Util\Import;
|
||||
use App\Jobs\Util\StartMigration;
|
||||
use App\Mail\MigrationFailed;
|
||||
use App\Models\Account;
|
||||
use App\Models\Company;
|
||||
@ -64,8 +63,6 @@ class ImportMigrations extends Command
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->faker = Factory::create();
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
@ -76,6 +73,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 +104,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());
|
||||
|
@ -11,8 +11,6 @@
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\Company;
|
||||
use App\Models\User;
|
||||
use App\Utils\CurlUtils;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
@ -63,12 +61,14 @@ class MobileLocalization extends Command
|
||||
|
||||
private function laravelResources()
|
||||
{
|
||||
$resources = $this->getResources();
|
||||
$resources =(array)$this->getResources();
|
||||
|
||||
foreach ($resources as $key => $val) {
|
||||
$transKey = "texts.{$key}";
|
||||
if (trans($transKey) == $transKey) {
|
||||
echo "'$key' => '$val',\n";
|
||||
if(is_iterable($resources)) {
|
||||
foreach ($resources as $key => $val) {
|
||||
$transKey = "texts.{$key}";
|
||||
if (trans($transKey) == $transKey) {
|
||||
echo "'$key' => '$val',\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
118
app/Console/Commands/OpenApiYaml.php
Normal file
118
app/Console/Commands/OpenApiYaml.php
Normal file
@ -0,0 +1,118 @@
|
||||
<?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\Console\Commands;
|
||||
|
||||
use DirectoryIterator;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class OpenApiYaml extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'ninja:openapi';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Build OpenApi YAML';
|
||||
|
||||
private array $directories = [
|
||||
'/components/schemas',
|
||||
'/paths/'
|
||||
];
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$path = base_path('openapi');
|
||||
|
||||
$directory = new DirectoryIterator($path);
|
||||
|
||||
$this->info($directory);
|
||||
|
||||
foreach ($directory as $file) {
|
||||
$this->info($file);
|
||||
}
|
||||
|
||||
Storage::disk('base')->delete('/openapi/api-docs.yaml');
|
||||
Storage::disk('base')->append('/openapi/api-docs.yaml', file_get_contents($path.'/info.yaml'));
|
||||
Storage::disk('base')->append('/openapi/api-docs.yaml', file_get_contents($path.'/paths.yaml'));
|
||||
|
||||
//iterate paths
|
||||
$directory = new DirectoryIterator($path . '/paths/');
|
||||
|
||||
foreach ($directory as $file) {
|
||||
if ($file->isFile() && ! $file->isDot()) {
|
||||
Storage::disk('base')->append('/openapi/api-docs.yaml', file_get_contents("{$path}/paths/{$file->getFilename()}"));
|
||||
}
|
||||
}
|
||||
|
||||
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/');
|
||||
|
||||
foreach ($directory as $file) {
|
||||
if ($file->isFile() && ! $file->isDot()) {
|
||||
Storage::disk('base')->append('/openapi/api-docs.yaml', file_get_contents("{$path}/components/responses/{$file->getFilename()}"));
|
||||
}
|
||||
}
|
||||
|
||||
Storage::disk('base')->append('/openapi/api-docs.yaml', file_get_contents($path.'/components/parameters.yaml'));
|
||||
|
||||
$directory = new DirectoryIterator($path . '/components/parameters/');
|
||||
|
||||
foreach ($directory as $file) {
|
||||
if ($file->isFile() && ! $file->isDot()) {
|
||||
Storage::disk('base')->append('/openapi/api-docs.yaml', file_get_contents("{$path}/components/parameters/{$file->getFilename()}"));
|
||||
}
|
||||
}
|
||||
|
||||
Storage::disk('base')->append('/openapi/api-docs.yaml', file_get_contents($path.'/components/schemas.yaml'));
|
||||
|
||||
//iterate schemas
|
||||
|
||||
$directory = new DirectoryIterator($path . '/components/schemas/');
|
||||
|
||||
foreach ($directory as $file) {
|
||||
if ($file->isFile() && ! $file->isDot()) {
|
||||
Storage::disk('base')->append('/openapi/api-docs.yaml', file_get_contents("{$path}/components/schemas/{$file->getFilename()}"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Storage::disk('base')->append('/openapi/api-docs.yaml', file_get_contents($path.'/components/schemas/account.yaml'));
|
||||
Storage::disk('base')->append('/openapi/api-docs.yaml', file_get_contents($path.'/misc/misc.yaml'));
|
||||
}
|
||||
}
|
@ -12,7 +12,6 @@
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Jobs\Util\VersionCheck;
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\Traits\AppSetup;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
@ -63,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');
|
||||
|
@ -11,12 +11,7 @@
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\Backup;
|
||||
use App\Models\Design;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use stdClass;
|
||||
|
||||
class ReactBuilder extends Command
|
||||
{
|
||||
@ -53,19 +48,26 @@ class ReactBuilder extends Command
|
||||
{
|
||||
$includes = '';
|
||||
|
||||
$directoryIterator = new \RecursiveDirectoryIterator(public_path('react'), \RecursiveDirectoryIterator::SKIP_DOTS);
|
||||
$directoryIterator = false;
|
||||
|
||||
try {
|
||||
$directoryIterator = new \RecursiveDirectoryIterator(public_path('react/v'.config('ninja.app_version').'/'), \RecursiveDirectoryIterator::SKIP_DOTS);
|
||||
} catch (\Exception $e) {
|
||||
$this->error('React files not found');
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (new \RecursiveIteratorIterator($directoryIterator) as $file) {
|
||||
if (str_contains($file->getFileName(), '.js') && !strpos($file->getFileName(), '.json')) {
|
||||
if (str_contains($file->getFileName(), 'index.')) {
|
||||
$includes .= '<script type="module" crossorigin src="/react/'.$file->getFileName().'"></script>'."\n";
|
||||
if ($file->getExtension() == 'js') {
|
||||
if (str_contains($file->getFileName(), 'index-')) {
|
||||
$includes .= '<script type="module" crossorigin src="/react/v'.config('ninja.app_version').'/'.$file->getFileName().'"></script>'."\n";
|
||||
} else {
|
||||
$includes .= '<link rel="modulepreload" href="/react/'.$file->getFileName().'">'."\n";
|
||||
$includes .= '<link rel="modulepreload" href="/react/v'.config('ninja.app_version').'/'.$file->getFileName().'">'."\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (str_contains($file->getFileName(), '.css')) {
|
||||
$includes .= '<link rel="stylesheet" href="/react/'.$file->getFileName().'">'."\n";
|
||||
$includes .= '<link rel="stylesheet" href="/react/v'.config('ninja.app_version').'/'.$file->getFileName().'">'."\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,6 @@ class S3Cleanup extends Command
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
|
@ -14,7 +14,6 @@ namespace App\Console\Commands;
|
||||
use App\DataMapper\InvoiceItem;
|
||||
use App\Events\Invoice\InvoiceWasEmailed;
|
||||
use App\Jobs\Entity\EmailEntity;
|
||||
use App\Jobs\Ninja\SendReminders;
|
||||
use App\Jobs\Util\WebhookHandler;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\Invoice;
|
||||
@ -58,7 +57,6 @@ class SendRemindersCron extends Command
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
@ -97,7 +95,6 @@ class SendRemindersCron extends Command
|
||||
$invoice->save();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private function calcLateFee($invoice, $template) :Invoice
|
||||
@ -175,15 +172,13 @@ class SendRemindersCron extends Command
|
||||
|
||||
/**Refresh Invoice values*/
|
||||
$invoice->calc()->getInvoice()->save();
|
||||
$invoice->fresh();
|
||||
$invoice->service()->deletePdf()->save();
|
||||
$invoice = $invoice->fresh();
|
||||
|
||||
/* Refresh the client here to ensure the balance is fresh */
|
||||
$client = $invoice->client;
|
||||
$client = $client->fresh();
|
||||
|
||||
nlog('adjusting client balance and invoice balance by '.($invoice->balance - $temp_invoice_balance));
|
||||
$client->service()->updateBalance($invoice->balance - $temp_invoice_balance)->save();
|
||||
$client->service()->calculateBalance();
|
||||
$invoice->ledger()->updateInvoiceBalance($invoice->balance - $temp_invoice_balance, "Late Fee Adjustment for invoice {$invoice->number}");
|
||||
|
||||
return $invoice;
|
||||
|
@ -11,22 +11,9 @@
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\DataMapper\CompanySettings;
|
||||
use App\DataMapper\DefaultSettings;
|
||||
use App\Factory\ClientFactory;
|
||||
use App\Factory\InvoiceFactory;
|
||||
use App\Factory\InvoiceInvitationFactory;
|
||||
use App\Jobs\Invoice\CreateEntityPdf;
|
||||
use App\Jobs\Mail\NinjaMailerJob;
|
||||
use App\Jobs\Mail\NinjaMailerObject;
|
||||
use App\Mail\Migration\MaxCompanies;
|
||||
use App\Mail\TemplateEmail;
|
||||
use App\Models\Account;
|
||||
use App\Models\Client;
|
||||
use App\Models\ClientContact;
|
||||
use App\Models\Company;
|
||||
use App\Mail\TestMailServer;
|
||||
use App\Models\User;
|
||||
use Faker\Factory;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
@ -63,39 +50,26 @@ class SendTestEmails extends Command
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$faker = Factory::create();
|
||||
|
||||
$account = Account::factory()->create();
|
||||
|
||||
$user = User::factory()->create([
|
||||
'account_id' => $account->id,
|
||||
'confirmation_code' => '123',
|
||||
'email' => $faker->safeEmail(),
|
||||
'first_name' => 'John',
|
||||
'last_name' => 'Doe',
|
||||
]);
|
||||
|
||||
$company = Company::factory()->create([
|
||||
'account_id' => $account->id,
|
||||
]);
|
||||
|
||||
$user->companies()->attach($company->id, [
|
||||
'account_id' => $account->id,
|
||||
'is_owner' => 1,
|
||||
'is_admin' => 1,
|
||||
'is_locked' => 0,
|
||||
'permissions' => '',
|
||||
'notifications' => CompanySettings::notificationDefaults(),
|
||||
//'settings' => DefaultSettings::userSettings(),
|
||||
'settings' => null,
|
||||
]);
|
||||
$to_user = User::first();
|
||||
|
||||
$nmo = new NinjaMailerObject;
|
||||
$nmo->mailable = new MaxCompanies($user->account->companies()->first());
|
||||
$nmo->company = $user->account->companies()->first();
|
||||
$nmo->settings = $user->account->companies()->first()->settings;
|
||||
$nmo->to_user = $user;
|
||||
$nmo->mailable = new TestMailServer('Email Server Works!', config('mail.from.address'));
|
||||
$nmo->company = $to_user->account->companies()->first();
|
||||
$nmo->settings = $to_user->account->companies()->first()->settings;
|
||||
$nmo->to_user = $to_user;
|
||||
|
||||
(new NinjaMailerJob($nmo))->handle();
|
||||
try {
|
||||
|
||||
Mail::raw("Test Message", function ($message) {
|
||||
$message->to(config('mail.from.address'))
|
||||
->from(config('mail.from.address'), config('mail.from.name'))
|
||||
->subject('Test Email');
|
||||
});
|
||||
|
||||
|
||||
} catch(\Exception $e) {
|
||||
$this->info("Error sending email: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,14 +11,10 @@
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\Backup;
|
||||
use App\Models\Design;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Lang;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use stdClass;
|
||||
|
||||
class TranslationsExport extends Command
|
||||
{
|
||||
@ -55,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',
|
||||
@ -98,42 +97,35 @@ class TranslationsExport extends Command
|
||||
{
|
||||
$type =$this->option('type') ?? 'export';
|
||||
|
||||
if($type == 'import')
|
||||
if ($type == 'import') {
|
||||
$this->import();
|
||||
}
|
||||
|
||||
if($type == 'export')
|
||||
if ($type == 'export') {
|
||||
$this->export();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private function import()
|
||||
{
|
||||
//loop and
|
||||
|
||||
foreach($this->langs as $lang)
|
||||
{
|
||||
|
||||
foreach ($this->langs as $lang) {
|
||||
$import_file = "textsphp_{$lang}.php";
|
||||
$dir = $this->option('path') ?? storage_path('lang_import/');
|
||||
$path = $dir.$import_file;
|
||||
|
||||
if(file_exists($path)){
|
||||
if (file_exists($path)) {
|
||||
$this->logMessage($path);
|
||||
|
||||
$trans = file_get_contents($path);
|
||||
|
||||
file_put_contents(lang_path("/{$lang}/texts.php"), $trans);
|
||||
|
||||
}
|
||||
else{
|
||||
|
||||
} else {
|
||||
$this->logMessage("Could not open file");
|
||||
$this->logMessage($path);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -145,9 +137,8 @@ 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function logMessage($str)
|
||||
@ -156,5 +147,4 @@ class TranslationsExport extends Command
|
||||
$this->info($str);
|
||||
$this->log .= $str."\n";
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -11,17 +11,11 @@
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Http\ValidationRules\ValidClientGroupSettingsRule;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\Backup;
|
||||
use App\Models\Client;
|
||||
use App\Models\Company;
|
||||
use App\Models\Design;
|
||||
use App\Utils\Traits\ClientGroupSettingsSaver;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use stdClass;
|
||||
|
||||
class TypeCheck extends Command
|
||||
{
|
||||
@ -128,7 +122,7 @@ class TypeCheck extends Command
|
||||
$client->save();
|
||||
});
|
||||
|
||||
Company::cursor()->each(function ($company) {
|
||||
Company::query()->cursor()->each(function ($company) {
|
||||
$this->logMessage("Checking company {$company->id}");
|
||||
$company->saveSettings($company->settings, $company);
|
||||
});
|
||||
|
@ -15,20 +15,20 @@ use App\Jobs\Cron\AutoBillCron;
|
||||
use App\Jobs\Cron\RecurringExpensesCron;
|
||||
use App\Jobs\Cron\RecurringInvoicesCron;
|
||||
use App\Jobs\Cron\SubscriptionCron;
|
||||
use App\Jobs\Ledger\LedgerBalanceUpdate;
|
||||
use App\Jobs\Cron\UpdateCalculatedFields;
|
||||
use App\Jobs\Invoice\InvoiceCheckLateWebhook;
|
||||
use App\Jobs\Ninja\AdjustEmailQuota;
|
||||
use App\Jobs\Ninja\BankTransactionSync;
|
||||
use App\Jobs\Ninja\CheckACHStatus;
|
||||
use App\Jobs\Ninja\CompanySizeCheck;
|
||||
use App\Jobs\Ninja\QueueSize;
|
||||
use App\Jobs\Ninja\SystemMaintenance;
|
||||
use App\Jobs\Ninja\TaskScheduler;
|
||||
use App\Jobs\Invoice\InvoiceCheckLateWebhook;
|
||||
use App\Jobs\Quote\QuoteCheckExpired;
|
||||
use App\Jobs\Subscription\CleanStaleInvoiceOrder;
|
||||
use App\Jobs\Util\DiskCleanup;
|
||||
use App\Jobs\Util\ReminderJob;
|
||||
use App\Jobs\Util\SchedulerCheck;
|
||||
use App\Jobs\Util\SendFailedEmails;
|
||||
use App\Jobs\Util\UpdateExchangeRates;
|
||||
use App\Jobs\Util\VersionCheck;
|
||||
use App\Models\Account;
|
||||
@ -49,14 +49,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();
|
||||
@ -67,67 +76,54 @@ 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 () {
|
||||
Account::whereNotNull('id')->update(['is_scheduler_running' => true]);
|
||||
})->everyFiveMinutes();
|
||||
|
||||
}
|
||||
|
||||
/* Run hosted specific jobs */
|
||||
if (Ninja::isHosted()) {
|
||||
|
||||
$schedule->job(new AdjustEmailQuota)->dailyAt('23:30')->withoutOverlapping();
|
||||
|
||||
/* Pulls in bank transactions from third party services */
|
||||
$schedule->job(new BankTransactionSync)->dailyAt('04:10')->withoutOverlapping()->name('bank-trans-sync-job')->onOneServer();
|
||||
$schedule->job(new BankTransactionSync)->everyFourHours()->withoutOverlapping()->name('bank-trans-sync-job')->onOneServer();
|
||||
|
||||
//not used @deprecate
|
||||
// $schedule->job(new SendFailedEmails)->daily()->withoutOverlapping();
|
||||
/* Checks ACH verification status and updates state to authorize when verified */
|
||||
$schedule->job(new CheckACHStatus)->everySixHours()->withoutOverlapping()->name('ach-status-job')->onOneServer();
|
||||
|
||||
$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();
|
||||
|
||||
$schedule->command('ninja:s3-cleanup')->dailyAt('23:15')->withoutOverlapping()->name('s3-cleanup-job')->onOneServer();
|
||||
|
||||
}
|
||||
|
||||
if (config('queue.default') == 'database' && Ninja::isSelfHost() && config('ninja.internal_queue_enabled') && ! config('ninja.is_docker')) {
|
||||
|
||||
$schedule->command('queue:work database --stop-when-empty --memory=256')->everyMinute()->withoutOverlapping();
|
||||
|
||||
$schedule->command('queue:restart')->everyFiveMinutes()->withoutOverlapping();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,6 @@ class AccountCreated extends GenericCounter
|
||||
*
|
||||
* date("Y-m-d H:i:s")
|
||||
*
|
||||
* @var DateTime
|
||||
*/
|
||||
public $datetime;
|
||||
|
||||
|
@ -37,7 +37,6 @@ class AccountDeleted extends GenericCounter
|
||||
*
|
||||
* date("Y-m-d H:i:s")
|
||||
*
|
||||
* @var DateTime
|
||||
*/
|
||||
public $datetime;
|
||||
|
||||
|
@ -37,7 +37,6 @@ class AccountPlatform extends GenericMixedMetric
|
||||
*
|
||||
* date("Y-m-d H:i:s")
|
||||
*
|
||||
* @var DateTime
|
||||
*/
|
||||
public $datetime;
|
||||
|
||||
|
@ -37,7 +37,6 @@ class AccountSignup extends GenericMixedMetric
|
||||
*
|
||||
* date("Y-m-d H:i:s")
|
||||
*
|
||||
* @var DateTime
|
||||
*/
|
||||
public $datetime;
|
||||
|
||||
@ -61,7 +60,7 @@ class AccountSignup extends GenericMixedMetric
|
||||
* The counter
|
||||
* set to 1.
|
||||
*
|
||||
* @var string
|
||||
* @var int
|
||||
*/
|
||||
public $int_metric1 = 1;
|
||||
|
||||
|
@ -37,7 +37,6 @@ class BankAccountsCreated extends GenericMixedMetric
|
||||
*
|
||||
* date("Y-m-d H:i:s")
|
||||
*
|
||||
* @var DateTime
|
||||
*/
|
||||
public $datetime;
|
||||
|
||||
|
@ -37,7 +37,6 @@ class DbQuery extends GenericMixedMetric
|
||||
*
|
||||
* date("Y-m-d H:i:s")
|
||||
*
|
||||
* @var DateTime
|
||||
*/
|
||||
public $datetime;
|
||||
|
||||
@ -57,7 +56,7 @@ class DbQuery extends GenericMixedMetric
|
||||
* The counter
|
||||
* set to 1.
|
||||
*
|
||||
* @var string
|
||||
* @var int
|
||||
*/
|
||||
public $int_metric1 = 1;
|
||||
|
||||
|
@ -37,7 +37,6 @@ class EmailCount extends GenericMixedMetric
|
||||
*
|
||||
* date("Y-m-d H:i:s")
|
||||
*
|
||||
* @var DateTime
|
||||
*/
|
||||
public $datetime;
|
||||
|
||||
|
@ -37,7 +37,6 @@ class EmailFailure extends GenericMixedMetric
|
||||
*
|
||||
* date("Y-m-d H:i:s")
|
||||
*
|
||||
* @var DateTime
|
||||
*/
|
||||
public $datetime;
|
||||
|
||||
@ -61,7 +60,6 @@ class EmailFailure extends GenericMixedMetric
|
||||
* The counter
|
||||
* set to 1.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $int_metric1 = 1;
|
||||
|
||||
|
@ -37,7 +37,6 @@ class EmailInvoiceFailure extends GenericMixedMetric
|
||||
*
|
||||
* date("Y-m-d H:i:s")
|
||||
*
|
||||
* @var DateTime
|
||||
*/
|
||||
public $datetime;
|
||||
|
||||
|
@ -37,7 +37,6 @@ class EmailSuccess extends GenericMixedMetric
|
||||
*
|
||||
* date("Y-m-d H:i:s")
|
||||
*
|
||||
* @var DateTime
|
||||
*/
|
||||
public $datetime;
|
||||
|
||||
@ -61,7 +60,6 @@ class EmailSuccess extends GenericMixedMetric
|
||||
* The counter
|
||||
* set to 1.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $int_metric1 = 1;
|
||||
|
||||
@ -71,8 +69,15 @@ class EmailSuccess extends GenericMixedMetric
|
||||
*/
|
||||
public $string_metric7 = '';
|
||||
|
||||
public function __construct($string_metric7)
|
||||
/**
|
||||
* Subject
|
||||
* @var string
|
||||
*/
|
||||
public $string_metric8 = '';
|
||||
|
||||
public function __construct($string_metric7 = '', $string_metric8 = '')
|
||||
{
|
||||
$this->string_metric7 = $string_metric7;
|
||||
$this->string_metric8 = $string_metric8;
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,6 @@ class LivePreview extends GenericCounter
|
||||
*
|
||||
* date("Y-m-d H:i:s")
|
||||
*
|
||||
* @var DateTime
|
||||
*/
|
||||
public $datetime;
|
||||
|
||||
|
@ -37,7 +37,6 @@ class LoginFailure extends GenericCounter
|
||||
*
|
||||
* date("Y-m-d H:i:s")
|
||||
*
|
||||
* @var DateTime
|
||||
*/
|
||||
public $datetime;
|
||||
|
||||
|
@ -37,7 +37,6 @@ class LoginSuccess extends GenericCounter
|
||||
*
|
||||
* date("Y-m-d H:i:s")
|
||||
*
|
||||
* @var DateTime
|
||||
*/
|
||||
public $datetime;
|
||||
|
||||
|
@ -37,7 +37,6 @@ class EmailBounce extends GenericMixedMetric
|
||||
*
|
||||
* date("Y-m-d H:i:s")
|
||||
*
|
||||
* @var DateTime
|
||||
*/
|
||||
public $datetime;
|
||||
|
||||
@ -67,7 +66,6 @@ class EmailBounce extends GenericMixedMetric
|
||||
* The counter
|
||||
* set to 1.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $int_metric1 = 1;
|
||||
|
||||
|
@ -37,7 +37,7 @@ class EmailSpam extends GenericMixedMetric
|
||||
*
|
||||
* date("Y-m-d H:i:s")
|
||||
*
|
||||
* @var DateTime
|
||||
* @var \DateTime
|
||||
*/
|
||||
public $datetime;
|
||||
|
||||
|
@ -37,7 +37,7 @@ class MigrationFailure extends GenericMixedMetric
|
||||
*
|
||||
* date("Y-m-d H:i:s")
|
||||
*
|
||||
* @var DateTime
|
||||
* @var \DateTime
|
||||
*/
|
||||
public $datetime;
|
||||
|
||||
|
@ -37,7 +37,7 @@ class QueueSize extends GenericMixedMetric
|
||||
*
|
||||
* date("Y-m-d H:i:s")
|
||||
*
|
||||
* @var DateTime
|
||||
* @var \DateTime
|
||||
*/
|
||||
public $datetime;
|
||||
|
||||
|
101
app/DataMapper/Analytics/RevenueTrack.php
Normal file
101
app/DataMapper/Analytics/RevenueTrack.php
Normal file
@ -0,0 +1,101 @@
|
||||
<?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\Analytics;
|
||||
|
||||
use Turbo124\Beacon\ExampleMetric\GenericMixedMetric;
|
||||
|
||||
class RevenueTrack extends GenericMixedMetric
|
||||
{
|
||||
/**
|
||||
* The type of Sample.
|
||||
*
|
||||
* Monotonically incrementing counter
|
||||
*
|
||||
* - counter
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $type = 'mixed_metric';
|
||||
|
||||
/**
|
||||
* The name of the counter.
|
||||
* @var string
|
||||
*/
|
||||
public $name = 'app.revenue';
|
||||
|
||||
/**
|
||||
* The datetime of the counter measurement.
|
||||
*
|
||||
* date("Y-m-d H:i:s")
|
||||
*
|
||||
*/
|
||||
public $datetime;
|
||||
|
||||
/**
|
||||
* The Client email
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $string_metric5 = 'email';
|
||||
|
||||
/**
|
||||
* The AccountKey email
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $string_metric6 = 'key';
|
||||
|
||||
/**
|
||||
* Product Type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $string_metric7 = 'product';
|
||||
|
||||
/**
|
||||
* Gateway Reference
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $string_metric8 = 'gateway_reference';
|
||||
|
||||
public $string_metric9 = 'entity_reference';
|
||||
|
||||
public $string_metric10 = 'gateway_type';
|
||||
|
||||
/**
|
||||
* The counter
|
||||
* set to 1.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $int_metric1 = 1;
|
||||
|
||||
/**
|
||||
* Amount Received
|
||||
*
|
||||
* @var double
|
||||
*/
|
||||
public $double_metric2 = 0;
|
||||
|
||||
public function __construct($string_metric5, $string_metric6, $int_metric1, $double_metric2, $string_metric7, $string_metric8, $string_metric9, $string_metric10)
|
||||
{
|
||||
$this->int_metric1 = $int_metric1;
|
||||
$this->double_metric2 = $double_metric2;
|
||||
$this->string_metric5 = $string_metric5;
|
||||
$this->string_metric6 = $string_metric6;
|
||||
$this->string_metric7 = $string_metric7;
|
||||
$this->string_metric8 = $string_metric8;
|
||||
$this->string_metric9 = $string_metric9;
|
||||
$this->string_metric10 = $string_metric10;
|
||||
}
|
||||
}
|
@ -37,7 +37,7 @@ class SendRecurringFailure extends GenericMixedMetric
|
||||
*
|
||||
* date("Y-m-d H:i:s")
|
||||
*
|
||||
* @var DateTime
|
||||
* @var \DateTime
|
||||
*/
|
||||
public $datetime;
|
||||
|
||||
|
@ -37,7 +37,7 @@ class TrialFinished extends GenericCounter
|
||||
*
|
||||
* date("Y-m-d H:i:s")
|
||||
*
|
||||
* @var DateTime
|
||||
* @var \DateTime
|
||||
*/
|
||||
public $datetime;
|
||||
|
||||
|
@ -37,7 +37,7 @@ class TrialStarted extends GenericCounter
|
||||
*
|
||||
* date("Y-m-d H:i:s")
|
||||
*
|
||||
* @var DateTime
|
||||
* @var \DateTime
|
||||
*/
|
||||
public $datetime;
|
||||
|
||||
|
@ -16,13 +16,13 @@ namespace App\DataMapper;
|
||||
*/
|
||||
class BaseSettings
|
||||
{
|
||||
//@deprecated
|
||||
public function __construct($obj)
|
||||
{
|
||||
// foreach ($obj as $key => $value) {
|
||||
// $obj->{$key} = $value;
|
||||
// }
|
||||
}
|
||||
// //@deprecated
|
||||
// public function __construct($obj)
|
||||
// {
|
||||
// // foreach ($obj as $key => $value) {
|
||||
// // $obj->{$key} = $value;
|
||||
// // }
|
||||
// }
|
||||
|
||||
public static function setCasts($obj, $casts)
|
||||
{
|
||||
@ -57,5 +57,4 @@ class BaseSettings
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -20,82 +20,102 @@ class ClientRegistrationFields
|
||||
[
|
||||
'key' => 'first_name',
|
||||
'required' => true,
|
||||
'visible' => true,
|
||||
],
|
||||
[
|
||||
'key' => 'last_name',
|
||||
'required' => true,
|
||||
'visible' => true,
|
||||
],
|
||||
[
|
||||
'key' => 'email',
|
||||
'required' => true,
|
||||
'visible' => true,
|
||||
],
|
||||
[
|
||||
'key' => 'phone',
|
||||
'required' => false,
|
||||
'visible' => true,
|
||||
],
|
||||
[
|
||||
'key' => 'password',
|
||||
'required' => true,
|
||||
'visible' => true,
|
||||
],
|
||||
[
|
||||
'key' => 'name',
|
||||
'required' => false,
|
||||
'visible' => false,
|
||||
],
|
||||
[
|
||||
'key' => 'website',
|
||||
'required' => false,
|
||||
'visible' => false,
|
||||
],
|
||||
[
|
||||
'key' => 'address1',
|
||||
'required' => false,
|
||||
'visible' => false,
|
||||
],
|
||||
[
|
||||
'key' => 'address2',
|
||||
'required' => false,
|
||||
'visible' => false,
|
||||
],
|
||||
[
|
||||
'key' => 'city',
|
||||
'required' => false,
|
||||
'visible' => false,
|
||||
],
|
||||
[
|
||||
'key' => 'state',
|
||||
'required' => false,
|
||||
'visible' => false,
|
||||
],
|
||||
[
|
||||
'key' => 'postal_code',
|
||||
'required' => false,
|
||||
'visible' => false,
|
||||
],
|
||||
[
|
||||
'key' => 'country_id',
|
||||
'required' => false,
|
||||
'visible' => false,
|
||||
],
|
||||
[
|
||||
'key' => 'custom_value1',
|
||||
'required' => false,
|
||||
'visible' => false,
|
||||
],
|
||||
[
|
||||
'key' => 'custom_value2',
|
||||
'required' => false,
|
||||
'visible' => false,
|
||||
],
|
||||
[
|
||||
'key' => 'custom_value3',
|
||||
'required' => false,
|
||||
'visible' => false,
|
||||
],
|
||||
[
|
||||
'key' => 'custom_value4',
|
||||
'required' => false,
|
||||
'visible' => false,
|
||||
],
|
||||
[
|
||||
'key' => 'public_notes',
|
||||
'required' => false,
|
||||
'visible' => false,
|
||||
],
|
||||
[
|
||||
'key' => 'vat_number',
|
||||
'required' => false,
|
||||
'visible' => false,
|
||||
],
|
||||
[
|
||||
'key' => 'currency_id',
|
||||
'required' => false,
|
||||
'visible' => false,
|
||||
],
|
||||
];
|
||||
|
||||
|
@ -47,17 +47,17 @@ class ClientSettings extends BaseSettings
|
||||
'send_reminders' => 'bool',
|
||||
];
|
||||
|
||||
/**
|
||||
* Cast object values and return entire class
|
||||
* prevents missing properties from not being returned
|
||||
* and always ensure an up to date class is returned.
|
||||
*
|
||||
* @param $obj
|
||||
*/
|
||||
public function __construct($obj)
|
||||
{
|
||||
parent::__construct($obj);
|
||||
}
|
||||
// /**
|
||||
// * Cast object values and return entire class
|
||||
// * prevents missing properties from not being returned
|
||||
// * and always ensure an up to date class is returned.
|
||||
// *
|
||||
// * @param $obj
|
||||
// */
|
||||
// public function __construct($obj)
|
||||
// {
|
||||
// // parent::__construct($obj);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Default Client Settings scaffold.
|
||||
@ -78,8 +78,8 @@ class ClientSettings extends BaseSettings
|
||||
/**
|
||||
* Merges settings from Company to Client.
|
||||
*
|
||||
* @param stdClass $company_settings
|
||||
* @param stdClass $client_settings
|
||||
* @param $company_settings
|
||||
* @param $client_settings
|
||||
* @return stdClass of merged settings
|
||||
*/
|
||||
public static function buildClientSettings($company_settings, $client_settings)
|
||||
@ -88,6 +88,10 @@ class ClientSettings extends BaseSettings
|
||||
return $company_settings;
|
||||
}
|
||||
|
||||
if (is_array($client_settings)) {
|
||||
$client_settings = (object)$client_settings;
|
||||
}
|
||||
|
||||
foreach ($company_settings as $key => $value) {
|
||||
/* pseudo code
|
||||
if the property exists and is a string BUT has no length, treat it as TRUE
|
||||
|
@ -229,7 +229,7 @@ class CompanySettings extends BaseSettings
|
||||
public $require_quote_signature = false; //@TODO ben to confirm
|
||||
|
||||
//email settings
|
||||
public $email_sending_method = 'default'; //enum 'default','gmail','office365' 'client_postmark', 'client_mailgun'//@implemented
|
||||
public $email_sending_method = 'default'; //enum 'default','gmail','office365' 'client_postmark', 'client_mailgun' //@implemented
|
||||
|
||||
public $gmail_sending_user_id = '0'; //@implemented
|
||||
|
||||
@ -383,7 +383,7 @@ class CompanySettings extends BaseSettings
|
||||
|
||||
public $page_layout = 'portrait';
|
||||
|
||||
public $font_size = 7; //@implemented
|
||||
public $font_size = 16; //@implemented
|
||||
|
||||
public $primary_font = 'Roboto';
|
||||
|
||||
@ -442,11 +442,15 @@ class CompanySettings extends BaseSettings
|
||||
public $send_email_on_mark_paid = false;
|
||||
|
||||
public $postmark_secret = '';
|
||||
|
||||
public $custom_sending_email = '';
|
||||
|
||||
public $mailgun_secret = '';
|
||||
|
||||
public $mailgun_domain = '';
|
||||
|
||||
public $mailgun_endpoint = 'api.mailgun.net'; //api.eu.mailgun.net
|
||||
|
||||
public $auto_bill_standard_invoices = false;
|
||||
|
||||
public $email_alignment = 'center'; // center , left, right
|
||||
@ -459,7 +463,55 @@ class CompanySettings extends BaseSettings
|
||||
|
||||
public $show_shipping_address = false;
|
||||
|
||||
public $accept_client_input_quote_approval = false;
|
||||
|
||||
public $allow_billable_task_items = true;
|
||||
|
||||
public $show_task_item_description = false;
|
||||
|
||||
public $client_initiated_payments = false;
|
||||
|
||||
public $client_initiated_payments_minimum = 0;
|
||||
|
||||
public $sync_invoice_quote_columns = true;
|
||||
|
||||
public $e_invoice_type = 'EN16931';
|
||||
|
||||
public $default_expense_payment_type_id = '0';
|
||||
|
||||
public $enable_e_invoice = false;
|
||||
|
||||
public $delivery_note_design_id = '';
|
||||
|
||||
public $statement_design_id = '';
|
||||
|
||||
public $payment_receipt_design_id = '';
|
||||
|
||||
public $payment_refund_design_id = '';
|
||||
|
||||
public $classification = ''; // individual, business, partnership, trust, charity, government, other
|
||||
|
||||
public $payment_email_all_contacts = false;
|
||||
|
||||
public static $casts = [
|
||||
'payment_email_all_contacts' => 'bool',
|
||||
'statement_design_id' => 'string',
|
||||
'delivery_note_design_id' => 'string',
|
||||
'payment_receipt_design_id' => 'string',
|
||||
'payment_refund_design_id' => 'string',
|
||||
'classification' => 'string',
|
||||
'enable_e_invoice' => 'bool',
|
||||
'classification' => 'string',
|
||||
'default_expense_payment_type_id' => 'string',
|
||||
'e_invoice_type' => 'string',
|
||||
'mailgun_endpoint' => 'string',
|
||||
'client_initiated_payments' => 'bool',
|
||||
'client_initiated_payments_minimum' => 'float',
|
||||
'sync_invoice_quote_columns' => 'bool',
|
||||
'show_task_item_description' => 'bool',
|
||||
'allow_billable_task_items' => 'bool',
|
||||
'accept_client_input_quote_approval' => 'bool',
|
||||
'custom_sending_email' => 'string',
|
||||
'show_paid_stamp' => 'bool',
|
||||
'show_shipping_address' => 'bool',
|
||||
'company_logo_size' => 'string',
|
||||
@ -481,7 +533,6 @@ class CompanySettings extends BaseSettings
|
||||
'purchase_order_design_id' => 'string',
|
||||
'purchase_order_footer' => 'string',
|
||||
'purchase_order_number_pattern' => 'string',
|
||||
'purchase_order_number_counter' => 'int',
|
||||
'page_numbering_alignment' => 'string',
|
||||
'page_numbering' => 'bool',
|
||||
'auto_archive_invoice_cancelled' => 'bool',
|
||||
@ -513,7 +564,6 @@ class CompanySettings extends BaseSettings
|
||||
'reminder_send_time' => 'int',
|
||||
'email_sending_method' => 'string',
|
||||
'gmail_sending_user_id' => 'string',
|
||||
'currency_id' => 'string',
|
||||
'counter_number_applied' => 'string',
|
||||
'quote_number_applied' => 'string',
|
||||
'email_subject_custom1' => 'string',
|
||||
@ -734,20 +784,22 @@ class CompanySettings extends BaseSettings
|
||||
'quote_design_id',
|
||||
'credit_design_id',
|
||||
'purchase_order_design_id',
|
||||
'statement_design_id',
|
||||
'delivery_note_design_id',
|
||||
];
|
||||
|
||||
/**
|
||||
* Cast object values and return entire class
|
||||
* prevents missing properties from not being returned
|
||||
* and always ensure an up to date class is returned.
|
||||
*
|
||||
* @param $obj
|
||||
* @deprecated
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
// parent::__construct($obj);
|
||||
}
|
||||
// /**
|
||||
// * Cast object values and return entire class
|
||||
// * prevents missing properties from not being returned
|
||||
// * and always ensure an up to date class is returned.
|
||||
// *
|
||||
// * @param $obj
|
||||
// * @deprecated
|
||||
// */
|
||||
// public function __construct()
|
||||
// {
|
||||
// // parent::__construct($obj);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Provides class defaults on init.
|
||||
@ -756,7 +808,6 @@ class CompanySettings extends BaseSettings
|
||||
*/
|
||||
public static function defaults(): stdClass
|
||||
{
|
||||
|
||||
$data = (object) get_class_vars(self::class);
|
||||
|
||||
unset($data->casts);
|
||||
@ -782,14 +833,14 @@ class CompanySettings extends BaseSettings
|
||||
* need to provide a fallback catch on old settings objects which will
|
||||
* set new properties to the object prior to being returned.
|
||||
*
|
||||
* @param $settings
|
||||
* @param \stdClass $settings
|
||||
*
|
||||
* @return stdClass
|
||||
*/
|
||||
public static function setProperties($settings): stdClass
|
||||
{
|
||||
$company_settings = (object) get_class_vars(self::class);
|
||||
|
||||
|
||||
foreach ($company_settings as $key => $value) {
|
||||
if (! property_exists($settings, $key)) {
|
||||
$settings->{$key} = self::castAttribute($key, $company_settings->{$key});
|
||||
@ -808,11 +859,30 @@ class CompanySettings extends BaseSettings
|
||||
{
|
||||
$notification = new stdClass;
|
||||
$notification->email = [];
|
||||
$notification->email = ['invoice_sent_all'];
|
||||
|
||||
// $notification->email = ['all_notifications'];
|
||||
|
||||
return $notification;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stubs the notification defaults
|
||||
*
|
||||
* @return stdClass
|
||||
*/
|
||||
public static function notificationAdminDefaults() :stdClass
|
||||
{
|
||||
$notification = new stdClass;
|
||||
$notification->email = [];
|
||||
$notification->email = ['invoice_sent_all'];
|
||||
|
||||
return $notification;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Defines entity variables for PDF generation
|
||||
*
|
||||
@ -828,7 +898,6 @@ class CompanySettings extends BaseSettings
|
||||
'$client.address1',
|
||||
'$client.address2',
|
||||
'$client.city_state_postal',
|
||||
'$client.postal_city',
|
||||
'$client.country',
|
||||
'$client.phone',
|
||||
'$contact.email',
|
||||
@ -840,7 +909,6 @@ class CompanySettings extends BaseSettings
|
||||
'$vendor.address1',
|
||||
'$vendor.address2',
|
||||
'$vendor.city_state_postal',
|
||||
'$vendor.postal_city',
|
||||
'$vendor.country',
|
||||
'$vendor.phone',
|
||||
'$contact.email',
|
||||
@ -865,7 +933,6 @@ class CompanySettings extends BaseSettings
|
||||
'$company.address1',
|
||||
'$company.address2',
|
||||
'$company.city_state_postal',
|
||||
'$company.postal_city',
|
||||
'$company.country',
|
||||
],
|
||||
'invoice_details' => [
|
||||
@ -899,6 +966,15 @@ class CompanySettings extends BaseSettings
|
||||
'$product.tax',
|
||||
'$product.line_total',
|
||||
],
|
||||
'product_quote_columns' => [
|
||||
'$product.item',
|
||||
'$product.description',
|
||||
'$product.unit_cost',
|
||||
'$product.quantity',
|
||||
'$product.discount',
|
||||
'$product.tax',
|
||||
'$product.line_total',
|
||||
],
|
||||
'task_columns' =>[
|
||||
'$task.service',
|
||||
'$task.description',
|
||||
@ -935,6 +1011,21 @@ class CompanySettings extends BaseSettings
|
||||
'$method',
|
||||
'$statement_amount',
|
||||
],
|
||||
'statement_credit_columns' => [
|
||||
'$credit.number',
|
||||
'$credit.date',
|
||||
'$total',
|
||||
'$credit.balance',
|
||||
],
|
||||
'statement_details' => [
|
||||
'$statement_date',
|
||||
'$balance'
|
||||
],
|
||||
'delivery_note_columns' => [
|
||||
'$product.item',
|
||||
'$product.description',
|
||||
'$product.quantity',
|
||||
],
|
||||
];
|
||||
|
||||
return json_decode(json_encode($variables));
|
||||
|
@ -34,13 +34,4 @@ class DefaultSettings extends BaseSettings
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return stdClass
|
||||
*/
|
||||
private static function userSettingsObject() : stdClass
|
||||
{
|
||||
return (object) [
|
||||
// 'per_page' => self::$per_page,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -20,100 +20,100 @@ class EmailTemplateDefaults
|
||||
App::setLocale($locale);
|
||||
|
||||
switch ($template) {
|
||||
|
||||
/* Template */
|
||||
|
||||
case 'email_template_invoice':
|
||||
return self::emailInvoiceTemplate();
|
||||
break;
|
||||
case 'email_template_quote':
|
||||
return self::emailQuoteTemplate();
|
||||
break;
|
||||
case 'email_template_credit':
|
||||
return self::emailCreditTemplate();
|
||||
break;
|
||||
case 'email_template_payment':
|
||||
return self::emailPaymentTemplate();
|
||||
break;
|
||||
case 'email_template_payment_partial':
|
||||
return self::emailPaymentPartialTemplate();
|
||||
break;
|
||||
case 'email_template_statement':
|
||||
return self::emailStatementTemplate();
|
||||
break;
|
||||
case 'email_template_reminder1':
|
||||
return self::emailReminder1Template();
|
||||
break;
|
||||
case 'email_template_reminder2':
|
||||
return self::emailReminder2Template();
|
||||
break;
|
||||
case 'email_template_reminder3':
|
||||
return self::emailReminder3Template();
|
||||
break;
|
||||
case 'email_template_reminder_endless':
|
||||
return self::emailReminderEndlessTemplate();
|
||||
break;
|
||||
case 'email_template_custom1':
|
||||
return self::emailInvoiceTemplate();
|
||||
break;
|
||||
case 'email_template_custom2':
|
||||
return self::emailInvoiceTemplate();
|
||||
break;
|
||||
case 'email_template_custom3':
|
||||
return self::emailInvoiceTemplate();
|
||||
case 'email_template_purchase_order':
|
||||
return self::emailPurchaseOrderTemplate();
|
||||
break;
|
||||
|
||||
/* Subject */
|
||||
/* Subject */
|
||||
case 'email_subject_purchase_order':
|
||||
return self::emailPurchaseOrderSubject();
|
||||
case 'email_subject_invoice':
|
||||
return self::emailInvoiceSubject();
|
||||
break;
|
||||
|
||||
case 'email_subject_quote':
|
||||
return self::emailQuoteSubject();
|
||||
break;
|
||||
|
||||
case 'email_subject_credit':
|
||||
return self::emailCreditSubject();
|
||||
break;
|
||||
|
||||
case 'email_subject_payment':
|
||||
return self::emailPaymentSubject();
|
||||
break;
|
||||
|
||||
case 'email_subject_payment_partial':
|
||||
return self::emailPaymentPartialSubject();
|
||||
break;
|
||||
|
||||
case 'email_subject_statement':
|
||||
return self::emailStatementSubject();
|
||||
break;
|
||||
|
||||
case 'email_subject_reminder1':
|
||||
return self::emailReminder1Subject();
|
||||
break;
|
||||
|
||||
case 'email_subject_reminder2':
|
||||
return self::emailReminder2Subject();
|
||||
break;
|
||||
|
||||
case 'email_subject_reminder3':
|
||||
return self::emailReminder3Subject();
|
||||
break;
|
||||
|
||||
case 'email_subject_reminder_endless':
|
||||
return self::emailReminderEndlessSubject();
|
||||
break;
|
||||
|
||||
case 'email_subject_custom1':
|
||||
return self::emailInvoiceSubject();
|
||||
break;
|
||||
|
||||
case 'email_subject_custom2':
|
||||
return self::emailInvoiceSubject();
|
||||
break;
|
||||
|
||||
case 'email_subject_custom3':
|
||||
return self::emailInvoiceSubject();
|
||||
break;
|
||||
|
||||
case 'email_vendor_notification_subject':
|
||||
return self::emailVendorNotificationSubject();
|
||||
|
||||
case 'email_vendor_notification_body':
|
||||
return self::emailVendorNotificationBody();
|
||||
|
||||
default:
|
||||
return self::emailInvoiceTemplate();
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static function emailVendorNotificationSubject()
|
||||
{
|
||||
return self::transformText('vendor_notification_subject');
|
||||
}
|
||||
|
||||
public static function emailVendorNotificationBody()
|
||||
{
|
||||
return self::transformText('vendor_notification_body');
|
||||
}
|
||||
|
||||
public static function emailInvoiceSubject()
|
||||
{
|
||||
return ctrans('texts.invoice_subject', ['number'=>'$number', 'account'=>'$company.name']);
|
||||
@ -240,7 +240,6 @@ class EmailTemplateDefaults
|
||||
|
||||
public static function emailStatementTemplate()
|
||||
{
|
||||
|
||||
$statement_message = '<p>$client<br><br>'.self::transformText('client_statement_body').'<br></p>';
|
||||
|
||||
return $statement_message;
|
||||
|
@ -44,7 +44,7 @@ class FreeCompanySettings extends BaseSettings
|
||||
|
||||
public $date_format_id = '';
|
||||
|
||||
// public $enabled_item_tax_rates = 0;
|
||||
// public $enabled_item_tax_rates = 0;
|
||||
public $expense_number_pattern = '';
|
||||
|
||||
public $expense_number_counter = 1;
|
||||
@ -141,7 +141,6 @@ class FreeCompanySettings extends BaseSettings
|
||||
|
||||
public static $casts = [
|
||||
'portal_design_id' => 'string',
|
||||
'currency_id' => 'string',
|
||||
'task_number_pattern' => 'string',
|
||||
'task_number_counter' => 'int',
|
||||
'expense_number_pattern' => 'string',
|
||||
@ -191,16 +190,16 @@ class FreeCompanySettings extends BaseSettings
|
||||
'website' => 'string',
|
||||
];
|
||||
|
||||
/**
|
||||
* Cast object values and return entire class
|
||||
* prevents missing properties from not being returned
|
||||
* and always ensure an up to date class is returned.
|
||||
*
|
||||
* @param $obj
|
||||
*/
|
||||
public function __construct($obj)
|
||||
{
|
||||
}
|
||||
// /**
|
||||
// * Cast object values and return entire class
|
||||
// * prevents missing properties from not being returned
|
||||
// * and always ensure an up to date class is returned.
|
||||
// *
|
||||
// * @param $obj
|
||||
// */
|
||||
// public function __construct($obj)
|
||||
// {
|
||||
// }
|
||||
|
||||
/**
|
||||
* Provides class defaults on init.
|
||||
@ -223,7 +222,7 @@ class FreeCompanySettings extends BaseSettings
|
||||
$data->date_format_id = (string) config('ninja.i18n.date_format_id');
|
||||
$data->country_id = (string) config('ninja.i18n.country_id');
|
||||
$data->translations = (object) [];
|
||||
$data->pdf_variables = (object) self::getEntityVariableDefaults();
|
||||
// $data->pdf_variables = (object) self::getEntityVariableDefaults();
|
||||
|
||||
return self::setCasts($data, self::$casts);
|
||||
}
|
||||
|
@ -59,7 +59,16 @@ class InvoiceItem
|
||||
|
||||
public $type_id = '1'; //1 = product, 2 = service, 3 unpaid gateway fee, 4 paid gateway fee, 5 late fee, 6 expense
|
||||
|
||||
public $tax_id = '';
|
||||
|
||||
public $task_id = '';
|
||||
|
||||
public $expense_id = '';
|
||||
|
||||
public static $casts = [
|
||||
'task_id' => 'string',
|
||||
'expense_id' => 'string',
|
||||
'tax_id' => 'string',
|
||||
'type_id' => 'string',
|
||||
'quantity' => 'float',
|
||||
'cost' => 'float',
|
||||
|
36
app/DataMapper/Schedule/EmailRecord.php
Normal file
36
app/DataMapper/Schedule/EmailRecord.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?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 EmailRecord
|
||||
{
|
||||
/**
|
||||
* Defines the template name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $template = 'email_record';
|
||||
|
||||
/**
|
||||
* Defines the template name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $entity = ''; // invoice, credit, quote, purchase_order
|
||||
|
||||
/**
|
||||
* Defines the template name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $entity_id = '';
|
||||
}
|
111
app/DataMapper/Schedule/EmailReport.php
Normal file
111
app/DataMapper/Schedule/EmailReport.php
Normal file
@ -0,0 +1,111 @@
|
||||
<?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 report 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 = '';
|
||||
|
||||
/******************************* Parameters **********************************/
|
||||
|
||||
/** @var string $report_name */
|
||||
|
||||
public string $report_name = '';
|
||||
|
||||
/**
|
||||
* Optional array of report keys for
|
||||
* filter the columns of the report
|
||||
*
|
||||
* @var array $report_keys
|
||||
*
|
||||
* */
|
||||
public array $report_keys = [];
|
||||
|
||||
/** Profit Loss Parameters */
|
||||
public bool $is_income_billed = true;
|
||||
|
||||
public bool $is_expense_billed = true;
|
||||
|
||||
public bool $include_tax = true;
|
||||
|
||||
/**
|
||||
* Comma separated string of statuses for filtering the Invoice report
|
||||
*
|
||||
* all
|
||||
* draft
|
||||
* sent
|
||||
* paid
|
||||
* unpaid
|
||||
* overdue
|
||||
* viewed
|
||||
*
|
||||
* */
|
||||
public string $status = '';
|
||||
|
||||
/**
|
||||
* Comma separated list of product.product_keys
|
||||
* to filter the report by
|
||||
*/
|
||||
public string $product_key = '';
|
||||
}
|
@ -11,24 +11,20 @@
|
||||
|
||||
namespace App\DataMapper\Schedule;
|
||||
|
||||
use App\Models\Client;
|
||||
use stdClass;
|
||||
|
||||
class ClientStatement
|
||||
class EmailStatement
|
||||
{
|
||||
|
||||
/**
|
||||
* Defines the template name
|
||||
*
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $template = 'client_statement';
|
||||
public string $template = 'email_statement';
|
||||
|
||||
/**
|
||||
* An array of clients hashed_ids
|
||||
*
|
||||
* Leave blank if this action should apply to all clients
|
||||
*
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public array $clients = [];
|
||||
@ -36,17 +32,22 @@ class ClientStatement
|
||||
/**
|
||||
* The consts to be used to define the date_range variable of the statement
|
||||
*/
|
||||
public const THIS_MONTH = 'this_month';
|
||||
public const THIS_QUARTER = 'this_quarter';
|
||||
public const THIS_YEAR = 'this_year';
|
||||
public const PREVIOUS_MONTH = 'previous_month';
|
||||
public const PREVIOUS_QUARTER = 'previous_quarter';
|
||||
public const PREVIOUS_YEAR = 'previous_year';
|
||||
public const CUSTOM_RANGE = "custom_range";
|
||||
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 ALL_TIME = "all_time";
|
||||
public const CUSTOM_RANGE = "custom";
|
||||
|
||||
|
||||
/**
|
||||
* The date range the statement should include
|
||||
*
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $date_range = 'this_month';
|
||||
@ -54,7 +55,7 @@ class ClientStatement
|
||||
/**
|
||||
* 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 = '';
|
||||
@ -62,7 +63,7 @@ class ClientStatement
|
||||
/**
|
||||
* 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 = '';
|
||||
@ -87,10 +88,8 @@ class ClientStatement
|
||||
* String const which defines whether
|
||||
* the invoices to be shown are either
|
||||
* paid or unpaid
|
||||
*
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $status = 'paid'; // paid | unpaid
|
||||
|
||||
|
||||
}
|
||||
}
|
516
app/DataMapper/Settings/SettingsData.php
Normal file
516
app/DataMapper/Settings/SettingsData.php
Normal file
@ -0,0 +1,516 @@
|
||||
<?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\Settings;
|
||||
|
||||
class SettingsData
|
||||
{
|
||||
|
||||
public bool $auto_archive_invoice = false; // @implemented
|
||||
|
||||
public string $qr_iban = ''; //@implemented
|
||||
|
||||
public string $besr_id = ''; //@implemented
|
||||
|
||||
public string $lock_invoices = 'off'; // off, when_sent, when_paid //@implemented
|
||||
|
||||
public bool $enable_client_portal_tasks = false; //@ben to implement
|
||||
|
||||
public string $show_all_tasks_client_portal = 'invoiced'; // all, uninvoiced, invoiced
|
||||
|
||||
public bool $enable_client_portal_password = false; //@implemented
|
||||
|
||||
public bool $enable_client_portal = true; //@implemented
|
||||
|
||||
public bool $enable_client_portal_dashboard = false; // @TODO There currently is no dashboard, so this is pending
|
||||
|
||||
public bool $signature_on_pdf = false; //@implemented
|
||||
|
||||
public bool $document_email_attachment = false; //@TODO I assume this is 3rd party attachments on the entity to be included
|
||||
|
||||
public string $portal_design_id = '1'; //? @deprecated
|
||||
|
||||
public string $timezone_id = ''; //@implemented
|
||||
|
||||
public string $date_format_id = ''; //@implemented
|
||||
|
||||
public bool $military_time = false; // @TODO Implemented in Tasks only?
|
||||
|
||||
public string $language_id = ''; //@implemented
|
||||
|
||||
public bool $show_currency_code = false; //@implemented
|
||||
|
||||
public string $company_gateway_ids = ''; //@implemented
|
||||
|
||||
public string $currency_id = '1'; //@implemented
|
||||
|
||||
public string $custom_value1 = ''; //@implemented
|
||||
|
||||
public string $custom_value2 = ''; //@implemented
|
||||
|
||||
public string $custom_value3 = ''; //@implemented
|
||||
|
||||
public string $custom_value4 = ''; //@implemented
|
||||
|
||||
public float $default_task_rate = 0; // @TODO Where do we inject this?
|
||||
|
||||
public string $payment_terms = ''; //@implemented
|
||||
|
||||
public bool $send_reminders = true; //@TODO
|
||||
|
||||
public string $custom_message_dashboard = ''; // @TODO There currently is no dashboard, so this is pending
|
||||
|
||||
public string $custom_message_unpaid_invoice = '';
|
||||
|
||||
public string $custom_message_paid_invoice = '';
|
||||
|
||||
public string $custom_message_unapproved_quote = '';
|
||||
|
||||
public bool $auto_archive_quote = false; //@implemented
|
||||
|
||||
public bool $auto_convert_quote = true; //@implemented
|
||||
|
||||
public bool $auto_email_invoice = true; //@only used for Recurring Invoices, if set to false, we never send?
|
||||
|
||||
public int $entity_send_time = 6;
|
||||
|
||||
public bool $inclusive_taxes = false; //@implemented
|
||||
|
||||
public string $quote_footer = ''; //@implemented
|
||||
|
||||
public object $translations;
|
||||
|
||||
public string $counter_number_applied = 'when_saved'; // when_saved, when_sent //@implemented
|
||||
|
||||
public string $quote_number_applied = 'when_saved'; // when_saved, when_sent //@implemented
|
||||
|
||||
public string $invoice_number_pattern = ''; //@implemented
|
||||
|
||||
public int $invoice_number_counter = 1; //@implemented
|
||||
|
||||
public string $recurring_invoice_number_pattern = ''; //@implemented
|
||||
|
||||
public int $recurring_invoice_number_counter = 1; //@implemented
|
||||
|
||||
public string $quote_number_pattern = ''; //@implemented
|
||||
|
||||
public int $quote_number_counter = 1; //@implemented
|
||||
|
||||
public string $client_number_pattern = ''; //@implemented
|
||||
|
||||
public int $client_number_counter = 1; //@implemented
|
||||
|
||||
public string $credit_number_pattern = ''; //@implemented
|
||||
|
||||
public int $credit_number_counter = 1; //@implemented
|
||||
|
||||
public string $task_number_pattern = ''; //@implemented
|
||||
|
||||
public int $task_number_counter = 1; //@implemented
|
||||
|
||||
public string $expense_number_pattern = ''; //@implemented
|
||||
|
||||
public int $expense_number_counter = 1; //@implemented
|
||||
|
||||
public string $recurring_expense_number_pattern = '';
|
||||
|
||||
public int $recurring_expense_number_counter = 1;
|
||||
|
||||
public string $recurring_quote_number_pattern = '';
|
||||
|
||||
public int $recurring_quote_number_counter = 1;
|
||||
|
||||
public string $vendor_number_pattern = ''; //@implemented
|
||||
|
||||
public int $vendor_number_counter = 1; //@implemented
|
||||
|
||||
public string $ticket_number_pattern = ''; //@implemented
|
||||
|
||||
public int $ticket_number_counter = 1; //@implemented
|
||||
|
||||
public string $payment_number_pattern = ''; //@implemented
|
||||
|
||||
public int $payment_number_counter = 1; //@implemented
|
||||
|
||||
public string $project_number_pattern = ''; //@implemented
|
||||
|
||||
public int $project_number_counter = 1; //@implemented
|
||||
|
||||
public string $purchase_order_number_pattern = ''; //@implemented
|
||||
|
||||
public int $purchase_order_number_counter = 1; //@implemented
|
||||
|
||||
public bool $shared_invoice_quote_counter = false; //@implemented
|
||||
|
||||
public bool $shared_invoice_credit_counter = false; //@implemented
|
||||
|
||||
public string $recurring_number_prefix = ''; //@implemented
|
||||
|
||||
public string $reset_counter_frequency_id = '0'; //@implemented
|
||||
|
||||
public string $reset_counter_date = ''; //@implemented
|
||||
|
||||
public int $counter_padding = 4; //@implemented
|
||||
|
||||
public string $auto_bill = 'off'; // off, always, opt-in, opt-out //@implemented
|
||||
|
||||
public string $auto_bill_date = 'on_due_date'; // on_due_date, on_send_date //@implemented
|
||||
|
||||
public string $invoice_terms = ''; //@implemented
|
||||
|
||||
public string $quote_terms = ''; //@implemented
|
||||
|
||||
public int $invoice_taxes = 0; // ? used in AP only?
|
||||
|
||||
public string $invoice_design_id = 'Wpmbk5ezJn'; //@implemented
|
||||
|
||||
public string $quote_design_id = 'Wpmbk5ezJn'; //@implemented
|
||||
|
||||
public string $credit_design_id = 'Wpmbk5ezJn'; //@implemented
|
||||
|
||||
public string $purchase_order_design_id = 'Wpmbk5ezJn';
|
||||
|
||||
public string $purchase_order_footer = ''; //@implemented
|
||||
|
||||
public string $purchase_order_terms = ''; //@implemented
|
||||
|
||||
public string $purchase_order_public_notes = ''; //@implemented
|
||||
|
||||
public bool $require_purchase_order_signature = false; //@TODO ben to confirm
|
||||
|
||||
public string $invoice_footer = ''; //@implemented
|
||||
|
||||
public string $credit_footer = ''; //@implemented
|
||||
|
||||
public string $credit_terms = ''; //@implemented
|
||||
|
||||
public string $invoice_labels = ''; //@TODO used in AP only?
|
||||
|
||||
public string $tax_name1 = ''; //@TODO where do we use this?
|
||||
|
||||
public float $tax_rate1 = 0; //@TODO where do we use this?
|
||||
|
||||
public string $tax_name2 = ''; //@TODO where do we use this?
|
||||
|
||||
public float $tax_rate2 = 0; //@TODO where do we use this?
|
||||
|
||||
public string $tax_name3 = ''; //@TODO where do we use this?
|
||||
|
||||
public float $tax_rate3 = 0; //@TODO where do we use this?
|
||||
|
||||
public string $payment_type_id = '0'; //@TODO where do we use this?
|
||||
|
||||
public string $valid_until = ''; //@implemented
|
||||
|
||||
public bool $show_accept_invoice_terms = false; //@TODO ben to confirm
|
||||
|
||||
public bool $show_accept_quote_terms = false; //@TODO ben to confirm
|
||||
|
||||
public string $email_sending_method = 'default'; // enum 'default', 'gmail', 'office365', 'client_postmark', 'client_mailgun' //@implemented
|
||||
|
||||
public string $gmail_sending_user_id = '0'; //@implemented
|
||||
|
||||
public string $reply_to_email = ''; //@implemented
|
||||
|
||||
public string $reply_to_name = ''; //@implemented
|
||||
|
||||
public string $bcc_email = ''; //@TODO
|
||||
|
||||
public bool $pdf_email_attachment = false; //@implemented
|
||||
|
||||
public bool $ubl_email_attachment = false; //@implemented
|
||||
|
||||
public string $email_style = 'light'; // plain, light, dark, custom //@implemented
|
||||
|
||||
public string $email_style_custom = ''; // the template itself //@implemented
|
||||
|
||||
public string $email_subject_invoice = ''; //@implemented
|
||||
|
||||
public string $email_subject_quote = ''; //@implemented
|
||||
|
||||
public string $email_subject_credit = ''; //@implemented
|
||||
|
||||
public string $email_subject_payment = ''; //@implemented
|
||||
|
||||
public string $email_subject_payment_partial = ''; //@implemented
|
||||
|
||||
public string $email_subject_statement = ''; //@implemented
|
||||
|
||||
public string $email_subject_purchase_order = ''; //@implemented
|
||||
|
||||
public string $email_template_purchase_order = ''; //@implemented
|
||||
|
||||
public string $email_template_invoice = ''; //@implemented
|
||||
|
||||
public string $email_template_credit = ''; //@implemented
|
||||
|
||||
public string $email_template_quote = ''; //@implemented
|
||||
|
||||
public string $email_template_payment = ''; //@implemented
|
||||
|
||||
public string $email_template_payment_partial = ''; //@implemented
|
||||
|
||||
public string $email_template_statement = ''; //@implemented
|
||||
|
||||
public string $email_subject_reminder1 = ''; //@implemented
|
||||
|
||||
public string $email_subject_reminder2 = ''; //@implemented
|
||||
|
||||
public string $email_subject_reminder3 = ''; //@implemented
|
||||
|
||||
public string $email_subject_reminder_endless = ''; //@implemented
|
||||
|
||||
public string $email_template_reminder1 = ''; //@implemented
|
||||
|
||||
public string $email_template_reminder2 = ''; //@implemented
|
||||
|
||||
public string $email_template_reminder3 = ''; //@implemented
|
||||
|
||||
public string $email_template_reminder_endless = ''; //@implemented
|
||||
|
||||
public string $email_signature = ''; //@implemented
|
||||
|
||||
public bool $enable_email_markup = true; //@TODO -
|
||||
|
||||
public string $email_subject_custom1 = ''; //@TODO
|
||||
|
||||
public string $email_subject_custom2 = ''; //@TODO
|
||||
|
||||
public string $email_subject_custom3 = ''; //@TODO
|
||||
|
||||
public string $email_template_custom1 = ''; //@TODO
|
||||
|
||||
public string $email_template_custom2 = ''; //@TODO
|
||||
|
||||
public string $email_template_custom3 = ''; //@TODO
|
||||
|
||||
public bool $enable_reminder1 = false; //@implmemented
|
||||
|
||||
public bool $enable_reminder2 = false; //@implmemented
|
||||
|
||||
public bool $enable_reminder3 = false; //@implmemented
|
||||
|
||||
public bool $enable_reminder_endless = false; //@implmemented
|
||||
|
||||
public int $num_days_reminder1 = 0; //@implmemented
|
||||
|
||||
public int $num_days_reminder2 = 0; //@implmemented
|
||||
|
||||
public int $num_days_reminder3 = 0; //@implmemented
|
||||
|
||||
public string $schedule_reminder1 = ''; // (enum: after_invoice_date, before_due_date, after_due_date) implmemented
|
||||
|
||||
public string $schedule_reminder2 = ''; // (enum: after_invoice_date, before_due_date, after_due_date) implmemented
|
||||
|
||||
public string $schedule_reminder3 = ''; // (enum: after_invoice_date, before_due_date, after_due_date) implmemented
|
||||
|
||||
public int $reminder_send_time = 0; // number of seconds from UTC +0 to send reminders @TODO
|
||||
|
||||
public float $late_fee_amount1 = 0; //@implemented
|
||||
|
||||
public float $late_fee_amount2 = 0; //@implemented
|
||||
|
||||
public float $late_fee_amount3 = 0; //@implemented
|
||||
|
||||
public float $late_fee_percent1 = 0; //@implemented
|
||||
|
||||
public float $late_fee_percent2 = 0; //@implemented
|
||||
|
||||
public float $late_fee_percent3 = 0; //@implemented
|
||||
|
||||
public string $endless_reminder_frequency_id = '0'; //@implemented
|
||||
|
||||
public float $late_fee_endless_amount = 0; //@implemented
|
||||
|
||||
public float $late_fee_endless_percent = 0; //@implemented
|
||||
|
||||
public bool $client_online_payment_notification = true; //@todo implement in notifications check this bool prior to sending payment notification to client
|
||||
|
||||
public bool $client_manual_payment_notification = true; //@todo implement in notifications check this bool prior to sending manual payment notification to client
|
||||
|
||||
public string $name = ''; //@implemented
|
||||
|
||||
public string $company_logo = ''; //@implemented
|
||||
|
||||
public string $website = ''; //@implemented
|
||||
|
||||
public string $address1 = ''; //@implemented
|
||||
|
||||
public string $address2 = ''; //@implemented
|
||||
|
||||
public string $city = ''; //@implemented
|
||||
|
||||
public string $state = ''; //@implemented
|
||||
|
||||
public string $postal_code = ''; //@implemented
|
||||
|
||||
public string $phone = ''; //@implemented
|
||||
|
||||
public string $email = ''; //@implemented
|
||||
|
||||
public string $country_id = ''; //@implemented
|
||||
|
||||
public string $vat_number = ''; //@implemented
|
||||
|
||||
public string $id_number = ''; //@implemented
|
||||
|
||||
public string $page_size = 'A4'; // Letter, Legal, Tabloid, Ledger, A0, A1, A2, A3, A4, A5, A6
|
||||
|
||||
public string $page_layout = 'portrait';
|
||||
|
||||
public int $font_size = 16; //@implemented
|
||||
|
||||
public string $primary_font = 'Roboto';
|
||||
|
||||
public string $secondary_font = 'Roboto';
|
||||
|
||||
public string $primary_color = '#298AAB';
|
||||
|
||||
public string $secondary_color = '#7081e0';
|
||||
|
||||
public bool $page_numbering = false;
|
||||
|
||||
public string $page_numbering_alignment = 'C'; // C, R, L
|
||||
|
||||
public bool $hide_paid_to_date = false; //@TODO where?
|
||||
|
||||
public bool $embed_documents = false; //@TODO where?
|
||||
|
||||
public bool $all_pages_header = false; //@deprecated 31-05-2021
|
||||
|
||||
public bool $all_pages_footer = false; //@deprecated 31-05-2021
|
||||
|
||||
public string $pdf_variables = ''; //@implemented
|
||||
|
||||
public string $portal_custom_head = ''; //@TODO @BEN
|
||||
|
||||
public string $portal_custom_css = ''; //@TODO @BEN
|
||||
|
||||
public string $portal_custom_footer = ''; //@TODO @BEN
|
||||
|
||||
public string $portal_custom_js = ''; //@TODO @BEN
|
||||
|
||||
public bool $client_can_register = false; //@deprecated 04/06/2021
|
||||
|
||||
public string $client_portal_terms = ''; //@TODO @BEN
|
||||
|
||||
public string $client_portal_privacy_policy = ''; //@TODO @BEN
|
||||
|
||||
public bool $client_portal_enable_uploads = false; //@implemented
|
||||
|
||||
public bool $client_portal_allow_under_payment = false; //@implemented
|
||||
|
||||
public float $client_portal_under_payment_minimum = 0; //@implemented
|
||||
|
||||
public bool $client_portal_allow_over_payment = false; //@implemented
|
||||
|
||||
public string $use_credits_payment = 'off'; // always, option, off //@implemented
|
||||
|
||||
public bool $hide_empty_columns_on_pdf = false;
|
||||
|
||||
public string $email_from_name = '';
|
||||
|
||||
public bool $auto_archive_invoice_cancelled = false;
|
||||
|
||||
public bool $vendor_portal_enable_uploads = false;
|
||||
|
||||
public bool $send_email_on_mark_paid = false;
|
||||
|
||||
public string $postmark_secret = '';
|
||||
|
||||
public string $custom_sending_email = '';
|
||||
|
||||
public string $mailgun_secret = '';
|
||||
|
||||
public string $mailgun_domain = '';
|
||||
|
||||
public string $mailgun_endpoint = 'api.mailgun.net'; // api.eu.mailgun.net
|
||||
|
||||
public bool $auto_bill_standard_invoices = false;
|
||||
|
||||
public string $email_alignment = 'center'; // center, left, right
|
||||
|
||||
public bool $show_email_footer = true;
|
||||
|
||||
public string $company_logo_size = '';
|
||||
|
||||
public bool $show_paid_stamp = false;
|
||||
|
||||
public bool $show_shipping_address = false;
|
||||
|
||||
public bool $accept_client_input_quote_approval = false;
|
||||
|
||||
public bool $allow_billable_task_items = true;
|
||||
|
||||
public bool $show_task_item_description = false;
|
||||
|
||||
public bool $client_initiated_payments = false;
|
||||
|
||||
public float $client_initiated_payments_minimum = 0;
|
||||
|
||||
public bool $sync_invoice_quote_columns = true;
|
||||
|
||||
public string $e_invoice_type = 'EN16931';
|
||||
|
||||
public string $default_expense_payment_type_id = '0';
|
||||
|
||||
public bool $enable_e_invoice = false;
|
||||
|
||||
public string $classification = '';
|
||||
|
||||
private mixed $object;
|
||||
|
||||
public function cast(mixed $object)
|
||||
{
|
||||
if(is_array($object)) {
|
||||
$object = (object)$object;
|
||||
}
|
||||
|
||||
if (is_object($object)) {
|
||||
foreach ($object as $key => $value) {
|
||||
|
||||
try {
|
||||
settype($object->{$key}, gettype($this->{$key}));
|
||||
} catch(\Exception | \Error | \Throwable $e) {
|
||||
|
||||
if(property_exists($this, $key)) {
|
||||
$object->{$key} = $this->{$key};
|
||||
} else {
|
||||
unset($object->{$key});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// if(!property_exists($this, $key)) {
|
||||
// unset($object->{$key});
|
||||
// }
|
||||
// elseif(is_array($object->{$key}) && gettype($this->{$key} != 'array')){
|
||||
// $object->{$key} = $this->{$key};
|
||||
// }
|
||||
// else {
|
||||
// settype($object->{$key}, gettype($this->{$key}));
|
||||
// }
|
||||
}
|
||||
}
|
||||
$this->object = $object;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function toObject(): object
|
||||
{
|
||||
return (object)$this->object;
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
return (array)$this->object;
|
||||
}
|
||||
}
|
44
app/DataMapper/Tax/AT/Rule.php
Normal file
44
app/DataMapper/Tax/AT/Rule.php
Normal 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';
|
||||
|
||||
}
|
260
app/DataMapper/Tax/AU/Rule.php
Normal file
260
app/DataMapper/Tax/AU/Rule.php
Normal 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 || !property_exists($item, 'tax_id')) {
|
||||
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 ?? 0;
|
||||
$this->reduced_tax_rate = $this->client->company->tax_data->regions->AU->subregions->{$this->client->company->country()->iso_3166_2}->tax_rate ?? 0;
|
||||
|
||||
return $this;
|
||||
|
||||
}
|
||||
|
||||
}
|
44
app/DataMapper/Tax/BE/Rule.php
Normal file
44
app/DataMapper/Tax/BE/Rule.php
Normal 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';
|
||||
|
||||
}
|
44
app/DataMapper/Tax/BG/Rule.php
Normal file
44
app/DataMapper/Tax/BG/Rule.php
Normal 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 = 'НДС';
|
||||
|
||||
}
|
393
app/DataMapper/Tax/BaseRule.php
Normal file
393
app/DataMapper/Tax/BaseRule.php
Normal file
@ -0,0 +1,393 @@
|
||||
<?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;
|
||||
|
||||
use App\DataMapper\Tax\ZipTax\Response;
|
||||
use App\DataProviders\USStates;
|
||||
use App\Models\Client;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Product;
|
||||
|
||||
class BaseRule implements RuleInterface
|
||||
{
|
||||
/** EU TAXES */
|
||||
public bool $consumer_tax_exempt = false;
|
||||
|
||||
public bool $business_tax_exempt = true;
|
||||
|
||||
public bool $eu_business_tax_exempt = true;
|
||||
|
||||
public bool $foreign_business_tax_exempt = true;
|
||||
|
||||
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
|
||||
];
|
||||
|
||||
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 */
|
||||
|
||||
|
||||
public string $tax_name1 = '';
|
||||
public float $tax_rate1 = 0;
|
||||
|
||||
public string $tax_name2 = '';
|
||||
public float $tax_rate2 = 0;
|
||||
|
||||
public string $tax_name3 = '';
|
||||
public float $tax_rate3 = 0;
|
||||
|
||||
protected ?Client $client;
|
||||
|
||||
public ?Response $tax_data;
|
||||
|
||||
public mixed $invoice;
|
||||
|
||||
private bool $should_calc_tax = true;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
public function init(): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function shouldCalcTax(): bool
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configigures the Tax Data for the entity
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
private function configTaxData(): self
|
||||
{
|
||||
/* 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) {
|
||||
|
||||
try {
|
||||
$this->invoice->saveQuietly();
|
||||
} catch(\Exception $e) {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
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($item = null): self
|
||||
{
|
||||
|
||||
if ($this->client->is_tax_exempt || !property_exists($item, 'tax_id')) {
|
||||
|
||||
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 taxReduced($item): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function taxExempt($item): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function taxDigital($item): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function taxService($item): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function taxShipping($item): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function taxPhysical($item): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function default($item): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function override($item): self
|
||||
{
|
||||
$this->tax_rate1 = $item->tax_rate1;
|
||||
$this->tax_name1 = $item->tax_name1;
|
||||
$this->tax_rate2 = $item->tax_rate2;
|
||||
$this->tax_name2 = $item->tax_name2;
|
||||
$this->tax_rate3 = $item->tax_rate3;
|
||||
$this->tax_name3 = $item->tax_name3;
|
||||
|
||||
return $this;
|
||||
|
||||
}
|
||||
|
||||
public function calculateRates(): self
|
||||
{
|
||||
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)));
|
||||
}
|
||||
|
||||
}
|
44
app/DataMapper/Tax/CY/Rule.php
Normal file
44
app/DataMapper/Tax/CY/Rule.php
Normal 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 = 'ΦΠΑ';
|
||||
|
||||
}
|
44
app/DataMapper/Tax/CZ/Rule.php
Normal file
44
app/DataMapper/Tax/CZ/Rule.php
Normal 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';
|
||||
|
||||
}
|
254
app/DataMapper/Tax/DE/Rule.php
Normal file
254
app/DataMapper/Tax/DE/Rule.php
Normal file
@ -0,0 +1,254 @@
|
||||
<?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\DE;
|
||||
|
||||
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 = '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 = 'MwSt.';
|
||||
/**
|
||||
* 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 || !property_exists($item, 'tax_id')) {
|
||||
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 = 0;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the tax rate for a digital product
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function taxDigital($item): self
|
||||
{
|
||||
|
||||
$this->tax_rate1 = $this->tax_rate;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the tax rate for a service product
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function taxService($item): self
|
||||
{
|
||||
|
||||
$this->tax_rate1 = $this->tax_rate;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the tax rate for a shipping product
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function taxShipping($item): self
|
||||
{
|
||||
|
||||
$this->tax_rate1 = $this->tax_rate;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the tax rate for a physical product
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function taxPhysical($item): self
|
||||
{
|
||||
|
||||
$this->tax_rate1 = $this->tax_rate;
|
||||
|
||||
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) {
|
||||
// nlog("tax exempt");
|
||||
$this->tax_rate = 0;
|
||||
$this->reduced_tax_rate = 0;
|
||||
} 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)
|
||||
// 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->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;
|
||||
}
|
||||
} else {
|
||||
// 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;
|
||||
|
||||
}
|
||||
|
||||
}
|
44
app/DataMapper/Tax/DK/Rule.php
Normal file
44
app/DataMapper/Tax/DK/Rule.php
Normal 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';
|
||||
|
||||
}
|
44
app/DataMapper/Tax/EE/Rule.php
Normal file
44
app/DataMapper/Tax/EE/Rule.php
Normal 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';
|
||||
|
||||
}
|
44
app/DataMapper/Tax/ES/Rule.php
Normal file
44
app/DataMapper/Tax/ES/Rule.php
Normal 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';
|
||||
|
||||
}
|
44
app/DataMapper/Tax/FI/Rule.php
Normal file
44
app/DataMapper/Tax/FI/Rule.php
Normal 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';
|
||||
|
||||
}
|
44
app/DataMapper/Tax/FR/Rule.php
Normal file
44
app/DataMapper/Tax/FR/Rule.php
Normal 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';
|
||||
|
||||
}
|
44
app/DataMapper/Tax/GR/Rule.php
Normal file
44
app/DataMapper/Tax/GR/Rule.php
Normal 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';
|
||||
|
||||
}
|
44
app/DataMapper/Tax/HR/Rule.php
Normal file
44
app/DataMapper/Tax/HR/Rule.php
Normal 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';
|
||||
|
||||
}
|
44
app/DataMapper/Tax/HU/Rule.php
Normal file
44
app/DataMapper/Tax/HU/Rule.php
Normal 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';
|
||||
|
||||
}
|
44
app/DataMapper/Tax/IE/Rule.php
Normal file
44
app/DataMapper/Tax/IE/Rule.php
Normal 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';
|
||||
|
||||
}
|
44
app/DataMapper/Tax/IT/Rule.php
Normal file
44
app/DataMapper/Tax/IT/Rule.php
Normal 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';
|
||||
|
||||
}
|
44
app/DataMapper/Tax/LT/Rule.php
Normal file
44
app/DataMapper/Tax/LT/Rule.php
Normal 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';
|
||||
|
||||
}
|
44
app/DataMapper/Tax/LU/Rule.php
Normal file
44
app/DataMapper/Tax/LU/Rule.php
Normal 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';
|
||||
|
||||
}
|
44
app/DataMapper/Tax/LV/Rule.php
Normal file
44
app/DataMapper/Tax/LV/Rule.php
Normal 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';
|
||||
|
||||
}
|
44
app/DataMapper/Tax/MT/Rule.php
Normal file
44
app/DataMapper/Tax/MT/Rule.php
Normal 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';
|
||||
|
||||
}
|
44
app/DataMapper/Tax/NL/Rule.php
Normal file
44
app/DataMapper/Tax/NL/Rule.php
Normal 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';
|
||||
|
||||
}
|
44
app/DataMapper/Tax/PT/Rule.php
Normal file
44
app/DataMapper/Tax/PT/Rule.php
Normal 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';
|
||||
|
||||
}
|
44
app/DataMapper/Tax/RO/Rule.php
Normal file
44
app/DataMapper/Tax/RO/Rule.php
Normal 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';
|
||||
|
||||
}
|
39
app/DataMapper/Tax/RuleInterface.php
Normal file
39
app/DataMapper/Tax/RuleInterface.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?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;
|
||||
|
||||
interface RuleInterface
|
||||
{
|
||||
public function init();
|
||||
|
||||
public function tax($item);
|
||||
|
||||
public function taxByType($type);
|
||||
|
||||
public function taxExempt($item);
|
||||
|
||||
public function taxDigital($item);
|
||||
|
||||
public function taxService($item);
|
||||
|
||||
public function taxShipping($item);
|
||||
|
||||
public function taxPhysical($item);
|
||||
|
||||
public function taxReduced($item);
|
||||
|
||||
public function default($item);
|
||||
|
||||
public function override($item);
|
||||
|
||||
public function calculateRates();
|
||||
}
|
44
app/DataMapper/Tax/SE/Rule.php
Normal file
44
app/DataMapper/Tax/SE/Rule.php
Normal 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';
|
||||
|
||||
}
|
44
app/DataMapper/Tax/SI/Rule.php
Normal file
44
app/DataMapper/Tax/SI/Rule.php
Normal 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';
|
||||
|
||||
}
|
44
app/DataMapper/Tax/SK/Rule.php
Normal file
44
app/DataMapper/Tax/SK/Rule.php
Normal 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';
|
||||
|
||||
}
|
31
app/DataMapper/Tax/TaxData.php
Normal file
31
app/DataMapper/Tax/TaxData.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?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;
|
||||
|
||||
use App\DataMapper\Tax\ZipTax\Response;
|
||||
|
||||
/**
|
||||
* InvoiceTaxData
|
||||
*
|
||||
* Definition for the invoice tax data structure
|
||||
*/
|
||||
class TaxData
|
||||
{
|
||||
public int $updated_at;
|
||||
|
||||
public function __construct(public Response $origin)
|
||||
{
|
||||
foreach($origin as $key => $value) {
|
||||
$this->{$key} = $value;
|
||||
}
|
||||
}
|
||||
}
|
512
app/DataMapper/Tax/TaxModel.php
Normal file
512
app/DataMapper/Tax/TaxModel.php
Normal file
@ -0,0 +1,512 @@
|
||||
<?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;
|
||||
|
||||
class TaxModel
|
||||
{
|
||||
|
||||
/** @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)
|
||||
{
|
||||
|
||||
if(!$this->model) {
|
||||
$this->regions = $this->init();
|
||||
} else {
|
||||
$this->regions = $model;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()
|
||||
->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;
|
||||
$this->regions->US->tax_all_subregions = false;
|
||||
$this->usSubRegions();
|
||||
|
||||
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->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->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->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->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->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->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->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->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->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->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->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->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->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->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->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->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->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->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->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->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->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->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->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->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->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->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->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->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;
|
||||
|
||||
}
|
||||
|
||||
}
|
226
app/DataMapper/Tax/US/Rule.php
Normal file
226
app/DataMapper/Tax/US/Rule.php
Normal file
@ -0,0 +1,226 @@
|
||||
<?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\US;
|
||||
|
||||
use App\DataMapper\Tax\BaseRule;
|
||||
use App\DataMapper\Tax\RuleInterface;
|
||||
use App\Models\Product;
|
||||
|
||||
/**
|
||||
* 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
|
||||
{
|
||||
|
||||
/** @var string $seller_region */
|
||||
public string $seller_region = 'US';
|
||||
|
||||
/**
|
||||
* Initializes the rules and builds any required data.
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function init(): self
|
||||
{
|
||||
$this->calculateRates();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override tax class, we use this when we do not modify the input taxes
|
||||
*
|
||||
* @param mixed $item
|
||||
* @return self
|
||||
*/
|
||||
public function override($item): self
|
||||
{
|
||||
|
||||
$this->tax_rate1 = $item->tax_rate1;
|
||||
$this->tax_name1 = $item->tax_name1;
|
||||
$this->tax_rate2 = $item->tax_rate2;
|
||||
$this->tax_name2 = $item->tax_name2;
|
||||
$this->tax_rate3 = $item->tax_rate3;
|
||||
$this->tax_name3 = $item->tax_name3;
|
||||
|
||||
return $this;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the correct tax rate based on the product type.
|
||||
*
|
||||
* @param mixed $item
|
||||
* @return self
|
||||
*/
|
||||
public function taxByType($item): self
|
||||
{
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the tax rate for a digital product
|
||||
* @param mixed $item
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function taxDigital($item): self
|
||||
{
|
||||
$this->default($item);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the tax rate for a service product
|
||||
* @param mixed $item
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function taxService($item): self
|
||||
{
|
||||
if(in_array($this->tax_data?->txbService, ['Y','L'])) {
|
||||
$this->default($item);
|
||||
} else {
|
||||
$this->taxExempt($item);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the tax rate for a shipping product
|
||||
* @param mixed $item
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function taxShipping($item): self
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the tax rate for an undefined product uses the default tax rate for the client county
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function default($item): self
|
||||
{
|
||||
|
||||
if($this->tax_data?->stateSalesTax == 0) {
|
||||
|
||||
$this->tax_rate1 = 0;
|
||||
$this->tax_name1 = '';
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->tax_rate1 = $this->tax_data->taxSales * 100;
|
||||
$this->tax_name1 = "Sales Tax";
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function zeroRated($item): self
|
||||
{
|
||||
|
||||
$this->tax_rate1 = 0;
|
||||
$this->tax_name1 = "{$this->tax_data->geoState} Zero Rated Tax";
|
||||
|
||||
return $this;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
116
app/DataMapper/Tax/ZipTax/Response.php
Normal file
116
app/DataMapper/Tax/ZipTax/Response.php
Normal file
@ -0,0 +1,116 @@
|
||||
<?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\ZipTax;
|
||||
|
||||
class Response
|
||||
{
|
||||
public string $version = 'v40';
|
||||
|
||||
public int $rCode = 100;
|
||||
|
||||
/**
|
||||
* [
|
||||
* "geoPostalCode" => "92582",
|
||||
* "geoCity" => "SAN JACINTO",
|
||||
* "geoCounty" => "RIVERSIDE",
|
||||
* "geoState" => "CA",
|
||||
* "taxSales" => 0.0875,
|
||||
* "taxUse" => 0.0875,
|
||||
* "txbService" => "N",
|
||||
* "txbFreight" => "N",
|
||||
* "stateSalesTax" => 0.06,
|
||||
* "stateUseTax" => 0.06,
|
||||
* "citySalesTax" => 0.01,
|
||||
* "cityUseTax" => 0.01,
|
||||
* "cityTaxCode" => "874",
|
||||
* "countySalesTax" => 0.0025,
|
||||
* "countyUseTax" => 0.0025,
|
||||
* "countyTaxCode" => "",
|
||||
* "districtSalesTax" => 0.015,
|
||||
* "districtUseTax" => 0.015,
|
||||
* "district1Code" => "26",
|
||||
* "district1SalesTax" => 0,
|
||||
* "district1UseTax" => 0,
|
||||
* "district2Code" => "26",
|
||||
* "district2SalesTax" => 0.005,
|
||||
* "district2UseTax" => 0.005,
|
||||
* "district3Code" => "",
|
||||
* "district3SalesTax" => 0,
|
||||
* "district3UseTax" => 0,
|
||||
* "district4Code" => "33",
|
||||
* "district4SalesTax" => 0.01,
|
||||
* "district4UseTax" => 0.01,
|
||||
* "district5Code" => "",
|
||||
* "district5SalesTax" => 0,
|
||||
* "district5UseTax" => 0,
|
||||
* "originDestination" => "D",
|
||||
*
|
||||
* ];
|
||||
*
|
||||
*/
|
||||
public string $seller_subregion = "";
|
||||
//US
|
||||
|
||||
public string $geoPostalCode = "";
|
||||
public string $geoCity = "";
|
||||
public string $geoCounty = "";
|
||||
public string $geoState = "";
|
||||
public float $taxSales = 0;
|
||||
public string $taxName = "";
|
||||
public float $taxUse = 0;
|
||||
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 = "";
|
||||
public float $districtSalesTax = 0;
|
||||
public float $districtUseTax = 0;
|
||||
public string $district1Code = "";
|
||||
public float $district1SalesTax = 0;
|
||||
public float $district1UseTax = 0;
|
||||
public string $district2Code = "";
|
||||
public float $district2SalesTax = 0;
|
||||
public float $district2UseTax = 0;
|
||||
public string $district3Code = "";
|
||||
public float $district3SalesTax = 0;
|
||||
public float $district3UseTax = 0;
|
||||
public string $district4Code = "";
|
||||
public float $district4SalesTax = 0;
|
||||
public float $district4UseTax = 0;
|
||||
public string $district5Code = "";
|
||||
public float $district5SalesTax = 0;
|
||||
public float $district5UseTax = 0;
|
||||
/* US SPECIFIC TAX CODES */
|
||||
|
||||
public string $originDestination = "D"; // defines if the client origin is the locale where the tax is remitted to
|
||||
|
||||
public function __construct($data = null)
|
||||
{
|
||||
|
||||
if($data) {
|
||||
|
||||
foreach($data as $key => $value) {
|
||||
$this->{$key} = $value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
219
app/DataMapper/Tax/tax_model.yaml
Normal file
219
app/DataMapper/Tax/tax_model.yaml
Normal file
@ -0,0 +1,219 @@
|
||||
region:
|
||||
US:
|
||||
tax_all_subregions: false
|
||||
seller_subregion: CA
|
||||
has_sales_above_threshold: false
|
||||
subregions:
|
||||
AL:
|
||||
apply_tax: false
|
||||
AK:
|
||||
apply_tax: false
|
||||
AZ:
|
||||
apply_tax: false
|
||||
AR:
|
||||
apply_tax: false
|
||||
CA:
|
||||
apply_tax: false
|
||||
CO:
|
||||
apply_tax: false
|
||||
CT:
|
||||
apply_tax: false
|
||||
DE:
|
||||
apply_tax: false
|
||||
FL:
|
||||
apply_tax: false
|
||||
GA:
|
||||
apply_tax: false
|
||||
HI:
|
||||
apply_tax: false
|
||||
ID:
|
||||
apply_tax: false
|
||||
IL:
|
||||
apply_tax: false
|
||||
IN:
|
||||
apply_tax: false
|
||||
IA:
|
||||
apply_tax: false
|
||||
KS:
|
||||
apply_tax: false
|
||||
KY:
|
||||
apply_tax: false
|
||||
LA:
|
||||
apply_tax: false
|
||||
ME:
|
||||
apply_tax: false
|
||||
MD:
|
||||
apply_tax: false
|
||||
MA:
|
||||
apply_tax: false
|
||||
MI:
|
||||
apply_tax: false
|
||||
MN:
|
||||
apply_tax: false
|
||||
MS:
|
||||
apply_tax: false
|
||||
MO:
|
||||
apply_tax: false
|
||||
MT:
|
||||
apply_tax: false
|
||||
NE:
|
||||
apply_tax: false
|
||||
NV:
|
||||
apply_tax: false
|
||||
NH:
|
||||
apply_tax: false
|
||||
NJ:
|
||||
apply_tax: false
|
||||
NM:
|
||||
apply_tax: false
|
||||
NY:
|
||||
apply_tax: false
|
||||
NC:
|
||||
apply_tax: false
|
||||
ND:
|
||||
apply_tax: false
|
||||
OH:
|
||||
apply_tax: false
|
||||
OK:
|
||||
apply_tax: false
|
||||
OR:
|
||||
apply_tax: false
|
||||
PA:
|
||||
apply_tax: false
|
||||
RI:
|
||||
apply_tax: false
|
||||
SC:
|
||||
apply_tax: false
|
||||
SD:
|
||||
apply_tax: false
|
||||
TN:
|
||||
apply_tax: false
|
||||
TX:
|
||||
apply_tax: false
|
||||
UT:
|
||||
apply_tax: false
|
||||
VT:
|
||||
apply_tax: false
|
||||
VA:
|
||||
apply_tax: false
|
||||
WA:
|
||||
apply_tax: false
|
||||
WV:
|
||||
apply_tax: false
|
||||
WI:
|
||||
apply_tax: false
|
||||
WY:
|
||||
apply_tax: false
|
||||
EU:
|
||||
tax_all: false
|
||||
tax_threshold: 10000
|
||||
has_sales_above_threshold: false
|
||||
subregions:
|
||||
AT:
|
||||
vat: 21
|
||||
reduced_vat: 11
|
||||
apply_tax: false
|
||||
BE:
|
||||
vat: 21
|
||||
reduced_vat: 6
|
||||
apply_tax: false
|
||||
BG:
|
||||
vat: 20
|
||||
reduced_vat: 9
|
||||
apply_tax: false
|
||||
CY:
|
||||
vat: 19
|
||||
reduced_vat: 9
|
||||
apply_tax: false
|
||||
CZ:
|
||||
vat: 21
|
||||
reduced_vat: 15
|
||||
apply_tax: false
|
||||
DE:
|
||||
vat: 19
|
||||
reduced_vat: 7
|
||||
apply_tax: false
|
||||
DK:
|
||||
vat: 25
|
||||
reduced_vat: 0
|
||||
apply_tax: false
|
||||
EE:
|
||||
vat: 20
|
||||
reduced_vat: 9
|
||||
apply_tax: false
|
||||
ES:
|
||||
vat: 21
|
||||
reduced_vat: 10
|
||||
apply_tax: false
|
||||
FI:
|
||||
vat: 24
|
||||
reduced_vat: 14
|
||||
apply_tax: false
|
||||
FR:
|
||||
vat: 20
|
||||
reduced_vat: 5.5
|
||||
apply_tax: false
|
||||
GB:
|
||||
vat: 20
|
||||
reduced_vat: 0
|
||||
apply_tax: false
|
||||
GR:
|
||||
vat: 24
|
||||
reduced_vat: 13
|
||||
apply_tax: false
|
||||
HR:
|
||||
vat: 25
|
||||
reduced_vat: 5
|
||||
apply_tax: false
|
||||
HU:
|
||||
vat: 27
|
||||
reduced_vat: 5
|
||||
apply_tax: false
|
||||
IE:
|
||||
vat: 23
|
||||
reduced_vat: 0
|
||||
apply_tax: false
|
||||
IT:
|
||||
vat: 22
|
||||
reduced_vat: 10
|
||||
apply_tax: false
|
||||
LT:
|
||||
vat: 21
|
||||
reduced_vat: 9
|
||||
apply_tax: false
|
||||
LU:
|
||||
vat: 17
|
||||
reduced_vat: 3
|
||||
apply_tax: false
|
||||
LV:
|
||||
vat: 21
|
||||
reduced_vat: 12
|
||||
apply_tax: false
|
||||
MT:
|
||||
vat: 18
|
||||
reduced_vat: 5
|
||||
apply_tax: false
|
||||
NL:
|
||||
vat: 21
|
||||
reduced_vat: 9
|
||||
apply_tax: false
|
||||
PT:
|
||||
vat: 23
|
||||
reduced_vat: 6
|
||||
apply_tax: false
|
||||
RO:
|
||||
vat: 19
|
||||
reduced_vat: 5
|
||||
apply_tax: false
|
||||
SE:
|
||||
vat: 25
|
||||
reduced_vat: 12
|
||||
apply_tax: false
|
||||
SI:
|
||||
vat: 22
|
||||
reduced_vat: 9.5
|
||||
apply_tax: false
|
||||
SK:
|
||||
vat: 20
|
||||
reduced_vat: 10
|
||||
apply_tax: false
|
@ -11,10 +11,6 @@
|
||||
|
||||
namespace App\DataMapper\Transactions;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Models\Credit;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\TransactionEvent;
|
||||
|
||||
/**
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user