diff --git a/app/DataMapper/InvoiceItem.php b/app/DataMapper/InvoiceItem.php index 228d2d0d5577..49571d668fdf 100644 --- a/app/DataMapper/InvoiceItem.php +++ b/app/DataMapper/InvoiceItem.php @@ -59,7 +59,11 @@ 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 static $casts = [ + 'tax_id' => 'string', 'type_id' => 'string', 'quantity' => 'float', 'cost' => 'float', diff --git a/app/DataMapper/Tax/BaseRule.php b/app/DataMapper/Tax/BaseRule.php new file mode 100644 index 000000000000..39bf2f4833d0 --- /dev/null +++ b/app/DataMapper/Tax/BaseRule.php @@ -0,0 +1,156 @@ +client = $client; + + return $this; + } + + public function setTaxData(Response $tax_data): self + { + $this->tax_data = $tax_data; + + return $this; + } + + public function tax($product_tax_type): self + { + return $this; + } + + public function taxByType($product_tax_type): self + { + return $this; + } + + public function taxReduced(): self + { + return $this; + } + + public function taxExempt(): self + { + return $this; + } + + public function taxDigital(): self + { + return $this; + } + + public function taxService(): self + { + return $this; + } + + public function taxShipping(): self + { + return $this; + } + + public function taxPhysical(): self + { + return $this; + } + + public function default(): self + { + return $this; + } + + public function override(): self + { + return $this; + } + + public function calculateRates(): self + { + return $this; + } +} diff --git a/app/DataMapper/Tax/ClientTaxData.php b/app/DataMapper/Tax/ClientTaxData.php deleted file mode 100644 index 3f92e8866781..000000000000 --- a/app/DataMapper/Tax/ClientTaxData.php +++ /dev/null @@ -1,28 +0,0 @@ -client_country_code = $this->client->shipping_country ? $this->client->shipping_country->iso_3166_2 : $this->client->country->iso_3166_2; + $this->calculateRates(); + + return $this; + } + + public function setClient(Client $client): self + { + $this->client = $client; + + return $this; + } + + public function setTaxData(Response $tax_data): self + { + $this->tax_data = $tax_data; + + return $this; + } + + //need to add logic here to capture if + public function tax($type): self + { + + + if ($this->client->is_tax_exempt) { + return $this->taxExempt(); + } elseif ($this->client->company->tax_data->regions->EU->tax_all) { + + $this->tax_rate1 = $this->vat_rate; + $this->tax_name1 = "MwSt."; + + + return $this; + } + + if ($type) + return $this->taxByType($type); + + + return $this; + + } + + public function taxByType($product_tax_type): self + { + + if ($this->client->is_tax_exempt) { + return $this->taxExempt(); + } + + if(!$product_tax_type) + return $this; + + match($product_tax_type){ + Product::PRODUCT_TYPE_EXEMPT => $this->taxExempt(), + Product::PRODUCT_TYPE_DIGITAL => $this->taxDigital(), + Product::PRODUCT_TYPE_SERVICE => $this->taxService(), + Product::PRODUCT_TYPE_SHIPPING => $this->taxShipping(), + Product::PRODUCT_TYPE_PHYSICAL => $this->taxPhysical(), + Product::PRODUCT_TYPE_REDUCED_TAX => $this->taxReduced(), + Product::PRODUCT_TYPE_OVERRIDE_TAX => $this->override(), + default => $this->default(), + }; + + return $this; + } + + public function taxReduced(): self + { + $this->tax_rate1 = $this->reduced_vat_rate; + $this->tax_name1 = 'ermäßigte MwSt.'; + + return $this; + } + + public function taxExempt(): self + { + $this->tax_name1 = ''; + $this->tax_rate1 = 0; + + return $this; + } + + public function taxDigital(): self + { + $this->tax(); + + return $this; + } + + public function taxService(): self + { + $this->tax(); + + return $this; + } + + public function taxShipping(): self + { + $this->tax(); + + return $this; + } + + public function taxPhysical(): self + { + $this->tax(); + + return $this; + } + + public function default(): self + { + + $this->tax_name1 = ''; + $this->tax_rate1 = 0; + + return $this; + } + + public function override(): self + { + return $this; + } + + public function calculateRates(): self + { + + if ($this->client->is_tax_exempt) { + $this->vat_rate = 0; + $this->reduced_vat_rate = 0; + } + elseif($this->client_country_code != $this->vendor_country_code && in_array($this->client_country_code, $this->eu_country_codes) && $this->client->has_valid_vat_number && $this->eu_business_tax_exempt) + { + $this->vat_rate = 0; + $this->reduced_vat_rate = 0; + // nlog("euro zone and tax exempt"); + } + elseif(!in_array(strtoupper($this->client_country_code), $this->eu_country_codes) && ($this->foreign_consumer_tax_exempt || $this->foreign_business_tax_exempt)) //foreign + tax exempt + { + $this->vat_rate = 0; + $this->reduced_vat_rate = 0; + // nlog("foreign and tax exempt"); + } + elseif(in_array(strtoupper($this->client_country_code), $this->eu_country_codes) && !$this->client->has_valid_vat_number) //eu country / no valid vat + { + if(($this->vendor_country_code != $this->client_country_code) && $this->client->company->tax_data->regions->EU->has_sales_above_threshold) + { + $this->vat_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->country->iso_3166_2}->vat_rate; + $this->reduced_vat_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->country->iso_3166_2}->reduced_vat_rate; + // nlog("eu zone with sales above threshold"); + } + else { + $this->vat_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->company->country()->iso_3166_2}->vat_rate; + $this->reduced_vat_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->company->country()->iso_3166_2}->reduced_vat_rate; + // nlog("same eu country with"); + } + } + else { + $this->vat_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->company->country()->iso_3166_2}->vat_rate; + $this->reduced_vat_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->company->country()->iso_3166_2}->reduced_vat_rate; + // nlog("default tax"); + } + + return $this; + + } + + +} diff --git a/app/DataMapper/Tax/RuleInterface.php b/app/DataMapper/Tax/RuleInterface.php index ec88cd72c67d..c210f2809c6a 100644 --- a/app/DataMapper/Tax/RuleInterface.php +++ b/app/DataMapper/Tax/RuleInterface.php @@ -11,7 +11,36 @@ namespace App\DataMapper\Tax; +use App\Models\Client; +use App\DataMapper\Tax\ZipTax\Response; + interface RuleInterface { - public function run(); + public function init(); + + public function tax(mixed $type); + + public function taxByType($type); + + public function taxExempt(); + + public function taxDigital(); + + public function taxService(); + + public function taxShipping(); + + public function taxPhysical(); + + public function taxReduced(); + + public function default(); + + public function override(); + + public function setClient(Client $client); + + public function setTaxData(Response $tax_data); + + public function calculateRates(); } \ No newline at end of file diff --git a/app/DataMapper/Tax/InvoiceTaxData.php b/app/DataMapper/Tax/TaxData.php similarity index 83% rename from app/DataMapper/Tax/InvoiceTaxData.php rename to app/DataMapper/Tax/TaxData.php index f8e8667109a5..c1696ef2a43e 100644 --- a/app/DataMapper/Tax/InvoiceTaxData.php +++ b/app/DataMapper/Tax/TaxData.php @@ -18,11 +18,14 @@ use App\DataMapper\Tax\ZipTax\Response; * * Definition for the invoice tax data structure */ -class InvoiceTaxData +class TaxData { public int $updated_at; public function __construct(public Response $origin) { + foreach($origin as $key => $value) { + $this->{$key} = $value; + } } } diff --git a/app/DataMapper/Tax/TaxModel.php b/app/DataMapper/Tax/TaxModel.php new file mode 100644 index 000000000000..1d6be0261666 --- /dev/null +++ b/app/DataMapper/Tax/TaxModel.php @@ -0,0 +1,316 @@ +model) + $this->regions = $this->init(); + else + $this->regions = $model; + + } + + public function init() + { + $this->regions = new \stdClass(); + $this->regions->US = new \stdClass(); + $this->regions->EU = new \stdClass(); + + $this->usRegion() + ->euRegion(); + + + return $this->regions; + } + + private function usRegion(): self + { + $this->regions->US->has_sales_above_threshold = false; + $this->regions->US->tax_all_subregions = false; + $this->usSubRegions(); + + return $this; + } + + private function euRegion(): self + { + + $this->regions->EU->has_sales_above_threshold = false; + $this->regions->EU->tax_all_subregions = false; + $this->regions->EU->vat_threshold = 10000; + $this->euSubRegions(); + + return $this; + } + + 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->AK = new \stdClass(); + $this->regions->US->subregions->AK->apply_tax = false; + $this->regions->US->subregions->AZ = new \stdClass(); + $this->regions->US->subregions->AZ->apply_tax = false; + $this->regions->US->subregions->AR = new \stdClass(); + $this->regions->US->subregions->AR->apply_tax = false; + $this->regions->US->subregions->CA = new \stdClass(); + $this->regions->US->subregions->CA->apply_tax = false; + $this->regions->US->subregions->CO = new \stdClass(); + $this->regions->US->subregions->CO->apply_tax = false; + $this->regions->US->subregions->CT = new \stdClass(); + $this->regions->US->subregions->CT->apply_tax = false; + $this->regions->US->subregions->DE = new \stdClass(); + $this->regions->US->subregions->DE->apply_tax = false; + $this->regions->US->subregions->FL = new \stdClass(); + $this->regions->US->subregions->FL->apply_tax = false; + $this->regions->US->subregions->GA = new \stdClass(); + $this->regions->US->subregions->GA->apply_tax = false; + $this->regions->US->subregions->HI = new \stdClass(); + $this->regions->US->subregions->HI->apply_tax = false; + $this->regions->US->subregions->ID = new \stdClass(); + $this->regions->US->subregions->ID->apply_tax = false; + $this->regions->US->subregions->IL = new \stdClass(); + $this->regions->US->subregions->IL->apply_tax = false; + $this->regions->US->subregions->IN = new \stdClass(); + $this->regions->US->subregions->IN->apply_tax = false; + $this->regions->US->subregions->IA = new \stdClass(); + $this->regions->US->subregions->IA->apply_tax = false; + $this->regions->US->subregions->KS = new \stdClass(); + $this->regions->US->subregions->KS->apply_tax = false; + $this->regions->US->subregions->KY = new \stdClass(); + $this->regions->US->subregions->KY->apply_tax = false; + $this->regions->US->subregions->LA = new \stdClass(); + $this->regions->US->subregions->LA->apply_tax = false; + $this->regions->US->subregions->ME = new \stdClass(); + $this->regions->US->subregions->ME->apply_tax = false; + $this->regions->US->subregions->MD = new \stdClass(); + $this->regions->US->subregions->MD->apply_tax = false; + $this->regions->US->subregions->MA = new \stdClass(); + $this->regions->US->subregions->MA->apply_tax = false; + $this->regions->US->subregions->MI = new \stdClass(); + $this->regions->US->subregions->MI->apply_tax = false; + $this->regions->US->subregions->MN = new \stdClass(); + $this->regions->US->subregions->MN->apply_tax = false; + $this->regions->US->subregions->MS = new \stdClass(); + $this->regions->US->subregions->MS->apply_tax = false; + $this->regions->US->subregions->MO = new \stdClass(); + $this->regions->US->subregions->MO->apply_tax = false; + $this->regions->US->subregions->MT = new \stdClass(); + $this->regions->US->subregions->MT->apply_tax = false; + $this->regions->US->subregions->NE = new \stdClass(); + $this->regions->US->subregions->NE->apply_tax = false; + $this->regions->US->subregions->NV = new \stdClass(); + $this->regions->US->subregions->NV->apply_tax = false; + $this->regions->US->subregions->NH = new \stdClass(); + $this->regions->US->subregions->NH->apply_tax = false; + $this->regions->US->subregions->NJ = new \stdClass(); + $this->regions->US->subregions->NJ->apply_tax = false; + $this->regions->US->subregions->NM = new \stdClass(); + $this->regions->US->subregions->NM->apply_tax = false; + $this->regions->US->subregions->NY = new \stdClass(); + $this->regions->US->subregions->NY->apply_tax = false; + $this->regions->US->subregions->NC = new \stdClass(); + $this->regions->US->subregions->NC->apply_tax = false; + $this->regions->US->subregions->ND = new \stdClass(); + $this->regions->US->subregions->ND->apply_tax = false; + $this->regions->US->subregions->OH = new \stdClass(); + $this->regions->US->subregions->OH->apply_tax = false; + $this->regions->US->subregions->OK = new \stdClass(); + $this->regions->US->subregions->OK->apply_tax = false; + $this->regions->US->subregions->OR = new \stdClass(); + $this->regions->US->subregions->OR->apply_tax = false; + $this->regions->US->subregions->PA = new \stdClass(); + $this->regions->US->subregions->PA->apply_tax = false; + $this->regions->US->subregions->RI = new \stdClass(); + $this->regions->US->subregions->RI->apply_tax = false; + $this->regions->US->subregions->SC = new \stdClass(); + $this->regions->US->subregions->SC->apply_tax = false; + $this->regions->US->subregions->SD = new \stdClass(); + $this->regions->US->subregions->SD->apply_tax = false; + $this->regions->US->subregions->TN = new \stdClass(); + $this->regions->US->subregions->TN->apply_tax = false; + $this->regions->US->subregions->TX = new \stdClass(); + $this->regions->US->subregions->TX->apply_tax = false; + $this->regions->US->subregions->UT = new \stdClass(); + $this->regions->US->subregions->UT->apply_tax = false; + $this->regions->US->subregions->VT = new \stdClass(); + $this->regions->US->subregions->VT->apply_tax = false; + $this->regions->US->subregions->VA = new \stdClass(); + $this->regions->US->subregions->VA->apply_tax = false; + $this->regions->US->subregions->WA = new \stdClass(); + $this->regions->US->subregions->WA->apply_tax = false; + $this->regions->US->subregions->WV = new \stdClass(); + $this->regions->US->subregions->WV->apply_tax = false; + $this->regions->US->subregions->WI = new \stdClass(); + $this->regions->US->subregions->WI->apply_tax = false; + $this->regions->US->subregions->WY = new \stdClass(); + $this->regions->US->subregions->WY->apply_tax = false; + + return $this; + } + + private function euSubRegions(): self + { + + $this->regions->EU->subregions = new \stdClass(); + + $this->regions->EU->subregions->AT = new \stdClass(); + $this->regions->EU->subregions->AT->vat_rate = 21; + $this->regions->EU->subregions->AT->reduced_vat_rate = 11; + $this->regions->EU->subregions->AT->apply_tax = false; + + $this->regions->EU->subregions->BE = new \stdClass(); + $this->regions->EU->subregions->BE->vat_rate = 21; + $this->regions->EU->subregions->BE->reduced_vat_rate = 6; + $this->regions->EU->subregions->BE->apply_tax = false; + + $this->regions->EU->subregions->BG = new \stdClass(); + $this->regions->EU->subregions->BG->vat_rate = 20; + $this->regions->EU->subregions->BG->reduced_vat_rate = 9; + $this->regions->EU->subregions->BG->apply_tax = false; + + $this->regions->EU->subregions->CY = new \stdClass(); + $this->regions->EU->subregions->CY->vat_rate = 19; + $this->regions->EU->subregions->CY->reduced_vat_rate = 9; + $this->regions->EU->subregions->CY->apply_tax = false; + + $this->regions->EU->subregions->CZ = new \stdClass(); + $this->regions->EU->subregions->CZ->vat_rate = 21; + $this->regions->EU->subregions->CZ->reduced_vat_rate = 15; + $this->regions->EU->subregions->CZ->apply_tax = false; + + $this->regions->EU->subregions->DE = new \stdClass(); + $this->regions->EU->subregions->DE->vat_rate = 19; + $this->regions->EU->subregions->DE->reduced_vat_rate = 7; + $this->regions->EU->subregions->DE->apply_tax = false; + + $this->regions->EU->subregions->DK = new \stdClass(); + $this->regions->EU->subregions->DK->vat_rate = 25; + $this->regions->EU->subregions->DK->reduced_vat_rate = 0; + $this->regions->EU->subregions->DK->apply_tax = false; + + $this->regions->EU->subregions->EE = new \stdClass(); + $this->regions->EU->subregions->EE->vat_rate = 20; + $this->regions->EU->subregions->EE->reduced_vat_rate = 9; + $this->regions->EU->subregions->EE->apply_tax = false; + + $this->regions->EU->subregions->ES = new \stdClass(); + $this->regions->EU->subregions->ES->vat_rate = 21; + $this->regions->EU->subregions->ES->reduced_vat_rate = 10; + $this->regions->EU->subregions->ES->apply_tax = false; + + $this->regions->EU->subregions->FI = new \stdClass(); + $this->regions->EU->subregions->FI->vat_rate = 24; + $this->regions->EU->subregions->FI->reduced_vat_rate = 14; + $this->regions->EU->subregions->FI->apply_tax = false; + + $this->regions->EU->subregions->FR = new \stdClass(); + $this->regions->EU->subregions->FR->vat_rate = 20; + $this->regions->EU->subregions->FR->reduced_vat_rate = 5.5; + $this->regions->EU->subregions->FR->apply_tax = false; + + // $this->regions->EU->subregions->GB = new \stdClass(); + // $this->regions->EU->subregions->GB->vat_rate = 20; + // $this->regions->EU->subregions->GB->reduced_vat_rate = 0; + // $this->regions->EU->subregions->GB->apply_tax = false; + + $this->regions->EU->subregions->GR = new \stdClass(); + $this->regions->EU->subregions->GR->vat_rate = 24; + $this->regions->EU->subregions->GR->reduced_vat_rate = 13; + $this->regions->EU->subregions->GR->apply_tax = false; + + $this->regions->EU->subregions->HR = new \stdClass(); + $this->regions->EU->subregions->HR->vat_rate = 25; + $this->regions->EU->subregions->HR->reduced_vat_rate = 5; + $this->regions->EU->subregions->HR->apply_tax = false; + + $this->regions->EU->subregions->HU = new \stdClass(); + $this->regions->EU->subregions->HU->vat_rate = 27; + $this->regions->EU->subregions->HU->reduced_vat_rate = 5; + $this->regions->EU->subregions->HU->apply_tax = false; + + $this->regions->EU->subregions->IE = new \stdClass(); + $this->regions->EU->subregions->IE->vat_rate = 23; + $this->regions->EU->subregions->IE->reduced_vat_rate = 0; + $this->regions->EU->subregions->IE->apply_tax = false; + + $this->regions->EU->subregions->IT = new \stdClass(); + $this->regions->EU->subregions->IT->vat_rate = 22; + $this->regions->EU->subregions->IT->reduced_vat_rate = 10; + $this->regions->EU->subregions->IT->apply_tax = false; + + $this->regions->EU->subregions->LT = new \stdClass(); + $this->regions->EU->subregions->LT->vat_rate = 21; + $this->regions->EU->subregions->LT->reduced_vat_rate = 9; + $this->regions->EU->subregions->LT->apply_tax = false; + + $this->regions->EU->subregions->LU = new \stdClass(); + $this->regions->EU->subregions->LU->vat_rate = 17; + $this->regions->EU->subregions->LU->reduced_vat_rate = 3; + $this->regions->EU->subregions->LU->apply_tax = false; + + $this->regions->EU->subregions->LV = new \stdClass(); + $this->regions->EU->subregions->LV->vat_rate = 21; + $this->regions->EU->subregions->LV->reduced_vat_rate = 12; + $this->regions->EU->subregions->LV->apply_tax = false; + + $this->regions->EU->subregions->MT = new \stdClass(); + $this->regions->EU->subregions->MT->vat_rate = 18; + $this->regions->EU->subregions->MT->reduced_vat_rate = 5; + $this->regions->EU->subregions->MT->apply_tax = false; + + $this->regions->EU->subregions->NL = new \stdClass(); + $this->regions->EU->subregions->NL->vat_rate = 21; + $this->regions->EU->subregions->NL->reduced_vat_rate = 9; + $this->regions->EU->subregions->NL->apply_tax = false; + + $this->regions->EU->subregions->PT = new \stdClass(); + $this->regions->EU->subregions->PT->vat_rate = 23; + $this->regions->EU->subregions->PT->reduced_vat_rate = 6; + $this->regions->EU->subregions->PT->apply_tax = false; + + $this->regions->EU->subregions->RO = new \stdClass(); + $this->regions->EU->subregions->RO->vat_rate = 19; + $this->regions->EU->subregions->RO->reduced_vat_rate = 5; + $this->regions->EU->subregions->RO->apply_tax = false; + + $this->regions->EU->subregions->SE = new \stdClass(); + $this->regions->EU->subregions->SE->vat_rate = 25; + $this->regions->EU->subregions->SE->reduced_vat_rate = 12; + $this->regions->EU->subregions->SE->apply_tax = false; + + $this->regions->EU->subregions->SI = new \stdClass(); + $this->regions->EU->subregions->SI->vat_rate = 22; + $this->regions->EU->subregions->SI->reduced_vat_rate = 9.5; + $this->regions->EU->subregions->SI->apply_tax = false; + + $this->regions->EU->subregions->SK = new \stdClass(); + $this->regions->EU->subregions->SK->vat_rate = 20; + $this->regions->EU->subregions->SK->reduced_vat_rate = 10; + $this->regions->EU->subregions->SK->apply_tax = false; + + return $this; + + } + +} diff --git a/app/DataMapper/Tax/US/Rule.php b/app/DataMapper/Tax/US/Rule.php new file mode 100644 index 000000000000..8dabf504dea5 --- /dev/null +++ b/app/DataMapper/Tax/US/Rule.php @@ -0,0 +1,161 @@ +tax_data = $tax_data; + + return $this; + } + + public function setClient(Client $client):self + { + $this->client = $client; + + return $this; + } + + public function tax($type): self + { + + if ($this->client->is_tax_exempt) { + return $this->taxExempt(); + } + else if($this->client->company->tax_data->regions->US->tax_all){ + + $this->tax_rate1 = $this->tax_data->taxSales * 100; + $this->tax_name1 = "{$this->tax_data->geoState} Sales Tax"; + + return $this; + } + + if($type) + return $this->taxByType($type); + + return $this; + + } + + public function taxByType($product_tax_type): self + { + if(!$product_tax_type) + return $this; + + match($product_tax_type){ + Product::PRODUCT_TYPE_EXEMPT => $this->taxExempt(), + Product::PRODUCT_TYPE_DIGITAL => $this->taxDigital(), + Product::PRODUCT_TYPE_SERVICE => $this->taxService(), + Product::PRODUCT_TYPE_SHIPPING => $this->taxShipping(), + Product::PRODUCT_TYPE_PHYSICAL => $this->taxPhysical(), + Product::PRODUCT_TYPE_REDUCED_TAX => $this->taxReduced(), + Product::PRODUCT_TYPE_OVERRIDE_TAX => $this->override(), + default => $this->default(), + }; + + return $this; + } + + public function taxExempt(): self + { + $this->tax_name1 = ''; + $this->tax_rate1 = 0; + + return $this; + } + + public function taxDigital(): self + { + $this->default(); + + return $this; + } + + public function taxService(): self + { + if($this->tax_data->txbService == 'Y') + $this->default(); + + return $this; + } + + public function taxShipping(): self + { + if($this->tax_data->txbFreight == 'Y') + $this->default(); + + return $this; + } + + public function taxPhysical(): self + { + $this->default(); + + return $this; + } + + public function default(): self + { + + $this->tax_rate1 = $this->tax_data->taxSales * 100; + $this->tax_name1 = "{$this->tax_data->geoState} Sales Tax"; + + return $this; + } + + public function taxReduced(): self + { + $this->default(); + + return $this; + } + + public function init(): self + { + return $this; + } + + public function calculateRates(): self + { + return $this; + } +} diff --git a/app/DataMapper/Tax/ZipTax/Response.php b/app/DataMapper/Tax/ZipTax/Response.php index dfeea6e1f1cd..3e4893cdd28c 100644 --- a/app/DataMapper/Tax/ZipTax/Response.php +++ b/app/DataMapper/Tax/ZipTax/Response.php @@ -18,8 +18,7 @@ class Response public int $rCode = 100; /** - * ["results" => [ - * [ + * [ * "geoPostalCode" => "92582", * "geoCity" => "SAN JACINTO", * "geoCounty" => "RIVERSIDE", @@ -54,13 +53,56 @@ class Response * "district5SalesTax" => 0, * "district5UseTax" => 0, * "originDestination" => "D", - * ], - * ] + * * ]; - * - * @var mixed[] + * */ - public array $results = []; + public string $seller_region = ""; + //US + + public string $geoPostalCode = ""; + public string $geoCity = ""; + public string $geoCounty = ""; + public string $geoState = ""; + public float $taxSales = 0; + public float $taxUse = 0; + public string $txbService = ""; // N = No, Y = Yes + public string $txbFreight = ""; // N = No, Y = Yes + public float $stateSalesTax = 0; + public float $stateUseTax = 0; + public float $citySalesTax = 0; + public float $cityUseTax = 0; + public string $cityTaxCode = ""; + 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; + public string $originDestination = ""; + + public function __construct($data) + { + + foreach($data as $key => $value){ + $this->{$key} = $value; + } + + } } diff --git a/app/DataMapper/Tax/de/Rule.php b/app/DataMapper/Tax/de/Rule.php deleted file mode 100644 index 4332abfa81c9..000000000000 --- a/app/DataMapper/Tax/de/Rule.php +++ /dev/null @@ -1,96 +0,0 @@ -custom_value3 = ''; $product->custom_value4 = ''; $product->is_deleted = 0; - + $product->tax_id = 1; + return $product; } } diff --git a/app/Helpers/Invoice/InvoiceItemSum.php b/app/Helpers/Invoice/InvoiceItemSum.php index 464679e2f5e2..6e9cce110e71 100644 --- a/app/Helpers/Invoice/InvoiceItemSum.php +++ b/app/Helpers/Invoice/InvoiceItemSum.php @@ -11,10 +11,13 @@ namespace App\Helpers\Invoice; -use App\DataMapper\BaseSettings; -use App\DataMapper\InvoiceItem; +use App\Models\Client; use App\Models\Invoice; +use App\DataMapper\InvoiceItem; +use App\DataMapper\BaseSettings; +use App\DataMapper\Tax\RuleInterface; use App\Utils\Traits\NumberFormatter; +use App\DataMapper\Tax\ZipTax\Response; class InvoiceItemSum { @@ -22,6 +25,38 @@ class InvoiceItemSum use Discounter; use Taxer; + private array $tax_jurisdictions = [ + '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 + + 'US', //USA + ]; + protected $invoice; private $items; @@ -48,6 +83,12 @@ class InvoiceItemSum private $tax_collection; + private ?Client $client; + + private bool $calc_tax = false; + + private RuleInterface $rule; + public function __construct($invoice) { $this->tax_collection = collect([]); @@ -56,6 +97,8 @@ class InvoiceItemSum if ($this->invoice->client) { $this->currency = $this->invoice->client->currency(); + $this->client = $this->invoice->client; + $this->shouldCalculateTax(); } else { $this->currency = $this->invoice->vendor->currency(); } @@ -89,6 +132,33 @@ class InvoiceItemSum return $this; } + private function shouldCalculateTax(): self + { + if (!$this->invoice->company->calculate_taxes) { + $this->calc_tax = false; + return $this; + } + + //should we be filtering by client country here? do we need to reflect at the company <=> client level? + if (in_array($this->client->country->iso_3166_2, $this->tax_jurisdictions)) { //only calculate for supported tax jurisdictions + $class = "App\DataMapper\Tax\\".$this->client->company->country()->iso_3166_2."\\Rule"; + + $tax_data = new Response($this->invoice->tax_data); + + $this->rule = new $class(); + $this->rule + ->setTaxData($tax_data) + ->setClient($this->client) + ->init(); + + $this->calc_tax = true; + + return $this; + } + + return $this; + } + private function push() { $this->sub_total += $this->getLineTotal(); @@ -122,8 +192,33 @@ class InvoiceItemSum return $this; } + /** + * Attempts to calculate taxes based on the clients location + * + * @return self + */ + private function calcTaxesAutomatically(): self + { + $this->rule->tax($this->item->tax_id ?? null); + + $this->item->tax_name1 = $this->rule->tax_name1; + $this->item->tax_rate1 = $this->rule->tax_rate1; + + $this->item->tax_name2 = $this->rule->tax_name2; + $this->item->tax_rate2 = $this->rule->tax_rate2; + + $this->item->tax_name3 = $this->rule->tax_name3; + $this->item->tax_rate3 = $this->rule->tax_rate3; + + return $this; + } + private function calcTaxes() { + if ($this->calc_tax) { + $this->calcTaxesAutomatically(); + } + $item_tax = 0; $amount = $this->item->line_total - ($this->item->line_total * ($this->invoice->discount / 100)); @@ -131,7 +226,6 @@ class InvoiceItemSum $item_tax += $item_tax_rate1_total; - // if($item_tax_rate1_total != 0) if (strlen($this->item->tax_name1) > 1) { $this->groupTax($this->item->tax_name1, $this->item->tax_rate1, $item_tax_rate1_total); } @@ -155,7 +249,7 @@ class InvoiceItemSum $this->setTotalTaxes($this->formatValue($item_tax, $this->currency->precision)); $this->item->gross_line_total = $this->getLineTotal() + $item_tax; - + $this->item->tax_amount = $item_tax; return $this; diff --git a/app/Http/Controllers/AccountController.php b/app/Http/Controllers/AccountController.php index 8c004691dd9f..2c6cc2ef8b3d 100644 --- a/app/Http/Controllers/AccountController.php +++ b/app/Http/Controllers/AccountController.php @@ -11,16 +11,17 @@ namespace App\Http\Controllers; -use App\Http\Requests\Account\CreateAccountRequest; -use App\Http\Requests\Account\UpdateAccountRequest; -use App\Jobs\Account\CreateAccount; use App\Models\Account; +use App\Libraries\MultiDB; +use App\Utils\TruthSource; use App\Models\CompanyUser; +use Illuminate\Http\Response; +use App\Jobs\Account\CreateAccount; use App\Transformers\AccountTransformer; use App\Transformers\CompanyUserTransformer; -use App\Utils\TruthSource; use Illuminate\Foundation\Bus\DispatchesJobs; -use Illuminate\Http\Response; +use App\Http\Requests\Account\CreateAccountRequest; +use App\Http\Requests\Account\UpdateAccountRequest; class AccountController extends BaseController { @@ -146,8 +147,10 @@ class AccountController extends BaseController if (! ($account instanceof Account)) { return $account; } + + MultiDB::findAndSetDbByAccountKey($account->key); - $cu = CompanyUser::where('user_id', auth()->user()->id); + $cu = CompanyUser::where('user_id', $account->users()->first()->id); $company_user = $cu->first(); diff --git a/app/Http/Controllers/HostedMigrationController.php b/app/Http/Controllers/HostedMigrationController.php index 479b8d0d137a..386722ca6e1f 100644 --- a/app/Http/Controllers/HostedMigrationController.php +++ b/app/Http/Controllers/HostedMigrationController.php @@ -38,6 +38,8 @@ class HostedMigrationController extends Controller $account->hosted_company_count = 10; $account->save(); + MultiDB::findAndSetDbByAccountKey($account->key); + $company = $account->companies->first(); $company_token = CompanyToken::where('user_id', auth()->user()->id) diff --git a/app/Http/Controllers/PreviewController.php b/app/Http/Controllers/PreviewController.php index eead3581a0e3..7e2ca56994a6 100644 --- a/app/Http/Controllers/PreviewController.php +++ b/app/Http/Controllers/PreviewController.php @@ -144,7 +144,7 @@ class PreviewController extends BaseController $maker ->design($design) ->build(); - + if (request()->query('html') == 'true') { return $maker->getCompiledHTML(); } diff --git a/app/Http/Requests/ClientPortal/PrePayments/StorePrePaymentRequest.php b/app/Http/Requests/ClientPortal/PrePayments/StorePrePaymentRequest.php index baa5e2a903f5..a1a4770cd6c9 100644 --- a/app/Http/Requests/ClientPortal/PrePayments/StorePrePaymentRequest.php +++ b/app/Http/Requests/ClientPortal/PrePayments/StorePrePaymentRequest.php @@ -26,7 +26,7 @@ class StorePrePaymentRequest extends FormRequest { return [ 'notes' => 'required|bail|', - 'amount' => 'required|bail|gte:minimum_amount', + 'amount' => 'required|bail|gte:minimum_amount|numeric', 'minimum_amount' => '', ]; } diff --git a/app/Http/Requests/Invoice/UploadInvoiceRequest.php b/app/Http/Requests/Invoice/UploadInvoiceRequest.php index 93396d9ee7aa..070fb4443d1b 100644 --- a/app/Http/Requests/Invoice/UploadInvoiceRequest.php +++ b/app/Http/Requests/Invoice/UploadInvoiceRequest.php @@ -12,6 +12,7 @@ namespace App\Http\Requests\Invoice; use App\Http\Requests\Request; +use Illuminate\Http\UploadedFile; class UploadInvoiceRequest extends Request { @@ -46,5 +47,24 @@ class UploadInvoiceRequest extends Request public function prepareForValidation() { + + //tests to see if upload via binary data works. + + // if(request()->getContent()) + // { + // // $file = new UploadedFile(request()->getContent(), request()->header('filename')); + // $file = new UploadedFile(request()->getContent(), 'something.png'); + // // request()->files->set('documents', $file); + + // $this->files->add(['file' => $file]); + + // // Merge it in request also (As I found this is not needed in every case) + // $this->merge(['file' => $file]); + + + // } + + + } } diff --git a/app/Jobs/Inventory/AdjustProductInventory.php b/app/Jobs/Inventory/AdjustProductInventory.php index fddf8cabdc7c..e46ac69398f4 100644 --- a/app/Jobs/Inventory/AdjustProductInventory.php +++ b/app/Jobs/Inventory/AdjustProductInventory.php @@ -115,9 +115,9 @@ class AdjustProductInventory implements ShouldQueue $p->in_stock_quantity -= $i->quantity; $p->saveQuietly(); - nlog($p->stock_notification_threshold); - nlog($p->in_stock_quantity); - nlog($p->stock_notification_threshold); + nlog("threshold ".$p->stock_notification_threshold); + nlog("stock q".$p->in_stock_quantity); + nlog("p stock not".$p->stock_notification_threshold); if ($this->company->stock_notification && $p->stock_notification && $p->stock_notification_threshold && $p->in_stock_quantity <= $p->stock_notification_threshold) { $this->notifyStockLevels($p, 'product'); @@ -131,7 +131,7 @@ class AdjustProductInventory implements ShouldQueue private function existingInventoryAdjustment() { - collect($this->invoice->line_items)->filter(function ($item) { + collect($this->old_invoice)->filter(function ($item) { return $item->type_id == '1'; })->each(function ($i) { $p = Product::where('product_key', $i->product_key)->where('company_id', $this->company->id)->first(); diff --git a/app/Models/Account.php b/app/Models/Account.php index 5514b7143d1a..90c3a8b23589 100644 --- a/app/Models/Account.php +++ b/app/Models/Account.php @@ -142,6 +142,26 @@ use Laracasts\Presenter\PresentableTrait; * @property-read \Illuminate\Database\Eloquent\Collection $companies * @property-read \Illuminate\Database\Eloquent\Collection $company_users * @property-read \Illuminate\Database\Eloquent\Collection $users + * @property-read \Illuminate\Database\Eloquent\Collection $bank_integrations + * @property-read \Illuminate\Database\Eloquent\Collection $companies + * @property-read \Illuminate\Database\Eloquent\Collection $company_users + * @property-read \Illuminate\Database\Eloquent\Collection $users + * @property-read \Illuminate\Database\Eloquent\Collection $bank_integrations + * @property-read \Illuminate\Database\Eloquent\Collection $companies + * @property-read \Illuminate\Database\Eloquent\Collection $company_users + * @property-read \Illuminate\Database\Eloquent\Collection $users + * @property-read \Illuminate\Database\Eloquent\Collection $bank_integrations + * @property-read \Illuminate\Database\Eloquent\Collection $companies + * @property-read \Illuminate\Database\Eloquent\Collection $company_users + * @property-read \Illuminate\Database\Eloquent\Collection $users + * @property-read \Illuminate\Database\Eloquent\Collection $bank_integrations + * @property-read \Illuminate\Database\Eloquent\Collection $companies + * @property-read \Illuminate\Database\Eloquent\Collection $company_users + * @property-read \Illuminate\Database\Eloquent\Collection $users + * @property-read \Illuminate\Database\Eloquent\Collection $bank_integrations + * @property-read \Illuminate\Database\Eloquent\Collection $companies + * @property-read \Illuminate\Database\Eloquent\Collection $company_users + * @property-read \Illuminate\Database\Eloquent\Collection $users * @mixin \Eloquent */ class Account extends BaseModel diff --git a/app/Models/BankAccount.php b/app/Models/BankAccount.php index bf5743792368..cf20fc461d3c 100644 --- a/app/Models/BankAccount.php +++ b/app/Models/BankAccount.php @@ -35,6 +35,11 @@ use Illuminate\Database\Eloquent\SoftDeletes; * @property-read \Illuminate\Database\Eloquent\Collection $bank_subaccounts * @property-read \Illuminate\Database\Eloquent\Collection $bank_subaccounts * @property-read \Illuminate\Database\Eloquent\Collection $bank_subaccounts + * @property-read \Illuminate\Database\Eloquent\Collection $bank_subaccounts + * @property-read \Illuminate\Database\Eloquent\Collection $bank_subaccounts + * @property-read \Illuminate\Database\Eloquent\Collection $bank_subaccounts + * @property-read \Illuminate\Database\Eloquent\Collection $bank_subaccounts + * @property-read \Illuminate\Database\Eloquent\Collection $bank_subaccounts * @mixin \Eloquent */ class BankAccount extends BaseModel diff --git a/app/Models/BankIntegration.php b/app/Models/BankIntegration.php index 2c66f8c5ad43..82d2d7200264 100644 --- a/app/Models/BankIntegration.php +++ b/app/Models/BankIntegration.php @@ -78,6 +78,11 @@ use Illuminate\Database\Eloquent\SoftDeletes; * @property-read \Illuminate\Database\Eloquent\Collection $transactions * @property-read \Illuminate\Database\Eloquent\Collection $transactions * @property-read \Illuminate\Database\Eloquent\Collection $transactions + * @property-read \Illuminate\Database\Eloquent\Collection $transactions + * @property-read \Illuminate\Database\Eloquent\Collection $transactions + * @property-read \Illuminate\Database\Eloquent\Collection $transactions + * @property-read \Illuminate\Database\Eloquent\Collection $transactions + * @property-read \Illuminate\Database\Eloquent\Collection $transactions * @mixin \Eloquent */ class BankIntegration extends BaseModel diff --git a/app/Models/Client.php b/app/Models/Client.php index 1a0ce79f91b2..e4907deaf4a8 100644 --- a/app/Models/Client.php +++ b/app/Models/Client.php @@ -221,6 +221,93 @@ use Laracasts\Presenter\PresentableTrait; * @property-read \Illuminate\Database\Eloquent\Collection $recurring_invoices * @property-read \Illuminate\Database\Eloquent\Collection $system_logs * @property-read \Illuminate\Database\Eloquent\Collection $tasks + * @property int $is_tax_exempt + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $company_ledger + * @property-read \Illuminate\Database\Eloquent\Collection $contacts + * @property-read \Illuminate\Database\Eloquent\Collection $credits + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $expenses + * @property-read \Illuminate\Database\Eloquent\Collection $gateway_tokens + * @property-read \Illuminate\Database\Eloquent\Collection $invoices + * @property-read \Illuminate\Database\Eloquent\Collection $ledger + * @property-read \Illuminate\Database\Eloquent\Collection $payments + * @property-read \Illuminate\Database\Eloquent\Collection $primary_contact + * @property-read \Illuminate\Database\Eloquent\Collection $projects + * @property-read \Illuminate\Database\Eloquent\Collection $quotes + * @property-read \Illuminate\Database\Eloquent\Collection $recurring_expenses + * @property-read \Illuminate\Database\Eloquent\Collection $recurring_invoices + * @property-read \Illuminate\Database\Eloquent\Collection $system_logs + * @property-read \Illuminate\Database\Eloquent\Collection $tasks + * @method static \Illuminate\Database\Eloquent\Builder|Client whereIsTaxExempt($value) + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $company_ledger + * @property-read \Illuminate\Database\Eloquent\Collection $contacts + * @property-read \Illuminate\Database\Eloquent\Collection $credits + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $expenses + * @property-read \Illuminate\Database\Eloquent\Collection $gateway_tokens + * @property-read \Illuminate\Database\Eloquent\Collection $invoices + * @property-read \Illuminate\Database\Eloquent\Collection $ledger + * @property-read \Illuminate\Database\Eloquent\Collection $payments + * @property-read \Illuminate\Database\Eloquent\Collection $primary_contact + * @property-read \Illuminate\Database\Eloquent\Collection $projects + * @property-read \Illuminate\Database\Eloquent\Collection $quotes + * @property-read \Illuminate\Database\Eloquent\Collection $recurring_expenses + * @property-read \Illuminate\Database\Eloquent\Collection $recurring_invoices + * @property-read \Illuminate\Database\Eloquent\Collection $system_logs + * @property-read \Illuminate\Database\Eloquent\Collection $tasks + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $company_ledger + * @property-read \Illuminate\Database\Eloquent\Collection $contacts + * @property-read \Illuminate\Database\Eloquent\Collection $credits + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $expenses + * @property-read \Illuminate\Database\Eloquent\Collection $gateway_tokens + * @property-read \Illuminate\Database\Eloquent\Collection $invoices + * @property-read \Illuminate\Database\Eloquent\Collection $ledger + * @property-read \Illuminate\Database\Eloquent\Collection $payments + * @property-read \Illuminate\Database\Eloquent\Collection $primary_contact + * @property-read \Illuminate\Database\Eloquent\Collection $projects + * @property-read \Illuminate\Database\Eloquent\Collection $quotes + * @property-read \Illuminate\Database\Eloquent\Collection $recurring_expenses + * @property-read \Illuminate\Database\Eloquent\Collection $recurring_invoices + * @property-read \Illuminate\Database\Eloquent\Collection $system_logs + * @property-read \Illuminate\Database\Eloquent\Collection $tasks + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $company_ledger + * @property-read \Illuminate\Database\Eloquent\Collection $contacts + * @property-read \Illuminate\Database\Eloquent\Collection $credits + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $expenses + * @property-read \Illuminate\Database\Eloquent\Collection $gateway_tokens + * @property-read \Illuminate\Database\Eloquent\Collection $invoices + * @property-read \Illuminate\Database\Eloquent\Collection $ledger + * @property-read \Illuminate\Database\Eloquent\Collection $payments + * @property-read \Illuminate\Database\Eloquent\Collection $primary_contact + * @property-read \Illuminate\Database\Eloquent\Collection $projects + * @property-read \Illuminate\Database\Eloquent\Collection $quotes + * @property-read \Illuminate\Database\Eloquent\Collection $recurring_expenses + * @property-read \Illuminate\Database\Eloquent\Collection $recurring_invoices + * @property-read \Illuminate\Database\Eloquent\Collection $system_logs + * @property-read \Illuminate\Database\Eloquent\Collection $tasks + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $company_ledger + * @property-read \Illuminate\Database\Eloquent\Collection $contacts + * @property-read \Illuminate\Database\Eloquent\Collection $credits + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $expenses + * @property-read \Illuminate\Database\Eloquent\Collection $gateway_tokens + * @property-read \Illuminate\Database\Eloquent\Collection $invoices + * @property-read \Illuminate\Database\Eloquent\Collection $ledger + * @property-read \Illuminate\Database\Eloquent\Collection $payments + * @property-read \Illuminate\Database\Eloquent\Collection $primary_contact + * @property-read \Illuminate\Database\Eloquent\Collection $projects + * @property-read \Illuminate\Database\Eloquent\Collection $quotes + * @property-read \Illuminate\Database\Eloquent\Collection $recurring_expenses + * @property-read \Illuminate\Database\Eloquent\Collection $recurring_invoices + * @property-read \Illuminate\Database\Eloquent\Collection $system_logs + * @property-read \Illuminate\Database\Eloquent\Collection $tasks * @mixin \Eloquent */ class Client extends BaseModel implements HasLocalePreference diff --git a/app/Models/ClientContact.php b/app/Models/ClientContact.php index 57a61715d5b3..361ab3101e73 100644 --- a/app/Models/ClientContact.php +++ b/app/Models/ClientContact.php @@ -138,6 +138,31 @@ use Laracasts\Presenter\PresentableTrait; * @property-read \Illuminate\Notifications\DatabaseNotificationCollection $notifications * @property-read \Illuminate\Database\Eloquent\Collection $quote_invitations * @property-read \Illuminate\Database\Eloquent\Collection $recurring_invoice_invitations + * @property-read \Illuminate\Database\Eloquent\Collection $credit_invitations + * @property-read \Illuminate\Database\Eloquent\Collection $invoice_invitations + * @property-read \Illuminate\Notifications\DatabaseNotificationCollection $notifications + * @property-read \Illuminate\Database\Eloquent\Collection $quote_invitations + * @property-read \Illuminate\Database\Eloquent\Collection $recurring_invoice_invitations + * @property-read \Illuminate\Database\Eloquent\Collection $credit_invitations + * @property-read \Illuminate\Database\Eloquent\Collection $invoice_invitations + * @property-read \Illuminate\Notifications\DatabaseNotificationCollection $notifications + * @property-read \Illuminate\Database\Eloquent\Collection $quote_invitations + * @property-read \Illuminate\Database\Eloquent\Collection $recurring_invoice_invitations + * @property-read \Illuminate\Database\Eloquent\Collection $credit_invitations + * @property-read \Illuminate\Database\Eloquent\Collection $invoice_invitations + * @property-read \Illuminate\Notifications\DatabaseNotificationCollection $notifications + * @property-read \Illuminate\Database\Eloquent\Collection $quote_invitations + * @property-read \Illuminate\Database\Eloquent\Collection $recurring_invoice_invitations + * @property-read \Illuminate\Database\Eloquent\Collection $credit_invitations + * @property-read \Illuminate\Database\Eloquent\Collection $invoice_invitations + * @property-read \Illuminate\Notifications\DatabaseNotificationCollection $notifications + * @property-read \Illuminate\Database\Eloquent\Collection $quote_invitations + * @property-read \Illuminate\Database\Eloquent\Collection $recurring_invoice_invitations + * @property-read \Illuminate\Database\Eloquent\Collection $credit_invitations + * @property-read \Illuminate\Database\Eloquent\Collection $invoice_invitations + * @property-read \Illuminate\Notifications\DatabaseNotificationCollection $notifications + * @property-read \Illuminate\Database\Eloquent\Collection $quote_invitations + * @property-read \Illuminate\Database\Eloquent\Collection $recurring_invoice_invitations * @mixin \Eloquent */ class ClientContact extends Authenticatable implements HasLocalePreference diff --git a/app/Models/Company.php b/app/Models/Company.php index 80da8ddbb355..35d3d3c0436a 100644 --- a/app/Models/Company.php +++ b/app/Models/Company.php @@ -419,6 +419,226 @@ use Laracasts\Presenter\PresentableTrait; * @property-read \Illuminate\Database\Eloquent\Collection $users * @property-read \Illuminate\Database\Eloquent\Collection $vendors * @property-read \Illuminate\Database\Eloquent\Collection $webhooks + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $all_activities + * @property-read \Illuminate\Database\Eloquent\Collection $all_documents + * @property-read \Illuminate\Database\Eloquent\Collection $bank_integrations + * @property-read \Illuminate\Database\Eloquent\Collection $bank_transaction_rules + * @property-read \Illuminate\Database\Eloquent\Collection $bank_transactions + * @property-read \Illuminate\Database\Eloquent\Collection $client_contacts + * @property-read \Illuminate\Database\Eloquent\Collection $client_gateway_tokens + * @property-read \Illuminate\Database\Eloquent\Collection $clients + * @property-read \Illuminate\Database\Eloquent\Collection $company_gateways + * @property-read \Illuminate\Database\Eloquent\Collection $company_users + * @property-read \Illuminate\Database\Eloquent\Collection $contacts + * @property-read \Illuminate\Database\Eloquent\Collection $credits + * @property-read \Illuminate\Database\Eloquent\Collection $designs + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $expense_categories + * @property-read \Illuminate\Database\Eloquent\Collection $expenses + * @property-read \Illuminate\Database\Eloquent\Collection $group_settings + * @property-read \Illuminate\Database\Eloquent\Collection $groups + * @property-read \Illuminate\Database\Eloquent\Collection $invoices + * @property-read \Illuminate\Database\Eloquent\Collection $ledger + * @property-read \Illuminate\Database\Eloquent\Collection $payment_terms + * @property-read \Illuminate\Database\Eloquent\Collection $payments + * @property-read \Illuminate\Database\Eloquent\Collection $products + * @property-read \Illuminate\Database\Eloquent\Collection $projects + * @property-read \Illuminate\Database\Eloquent\Collection $purchase_orders + * @property-read \Illuminate\Database\Eloquent\Collection $quotes + * @property-read \Illuminate\Database\Eloquent\Collection $recurring_expenses + * @property-read \Illuminate\Database\Eloquent\Collection $recurring_invoices + * @property-read \Illuminate\Database\Eloquent\Collection $schedulers + * @property-read \Illuminate\Database\Eloquent\Collection $subscriptions + * @property-read \Illuminate\Database\Eloquent\Collection $system_log_relation + * @property-read \Illuminate\Database\Eloquent\Collection $system_logs + * @property-read \Illuminate\Database\Eloquent\Collection $task_schedulers + * @property-read \Illuminate\Database\Eloquent\Collection $task_statuses + * @property-read \Illuminate\Database\Eloquent\Collection $tasks + * @property-read \Illuminate\Database\Eloquent\Collection $tax_rates + * @property-read \Illuminate\Database\Eloquent\Collection $tokens + * @property-read \Illuminate\Database\Eloquent\Collection $tokens_hashed + * @property-read \Illuminate\Database\Eloquent\Collection $user_designs + * @property-read \Illuminate\Database\Eloquent\Collection $user_payment_terms + * @property-read \Illuminate\Database\Eloquent\Collection $users + * @property-read \Illuminate\Database\Eloquent\Collection $vendors + * @property-read \Illuminate\Database\Eloquent\Collection $webhooks + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $all_activities + * @property-read \Illuminate\Database\Eloquent\Collection $all_documents + * @property-read \Illuminate\Database\Eloquent\Collection $bank_integrations + * @property-read \Illuminate\Database\Eloquent\Collection $bank_transaction_rules + * @property-read \Illuminate\Database\Eloquent\Collection $bank_transactions + * @property-read \Illuminate\Database\Eloquent\Collection $client_contacts + * @property-read \Illuminate\Database\Eloquent\Collection $client_gateway_tokens + * @property-read \Illuminate\Database\Eloquent\Collection $clients + * @property-read \Illuminate\Database\Eloquent\Collection $company_gateways + * @property-read \Illuminate\Database\Eloquent\Collection $company_users + * @property-read \Illuminate\Database\Eloquent\Collection $contacts + * @property-read \Illuminate\Database\Eloquent\Collection $credits + * @property-read \Illuminate\Database\Eloquent\Collection $designs + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $expense_categories + * @property-read \Illuminate\Database\Eloquent\Collection $expenses + * @property-read \Illuminate\Database\Eloquent\Collection $group_settings + * @property-read \Illuminate\Database\Eloquent\Collection $groups + * @property-read \Illuminate\Database\Eloquent\Collection $invoices + * @property-read \Illuminate\Database\Eloquent\Collection $ledger + * @property-read \Illuminate\Database\Eloquent\Collection $payment_terms + * @property-read \Illuminate\Database\Eloquent\Collection $payments + * @property-read \Illuminate\Database\Eloquent\Collection $products + * @property-read \Illuminate\Database\Eloquent\Collection $projects + * @property-read \Illuminate\Database\Eloquent\Collection $purchase_orders + * @property-read \Illuminate\Database\Eloquent\Collection $quotes + * @property-read \Illuminate\Database\Eloquent\Collection $recurring_expenses + * @property-read \Illuminate\Database\Eloquent\Collection $recurring_invoices + * @property-read \Illuminate\Database\Eloquent\Collection $schedulers + * @property-read \Illuminate\Database\Eloquent\Collection $subscriptions + * @property-read \Illuminate\Database\Eloquent\Collection $system_log_relation + * @property-read \Illuminate\Database\Eloquent\Collection $system_logs + * @property-read \Illuminate\Database\Eloquent\Collection $task_schedulers + * @property-read \Illuminate\Database\Eloquent\Collection $task_statuses + * @property-read \Illuminate\Database\Eloquent\Collection $tasks + * @property-read \Illuminate\Database\Eloquent\Collection $tax_rates + * @property-read \Illuminate\Database\Eloquent\Collection $tokens + * @property-read \Illuminate\Database\Eloquent\Collection $tokens_hashed + * @property-read \Illuminate\Database\Eloquent\Collection $user_designs + * @property-read \Illuminate\Database\Eloquent\Collection $user_payment_terms + * @property-read \Illuminate\Database\Eloquent\Collection $users + * @property-read \Illuminate\Database\Eloquent\Collection $vendors + * @property-read \Illuminate\Database\Eloquent\Collection $webhooks + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $all_activities + * @property-read \Illuminate\Database\Eloquent\Collection $all_documents + * @property-read \Illuminate\Database\Eloquent\Collection $bank_integrations + * @property-read \Illuminate\Database\Eloquent\Collection $bank_transaction_rules + * @property-read \Illuminate\Database\Eloquent\Collection $bank_transactions + * @property-read \Illuminate\Database\Eloquent\Collection $client_contacts + * @property-read \Illuminate\Database\Eloquent\Collection $client_gateway_tokens + * @property-read \Illuminate\Database\Eloquent\Collection $clients + * @property-read \Illuminate\Database\Eloquent\Collection $company_gateways + * @property-read \Illuminate\Database\Eloquent\Collection $company_users + * @property-read \Illuminate\Database\Eloquent\Collection $contacts + * @property-read \Illuminate\Database\Eloquent\Collection $credits + * @property-read \Illuminate\Database\Eloquent\Collection $designs + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $expense_categories + * @property-read \Illuminate\Database\Eloquent\Collection $expenses + * @property-read \Illuminate\Database\Eloquent\Collection $group_settings + * @property-read \Illuminate\Database\Eloquent\Collection $groups + * @property-read \Illuminate\Database\Eloquent\Collection $invoices + * @property-read \Illuminate\Database\Eloquent\Collection $ledger + * @property-read \Illuminate\Database\Eloquent\Collection $payment_terms + * @property-read \Illuminate\Database\Eloquent\Collection $payments + * @property-read \Illuminate\Database\Eloquent\Collection $products + * @property-read \Illuminate\Database\Eloquent\Collection $projects + * @property-read \Illuminate\Database\Eloquent\Collection $purchase_orders + * @property-read \Illuminate\Database\Eloquent\Collection $quotes + * @property-read \Illuminate\Database\Eloquent\Collection $recurring_expenses + * @property-read \Illuminate\Database\Eloquent\Collection $recurring_invoices + * @property-read \Illuminate\Database\Eloquent\Collection $schedulers + * @property-read \Illuminate\Database\Eloquent\Collection $subscriptions + * @property-read \Illuminate\Database\Eloquent\Collection $system_log_relation + * @property-read \Illuminate\Database\Eloquent\Collection $system_logs + * @property-read \Illuminate\Database\Eloquent\Collection $task_schedulers + * @property-read \Illuminate\Database\Eloquent\Collection $task_statuses + * @property-read \Illuminate\Database\Eloquent\Collection $tasks + * @property-read \Illuminate\Database\Eloquent\Collection $tax_rates + * @property-read \Illuminate\Database\Eloquent\Collection $tokens + * @property-read \Illuminate\Database\Eloquent\Collection $tokens_hashed + * @property-read \Illuminate\Database\Eloquent\Collection $user_designs + * @property-read \Illuminate\Database\Eloquent\Collection $user_payment_terms + * @property-read \Illuminate\Database\Eloquent\Collection $users + * @property-read \Illuminate\Database\Eloquent\Collection $vendors + * @property-read \Illuminate\Database\Eloquent\Collection $webhooks + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $all_activities + * @property-read \Illuminate\Database\Eloquent\Collection $all_documents + * @property-read \Illuminate\Database\Eloquent\Collection $bank_integrations + * @property-read \Illuminate\Database\Eloquent\Collection $bank_transaction_rules + * @property-read \Illuminate\Database\Eloquent\Collection $bank_transactions + * @property-read \Illuminate\Database\Eloquent\Collection $client_contacts + * @property-read \Illuminate\Database\Eloquent\Collection $client_gateway_tokens + * @property-read \Illuminate\Database\Eloquent\Collection $clients + * @property-read \Illuminate\Database\Eloquent\Collection $company_gateways + * @property-read \Illuminate\Database\Eloquent\Collection $company_users + * @property-read \Illuminate\Database\Eloquent\Collection $contacts + * @property-read \Illuminate\Database\Eloquent\Collection $credits + * @property-read \Illuminate\Database\Eloquent\Collection $designs + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $expense_categories + * @property-read \Illuminate\Database\Eloquent\Collection $expenses + * @property-read \Illuminate\Database\Eloquent\Collection $group_settings + * @property-read \Illuminate\Database\Eloquent\Collection $groups + * @property-read \Illuminate\Database\Eloquent\Collection $invoices + * @property-read \Illuminate\Database\Eloquent\Collection $ledger + * @property-read \Illuminate\Database\Eloquent\Collection $payment_terms + * @property-read \Illuminate\Database\Eloquent\Collection $payments + * @property-read \Illuminate\Database\Eloquent\Collection $products + * @property-read \Illuminate\Database\Eloquent\Collection $projects + * @property-read \Illuminate\Database\Eloquent\Collection $purchase_orders + * @property-read \Illuminate\Database\Eloquent\Collection $quotes + * @property-read \Illuminate\Database\Eloquent\Collection $recurring_expenses + * @property-read \Illuminate\Database\Eloquent\Collection $recurring_invoices + * @property-read \Illuminate\Database\Eloquent\Collection $schedulers + * @property-read \Illuminate\Database\Eloquent\Collection $subscriptions + * @property-read \Illuminate\Database\Eloquent\Collection $system_log_relation + * @property-read \Illuminate\Database\Eloquent\Collection $system_logs + * @property-read \Illuminate\Database\Eloquent\Collection $task_schedulers + * @property-read \Illuminate\Database\Eloquent\Collection $task_statuses + * @property-read \Illuminate\Database\Eloquent\Collection $tasks + * @property-read \Illuminate\Database\Eloquent\Collection $tax_rates + * @property-read \Illuminate\Database\Eloquent\Collection $tokens + * @property-read \Illuminate\Database\Eloquent\Collection $tokens_hashed + * @property-read \Illuminate\Database\Eloquent\Collection $user_designs + * @property-read \Illuminate\Database\Eloquent\Collection $user_payment_terms + * @property-read \Illuminate\Database\Eloquent\Collection $users + * @property-read \Illuminate\Database\Eloquent\Collection $vendors + * @property-read \Illuminate\Database\Eloquent\Collection $webhooks + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $all_activities + * @property-read \Illuminate\Database\Eloquent\Collection $all_documents + * @property-read \Illuminate\Database\Eloquent\Collection $bank_integrations + * @property-read \Illuminate\Database\Eloquent\Collection $bank_transaction_rules + * @property-read \Illuminate\Database\Eloquent\Collection $bank_transactions + * @property-read \Illuminate\Database\Eloquent\Collection $client_contacts + * @property-read \Illuminate\Database\Eloquent\Collection $client_gateway_tokens + * @property-read \Illuminate\Database\Eloquent\Collection $clients + * @property-read \Illuminate\Database\Eloquent\Collection $company_gateways + * @property-read \Illuminate\Database\Eloquent\Collection $company_users + * @property-read \Illuminate\Database\Eloquent\Collection $contacts + * @property-read \Illuminate\Database\Eloquent\Collection $credits + * @property-read \Illuminate\Database\Eloquent\Collection $designs + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $expense_categories + * @property-read \Illuminate\Database\Eloquent\Collection $expenses + * @property-read \Illuminate\Database\Eloquent\Collection $group_settings + * @property-read \Illuminate\Database\Eloquent\Collection $groups + * @property-read \Illuminate\Database\Eloquent\Collection $invoices + * @property-read \Illuminate\Database\Eloquent\Collection $ledger + * @property-read \Illuminate\Database\Eloquent\Collection $payment_terms + * @property-read \Illuminate\Database\Eloquent\Collection $payments + * @property-read \Illuminate\Database\Eloquent\Collection $products + * @property-read \Illuminate\Database\Eloquent\Collection $projects + * @property-read \Illuminate\Database\Eloquent\Collection $purchase_orders + * @property-read \Illuminate\Database\Eloquent\Collection $quotes + * @property-read \Illuminate\Database\Eloquent\Collection $recurring_expenses + * @property-read \Illuminate\Database\Eloquent\Collection $recurring_invoices + * @property-read \Illuminate\Database\Eloquent\Collection $schedulers + * @property-read \Illuminate\Database\Eloquent\Collection $subscriptions + * @property-read \Illuminate\Database\Eloquent\Collection $system_log_relation + * @property-read \Illuminate\Database\Eloquent\Collection $system_logs + * @property-read \Illuminate\Database\Eloquent\Collection $task_schedulers + * @property-read \Illuminate\Database\Eloquent\Collection $task_statuses + * @property-read \Illuminate\Database\Eloquent\Collection $tasks + * @property-read \Illuminate\Database\Eloquent\Collection $tax_rates + * @property-read \Illuminate\Database\Eloquent\Collection $tokens + * @property-read \Illuminate\Database\Eloquent\Collection $tokens_hashed + * @property-read \Illuminate\Database\Eloquent\Collection $user_designs + * @property-read \Illuminate\Database\Eloquent\Collection $user_payment_terms + * @property-read \Illuminate\Database\Eloquent\Collection $users + * @property-read \Illuminate\Database\Eloquent\Collection $vendors + * @property-read \Illuminate\Database\Eloquent\Collection $webhooks * @mixin \Eloquent */ class Company extends BaseModel diff --git a/app/Models/CompanyGateway.php b/app/Models/CompanyGateway.php index 4e7ebaf7c2c2..b19b65d98071 100644 --- a/app/Models/CompanyGateway.php +++ b/app/Models/CompanyGateway.php @@ -95,6 +95,11 @@ use Illuminate\Database\Eloquent\SoftDeletes; * @property-read \Illuminate\Database\Eloquent\Collection $client_gateway_tokens * @property-read \Illuminate\Database\Eloquent\Collection $client_gateway_tokens * @property-read \Illuminate\Database\Eloquent\Collection $client_gateway_tokens + * @property-read \Illuminate\Database\Eloquent\Collection $client_gateway_tokens + * @property-read \Illuminate\Database\Eloquent\Collection $client_gateway_tokens + * @property-read \Illuminate\Database\Eloquent\Collection $client_gateway_tokens + * @property-read \Illuminate\Database\Eloquent\Collection $client_gateway_tokens + * @property-read \Illuminate\Database\Eloquent\Collection $client_gateway_tokens * @mixin \Eloquent */ class CompanyGateway extends BaseModel diff --git a/app/Models/CompanyUser.php b/app/Models/CompanyUser.php index 17825b9ddc41..b88e459c54ab 100644 --- a/app/Models/CompanyUser.php +++ b/app/Models/CompanyUser.php @@ -76,6 +76,21 @@ use Illuminate\Database\Eloquent\SoftDeletes; * @property-read \Illuminate\Database\Eloquent\Collection $token * @property-read \Illuminate\Database\Eloquent\Collection $tokens * @property-read \Illuminate\Database\Eloquent\Collection $users + * @property-read \Illuminate\Database\Eloquent\Collection $token + * @property-read \Illuminate\Database\Eloquent\Collection $tokens + * @property-read \Illuminate\Database\Eloquent\Collection $users + * @property-read \Illuminate\Database\Eloquent\Collection $token + * @property-read \Illuminate\Database\Eloquent\Collection $tokens + * @property-read \Illuminate\Database\Eloquent\Collection $users + * @property-read \Illuminate\Database\Eloquent\Collection $token + * @property-read \Illuminate\Database\Eloquent\Collection $tokens + * @property-read \Illuminate\Database\Eloquent\Collection $users + * @property-read \Illuminate\Database\Eloquent\Collection $token + * @property-read \Illuminate\Database\Eloquent\Collection $tokens + * @property-read \Illuminate\Database\Eloquent\Collection $users + * @property-read \Illuminate\Database\Eloquent\Collection $token + * @property-read \Illuminate\Database\Eloquent\Collection $tokens + * @property-read \Illuminate\Database\Eloquent\Collection $users * @mixin \Eloquent */ class CompanyUser extends Pivot diff --git a/app/Models/Credit.php b/app/Models/Credit.php index d649e894f582..5f3255a1df57 100644 --- a/app/Models/Credit.php +++ b/app/Models/Credit.php @@ -206,6 +206,41 @@ use Laracasts\Presenter\PresentableTrait; * @property-read \Illuminate\Database\Eloquent\Collection $invitations * @property-read \Illuminate\Database\Eloquent\Collection $invoices * @property-read \Illuminate\Database\Eloquent\Collection $payments + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $company_ledger + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $history + * @property-read \Illuminate\Database\Eloquent\Collection $invitations + * @property-read \Illuminate\Database\Eloquent\Collection $invoices + * @property-read \Illuminate\Database\Eloquent\Collection $payments + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $company_ledger + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $history + * @property-read \Illuminate\Database\Eloquent\Collection $invitations + * @property-read \Illuminate\Database\Eloquent\Collection $invoices + * @property-read \Illuminate\Database\Eloquent\Collection $payments + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $company_ledger + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $history + * @property-read \Illuminate\Database\Eloquent\Collection $invitations + * @property-read \Illuminate\Database\Eloquent\Collection $invoices + * @property-read \Illuminate\Database\Eloquent\Collection $payments + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $company_ledger + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $history + * @property-read \Illuminate\Database\Eloquent\Collection $invitations + * @property-read \Illuminate\Database\Eloquent\Collection $invoices + * @property-read \Illuminate\Database\Eloquent\Collection $payments + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $company_ledger + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $history + * @property-read \Illuminate\Database\Eloquent\Collection $invitations + * @property-read \Illuminate\Database\Eloquent\Collection $invoices + * @property-read \Illuminate\Database\Eloquent\Collection $payments * @mixin \Eloquent */ class Credit extends BaseModel diff --git a/app/Models/Expense.php b/app/Models/Expense.php index 5bb420eca56a..f4a48d1cf35a 100644 --- a/app/Models/Expense.php +++ b/app/Models/Expense.php @@ -133,6 +133,11 @@ use Illuminate\Database\Eloquent\SoftDeletes; * @property-read \Illuminate\Database\Eloquent\Collection $documents * @property-read \Illuminate\Database\Eloquent\Collection $documents * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $documents * @mixin \Eloquent */ class Expense extends BaseModel diff --git a/app/Models/GatewayType.php b/app/Models/GatewayType.php index 5b8b42aa0fd1..98a9e6e71439 100644 --- a/app/Models/GatewayType.php +++ b/app/Models/GatewayType.php @@ -31,6 +31,11 @@ namespace App\Models; * @property-read \Illuminate\Database\Eloquent\Collection $payment_methods * @property-read \Illuminate\Database\Eloquent\Collection $payment_methods * @property-read \Illuminate\Database\Eloquent\Collection $payment_methods + * @property-read \Illuminate\Database\Eloquent\Collection $payment_methods + * @property-read \Illuminate\Database\Eloquent\Collection $payment_methods + * @property-read \Illuminate\Database\Eloquent\Collection $payment_methods + * @property-read \Illuminate\Database\Eloquent\Collection $payment_methods + * @property-read \Illuminate\Database\Eloquent\Collection $payment_methods * @mixin \Eloquent */ class GatewayType extends StaticModel diff --git a/app/Models/GroupSetting.php b/app/Models/GroupSetting.php index 0e065066a673..b736b4c6a72e 100644 --- a/app/Models/GroupSetting.php +++ b/app/Models/GroupSetting.php @@ -60,6 +60,16 @@ use Illuminate\Database\Eloquent\SoftDeletes; * @property-read \Illuminate\Database\Eloquent\Collection $documents * @property-read \Illuminate\Database\Eloquent\Collection $clients * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $clients + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $clients + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $clients + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $clients + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $clients + * @property-read \Illuminate\Database\Eloquent\Collection $documents * @mixin \Eloquent */ class GroupSetting extends StaticModel diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php index 311674d0cd3a..ffce822140e2 100644 --- a/app/Models/Invoice.php +++ b/app/Models/Invoice.php @@ -232,6 +232,51 @@ use Laracasts\Presenter\PresentableTrait; * @property-read \Illuminate\Database\Eloquent\Collection $invitations * @property-read \Illuminate\Database\Eloquent\Collection $payments * @property-read \Illuminate\Database\Eloquent\Collection $tasks + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $company_ledger + * @property-read \Illuminate\Database\Eloquent\Collection $credits + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $expenses + * @property-read \Illuminate\Database\Eloquent\Collection $history + * @property-read \Illuminate\Database\Eloquent\Collection $invitations + * @property-read \Illuminate\Database\Eloquent\Collection $payments + * @property-read \Illuminate\Database\Eloquent\Collection $tasks + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $company_ledger + * @property-read \Illuminate\Database\Eloquent\Collection $credits + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $expenses + * @property-read \Illuminate\Database\Eloquent\Collection $history + * @property-read \Illuminate\Database\Eloquent\Collection $invitations + * @property-read \Illuminate\Database\Eloquent\Collection $payments + * @property-read \Illuminate\Database\Eloquent\Collection $tasks + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $company_ledger + * @property-read \Illuminate\Database\Eloquent\Collection $credits + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $expenses + * @property-read \Illuminate\Database\Eloquent\Collection $history + * @property-read \Illuminate\Database\Eloquent\Collection $invitations + * @property-read \Illuminate\Database\Eloquent\Collection $payments + * @property-read \Illuminate\Database\Eloquent\Collection $tasks + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $company_ledger + * @property-read \Illuminate\Database\Eloquent\Collection $credits + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $expenses + * @property-read \Illuminate\Database\Eloquent\Collection $history + * @property-read \Illuminate\Database\Eloquent\Collection $invitations + * @property-read \Illuminate\Database\Eloquent\Collection $payments + * @property-read \Illuminate\Database\Eloquent\Collection $tasks + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $company_ledger + * @property-read \Illuminate\Database\Eloquent\Collection $credits + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $expenses + * @property-read \Illuminate\Database\Eloquent\Collection $history + * @property-read \Illuminate\Database\Eloquent\Collection $invitations + * @property-read \Illuminate\Database\Eloquent\Collection $payments + * @property-read \Illuminate\Database\Eloquent\Collection $tasks * @mixin \Eloquent */ class Invoice extends BaseModel diff --git a/app/Models/Payment.php b/app/Models/Payment.php index 15c738413b64..aed3fbc295d2 100644 --- a/app/Models/Payment.php +++ b/app/Models/Payment.php @@ -147,6 +147,31 @@ use Illuminate\Database\Eloquent\SoftDeletes; * @property-read \Illuminate\Database\Eloquent\Collection $documents * @property-read \Illuminate\Database\Eloquent\Collection $invoices * @property-read \Illuminate\Database\Eloquent\Collection $paymentables + * @property-read \Illuminate\Database\Eloquent\Collection $company_ledger + * @property-read \Illuminate\Database\Eloquent\Collection $credits + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $invoices + * @property-read \Illuminate\Database\Eloquent\Collection $paymentables + * @property-read \Illuminate\Database\Eloquent\Collection $company_ledger + * @property-read \Illuminate\Database\Eloquent\Collection $credits + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $invoices + * @property-read \Illuminate\Database\Eloquent\Collection $paymentables + * @property-read \Illuminate\Database\Eloquent\Collection $company_ledger + * @property-read \Illuminate\Database\Eloquent\Collection $credits + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $invoices + * @property-read \Illuminate\Database\Eloquent\Collection $paymentables + * @property-read \Illuminate\Database\Eloquent\Collection $company_ledger + * @property-read \Illuminate\Database\Eloquent\Collection $credits + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $invoices + * @property-read \Illuminate\Database\Eloquent\Collection $paymentables + * @property-read \Illuminate\Database\Eloquent\Collection $company_ledger + * @property-read \Illuminate\Database\Eloquent\Collection $credits + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $invoices + * @property-read \Illuminate\Database\Eloquent\Collection $paymentables * @mixin \Eloquent */ class Payment extends BaseModel diff --git a/app/Models/Product.php b/app/Models/Product.php index 44deea41a940..e360fd145ba7 100644 --- a/app/Models/Product.php +++ b/app/Models/Product.php @@ -101,6 +101,11 @@ use League\CommonMark\CommonMarkConverter; * @property-read \Illuminate\Database\Eloquent\Collection $documents * @method static \Illuminate\Database\Eloquent\Builder|Product whereTaxId($value) * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $documents * @mixin \Eloquent */ class Product extends BaseModel @@ -109,12 +114,13 @@ class Product extends BaseModel use SoftDeletes; use Filterable; - public const PRODUCT_TYPE_PHYSICAL = 1; public const PRODUCT_TYPE_SERVICE = 2; public const PRODUCT_TYPE_DIGITAL = 3; - public const PRODUCT_TYPE_FREIGHT = 4; - public const PRODUCT_TAX_EXEMPT = 5; + public const PRODUCT_TYPE_SHIPPING = 4; + public const PRODUCT_TYPE_EXEMPT = 5; + public const PRODUCT_TYPE_REDUCED_TAX = 6; + public const PRODUCT_TYPE_OVERRIDE_TAX = 7; protected $fillable = [ 'custom_value1', diff --git a/app/Models/Project.php b/app/Models/Project.php index 4eb60947d7a8..a4c837c69f80 100644 --- a/app/Models/Project.php +++ b/app/Models/Project.php @@ -78,6 +78,16 @@ use Laracasts\Presenter\PresentableTrait; * @property-read \Illuminate\Database\Eloquent\Collection $tasks * @property-read \Illuminate\Database\Eloquent\Collection $documents * @property-read \Illuminate\Database\Eloquent\Collection $tasks + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $tasks + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $tasks + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $tasks + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $tasks + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $tasks * @mixin \Eloquent */ class Project extends BaseModel diff --git a/app/Models/Proposal.php b/app/Models/Proposal.php index dd7133ee3004..7b86e0ed4b9c 100644 --- a/app/Models/Proposal.php +++ b/app/Models/Proposal.php @@ -31,6 +31,11 @@ use App\Utils\Traits\MakesHash; * @property-read \Illuminate\Database\Eloquent\Collection $documents * @property-read \Illuminate\Database\Eloquent\Collection $documents * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $documents * @mixin \Eloquent */ class Proposal extends BaseModel diff --git a/app/Models/PurchaseOrder.php b/app/Models/PurchaseOrder.php index 1a82c57c6abe..c44cf6abc865 100644 --- a/app/Models/PurchaseOrder.php +++ b/app/Models/PurchaseOrder.php @@ -198,6 +198,36 @@ use Illuminate\Support\Facades\Storage; * @property-read \Illuminate\Database\Eloquent\Collection $invitations * @property-read \Illuminate\Database\Eloquent\Collection $invoices * @property-read \Illuminate\Database\Eloquent\Collection $payments + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $history + * @property-read \Illuminate\Database\Eloquent\Collection $invitations + * @property-read \Illuminate\Database\Eloquent\Collection $invoices + * @property-read \Illuminate\Database\Eloquent\Collection $payments + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $history + * @property-read \Illuminate\Database\Eloquent\Collection $invitations + * @property-read \Illuminate\Database\Eloquent\Collection $invoices + * @property-read \Illuminate\Database\Eloquent\Collection $payments + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $history + * @property-read \Illuminate\Database\Eloquent\Collection $invitations + * @property-read \Illuminate\Database\Eloquent\Collection $invoices + * @property-read \Illuminate\Database\Eloquent\Collection $payments + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $history + * @property-read \Illuminate\Database\Eloquent\Collection $invitations + * @property-read \Illuminate\Database\Eloquent\Collection $invoices + * @property-read \Illuminate\Database\Eloquent\Collection $payments + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $history + * @property-read \Illuminate\Database\Eloquent\Collection $invitations + * @property-read \Illuminate\Database\Eloquent\Collection $invoices + * @property-read \Illuminate\Database\Eloquent\Collection $payments * @mixin \Eloquent */ class PurchaseOrder extends BaseModel diff --git a/app/Models/Quote.php b/app/Models/Quote.php index 71daf00ac449..1c0940c88d41 100644 --- a/app/Models/Quote.php +++ b/app/Models/Quote.php @@ -193,6 +193,26 @@ use Laracasts\Presenter\PresentableTrait; * @property-read \Illuminate\Database\Eloquent\Collection $documents * @property-read \Illuminate\Database\Eloquent\Collection $history * @property-read \Illuminate\Database\Eloquent\Collection $invitations + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $history + * @property-read \Illuminate\Database\Eloquent\Collection $invitations + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $history + * @property-read \Illuminate\Database\Eloquent\Collection $invitations + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $history + * @property-read \Illuminate\Database\Eloquent\Collection $invitations + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $history + * @property-read \Illuminate\Database\Eloquent\Collection $invitations + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $history + * @property-read \Illuminate\Database\Eloquent\Collection $invitations * @mixin \Eloquent */ class Quote extends BaseModel diff --git a/app/Models/RecurringExpense.php b/app/Models/RecurringExpense.php index d93e3f242a38..f96a0d9a85a4 100644 --- a/app/Models/RecurringExpense.php +++ b/app/Models/RecurringExpense.php @@ -142,6 +142,11 @@ use Illuminate\Support\Carbon; * @property-read \Illuminate\Database\Eloquent\Collection $documents * @property-read \Illuminate\Database\Eloquent\Collection $documents * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $documents * @mixin \Eloquent */ class RecurringExpense extends BaseModel diff --git a/app/Models/RecurringInvoice.php b/app/Models/RecurringInvoice.php index 83eed4296d32..3667b25583f3 100644 --- a/app/Models/RecurringInvoice.php +++ b/app/Models/RecurringInvoice.php @@ -194,6 +194,31 @@ use Laracasts\Presenter\PresentableTrait; * @property-read \Illuminate\Database\Eloquent\Collection $history * @property-read \Illuminate\Database\Eloquent\Collection $invitations * @property-read \Illuminate\Database\Eloquent\Collection $invoices + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $history + * @property-read \Illuminate\Database\Eloquent\Collection $invitations + * @property-read \Illuminate\Database\Eloquent\Collection $invoices + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $history + * @property-read \Illuminate\Database\Eloquent\Collection $invitations + * @property-read \Illuminate\Database\Eloquent\Collection $invoices + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $history + * @property-read \Illuminate\Database\Eloquent\Collection $invitations + * @property-read \Illuminate\Database\Eloquent\Collection $invoices + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $history + * @property-read \Illuminate\Database\Eloquent\Collection $invitations + * @property-read \Illuminate\Database\Eloquent\Collection $invoices + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $history + * @property-read \Illuminate\Database\Eloquent\Collection $invitations + * @property-read \Illuminate\Database\Eloquent\Collection $invoices * @mixin \Eloquent */ class RecurringInvoice extends BaseModel diff --git a/app/Models/RecurringQuote.php b/app/Models/RecurringQuote.php index 318bed3853b5..4759f90f5660 100644 --- a/app/Models/RecurringQuote.php +++ b/app/Models/RecurringQuote.php @@ -186,6 +186,31 @@ use Laracasts\Presenter\PresentableTrait; * @property-read \Illuminate\Database\Eloquent\Collection $history * @property-read \Illuminate\Database\Eloquent\Collection $invitations * @property-read \Illuminate\Database\Eloquent\Collection $quotes + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $history + * @property-read \Illuminate\Database\Eloquent\Collection $invitations + * @property-read \Illuminate\Database\Eloquent\Collection $quotes + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $history + * @property-read \Illuminate\Database\Eloquent\Collection $invitations + * @property-read \Illuminate\Database\Eloquent\Collection $quotes + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $history + * @property-read \Illuminate\Database\Eloquent\Collection $invitations + * @property-read \Illuminate\Database\Eloquent\Collection $quotes + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $history + * @property-read \Illuminate\Database\Eloquent\Collection $invitations + * @property-read \Illuminate\Database\Eloquent\Collection $quotes + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $history + * @property-read \Illuminate\Database\Eloquent\Collection $invitations + * @property-read \Illuminate\Database\Eloquent\Collection $quotes * @mixin \Eloquent */ class RecurringQuote extends BaseModel diff --git a/app/Models/Task.php b/app/Models/Task.php index 849d6cb9fa3f..70e00f1ac34f 100644 --- a/app/Models/Task.php +++ b/app/Models/Task.php @@ -94,6 +94,11 @@ use Illuminate\Support\Carbon; * @property-read \Illuminate\Database\Eloquent\Collection $documents * @property-read \Illuminate\Database\Eloquent\Collection $documents * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $documents * @mixin \Eloquent */ class Task extends BaseModel diff --git a/app/Models/User.php b/app/Models/User.php index ae02be639d32..ea4185e21620 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -160,6 +160,41 @@ use Laracasts\Presenter\PresentableTrait; * @property-read \Illuminate\Database\Eloquent\Collection $documents * @property-read \Illuminate\Notifications\DatabaseNotificationCollection $notifications * @property-read \Illuminate\Database\Eloquent\Collection $tokens + * @property-read \Illuminate\Database\Eloquent\Collection $clients + * @property-read \Illuminate\Database\Eloquent\Collection $companies + * @property-read \Illuminate\Database\Eloquent\Collection $company_users + * @property-read \Illuminate\Database\Eloquent\Collection $contacts + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Notifications\DatabaseNotificationCollection $notifications + * @property-read \Illuminate\Database\Eloquent\Collection $tokens + * @property-read \Illuminate\Database\Eloquent\Collection $clients + * @property-read \Illuminate\Database\Eloquent\Collection $companies + * @property-read \Illuminate\Database\Eloquent\Collection $company_users + * @property-read \Illuminate\Database\Eloquent\Collection $contacts + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Notifications\DatabaseNotificationCollection $notifications + * @property-read \Illuminate\Database\Eloquent\Collection $tokens + * @property-read \Illuminate\Database\Eloquent\Collection $clients + * @property-read \Illuminate\Database\Eloquent\Collection $companies + * @property-read \Illuminate\Database\Eloquent\Collection $company_users + * @property-read \Illuminate\Database\Eloquent\Collection $contacts + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Notifications\DatabaseNotificationCollection $notifications + * @property-read \Illuminate\Database\Eloquent\Collection $tokens + * @property-read \Illuminate\Database\Eloquent\Collection $clients + * @property-read \Illuminate\Database\Eloquent\Collection $companies + * @property-read \Illuminate\Database\Eloquent\Collection $company_users + * @property-read \Illuminate\Database\Eloquent\Collection $contacts + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Notifications\DatabaseNotificationCollection $notifications + * @property-read \Illuminate\Database\Eloquent\Collection $tokens + * @property-read \Illuminate\Database\Eloquent\Collection $clients + * @property-read \Illuminate\Database\Eloquent\Collection $companies + * @property-read \Illuminate\Database\Eloquent\Collection $company_users + * @property-read \Illuminate\Database\Eloquent\Collection $contacts + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Notifications\DatabaseNotificationCollection $notifications + * @property-read \Illuminate\Database\Eloquent\Collection $tokens * @mixin \Eloquent */ class User extends Authenticatable implements MustVerifyEmail diff --git a/app/Models/Vendor.php b/app/Models/Vendor.php index 8d2df534ef38..4c8f916729d0 100644 --- a/app/Models/Vendor.php +++ b/app/Models/Vendor.php @@ -116,6 +116,26 @@ use Laracasts\Presenter\PresentableTrait; * @property-read \Illuminate\Database\Eloquent\Collection $contacts * @property-read \Illuminate\Database\Eloquent\Collection $documents * @property-read \Illuminate\Database\Eloquent\Collection $primary_contact + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $contacts + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $primary_contact + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $contacts + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $primary_contact + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $contacts + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $primary_contact + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $contacts + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $primary_contact + * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $contacts + * @property-read \Illuminate\Database\Eloquent\Collection $documents + * @property-read \Illuminate\Database\Eloquent\Collection $primary_contact * @mixin \Eloquent */ class Vendor extends BaseModel diff --git a/app/Models/VendorContact.php b/app/Models/VendorContact.php index c6514203e01f..6f8fec742068 100644 --- a/app/Models/VendorContact.php +++ b/app/Models/VendorContact.php @@ -116,6 +116,16 @@ use Laracasts\Presenter\PresentableTrait; * @property-read \Illuminate\Database\Eloquent\Collection $purchase_order_invitations * @property-read \Illuminate\Notifications\DatabaseNotificationCollection $notifications * @property-read \Illuminate\Database\Eloquent\Collection $purchase_order_invitations + * @property-read \Illuminate\Notifications\DatabaseNotificationCollection $notifications + * @property-read \Illuminate\Database\Eloquent\Collection $purchase_order_invitations + * @property-read \Illuminate\Notifications\DatabaseNotificationCollection $notifications + * @property-read \Illuminate\Database\Eloquent\Collection $purchase_order_invitations + * @property-read \Illuminate\Notifications\DatabaseNotificationCollection $notifications + * @property-read \Illuminate\Database\Eloquent\Collection $purchase_order_invitations + * @property-read \Illuminate\Notifications\DatabaseNotificationCollection $notifications + * @property-read \Illuminate\Database\Eloquent\Collection $purchase_order_invitations + * @property-read \Illuminate\Notifications\DatabaseNotificationCollection $notifications + * @property-read \Illuminate\Database\Eloquent\Collection $purchase_order_invitations * @mixin \Eloquent */ class VendorContact extends Authenticatable implements HasLocalePreference diff --git a/app/Services/Tax/ProcessRule.php b/app/Services/Tax/ProcessRule.php deleted file mode 100644 index 21a4b197d799..000000000000 --- a/app/Services/Tax/ProcessRule.php +++ /dev/null @@ -1,153 +0,0 @@ -setUp() - ->validateVat() - ->calculateVatRates(); - } - - public function hasValidVatNumber(): bool - { - return $this->valid_vat_number; - } - - public function getVatRate(): float - { - return $this->vat_rate; - } - - public function getVatReducedRate(): float - { - return $this->vat_reduced_rate; - } - - public function getVendorCountryCode(): string - { - return $this->vendor_country_code; - } - - public function getClientCountryCode(): string - { - return $this->client_country_code; - } - - private function setUp(): self - { - $this->vendor_country_code = Str::lower($this->company->country()->iso_3166_2); - - $this->client_country_code = $this->client->shipping_country ? Str::lower($this->client->shipping_country->iso_3166_2) : Str::lower($this->client->country->iso_3166_2); - - $class = "App\\DataMapper\\Tax\\".$this->vendor_country_code."\\Rule"; - - $this->rule = new $class(); - - return $this; - } - - private function validateVat(): self - { - $vat_check = (new VatNumberCheck($this->client->vat_number, $this->client_country_code))->run(); - - $this->valid_vat_number = $vat_check->isValid(); - - return $this; - } - - private function calculateVatRates(): self - { - - if( - (($this->vendor_country_code == $this->client_country_code) && $this->valid_vat_number && $this->rule->business_tax_exempt) || - (in_array($this->client_country_code, $this->eu_country_codes) && $this->valid_vat_number && $this->rule->business_tax_exempt) - ) { - $this->vat_rate = 0.0; - $this->vat_reduced_rate = 0.0; - } - elseif(!in_array(strtoupper($this->client_country_code), $this->eu_country_codes) && ($this->rule->foreign_consumer_tax_exempt || $this->rule->foreign_business_tax_exempt)) { - nlog($this->client_country_code); - $this->vat_rate = 0.0; - $this->vat_reduced_rate = 0.0; - } - elseif(in_array(strtoupper($this->client_country_code), $this->eu_country_codes) && !$this->valid_vat_number) { - $rate_name = $this->client_country_code."_vat_rate"; - $this->vat_rate = $this->rule->{$rate_name}; - $this->vat_reduced_rate = $this->rule->vat_reduced_rate; - } - else { - $rate_name = $this->vendor_country_code."_vat_rate"; - $this->vat_rate = $this->rule->{$rate_name}; - $this->vat_reduced_rate = $this->rule->vat_reduced_rate; - } - - return $this; - - } -} diff --git a/app/Services/Tax/Providers/TaxProvider.php b/app/Services/Tax/Providers/TaxProvider.php new file mode 100644 index 000000000000..4d71522cf617 --- /dev/null +++ b/app/Services/Tax/Providers/TaxProvider.php @@ -0,0 +1,189 @@ +configureProvider($this->provider); //hard coded for now to one provider, but we'll be able to swap these out later + + $company_details = [ + 'address1' => $this->company->settings->address1, + 'address2' => $this->company->settings->address2, + 'city' => $this->company->settings->city, + 'state' => $this->company->settings->state, + 'postal_code' => $this->company->settings->postal_code, + 'country_id' => $this->company->settings->country_id, + ]; + + $tax_provider = new $this->provider($company_details); + + $tax_provider->setApiCredentials($this->api_credentials); + + $tax_data = $tax_provider->run(); + + $this->company->tax_data = $tax_data; + + $this->company->save(); + + return $this; + + } + + public function updateClientTaxData(): self + { + $this->configureProvider($this->provider); //hard coded for now to one provider, but we'll be able to swap these out later + + $billing_details =[ + 'address1' => $this->client->address1, + 'address2' => $this->client->address2, + 'city' => $this->client->city, + 'state' => $this->client->state, + 'postal_code' => $this->client->postal_code, + 'country_id' => $this->client->country_id, + ]; + + $shipping_details =[ + 'address1' => $this->client->shipping_address1, + 'address2' => $this->client->shipping_address2, + 'city' => $this->client->shipping_city, + 'state' => $this->client->shipping_state, + 'postal_code' => $this->client->shipping_postal_code, + 'country_id' => $this->client->shipping_country_id, + ]; + + + $tax_provider = new $this->provider(); + + $tax_provider->setApiCredentials($this->api_credentials); + + $tax_data = $tax_provider->run(); + + $this->company->tax_data = $tax_data; + + $this->company->save(); + + return $this; + + } + + private function configureProvider(?string $provider): self + { + + match($this->client->country->iso_3166_2){ + 'US' => $this->configureZipTax(), + "AT" => $this->configureEuTax(), + "BE" => $this->configureEuTax(), + "BG" => $this->configureEuTax(), + "HR" => $this->configureEuTax(), + "CY" => $this->configureEuTax(), + "CZ" => $this->configureEuTax(), + "DK" => $this->configureEuTax(), + "EE" => $this->configureEuTax(), + "FI" => $this->configureEuTax(), + "FR" => $this->configureEuTax(), + "DE" => $this->configureEuTax(), + "GR" => $this->configureEuTax(), + "HU" => $this->configureEuTax(), + "IE" => $this->configureEuTax(), + "IT" => $this->configureEuTax(), + "LV" => $this->configureEuTax(), + "LT" => $this->configureEuTax(), + "LU" => $this->configureEuTax(), + "MT" => $this->configureEuTax(), + "NL" => $this->configureEuTax(), + "PL" => $this->configureEuTax(), + "PT" => $this->configureEuTax(), + "RO" => $this->configureEuTax(), + "SK" => $this->configureEuTax(), + "SI" => $this->configureEuTax(), + "ES" => $this->configureEuTax(), + "SE" => $this->configureEuTax(), + default => $this->noTaxRegionDefined(), + }; + + return $this; + + } + + private function configureEuTax(): self + { + $this->provider = EuTax::class; + + return $this; + } + + private function noTaxRegionDefined(): self + { + throw new \Exception("No tax region defined for this country"); + + return $this; + } + + private function configureZipTax(): self + { + + $this->provider = ZipTax::class; + + $this->api_credentials = config('services.tax.zip_tax.key'); + + return $this; + + } + +} \ No newline at end of file diff --git a/app/DataMapper/Tax/CompanyTaxData.php b/app/Services/Tax/Providers/TaxProviderInterface.php similarity index 51% rename from app/DataMapper/Tax/CompanyTaxData.php rename to app/Services/Tax/Providers/TaxProviderInterface.php index 269d2b8a12e9..bd2a60dbaba9 100644 --- a/app/DataMapper/Tax/CompanyTaxData.php +++ b/app/Services/Tax/Providers/TaxProviderInterface.php @@ -9,20 +9,12 @@ * @license https://www.elastic.co/licensing/elastic-license */ -namespace App\DataMapper\Tax; +namespace App\Services\Tax\Providers; -use App\DataMapper\Tax\ZipTax\Response; - -/** - * CompanyTaxData - * - * Definition for the company tax data structure - */ -class CompanyTaxData +interface TaxProviderInterface { - public int $updated_at; - - public function __construct(public Response $origin) - { - } + public function run(); + + public function setApiCredentials(mixed $credentials); + } diff --git a/app/Services/Tax/Providers/ZipTax.php b/app/Services/Tax/Providers/ZipTax.php index 74d43fec16c7..f6e9e950bfb9 100644 --- a/app/Services/Tax/Providers/ZipTax.php +++ b/app/Services/Tax/Providers/ZipTax.php @@ -14,12 +14,14 @@ namespace App\Services\Tax\Providers; use Illuminate\Http\Client\Response; use Illuminate\Support\Facades\Http; -class ZipTax +class ZipTax implements TaxProviderInterface { private string $endpoint = 'https://api.zip-tax.com/request/v40'; - public function __construct(protected string $api_key, protected string $address, protected ?string $postal_code) + private string $api_key = ''; + + public function __construct(protected array $address) { } @@ -43,6 +45,13 @@ class ZipTax } + public function setApiCredentials($api_key): self + { + $this->api_key = $api_key; + + return $this; + } + /** * callApi * diff --git a/app/Services/Tax/TaxService.php b/app/Services/Tax/TaxService.php index 8d29eb299129..354681502bb7 100644 --- a/app/Services/Tax/TaxService.php +++ b/app/Services/Tax/TaxService.php @@ -13,6 +13,7 @@ namespace App\Services\Tax; use App\Models\Client; use App\Models\Company; +use App\Services\Tax\Providers\ZipTax; class TaxService @@ -22,4 +23,15 @@ class TaxService { } + private function validateVat(): self + { + $client_country_code = $this->client->shipping_country ? $this->client->shipping_country->iso_3166_2 : $this->client->country->iso_3166_2; + + $vat_check = (new VatNumberCheck($this->client->vat_number, $client_country_code))->run(); + + $this->client->has_valid_vat_number = $vat_check->isValid(); + $this->client->saveQuietly(); + + return $this; + } } \ No newline at end of file diff --git a/app/Transformers/ClientTransformer.php b/app/Transformers/ClientTransformer.php index 959e8f751985..af7f3338a536 100644 --- a/app/Transformers/ClientTransformer.php +++ b/app/Transformers/ClientTransformer.php @@ -147,6 +147,9 @@ class ClientTransformer extends EntityTransformer 'created_at' => (int) $client->created_at, 'display_name' => $client->present()->name(), 'number' => (string) $client->number ?: '', + 'has_valid_vat_number' => (bool) $client->has_valid_vat_number, + 'is_tax_exempt' => (bool) $client->is_tax_exempt, + 'tax_data' => $client->tax_data ?: '', ]; } } diff --git a/app/Transformers/CompanyTransformer.php b/app/Transformers/CompanyTransformer.php index 69d6f9a3163b..3338c1c26a8e 100644 --- a/app/Transformers/CompanyTransformer.php +++ b/app/Transformers/CompanyTransformer.php @@ -194,6 +194,7 @@ class CompanyTransformer extends EntityTransformer 'notify_vendor_when_paid' => (bool) $company->notify_vendor_when_paid, 'invoice_task_hours' => (bool) $company->invoice_task_hours, 'calculate_taxes' => (bool) $company->calculate_taxes, + 'tax_data' => $company->tax_data ?: '', ]; } diff --git a/app/Utils/HtmlEngine.php b/app/Utils/HtmlEngine.php index 36cd4e272206..cb51089e3207 100644 --- a/app/Utils/HtmlEngine.php +++ b/app/Utils/HtmlEngine.php @@ -374,7 +374,6 @@ class HtmlEngine $data['$user_iban'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'company1', $this->settings->custom_value1, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'company1')]; - $data['$invoice.public_notes'] = ['value' => Helpers::processReservedKeywords(\nl2br($this->entity->public_notes ?: ''), $this->client) ?: '', 'label' => ctrans('texts.public_notes')]; $data['$entity.public_notes'] = &$data['$invoice.public_notes']; $data['$public_notes'] = &$data['$invoice.public_notes']; diff --git a/config/services.php b/config/services.php index 78d3df8341d6..e252ef9a4b27 100644 --- a/config/services.php +++ b/config/services.php @@ -96,4 +96,9 @@ return [ 'redirect' => env('BITBUCKET_OAUTH_REDIRECT'), ], + 'tax' => [ + 'zip_tax' => [ + 'key' => env('ZIP_TAX_KEY', false), + ], + ], ]; diff --git a/database/migrations/2023_03_24_054758_add_client_is_exempt_from_taxes.php b/database/migrations/2023_03_24_054758_add_client_is_exempt_from_taxes.php new file mode 100644 index 000000000000..9de246de581d --- /dev/null +++ b/database/migrations/2023_03_24_054758_add_client_is_exempt_from_taxes.php @@ -0,0 +1,66 @@ +boolean('is_tax_exempt')->default(false); + $table->boolean('has_valid_vat_number')->default(false); + $table->mediumText('tax_data')->nullable()->change(); + }); + + Schema::table('companies', function (Illuminate\Database\Schema\Blueprint $table) { + $table->mediumText('tax_data')->nullable()->change(); + $table->dropColumn('tax_all_products'); + }); + + Schema::table('products', function (Blueprint $table) { + $table->unsignedInteger('tax_id')->nullable(); // the product tax constant + }); + + Company::query() + ->cursor() + ->each(function ($company) { + $company->tax_data = null; + $company->save(); + }); + + Client::query() + ->cursor() + ->each(function ($client) { + $client->tax_data = null; + $client->save(); + }); + + Product::query() + ->cursor() + ->each(function ($product) { + $product->tax_id = 1; + $product->save(); + }); + + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + } +}; diff --git a/phpstan.neon b/phpstan.neon index 772e2bd19fb3..0324dc8d0903 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -2,4 +2,5 @@ parameters: level: 2 paths: - app -# - tests + universalObjectCratesClasses: + - App\DataMapper\Tax\RuleInterface \ No newline at end of file diff --git a/tests/Unit/Tax/EuTaxTest.php b/tests/Unit/Tax/EuTaxTest.php new file mode 100644 index 000000000000..f6eae304295b --- /dev/null +++ b/tests/Unit/Tax/EuTaxTest.php @@ -0,0 +1,616 @@ +withoutMiddleware( + ThrottleRequests::class + ); + + $this->withoutExceptionHandling(); + + $this->makeTestData(); + } + + public function testInvoiceTaxCalcDetoBeNoVat() + { + $settings = CompanySettings::defaults(); + $settings->country_id = '276'; // germany + + $tax_data = new TaxModel(); + $tax_data->seller_region = 'DE'; + $tax_data->seller_subregion = 'DE'; + $tax_data->regions->EU->has_sales_above_threshold = true; + $tax_data->regions->EU->tax_all = true; + + $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' => 56, + 'shipping_country_id' => 56, + 'has_valid_vat_number' => 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_rate1' => 0, + 'tax_rate2' => 0, + 'tax_rate3' => 0, + 'tax_name1' => '', + 'tax_name2' => '', + 'tax_name3' => '', + 'tax_data' => new Response([]), + ]); + + $invoice = $invoice->calc()->getInvoice()->service()->markSent()->save(); + + $this->assertEquals(21, $invoice->line_items[0]->tax_rate1); + $this->assertEquals(121, $invoice->amount); + } + + public function testInvoiceTaxCalcDetoBe() + { + $settings = CompanySettings::defaults(); + $settings->country_id = '276'; // germany + + $tax_data = new TaxModel(); + $tax_data->seller_region = 'DE'; + $tax_data->seller_subregion = 'DE'; + $tax_data->regions->EU->has_sales_above_threshold = true; + $tax_data->regions->EU->tax_all = true; + + $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' => 56, + 'shipping_country_id' => 56, + 'has_valid_vat_number' => true, + ]); + + $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_rate1' => 0, + 'tax_rate2' => 0, + 'tax_rate3' => 0, + 'tax_name1' => '', + 'tax_name2' => '', + 'tax_name3' => '', + 'tax_data' => new Response([]), + ]); + + $invoice = $invoice->calc()->getInvoice()->service()->markSent()->save(); + + $this->assertEquals(0, $invoice->line_items[0]->tax_rate1); + $this->assertEquals(100, $invoice->amount); + } + + + public function testInvoiceTaxCalcDetoDe() + { + $settings = CompanySettings::defaults(); + $settings->country_id = '276'; // germany + + $tax_data = new TaxModel(); + $tax_data->seller_region = 'DE'; + $tax_data->seller_subregion = 'DE'; + $tax_data->regions->EU->has_sales_above_threshold = true; + $tax_data->regions->EU->tax_all = true; + + $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' => 276, + 'shipping_country_id' => 276, + 'has_valid_vat_number' => true, + ]); + + $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_rate1' => 0, + 'tax_rate2' => 0, + 'tax_rate3' => 0, + 'tax_name1' => '', + 'tax_name2' => '', + 'tax_name3' => '', + 'tax_data' => new Response([]), + ]); + + $invoice = $invoice->calc()->getInvoice(); + + $this->assertEquals(19, $invoice->line_items[0]->tax_rate1); + $this->assertEquals(119, $invoice->amount); + + } + + + public function testCorrectRuleInit() + { + + $settings = CompanySettings::defaults(); + $settings->country_id = '276'; // germany + + $tax_data = new TaxModel(); + $tax_data->seller_region = 'DE'; + $tax_data->seller_subregion = 'DE'; + $tax_data->regions->EU->has_sales_above_threshold = true; + $tax_data->regions->EU->tax_all = true; + + $company = Company::factory()->create([ + 'account_id' => $this->account->id, + 'settings' => $settings, + 'tax_data' => $tax_data, + ]); + + $client = Client::factory()->create([ + 'user_id' => $this->user->id, + 'company_id' => $company->id, + 'country_id' => 276, + 'shipping_country_id' => 276, + 'has_valid_vat_number' => false, + ]); + + $process = new Rule(); + $process->setClient($client); + $process->init(); + + $this->assertEquals('DE', $process->vendor_country_code); + + $this->assertEquals('DE', $process->client_country_code); + + $this->assertFalse($client->has_valid_vat_number); + + $this->assertInstanceOf(Rule::class, $process); + + $this->assertEquals(19, $process->vat_rate); + + $this->assertEquals(7, $process->reduced_vat_rate); + + + } + + public function testEuCorrectRuleInit() + { + + $settings = CompanySettings::defaults(); + $settings->country_id = '276'; // germany + + $tax_data = new TaxModel(); + $tax_data->seller_region = 'DE'; + $tax_data->seller_subregion = 'DE'; + $tax_data->regions->EU->has_sales_above_threshold = true; + $tax_data->regions->EU->tax_all = true; + + $company = Company::factory()->create([ + 'account_id' => $this->account->id, + 'settings' => $settings, + 'tax_data' => $tax_data, + ]); + + + $client = Client::factory()->create([ + 'user_id' => $this->user->id, + 'company_id' => $company->id, + 'country_id' => 56, + 'shipping_country_id' => 56, + 'has_valid_vat_number' => false, + ]); + + $process = new Rule(); + $process->setClient($client); + $process->init(); + + + $this->assertEquals('DE', $process->vendor_country_code); + + $this->assertEquals('BE', $process->client_country_code); + + $this->assertFalse($client->has_valid_vat_number); + + $this->assertInstanceOf(Rule::class, $process); + + $this->assertEquals(21, $process->vat_rate); + + $this->assertEquals(6, $process->reduced_vat_rate); + + + } + + public function testForeignCorrectRuleInit() + { + + $settings = CompanySettings::defaults(); + $settings->country_id = '276'; // germany + + $company = Company::factory()->create([ + 'account_id' => $this->account->id, + 'settings' => $settings + ]); + + $client = Client::factory()->create([ + 'user_id' => $this->user->id, + 'company_id' => $company->id, + 'country_id' => 840, + 'shipping_country_id' => 840, + 'has_valid_vat_number' => false, + ]); + + $process = new Rule(); + $process->setClient($client); + $process->init(); + + $this->assertEquals('DE', $process->vendor_country_code); + + $this->assertEquals('US', $process->client_country_code); + + $this->assertFalse($client->has_valid_vat_number); + + $this->assertInstanceOf(Rule::class, $process); + + $this->assertEquals(0, $process->vat_rate); + + $this->assertEquals(0, $process->reduced_vat_rate); + + + } + + public function testSubThresholdCorrectRate() + { + + $settings = CompanySettings::defaults(); + $settings->country_id = '276'; // germany + + $tax_data = new TaxModel(); + $tax_data->seller_region = 'DE'; + $tax_data->seller_subregion = 'DE'; + $tax_data->regions->EU->has_sales_above_threshold = false; + $tax_data->regions->EU->tax_all = true; + + $company = Company::factory()->create([ + 'account_id' => $this->account->id, + 'settings' => $settings, + 'tax_data' => $tax_data, + ]); + + + $client = Client::factory()->create([ + 'user_id' => $this->user->id, + 'company_id' => $company->id, + 'country_id' => 56, + 'shipping_country_id' => 56, + 'has_valid_vat_number' => false, + ]); + + $process = new Rule(); + $process->setClient($client); + $process->init(); + + $this->assertInstanceOf(Rule::class, $process); + + $this->assertFalse($client->has_valid_vat_number); + + $this->assertEquals(19, $process->vat_rate); + + $this->assertEquals(7, $process->reduced_vat_rate); + + } + + + //tests with valid vat. + public function testDeWithValidVat() + { + $settings = CompanySettings::defaults(); + $settings->country_id = '276'; // germany + + $tax_data = new TaxModel(); + $tax_data->seller_region = 'DE'; + $tax_data->seller_subregion = 'DE'; + $tax_data->regions->EU->has_sales_above_threshold = false; + $tax_data->regions->EU->tax_all = true; + + $company = Company::factory()->create([ + 'account_id' => $this->account->id, + 'settings' => $settings, + 'tax_data' => $tax_data, + ]); + + + $client = Client::factory()->create([ + 'user_id' => $this->user->id, + 'company_id' => $company->id, + 'country_id' => 276, + 'shipping_country_id' => 276, + 'has_valid_vat_number' => true, + ]); + + $process = new Rule(); + $process->setClient($client); + $process->init(); + + $this->assertInstanceOf(Rule::class, $process); + + $this->assertTrue($client->has_valid_vat_number); + + $this->assertEquals(19, $process->vat_rate); + + $this->assertEquals(7, $process->reduced_vat_rate); + + } + + //tests with valid vat. + public function testDeToEUWithValidVat() + { + $settings = CompanySettings::defaults(); + $settings->country_id = '276'; // germany + + $tax_data = new TaxModel(); + $tax_data->seller_region = 'DE'; + $tax_data->seller_subregion = 'DE'; + $tax_data->regions->EU->has_sales_above_threshold = false; + $tax_data->regions->EU->tax_all = true; + + $company = Company::factory()->create([ + 'account_id' => $this->account->id, + 'settings' => $settings, + 'tax_data' => $tax_data, + ]); + + + $client = Client::factory()->create([ + 'user_id' => $this->user->id, + 'company_id' => $company->id, + 'country_id' => 56, + 'shipping_country_id' => 56, + 'has_valid_vat_number' => true, + ]); + + $process = new Rule(); + $process->setClient($client); + $process->init(); + + $this->assertInstanceOf(Rule::class, $process); + + $this->assertTrue($client->has_valid_vat_number); + + $this->assertEquals(0, $process->vat_rate); + + $this->assertEquals(0, $process->reduced_vat_rate); + + } + + public function testTaxExemptionDeSellerBeBuyer() + { + $settings = CompanySettings::defaults(); + $settings->country_id = '276'; // germany + + $tax_data = new TaxModel(); + $tax_data->seller_region = 'DE'; + $tax_data->seller_subregion = 'DE'; + $tax_data->regions->EU->has_sales_above_threshold = false; + $tax_data->regions->EU->tax_all = true; + + $company = Company::factory()->create([ + 'account_id' => $this->account->id, + 'settings' => $settings, + 'tax_data' => $tax_data, + ]); + + + $client = Client::factory()->create([ + 'user_id' => $this->user->id, + 'company_id' => $company->id, + 'country_id' => 56, + 'shipping_country_id' => 56, + 'has_valid_vat_number' => true, + 'is_tax_exempt' => true, + ]); + + $process = new Rule(); + $process->setClient($client); + $process->init(); + + $this->assertInstanceOf(Rule::class, $process); + + $this->assertTrue($client->is_tax_exempt); + + $this->assertEquals(0, $process->vat_rate); + + $this->assertEquals(0, $process->reduced_vat_rate); + + } + + public function testTaxExemptionDeSellerDeBuyer() + { + $settings = CompanySettings::defaults(); + $settings->country_id = '276'; // germany + + $tax_data = new TaxModel(); + $tax_data->seller_region = 'DE'; + $tax_data->seller_subregion = 'DE'; + $tax_data->regions->EU->has_sales_above_threshold = false; + $tax_data->regions->EU->tax_all = true; + + $company = Company::factory()->create([ + 'account_id' => $this->account->id, + 'settings' => $settings, + 'tax_data' => $tax_data, + ]); + + + $client = Client::factory()->create([ + 'user_id' => $this->user->id, + 'company_id' => $company->id, + 'country_id' => 276, + 'shipping_country_id' => 276, + 'has_valid_vat_number' => true, + 'is_tax_exempt' => true, + ]); + + $process = new Rule(); + $process->setClient($client); + $process->init(); + + $this->assertInstanceOf(Rule::class, $process); + + $this->assertTrue($client->is_tax_exempt); + + $this->assertEquals(0, $process->vat_rate); + + $this->assertEquals(0, $process->reduced_vat_rate); + + } + + public function testTaxExemption3() + { + $settings = CompanySettings::defaults(); + $settings->country_id = '276'; // germany + + $tax_data = new TaxModel(); + $tax_data->seller_region = 'DE'; + $tax_data->seller_subregion = 'DE'; + $tax_data->regions->EU->has_sales_above_threshold = false; + $tax_data->regions->EU->tax_all = true; + + $company = Company::factory()->create([ + 'account_id' => $this->account->id, + 'settings' => $settings, + 'tax_data' => $tax_data, + ]); + + + $client = Client::factory()->create([ + 'user_id' => $this->user->id, + 'company_id' => $company->id, + 'country_id' => 840, + 'shipping_country_id' => 840, + 'has_valid_vat_number' => true, + 'is_tax_exempt' => true, + ]); + + $process = new Rule(); + $process->setClient($client); + $process->init(); + + $this->assertInstanceOf(Rule::class, $process); + + $this->assertTrue($client->is_tax_exempt); + + $this->assertEquals(0, $process->vat_rate); + + $this->assertEquals(0, $process->reduced_vat_rate); + + } + +} diff --git a/tests/Unit/Tax/ProcessRuleTest.php b/tests/Unit/Tax/ProcessRuleTest.php deleted file mode 100644 index f8c00ce48bb0..000000000000 --- a/tests/Unit/Tax/ProcessRuleTest.php +++ /dev/null @@ -1,154 +0,0 @@ -withoutMiddleware( - ThrottleRequests::class - ); - - $this->withoutExceptionHandling(); - - $this->makeTestData(); - } - - public function testCorrectRuleInit() - { - - $settings = CompanySettings::defaults(); - $settings->country_id = '276'; // germany - - $company = Company::factory()->create([ - 'account_id' => $this->account->id, - 'settings' => $settings - ]); - - $client = Client::factory()->create([ - 'user_id' => $this->user->id, - 'company_id' => $company->id, - 'country_id' => 276, - 'shipping_country_id' => 276, - ]); - - $process = new ProcessRule($company, $client); - $process->run(); - - $this->assertEquals('de', $process->getVendorCountryCode()); - - $this->assertEquals('de', $process->getClientCountryCode()); - - $this->assertFalse($process->hasValidVatNumber()); - - $this->assertInstanceOf(Rule::class, $process->rule); - - $this->assertEquals(19, $process->getVatRate()); - - $this->assertEquals(7, $process->getVatReducedRate()); - - - } - - public function testEuCorrectRuleInit() - { - - $settings = CompanySettings::defaults(); - $settings->country_id = '276'; // germany - - $company = Company::factory()->create([ - 'account_id' => $this->account->id, - 'settings' => $settings - ]); - - $client = Client::factory()->create([ - 'user_id' => $this->user->id, - 'company_id' => $company->id, - 'country_id' => 56, - 'shipping_country_id' => 56, - ]); - - $process = new ProcessRule($company, $client); - $process->run(); - - $this->assertEquals('de', $process->getVendorCountryCode()); - - $this->assertEquals('be', $process->getClientCountryCode()); - - $this->assertFalse($process->hasValidVatNumber()); - - $this->assertInstanceOf(Rule::class, $process->rule); - - $this->assertEquals(21, $process->getVatRate()); - - $this->assertEquals(7, $process->getVatReducedRate()); - - - } - - public function testForeignCorrectRuleInit() - { - - $settings = CompanySettings::defaults(); - $settings->country_id = '276'; // germany - - $company = Company::factory()->create([ - 'account_id' => $this->account->id, - 'settings' => $settings - ]); - - $client = Client::factory()->create([ - 'user_id' => $this->user->id, - 'company_id' => $company->id, - 'country_id' => 840, - 'shipping_country_id' => 840, - ]); - - $process = new ProcessRule($company, $client); - $process->run(); - - $this->assertEquals('de', $process->getVendorCountryCode()); - - $this->assertEquals('us', $process->getClientCountryCode()); - - $this->assertFalse($process->hasValidVatNumber()); - - $this->assertInstanceOf(Rule::class, $process->rule); - - $this->assertEquals(0, $process->getVatRate()); - - $this->assertEquals(0, $process->getVatReducedRate()); - - - } - - -} diff --git a/tests/Unit/Tax/SumTaxTest.php b/tests/Unit/Tax/SumTaxTest.php index 73cfcc06ffa2..5a67d72eff6f 100644 --- a/tests/Unit/Tax/SumTaxTest.php +++ b/tests/Unit/Tax/SumTaxTest.php @@ -12,7 +12,15 @@ namespace Tests\Unit\Tax; use Tests\TestCase; +use App\Models\Client; +use App\Models\Invoice; +use App\Models\Product; use Tests\MockAccountData; +use App\DataMapper\InvoiceItem; +use App\DataMapper\Tax\TaxData; +use App\Factory\InvoiceFactory; +use App\DataMapper\Tax\TaxModel; +use App\DataMapper\Tax\ZipTax\Response; use Illuminate\Routing\Middleware\ThrottleRequests; use Illuminate\Foundation\Testing\DatabaseTransactions; @@ -24,45 +32,43 @@ class SumTaxTest extends TestCase use MockAccountData; use DatabaseTransactions; - public array $response = - ["results" => [ - [ - "geoPostalCode" => "92582", - "geoCity" => "SAN JACINTO", - "geoCounty" => "RIVERSIDE", - "geoState" => "CA", - "taxSales" => 0.0875, - "taxUse" => 0.0875, // tax amount where destination does not charge sales tax, but origin does - "txbService" => "N", // whether services are taxed in this locale - "txbFreight" => "N", // whether freight is taxes in this locale - "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, //district1-5 portion of the district tax - "originDestination" => "D", //location where this is taxed origin/destination/null - ], - ] + public Response $response; + + public array $resp = [ + "geoPostalCode" => "92582", + "geoCity" => "SAN JACINTO", + "geoCounty" => "RIVERSIDE", + "geoState" => "CA", + "taxSales" => 0.0875, + "taxUse" => 0.0875, // tax amount where destination does not charge sales tax, but origin does + "txbService" => "N", // whether services are taxed in this locale + "txbFreight" => "N", // whether freight is taxes in this locale + "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, //district1-5 portion of the district tax + "originDestination" => "D", //location where this is taxed origin/destination/null ]; @@ -76,37 +82,178 @@ class SumTaxTest extends TestCase $this->withoutExceptionHandling(); - // $this->makeTestData(); + $this->makeTestData(); + + $this->response = new Response($this->resp); + + } + + /** Proves that we do not charge taxes automatically */ + public function testCalcInvoiceNoTax() + { + + + $tax_data = new TaxModel(); + $tax_data->seller_region = 'US'; + $tax_data->seller_subregion = 'CA'; + $tax_data->regions->US->has_sales_above_threshold = true; + $tax_data->regions->US->tax_all = true; + + $this->company->calculate_taxes = false; + $this->company->tax_data = $tax_data; + $this->company->save(); + + $client = Client::factory()->create([ + 'user_id' => $this->user->id, + 'company_id' => $this->company->id, + 'country_id' => 840, + ]); + + $invoice = InvoiceFactory::create($this->company->id, $this->user->id); + $invoice->client_id = $client->id; + $invoice->uses_inclusive_taxes = false; + + $line_items = []; + + $invoice->tax_data = new TaxData($this->response); + + $line_item = new InvoiceItem(); + $line_item->quantity = 1; + $line_item->cost = 10; + $line_item->product_key = 'Test'; + $line_item->notes = 'Test'; + $line_item->tax_id = Product::PRODUCT_TYPE_PHYSICAL; + $line_items[] = $line_item; + + $invoice->line_items = $line_items; + $invoice->save(); + + $invoice = $invoice->calc()->getInvoice(); + + $line_items = $invoice->line_items; + + + $this->assertEquals(10, $invoice->amount); + $this->assertEquals("", $line_items[0]->tax_name1); + $this->assertEquals(0, $line_items[0]->tax_rate1); + } + + /** Proves that we do calc taxes automatically */ + public function testCalcInvoiceTax() + { + + + + $tax_data = new TaxModel(); + $tax_data->seller_region = 'US'; + $tax_data->seller_subregion = 'CA'; + $tax_data->regions->US->has_sales_above_threshold = true; + $tax_data->regions->US->tax_all = true; + + $this->company->calculate_taxes = true; + $this->company->tax_data = $tax_data; + $this->company->save(); + + $client = Client::factory()->create([ + 'user_id' => $this->user->id, + 'company_id' => $this->company->id, + 'country_id' => 840, + ]); + + $invoice = InvoiceFactory::create($this->company->id, $this->user->id); + $invoice->client_id = $client->id; + $invoice->uses_inclusive_taxes = false; + + $line_items = []; + + $invoice->tax_data = new TaxData($this->response); + + $line_item = new InvoiceItem; + $line_item->quantity = 1; + $line_item->cost = 10; + $line_item->product_key = 'Test'; + $line_item->notes = 'Test'; + $line_item->tax_id = Product::PRODUCT_TYPE_PHYSICAL; + $line_items[] = $line_item; + + $invoice->line_items = $line_items; + $invoice->save(); + + $invoice = $invoice->calc()->getInvoice(); + + $line_items = $invoice->line_items; + + + $this->assertEquals(10.88, $invoice->amount); + $this->assertEquals("CA Sales Tax", $line_items[0]->tax_name1); + $this->assertEquals(8.75, $line_items[0]->tax_rate1); + } + + public function testTaxOnCompany() + { + + $tax_class = new TaxData($this->response); + + $this->company->tax_data = $tax_class; + $this->company->save(); + + $this->assertEquals("92582", $this->company->tax_data->origin->geoPostalCode); + $this->assertEquals(0.0875, $this->company->tax_data->origin->taxSales); + + } + + public function testTaxOnClient() + { + $c = Client::factory()->create([ + 'user_id' => $this->user->id, + 'company_id' => $this->company->id, + ]); + + $tax_class = new TaxData($this->response, $this->response); + + $c->tax_data = $tax_class; + $c->save(); + + $this->assertEquals("92582", $c->tax_data->origin->geoPostalCode); + $this->assertEquals(0.0875, $c->tax_data->origin->taxSales); + + } + + public function testTaxOnInvoice() + { + + $i = Invoice::factory()->create([ + 'company_id' => $this->company->id, + 'client_id' => $this->client->id, + 'user_id' => $this->user->id, + ]); + + $tax_class = new TaxData($this->response); + + $i->tax_data = $tax_class; + $i->save(); + + + $this->assertEquals("92582", $i->tax_data->origin->geoPostalCode); + $this->assertEquals(0.0875, $i->tax_data->origin->taxSales); + + } public function testSumOfInvoice() { - $this->assertEquals("CA", $this->response['results'][0]['geoState']); + $this->assertEquals("CA", $this->response->geoState); } public function testSumOfTaxes() { $sum = - $this->response['results'][0]['stateSalesTax'] + - // $this->response['results'][0]['stateUseTax'] + - $this->response['results'][0]['citySalesTax'] + - // $this->response['results'][0]['cityUseTax'] + - $this->response['results'][0]['countySalesTax'] + - // $this->response['results'][0]['countyUseTax'] + - $this->response['results'][0]['districtSalesTax']; - // // $this->response['results'][0]['districtUseTax'] + - // $this->response['results'][0]['district1SalesTax'] + - // // $this->response['results'][0]['district1UseTax'] + - // $this->response['results'][0]['district2SalesTax'] + - // // $this->response['results'][0]['district2UseTax'] + - // $this->response['results'][0]['district3SalesTax'] + - // // $this->response['results'][0]['district3UseTax'] + - // $this->response['results'][0]['district4SalesTax'] + - // // $this->response['results'][0]['district4UseTax'] + - // $this->response['results'][0]['district5SalesTax']; - // $this->response['results'][0]['district5UseTax']; + $this->response->stateSalesTax + + $this->response->citySalesTax + + $this->response->countySalesTax + + $this->response->districtSalesTax; $this->assertEquals(0.0875, $sum); } diff --git a/tests/Unit/Tax/UsTaxTest.php b/tests/Unit/Tax/UsTaxTest.php new file mode 100644 index 000000000000..e2299bc65da3 --- /dev/null +++ b/tests/Unit/Tax/UsTaxTest.php @@ -0,0 +1,287 @@ + "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", + ]; + + protected function setUp(): void + { + parent::setUp(); + + $this->withoutMiddleware( + ThrottleRequests::class + ); + + $this->withoutExceptionHandling(); + + $this->makeTestData(); + } + + private function invoiceStub(?string $postal_code = '') + { + + $settings = CompanySettings::defaults(); + $settings->country_id = '840'; // germany + + $tax_data = new TaxModel(); + $tax_data->seller_region = 'US'; + $tax_data->seller_subregion = 'CA'; + $tax_data->regions->US->has_sales_above_threshold = true; + $tax_data->regions->US->tax_all = true; + + $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, + 'shipping_country_id' => 840, + 'has_valid_vat_number' => false, + 'postal_code' => $postal_code, + ]); + + $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_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(); + + return $invoice; + } + + // public function testCompanyTaxAllOffTaxExemptProduct() + // { + + // $invoice = $this->invoiceStub('92582'); + // $client = $invoice->client; + // $client->is_tax_exempt = false; + // $client->save(); + + // $company = $invoice->company; + // $tax_data = $company->tax_data; + + // $tax_data->regions->US->has_sales_above_threshold = true; + // $tax_data->regions->US->tax_all = false; + + // $company->tax_data = $tax_data; + // $company->save(); + + // $invoice = $invoice->calc()->getInvoice()->service()->markSent()->save(); + + // $this->assertEquals(0, $invoice->line_items[0]->tax_rate1); + // $this->assertEquals(100, $invoice->amount); + + // } + + public function testCompanyTaxAllOffButTaxUSRegion() + { + + $invoice = $this->invoiceStub('92582'); + $client = $invoice->client; + $client->is_tax_exempt = false; + $client->save(); + + $company = $invoice->company; + $tax_data = $company->tax_data; + + $tax_data->regions->US->has_sales_above_threshold = true; + $tax_data->regions->US->tax_all = true; + + $company->tax_data = $tax_data; + $company->save(); + + $invoice = $invoice->calc()->getInvoice()->service()->markSent()->save(); + + $this->assertEquals(8.75, $invoice->line_items[0]->tax_rate1); + $this->assertEquals(108.75, $invoice->amount); + + } + + public function testCompanyTaxAllOff() + { + + $invoice = $this->invoiceStub('92582'); + $client = $invoice->client; + $client->is_tax_exempt = false; + $client->save(); + + $company = $invoice->company; + $tax_data = $company->tax_data; + + $tax_data->regions->US->has_sales_above_threshold = true; + $tax_data->regions->US->tax_all = false; + + $company->tax_data = $tax_data; + $company->save(); + + $invoice = $invoice->calc()->getInvoice()->service()->markSent()->save(); + + $this->assertEquals(0, $invoice->line_items[0]->tax_rate1); + $this->assertEquals(100, $invoice->amount); + + } + + + public function testThresholdLevelsAreMet() + { + + $invoice = $this->invoiceStub('92582'); + $client = $invoice->client; + $client->is_tax_exempt = true; + $client->save(); + + + $company = $invoice->company; + $tax_data = $company->tax_data; + + $tax_data->regions->US->has_sales_above_threshold = false; + $tax_data->regions->US->tax_all = true; + + $company->tax_data = $tax_data; + $company->save(); + + $invoice = $invoice->calc()->getInvoice()->service()->markSent()->save(); + + $this->assertEquals(0, $invoice->line_items[0]->tax_rate1); + $this->assertEquals(100, $invoice->amount); + + + } + + public function testHasValidVatMakesNoDifferenceToTaxCalc() + { + + $invoice = $this->invoiceStub('92582'); + $client = $invoice->client; + $client->has_valid_vat_number = true; + $client->save(); + + $invoice = $invoice->calc()->getInvoice()->service()->markSent()->save(); + + $this->assertEquals(8.75, $invoice->line_items[0]->tax_rate1); + $this->assertEquals(108.75, $invoice->amount); + } + + + public function testTaxExemption() + { + $invoice = $this->invoiceStub('92582'); + $client = $invoice->client; + $client->is_tax_exempt = true; + $client->save(); + + $invoice = $invoice->calc()->getInvoice()->service()->markSent()->save(); + + $this->assertEquals(0, $invoice->line_items[0]->tax_rate1); + $this->assertEquals(100, $invoice->amount); + } + + public function testBasicTaxCalculation() + { + + $invoice = $this->invoiceStub(); + + + $this->assertEquals(8.75, $invoice->line_items[0]->tax_rate1); + $this->assertEquals(108.75, $invoice->amount); + + + } + +}