1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-10 13:12:50 +01:00

Merge pull request #8473 from turbo124/v5-develop

FIxes for show_credits_tables
This commit is contained in:
David Bomba 2023-04-26 14:55:17 +10:00 committed by GitHub
commit e1eeabe700
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 297 additions and 184 deletions

View File

@ -1 +1 @@
5.5.107
5.5.108

View File

@ -235,7 +235,7 @@ class BaseRule implements RuleInterface
return $this;
} elseif($this->isTaxableRegion()) { //other regions outside of US
match($item->tax_id) {
match(intval($item->tax_id)) {
Product::PRODUCT_TYPE_EXEMPT => $this->taxExempt(),
Product::PRODUCT_TYPE_REDUCED_TAX => $this->taxReduced(),
Product::PRODUCT_TYPE_OVERRIDE_TAX => $this->override(),

View File

@ -66,7 +66,7 @@ class Rule extends BaseRule implements RuleInterface
return $this->taxExempt();
}
match($product_tax_type){
match(intval($product_tax_type)){
Product::PRODUCT_TYPE_EXEMPT => $this->taxExempt(),
Product::PRODUCT_TYPE_DIGITAL => $this->taxDigital(),
Product::PRODUCT_TYPE_SERVICE => $this->taxService(),

View File

@ -57,7 +57,7 @@ class Rule extends BaseRule implements RuleInterface
public function taxByType($product_tax_type): self
{
match($product_tax_type) {
match(intval($product_tax_type)) {
Product::PRODUCT_TYPE_EXEMPT => $this->taxExempt(),
Product::PRODUCT_TYPE_DIGITAL => $this->taxDigital(),
Product::PRODUCT_TYPE_SERVICE => $this->taxService(),
@ -103,7 +103,7 @@ class Rule extends BaseRule implements RuleInterface
*/
public function taxService(): self
{
if($this->tax_data->txbService == 'Y') {
if($this->tax_data?->txbService == 'Y') {
$this->default();
}
@ -117,7 +117,7 @@ class Rule extends BaseRule implements RuleInterface
*/
public function taxShipping(): self
{
if($this->tax_data->txbFreight == 'Y') {
if($this->tax_data?->txbFreight == 'Y') {
$this->default();
}

View File

@ -668,7 +668,7 @@ class BaseController extends Controller
* Passes back the miniloaded data response
*
* @param Builder $query
* @return void
*
*/
protected function timeConstrainedResponse($query)
{

View File

@ -64,7 +64,6 @@ class ChartController extends BaseController
* ),
* )
* @param Request $request
* @return Response|mixed
*/
public function totals(ShowChartRequest $request)
{

View File

@ -574,7 +574,7 @@ class ClientController extends BaseController
/**
* Update the specified resource in storage.
*
* @param UploadClientRequest $request
* @param PurgeClientRequest $request
* @param Client $client
* @return Response
*
@ -644,7 +644,7 @@ class ClientController extends BaseController
*
* @param PurgeClientRequest $request
* @param Client $client
* @param string $mergeable client hashed_id
* @param string $mergeable_client
* @return Response
*
*

View File

@ -46,20 +46,15 @@ class ClientGatewayTokenController extends BaseController
protected $entity_transformer = ClientGatewayTokenTransformer::class;
/**
* @var ClientGatewayTokenRepository
*/
protected $client_gateway_token_gateway_token_repo;
/**
* ClientGatewayTokenController constructor.
* @param ClientGatewayTokenRepository $client_gateway_token_gateway_token_repo
* @param ClientGatewayTokenRepository $client_gateway_token_repo
*/
public function __construct(ClientGatewayTokenRepository $client_gateway_token_gateway_token_repo)
public function __construct(protected ClientGatewayTokenRepository $client_gateway_token_repo)
{
parent::__construct();
$this->client_gateway_token_repo = $client_gateway_token_gateway_token_repo;
$this->client_gateway_token_repo = $client_gateway_token_repo;
}
/**
@ -69,8 +64,7 @@ class ClientGatewayTokenController extends BaseController
* tags={"client_gateway_tokens"},
* summary="Gets a list of client_gateway_tokens",
* description="Lists client_gateway_tokens, search and filters allow fine grained lists to be generated.
Query parameters can be added to performed more fine grained filtering of the client_gateway_tokens, these are handled by the ClientGatewayTokenFilters class which defines the methods available",
* Query parameters can be added to performed more fine grained filtering of the client_gateway_tokens, these are handled by the ClientGatewayTokenFilters class which defines the methods available",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
@ -94,7 +88,7 @@ class ClientGatewayTokenController extends BaseController
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
* @param ClientGatewayTokenFilters $filters
* @param ListClientGatewayTokenRequest $request
* @return Response|mixed
*/
public function index(ListClientGatewayTokenRequest $request)

View File

@ -11,17 +11,18 @@
namespace App\Http\Controllers\ClientPortal;
use App\Http\Controllers\Controller;
use App\Http\ViewComposers\PortalComposer;
use App\Models\RecurringInvoice;
use Auth;
use App\Models\RecurringInvoice;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Redirect;
use App\Http\ViewComposers\PortalComposer;
class ContactHashLoginController extends Controller
{
/**
* Logs a user into the client portal using their contact_key
* @param string $contact_key The contact key
* @return Auth|Redirect
* @return Redirect
*/
public function login(string $contact_key)
{

View File

@ -187,7 +187,6 @@ class InvoiceController extends Controller
*
* @param array $ids
*
* @return void
*/
private function downloadInvoicePDF(array $ids)
{

View File

@ -39,7 +39,7 @@ class StatementController extends Controller
public function raw(ShowStatementRequest $request)
{
$pdf = $request->client()->service()->statement(
$request->only(['start_date', 'end_date', 'show_payments_table', 'show_aging_table', 'status'])
$request->only(['start_date', 'end_date', 'show_payments_table', 'show_aging_table', 'show_credits_table', 'status'])
);
if ($pdf && $request->query('download')) {

View File

@ -24,7 +24,7 @@ class SubscriptionPlanSwitchController extends Controller
*
* @param ShowPlanSwitchRequest $request
* @param RecurringInvoice $recurring_invoice
* @param string $target
* @param Subscription $target
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function index(ShowPlanSwitchRequest $request, RecurringInvoice $recurring_invoice, Subscription $target)

View File

@ -11,16 +11,17 @@
namespace App\Http\Controllers\ClientPortal;
use App\Http\Controllers\Controller;
use Auth;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Redirect;
class TempRouteController extends Controller
{
/**
* Logs a user into the client portal using their contact_key
* @param string $contact_key The contact key
* @return Auth|Redirect
* @param string $hash The hash
* @return Redirect
*/
public function index(string $hash)
{

View File

@ -11,9 +11,10 @@
namespace App\Http\Controllers;
use App\Http\Requests\Statements\CreateStatementRequest;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\Pdf\PdfMaker;
use Illuminate\Support\Facades\Response;
use App\Http\Requests\Statements\CreateStatementRequest;
class ClientStatementController extends BaseController
{
@ -32,71 +33,6 @@ class ClientStatementController extends BaseController
*
* @param CreateStatementRequest $request
* @return Response
*
* @OA\Post(
* path="/api/v1/client_statement",
* operationId="clientStatement",
* tags={"clients"},
* summary="Return a PDF of the client statement",
* description="Return a PDF of the client statement",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\RequestBody(
* description="Statment Options",
* required=true,
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(
* property="start_date",
* description="The start date of the statement period - format Y-m-d",
* type="string",
* ),
* @OA\Property(
* property="end_date",
* description="The start date of the statement period - format Y-m-d",
* type="string",
* ),
* @OA\Property(
* property="client_id",
* description="The hashed ID of the client",
* type="string",
* ),
* @OA\Property(
* property="show_payments_table",
* description="Flag which determines if the payments table is shown",
* type="boolean",
* ),
* @OA\Property(
* property="show_aging_table",
* description="Flag which determines if the aging table is shown",
* type="boolean",
* )
* )
* )
* ),
* @OA\Response(
* response=200,
* description="Returns the client object",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
* @OA\JsonContent(ref="#/components/schemas/Client"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function statement(CreateStatementRequest $request)
{

View File

@ -603,7 +603,7 @@ class CompanyController extends BaseController
* Update the specified resource in storage.
*
* @param UploadCompanyRequest $request
* @param Company $client
* @param Company $company
* @return Response
*
*

View File

@ -39,6 +39,7 @@ class ShowStatementRequest extends FormRequest
$this->merge([
'show_payments_table' => $this->has('show_payments_table') ? \boolval($this->show_payments_table) : false,
'show_aging_table' => $this->has('show_aging_table') ? \boolval($this->show_aging_table) : false,
'show_credits_table' => $this->has('show_credits_table') ? \boolval($this->show_credits_table) : false,
]);
}

View File

@ -51,6 +51,7 @@ class CreateStatementRequest extends Request
$this->merge([
'show_payments_table' => $this->has('show_payments_table') ? \boolval($this->show_payments_table) : false,
'show_aging_table' => $this->has('show_aging_table') ? \boolval($this->show_aging_table) : false,
'show_credits_table' => $this->has('show_credits_table') ? \boolval($this->show_credits_table) : false,
]);
}

View File

@ -22,7 +22,6 @@ class CreateAccountActivity implements ShouldQueue
/**
* Create the event listener.
*
* @param ActivityRepository $activity_repo
*/
public function __construct()
{

View File

@ -4,7 +4,6 @@ namespace App\Listeners\Document;
use App\Libraries\MultiDB;
use App\Models\Document;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Support\Facades\Storage;
class DeleteCompanyDocuments
@ -31,10 +30,6 @@ class DeleteCompanyDocuments
$path = sprintf('%s/%s', public_path('storage'), $event->company->company_key);
// Remove all files & folders, under company's path.
// This will delete directory itself, as well.
// In case we want to remove the content of folder, we should use $fs->cleanDirectory();
//$filesystem = new Filesystem();
Storage::deleteDirectory($event->company->company_key);
Document::whereCompanyId($event->company->id)->delete();

View File

@ -310,7 +310,6 @@ use Laracasts\Presenter\PresentableTrait;
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\SystemLog> $system_logs
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Task> $tasks
* @property int $has_valid_vat_number
* @property string $leitweg_id
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Activity> $activities
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CompanyLedger> $company_ledger
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\ClientContact> $contacts

View File

@ -18,7 +18,6 @@ use App\Utils\Ninja;
use App\Utils\Traits\AppSetup;
use App\Utils\Traits\CompanySettingsSaver;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\ThrottlesEmail;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Notifications\Notification;
@ -785,7 +784,6 @@ class Company extends BaseModel
use PresentableTrait;
use MakesHash;
use CompanySettingsSaver;
use ThrottlesEmail;
use AppSetup;
use \Awobaz\Compoships\Compoships;

View File

@ -66,8 +66,9 @@ class EmailStatementService
return [
'start_date' =>$start_end[0],
'end_date' =>$start_end[1],
'show_payments_table' => $this->scheduler->parameters['show_payments_table'],
'show_aging_table' => $this->scheduler->parameters['show_aging_table'],
'show_payments_table' => $this->scheduler->parameters['show_payments_table'] ?? true,
'show_aging_table' => $this->scheduler->parameters['show_aging_table'] ?? true,
'show_credits_table' => $this->scheduler->parameters['show_credits_table'] ?? true,
'status' => $this->scheduler->parameters['status']
];
}

View File

@ -1,72 +0,0 @@
<?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\Utils\Traits;
use App\Models\Company;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Mail;
/**
* Class ThrottlesEmail.
*/
trait ThrottlesEmail
{
public function getDailyEmailLimit(Company $company)
{
$limit = config('ninja.daily_email_limit');
$limit += $company->created_at->diffInMonths() * 100;
return min($limit, 5000);
}
public function isThrottled(Company $company)
{
$key = $company->company_key;
// http://stackoverflow.com/questions/1375501/how-do-i-throttle-my-sites-api-users
$day = 60 * 60 * 24;
$day_limit = $this->getDailyEmailLimit($company);
$day_throttle = Cache::get("email_day_throttle:{$key}", null);
$last_api_request = Cache::get("last_email_request:{$key}", 0);
$last_api_diff = time() - $last_api_request;
if (is_null($day_throttle)) {
$new_day_throttle = 0;
} else {
$new_day_throttle = $day_throttle - $last_api_diff;
$new_day_throttle = $new_day_throttle < 0 ? 0 : $new_day_throttle;
$new_day_throttle += $day / $day_limit;
$day_hits_remaining = floor(($day - $new_day_throttle) * $day_limit / $day);
$day_hits_remaining = $day_hits_remaining >= 0 ? $day_hits_remaining : 0;
}
Cache::put("email_day_throttle:{$key}", $new_day_throttle, 60);
Cache::put("last_email_request:{$key}", time(), 60);
if ($new_day_throttle > $day) {
$error_email = config('ninja.error_email');
if ($error_email && ! Cache::get("throttle_notified:{$key}")) {
Mail::raw('Account Throttle: '.$company->company_key, function ($message) use ($error_email, $company) {
$message->to($error_email)
->from(config('ninja.contact.email'))
->subject('Email throttle triggered for company '.$company->id);
});
}
Cache::put("throttle_notified:{$key}", true, 60 * 24);
return true;
}
return false;
}
}

View File

@ -108,6 +108,7 @@
"laravel/dusk": "^6.15",
"mockery/mockery": "^1.4.4",
"nunomaduro/collision": "^6.1",
"nunomaduro/larastan": "^2.0",
"phpstan/phpstan": "^1.9",
"phpunit/phpunit": "^9.5.10",
"spatie/laravel-ignition": "^1.0",

185
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "7482363bb2c3f9f8fb07bbd3d517597b",
"content-hash": "8c21eb3ea2c2baeecb223d5fdbc8423c",
"packages": [
{
"name": "adrienrn/php-mimetyper",
@ -15445,6 +15445,102 @@
],
"time": "2023-01-03T12:54:54+00:00"
},
{
"name": "nunomaduro/larastan",
"version": "v2.6.0",
"source": {
"type": "git",
"url": "https://github.com/nunomaduro/larastan.git",
"reference": "ccac5b25949576807862cf32ba1fce1769c06c42"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nunomaduro/larastan/zipball/ccac5b25949576807862cf32ba1fce1769c06c42",
"reference": "ccac5b25949576807862cf32ba1fce1769c06c42",
"shasum": ""
},
"require": {
"ext-json": "*",
"illuminate/console": "^9.47.0 || ^10.0.0",
"illuminate/container": "^9.47.0 || ^10.0.0",
"illuminate/contracts": "^9.47.0 || ^10.0.0",
"illuminate/database": "^9.47.0 || ^10.0.0",
"illuminate/http": "^9.47.0 || ^10.0.0",
"illuminate/pipeline": "^9.47.0 || ^10.0.0",
"illuminate/support": "^9.47.0 || ^10.0.0",
"php": "^8.0.2",
"phpmyadmin/sql-parser": "^5.6.0",
"phpstan/phpstan": "~1.10.6"
},
"require-dev": {
"nikic/php-parser": "^4.15.2",
"orchestra/testbench": "^7.19.0 || ^8.0.0",
"phpunit/phpunit": "^9.5.27"
},
"suggest": {
"orchestra/testbench": "Using Larastan for analysing a package needs Testbench"
},
"type": "phpstan-extension",
"extra": {
"branch-alias": {
"dev-master": "2.0-dev"
},
"phpstan": {
"includes": [
"extension.neon"
]
}
},
"autoload": {
"psr-4": {
"NunoMaduro\\Larastan\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nuno Maduro",
"email": "enunomaduro@gmail.com"
}
],
"description": "Larastan - Discover bugs in your code without running it. A phpstan/phpstan wrapper for Laravel",
"keywords": [
"PHPStan",
"code analyse",
"code analysis",
"larastan",
"laravel",
"package",
"php",
"static analysis"
],
"support": {
"issues": "https://github.com/nunomaduro/larastan/issues",
"source": "https://github.com/nunomaduro/larastan/tree/v2.6.0"
},
"funding": [
{
"url": "https://www.paypal.com/paypalme/enunomaduro",
"type": "custom"
},
{
"url": "https://github.com/canvural",
"type": "github"
},
{
"url": "https://github.com/nunomaduro",
"type": "github"
},
{
"url": "https://www.patreon.com/nunomaduro",
"type": "patreon"
}
],
"time": "2023-04-20T12:40:01+00:00"
},
{
"name": "openlss/lib-array2xml",
"version": "1.0.0",
@ -15843,6 +15939,93 @@
},
"time": "2023-03-27T19:02:04+00:00"
},
{
"name": "phpmyadmin/sql-parser",
"version": "5.7.0",
"source": {
"type": "git",
"url": "https://github.com/phpmyadmin/sql-parser.git",
"reference": "0f5895aab2b6002d00b6831b60983523dea30bff"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpmyadmin/sql-parser/zipball/0f5895aab2b6002d00b6831b60983523dea30bff",
"reference": "0f5895aab2b6002d00b6831b60983523dea30bff",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0",
"symfony/polyfill-mbstring": "^1.3",
"symfony/polyfill-php80": "^1.16"
},
"conflict": {
"phpmyadmin/motranslator": "<3.0"
},
"require-dev": {
"phpbench/phpbench": "^1.1",
"phpmyadmin/coding-standard": "^3.0",
"phpmyadmin/motranslator": "^4.0 || ^5.0",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^1.9.12",
"phpstan/phpstan-phpunit": "^1.3.3",
"phpunit/php-code-coverage": "*",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
"psalm/plugin-phpunit": "^0.16.1",
"vimeo/psalm": "^4.11",
"zumba/json-serializer": "^3.0"
},
"suggest": {
"ext-mbstring": "For best performance",
"phpmyadmin/motranslator": "Translate messages to your favorite locale"
},
"bin": [
"bin/highlight-query",
"bin/lint-query",
"bin/tokenize-query"
],
"type": "library",
"autoload": {
"psr-4": {
"PhpMyAdmin\\SqlParser\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"GPL-2.0-or-later"
],
"authors": [
{
"name": "The phpMyAdmin Team",
"email": "developers@phpmyadmin.net",
"homepage": "https://www.phpmyadmin.net/team/"
}
],
"description": "A validating SQL lexer and parser with a focus on MySQL dialect.",
"homepage": "https://github.com/phpmyadmin/sql-parser",
"keywords": [
"analysis",
"lexer",
"parser",
"query linter",
"sql",
"sql lexer",
"sql linter",
"sql parser",
"sql syntax highlighter",
"sql tokenizer"
],
"support": {
"issues": "https://github.com/phpmyadmin/sql-parser/issues",
"source": "https://github.com/phpmyadmin/sql-parser"
},
"funding": [
{
"url": "https://www.phpmyadmin.net/donate/",
"type": "other"
}
],
"time": "2023-01-25T10:43:40+00:00"
},
{
"name": "phpstan/phpstan",
"version": "1.10.13",

View File

@ -15,8 +15,8 @@ return [
'require_https' => env('REQUIRE_HTTPS', true),
'app_url' => rtrim(env('APP_URL', ''), '/'),
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
'app_version' => '5.5.107',
'app_tag' => '5.5.107',
'app_version' => '5.5.108',
'app_tag' => '5.5.108',
'minimum_client_version' => '5.0.16',
'terms_version' => '1.0.1',
'api_secret' => env('API_SECRET', ''),

View File

@ -1,4 +1,9 @@
includes:
- ./vendor/nunomaduro/larastan/extension.neon
parameters:
ignoreErrors:
- '#Call to an undefined method .*badMethod\(\)#'
level: 2
paths:
- app

View File

@ -147,6 +147,77 @@ class UsTaxTest extends TestCase
return $invoice;
}
public function testSameSubregionAndExemptProduct()
{
$settings = CompanySettings::defaults();
$settings->country_id = '840'; // germany
$tax_data = new TaxModel();
$tax_data->seller_subregion = 'CA';
$tax_data->regions->US->has_sales_above_threshold = true;
$tax_data->regions->US->tax_all_subregions = true;
$tax_data->regions->EU->has_sales_above_threshold = true;
$tax_data->regions->EU->tax_all_subregions = true;
$tax_data->regions->EU->subregions->DE->tax_rate = 21;
$company = Company::factory()->create([
'account_id' => $this->account->id,
'settings' => $settings,
'tax_data' => $tax_data,
'calculate_taxes' => true,
]);
$client = Client::factory()->create([
'user_id' => $this->user->id,
'company_id' => $company->id,
'country_id' => 840,
'postal_code' => '90210',
'shipping_country_id' => 840,
'shipping_postal_code' => '90210',
'has_valid_vat_number' => false,
'postal_code' => 'xx',
'is_tax_exempt' => false,
]);
$invoice = Invoice::factory()->create([
'company_id' => $company->id,
'client_id' => $client->id,
'status_id' => 1,
'user_id' => $this->user->id,
'uses_inclusive_taxes' => false,
'discount' => 0,
'line_items' => [
[
'product_key' => 'Test',
'notes' => 'Test',
'cost' => 100,
'quantity' => 1,
'tax_name1' => '',
'tax_rate1' => 0,
'tax_name2' => '',
'tax_rate2' => 0,
'tax_name3' => '',
'tax_rate3' => 0,
'type_id' => '1',
'tax_id' => Product::PRODUCT_TYPE_EXEMPT,
],
],
'tax_rate1' => 0,
'tax_rate2' => 0,
'tax_rate3' => 0,
'tax_name1' => '',
'tax_name2' => '',
'tax_name3' => '',
'tax_data' => new Response($this->mock_response),
]);
$invoice = $invoice->calc()->getInvoice()->service()->markSent()->save();
$this->assertEquals(100, $invoice->amount);
}
public function testForeignTaxesEnabledWithExemptProduct()
{
$settings = CompanySettings::defaults();
@ -174,6 +245,7 @@ class UsTaxTest extends TestCase
'shipping_country_id' => 276,
'has_valid_vat_number' => false,
'postal_code' => 'xx',
'is_tax_exempt' => false,
]);
$invoice = Invoice::factory()->create([