mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-10 13:12:50 +01:00
commit
8a9a09463b
@ -1 +1 @@
|
||||
5.5.103
|
||||
5.5.104
|
73
app/DataMapper/Schedule/EmailReport.php
Normal file
73
app/DataMapper/Schedule/EmailReport.php
Normal file
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\DataMapper\Schedule;
|
||||
|
||||
class EmailReport
|
||||
{
|
||||
/**
|
||||
* Defines the template name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $template = 'email_report';
|
||||
|
||||
/**
|
||||
* An array of clients hashed_ids
|
||||
*
|
||||
* Leave blank if this action should apply to all clients
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public array $clients = [];
|
||||
|
||||
/**
|
||||
* The consts to be used to define the date_range variable of the statement
|
||||
*/
|
||||
public const LAST7 = "last7_days";
|
||||
public const LAST30 = "last30_days";
|
||||
public const LAST365 = "last365_days";
|
||||
public const THIS_MONTH = "this_month";
|
||||
public const LAST_MONTH = "last_month";
|
||||
public const THIS_QUARTER = "this_quarter";
|
||||
public const LAST_QUARTER = "last_quarter";
|
||||
public const THIS_YEAR = "this_year";
|
||||
public const LAST_YEAR = "last_year";
|
||||
public const CUSTOM_RANGE = "custom";
|
||||
|
||||
|
||||
/**
|
||||
* The date range the statement should include
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $date_range = 'this_month';
|
||||
|
||||
/**
|
||||
* If a custom range is select for the date range then
|
||||
* the start_date should be supplied in Y-m-d format
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $start_date = '';
|
||||
|
||||
/**
|
||||
* If a custom range is select for the date range then
|
||||
* the end_date should be supplied in Y-m-d format
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $end_date = '';
|
||||
|
||||
/** @var string $report_name */
|
||||
|
||||
public string $report_name = '';
|
||||
}
|
@ -11,8 +11,9 @@
|
||||
|
||||
namespace App\DataMapper\Tax;
|
||||
|
||||
use App\DataMapper\Tax\ZipTax\Response;
|
||||
use App\Models\Client;
|
||||
use App\Models\Product;
|
||||
use App\DataMapper\Tax\ZipTax\Response;
|
||||
|
||||
class BaseRule implements RuleInterface
|
||||
{
|
||||
@ -27,34 +28,74 @@ class BaseRule implements RuleInterface
|
||||
|
||||
public bool $foreign_consumer_tax_exempt = true;
|
||||
|
||||
public string $seller_region = '';
|
||||
|
||||
public string $client_region = '';
|
||||
|
||||
public string $client_subregion = '';
|
||||
|
||||
public array $eu_country_codes = [
|
||||
'AT', // Austria
|
||||
'BE', // Belgium
|
||||
'BG', // Bulgaria
|
||||
'CY', // Cyprus
|
||||
'CZ', // Czech Republic
|
||||
'DE', // Germany
|
||||
'DK', // Denmark
|
||||
'EE', // Estonia
|
||||
'ES', // Spain
|
||||
'FI', // Finland
|
||||
'FR', // France
|
||||
'GR', // Greece
|
||||
'HR', // Croatia
|
||||
'HU', // Hungary
|
||||
'IE', // Ireland
|
||||
'IT', // Italy
|
||||
'LT', // Lithuania
|
||||
'LU', // Luxembourg
|
||||
'LV', // Latvia
|
||||
'MT', // Malta
|
||||
'NL', // Netherlands
|
||||
'PL', // Poland
|
||||
'PT', // Portugal
|
||||
'RO', // Romania
|
||||
'SE', // Sweden
|
||||
'SI', // Slovenia
|
||||
'SK', // Slovakia
|
||||
'AT', // Austria
|
||||
'BE', // Belgium
|
||||
'BG', // Bulgaria
|
||||
'CY', // Cyprus
|
||||
'CZ', // Czech Republic
|
||||
'DE', // Germany
|
||||
'DK', // Denmark
|
||||
'EE', // Estonia
|
||||
'ES', // Spain
|
||||
'FI', // Finland
|
||||
'FR', // France
|
||||
'GR', // Greece
|
||||
'HR', // Croatia
|
||||
'HU', // Hungary
|
||||
'IE', // Ireland
|
||||
'IT', // Italy
|
||||
'LT', // Lithuania
|
||||
'LU', // Luxembourg
|
||||
'LV', // Latvia
|
||||
'MT', // Malta
|
||||
'NL', // Netherlands
|
||||
'PL', // Poland
|
||||
'PT', // Portugal
|
||||
'RO', // Romania
|
||||
'SE', // Sweden
|
||||
'SI', // Slovenia
|
||||
'SK', // Slovakia
|
||||
];
|
||||
|
||||
public array $region_codes = [
|
||||
'AT' => 'EU', // Austria
|
||||
'BE' => 'EU', // Belgium
|
||||
'BG' => 'EU', // Bulgaria
|
||||
'CY' => 'EU', // Cyprus
|
||||
'CZ' => 'EU', // Czech Republic
|
||||
'DE' => 'EU', // Germany
|
||||
'DK' => 'EU', // Denmark
|
||||
'EE' => 'EU', // Estonia
|
||||
'ES' => 'EU', // Spain
|
||||
'FI' => 'EU', // Finland
|
||||
'FR' => 'EU', // France
|
||||
'GR' => 'EU', // Greece
|
||||
'HR' => 'EU', // Croatia
|
||||
'HU' => 'EU', // Hungary
|
||||
'IE' => 'EU', // Ireland
|
||||
'IT' => 'EU', // Italy
|
||||
'LT' => 'EU', // Lithuania
|
||||
'LU' => 'EU', // Luxembourg
|
||||
'LV' => 'EU', // Latvia
|
||||
'MT' => 'EU', // Malta
|
||||
'NL' => 'EU', // Netherlands
|
||||
'PL' => 'EU', // Poland
|
||||
'PT' => 'EU', // Portugal
|
||||
'RO' => 'EU', // Romania
|
||||
'SE' => 'EU', // Sweden
|
||||
'SI' => 'EU', // Slovenia
|
||||
'SK' => 'EU', // Slovakia
|
||||
|
||||
'US' => 'US', // United States
|
||||
|
||||
'AU' => 'AU', // Australia
|
||||
];
|
||||
|
||||
/** EU TAXES */
|
||||
@ -89,6 +130,8 @@ class BaseRule implements RuleInterface
|
||||
{
|
||||
$this->client = $client;
|
||||
|
||||
$this->resolveRegions();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -99,12 +142,75 @@ class BaseRule implements RuleInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function tax($product_tax_type): self
|
||||
// Refactor to support switching between shipping / billing country / region / subregion
|
||||
private function resolveRegions(): self
|
||||
{
|
||||
|
||||
if(!array_key_exists($this->client->country->iso_3166_2, $this->region_codes))
|
||||
throw new \Exception('Automatic tax calculations not supported for this country');
|
||||
|
||||
$this->client_region = $this->region_codes[$this->client->country->iso_3166_2];
|
||||
|
||||
match($this->client_region){
|
||||
'US' => $this->client_subregion = $this->tax_data->geoState,
|
||||
'EU' => $this->client_subregion = $this->client->country->iso_3166_2,
|
||||
default => $this->client->country->iso_3166_2,
|
||||
};
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function taxByType($product_tax_type): self
|
||||
public function isTaxableRegion(): bool
|
||||
{
|
||||
return $this->client->company->tax_data->regions->{$this->client_region}->tax_all_subregions || $this->client->company->tax_data->regions->{$this->client_region}->subregions->{$this->client_subregion}->apply_tax;
|
||||
}
|
||||
|
||||
public function defaultForeign(): self
|
||||
{
|
||||
|
||||
if($this->client_region == 'US') {
|
||||
|
||||
$this->tax_rate1 = $this->tax_data->taxSales * 100;
|
||||
$this->tax_name1 = "{$this->tax_data->geoState} Sales Tax";
|
||||
|
||||
return $this;
|
||||
|
||||
}
|
||||
|
||||
|
||||
$this->tax_rate1 = $this->client->company->tax_data->regions->{$this->client_region}->subregions->{$this->client_subregion}->tax_rate;
|
||||
$this->tax_name1 = $this->client->company->tax_data->regions->{$this->client_region}->subregions->{$this->client_subregion}->tax_name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function tax($item = null): self
|
||||
{
|
||||
nlog($this->client_region);
|
||||
nlog($this->seller_region);
|
||||
|
||||
if ($this->client->is_tax_exempt) {
|
||||
return $this->taxExempt();
|
||||
} elseif($this->client_region == $this->seller_region && $this->isTaxableRegion()) {
|
||||
|
||||
$this->taxByType($item->tax_id);
|
||||
|
||||
return $this;
|
||||
} elseif($this->isTaxableRegion()) { //other regions outside of US
|
||||
|
||||
match($item->tax_id) {
|
||||
Product::PRODUCT_TYPE_EXEMPT => $this->taxExempt(),
|
||||
Product::PRODUCT_TYPE_REDUCED_TAX => $this->taxReduced(),
|
||||
Product::PRODUCT_TYPE_OVERRIDE_TAX => $this->override(),
|
||||
default => $this->defaultForeign(),
|
||||
};
|
||||
|
||||
}
|
||||
return $this;
|
||||
|
||||
}
|
||||
|
||||
public function taxByType(mixed $type): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
@ -11,97 +11,54 @@
|
||||
|
||||
namespace App\DataMapper\Tax\DE;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Models\Product;
|
||||
use Illuminate\Support\Str;
|
||||
use App\DataMapper\Tax\BaseRule;
|
||||
use App\DataMapper\Tax\RuleInterface;
|
||||
use App\DataMapper\Tax\ZipTax\Response;
|
||||
|
||||
class Rule extends BaseRule implements RuleInterface
|
||||
{
|
||||
public string $vendor_country_code = 'DE';
|
||||
|
||||
public string $client_country_code = 'DE';
|
||||
|
||||
{
|
||||
/** @var string $seller_region */
|
||||
public string $seller_region = 'EU';
|
||||
|
||||
/** @var bool $consumer_tax_exempt */
|
||||
public bool $consumer_tax_exempt = false;
|
||||
|
||||
|
||||
/** @var bool $business_tax_exempt */
|
||||
public bool $business_tax_exempt = false;
|
||||
|
||||
|
||||
/** @var bool $eu_business_tax_exempt */
|
||||
public bool $eu_business_tax_exempt = true;
|
||||
|
||||
|
||||
/** @var bool $foreign_business_tax_exempt */
|
||||
public bool $foreign_business_tax_exempt = true;
|
||||
|
||||
|
||||
/** @var bool $foreign_consumer_tax_exempt */
|
||||
public bool $foreign_consumer_tax_exempt = true;
|
||||
|
||||
public string $tax_name1 = '';
|
||||
|
||||
public float $tax_rate1 = 0;
|
||||
|
||||
public string $tax_name2 = '';
|
||||
|
||||
public float $tax_rate2 = 0;
|
||||
/** @var float $tax_rate */
|
||||
public float $tax_rate = 0;
|
||||
|
||||
public string $tax_name3 = '';
|
||||
/** @var float $reduced_tax_rate */
|
||||
public float $reduced_tax_rate = 0;
|
||||
|
||||
public float $tax_rate3 = 0;
|
||||
|
||||
public float $vat_rate = 0;
|
||||
|
||||
public float $reduced_vat_rate = 0;
|
||||
|
||||
protected ?Client $client;
|
||||
|
||||
protected ?Response $tax_data;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the rules and builds any required data.
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function init(): self
|
||||
{
|
||||
$this->client_country_code = $this->client->shipping_country ? $this->client->shipping_country->iso_3166_2 : $this->client->country->iso_3166_2;
|
||||
$this->calculateRates();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setClient(Client $client): self
|
||||
{
|
||||
$this->client = $client;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setTaxData(Response $tax_data): self
|
||||
{
|
||||
$this->tax_data = $tax_data;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
//need to add logic here to capture if
|
||||
public function tax($type): self
|
||||
{
|
||||
|
||||
|
||||
if ($this->client->is_tax_exempt) {
|
||||
|
||||
return $this->taxExempt();
|
||||
|
||||
} elseif ($this->client->company->tax_data->regions->EU->tax_all_subregions || $this->client->company->tax_data->regions->EU->subregions->{$this->client_country_code}->apply_tax) {
|
||||
|
||||
$this->taxByType($type);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return $this;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the correct tax rate based on the product type.
|
||||
*
|
||||
* @param mixed $product_tax_type
|
||||
* @return self
|
||||
*/
|
||||
public function taxByType($product_tax_type): self
|
||||
{
|
||||
|
||||
@ -122,15 +79,25 @@ class Rule extends BaseRule implements RuleInterface
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the tax rate for a reduced tax product
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function taxReduced(): self
|
||||
{
|
||||
$this->tax_rate1 = $this->reduced_vat_rate;
|
||||
$this->tax_rate1 = $this->reduced_tax_rate;
|
||||
$this->tax_name1 = 'ermäßigte MwSt.';
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the tax rate for a tax exempt product
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function taxExempt(): self
|
||||
{
|
||||
$this->tax_name1 = '';
|
||||
@ -138,37 +105,56 @@ class Rule extends BaseRule implements RuleInterface
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the tax rate for a digital product
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function taxDigital(): self
|
||||
{
|
||||
// $this->tax();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the tax rate for a service product
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function taxService(): self
|
||||
{
|
||||
// $this->tax();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the tax rate for a shipping product
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function taxShipping(): self
|
||||
{
|
||||
// $this->tax();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the tax rate for a physical product
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function taxPhysical(): self
|
||||
{
|
||||
// $this->tax();
|
||||
|
||||
$this->tax_rate1 = $this->vat_rate;
|
||||
$this->tax_rate1 = $this->tax_rate;
|
||||
$this->tax_name1 = 'MwSt.';
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the tax rate for a default product
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function default(): self
|
||||
{
|
||||
|
||||
@ -177,54 +163,63 @@ class Rule extends BaseRule implements RuleInterface
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the tax rate for an override product
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function override(): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the tax rates based on the client's location.
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function calculateRates(): self
|
||||
{
|
||||
|
||||
if ($this->client->is_tax_exempt) {
|
||||
$this->vat_rate = 0;
|
||||
$this->reduced_vat_rate = 0;
|
||||
// nlog("tax exempt");
|
||||
$this->tax_rate = 0;
|
||||
$this->reduced_tax_rate = 0;
|
||||
}
|
||||
elseif($this->client_country_code != $this->vendor_country_code && in_array($this->client_country_code, $this->eu_country_codes) && $this->client->has_valid_vat_number && $this->eu_business_tax_exempt)
|
||||
elseif($this->client_subregion != $this->client->company->tax_data->seller_subregion && in_array($this->client_subregion, $this->eu_country_codes) && $this->client->has_valid_vat_number && $this->eu_business_tax_exempt)
|
||||
{
|
||||
$this->vat_rate = 0;
|
||||
$this->reduced_vat_rate = 0;
|
||||
// nlog("euro zone and tax exempt");
|
||||
$this->tax_rate = 0;
|
||||
$this->reduced_tax_rate = 0;
|
||||
}
|
||||
elseif(!in_array(strtoupper($this->client_country_code), $this->eu_country_codes) && ($this->foreign_consumer_tax_exempt || $this->foreign_business_tax_exempt)) //foreign + tax exempt
|
||||
elseif(!in_array($this->client_subregion, $this->eu_country_codes) && ($this->foreign_consumer_tax_exempt || $this->foreign_business_tax_exempt)) //foreign + tax exempt
|
||||
{
|
||||
$this->vat_rate = 0;
|
||||
$this->reduced_vat_rate = 0;
|
||||
// nlog("foreign and tax exempt");
|
||||
$this->tax_rate = 0;
|
||||
$this->reduced_tax_rate = 0;
|
||||
}
|
||||
elseif(in_array(strtoupper($this->client_country_code), $this->eu_country_codes) && !$this->client->has_valid_vat_number) //eu country / no valid vat
|
||||
elseif(in_array($this->client_subregion, $this->eu_country_codes) && !$this->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)
|
||||
if(($this->client->company->tax_data->seller_subregion != $this->client_subregion) && $this->client->company->tax_data->regions->EU->has_sales_above_threshold)
|
||||
{
|
||||
$this->vat_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->country->iso_3166_2}->vat_rate;
|
||||
$this->reduced_vat_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->country->iso_3166_2}->reduced_vat_rate;
|
||||
// nlog("eu zone with sales above threshold");
|
||||
$this->tax_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->country->iso_3166_2}->tax_rate;
|
||||
$this->reduced_tax_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->country->iso_3166_2}->reduced_tax_rate;
|
||||
}
|
||||
else {
|
||||
$this->vat_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->company->country()->iso_3166_2}->vat_rate;
|
||||
$this->reduced_vat_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->company->country()->iso_3166_2}->reduced_vat_rate;
|
||||
// nlog("same eu country with");
|
||||
// nlog("EU with intra-community supply ie DE to DE");
|
||||
$this->tax_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->company->country()->iso_3166_2}->tax_rate;
|
||||
$this->reduced_tax_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->company->country()->iso_3166_2}->reduced_tax_rate;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$this->vat_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->company->country()->iso_3166_2}->vat_rate;
|
||||
$this->reduced_vat_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->company->country()->iso_3166_2}->reduced_vat_rate;
|
||||
// nlog("default tax");
|
||||
$this->tax_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->company->country()->iso_3166_2}->tax_rate;
|
||||
$this->reduced_tax_rate = $this->client->company->tax_data->regions->EU->subregions->{$this->client->company->country()->iso_3166_2}->reduced_tax_rate;
|
||||
}
|
||||
|
||||
return $this;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -11,14 +11,11 @@
|
||||
|
||||
namespace App\DataMapper\Tax;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\DataMapper\Tax\ZipTax\Response;
|
||||
|
||||
interface RuleInterface
|
||||
{
|
||||
public function init();
|
||||
|
||||
public function tax(mixed $type);
|
||||
public function tax($item = null);
|
||||
|
||||
public function taxByType($type);
|
||||
|
||||
@ -38,9 +35,5 @@ interface RuleInterface
|
||||
|
||||
public function override();
|
||||
|
||||
public function setClient(Client $client);
|
||||
|
||||
public function setTaxData(Response $tax_data);
|
||||
|
||||
public function calculateRates();
|
||||
}
|
@ -13,12 +13,22 @@ namespace App\DataMapper\Tax;
|
||||
|
||||
class TaxModel
|
||||
{
|
||||
// public string $seller_region = 'US';
|
||||
|
||||
|
||||
/** @var mixed $seller_subregion */
|
||||
public string $seller_subregion = 'CA';
|
||||
|
||||
|
||||
/** @var mixed $version */
|
||||
public string $version = 'alpha';
|
||||
|
||||
/** @var mixed $regions */
|
||||
public object $regions;
|
||||
|
||||
|
||||
/**
|
||||
* __construct
|
||||
*
|
||||
* @param mixed $model
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(public ?TaxModel $model = null)
|
||||
{
|
||||
|
||||
@ -28,7 +38,12 @@ class TaxModel
|
||||
$this->regions = $model;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the rules and builds any required data.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->regions = new \stdClass();
|
||||
@ -36,12 +51,51 @@ class TaxModel
|
||||
$this->regions->EU = new \stdClass();
|
||||
|
||||
$this->usRegion()
|
||||
->euRegion();
|
||||
->euRegion()
|
||||
->auRegion();
|
||||
|
||||
|
||||
return $this->regions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the model for Australian Taxes
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
private function auRegion(): self
|
||||
{
|
||||
$this->regions->AU = new \stdClass();
|
||||
$this->regions->AU->has_sales_above_threshold = false;
|
||||
$this->regions->AU->tax_all_subregions = false;
|
||||
$this->regions->AU->vat_threshold = 75000;
|
||||
$this->auSubRegions();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the model for Australian Subregions
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
private function auSubRegions(): self
|
||||
{
|
||||
|
||||
$this->regions->AU->subregions = new \stdClass();
|
||||
$this->regions->AU->subregions->AU = new \stdClass();
|
||||
$this->regions->AU->subregions->AU->apply_tax = false;
|
||||
$this->regions->AU->subregions->AU->tax_rate = 10;
|
||||
$this->regions->AU->subregions->AU->tax_name = 'GST';
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the model for US Taxes
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
private function usRegion(): self
|
||||
{
|
||||
$this->regions->US->has_sales_above_threshold = false;
|
||||
@ -50,7 +104,12 @@ class TaxModel
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Builds the model for EU Taxes
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
private function euRegion(): self
|
||||
{
|
||||
|
||||
@ -61,252 +120,387 @@ class TaxModel
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Builds the model for US States
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
private function usSubRegions(): self
|
||||
{
|
||||
$this->regions->US->subregions = new \stdClass();
|
||||
$this->regions->US->subregions->AL = new \stdClass();
|
||||
$this->regions->US->subregions->AL->apply_tax = false;
|
||||
$this->regions->US->subregions->AL->tax_rate = 4;
|
||||
$this->regions->US->subregions->AL->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->AK = new \stdClass();
|
||||
$this->regions->US->subregions->AK->apply_tax = false;
|
||||
$this->regions->US->subregions->AK->tax_rate = 0;
|
||||
$this->regions->US->subregions->AK->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->AZ = new \stdClass();
|
||||
$this->regions->US->subregions->AZ->apply_tax = false;
|
||||
$this->regions->US->subregions->AZ->tax_rate = 5.6;
|
||||
$this->regions->US->subregions->AZ->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->AR = new \stdClass();
|
||||
$this->regions->US->subregions->AR->apply_tax = false;
|
||||
$this->regions->US->subregions->AR->tax_rate = 6.5;
|
||||
$this->regions->US->subregions->AR->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->CA = new \stdClass();
|
||||
$this->regions->US->subregions->CA->apply_tax = false;
|
||||
$this->regions->US->subregions->CA->tax_rate = 7.25;
|
||||
$this->regions->US->subregions->CA->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->CO = new \stdClass();
|
||||
$this->regions->US->subregions->CO->apply_tax = false;
|
||||
$this->regions->US->subregions->CO->tax_rate = 2.9;
|
||||
$this->regions->US->subregions->CO->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->CT = new \stdClass();
|
||||
$this->regions->US->subregions->CT->apply_tax = false;
|
||||
$this->regions->US->subregions->CT->tax_rate = 6.35;
|
||||
$this->regions->US->subregions->CT->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->DE = new \stdClass();
|
||||
$this->regions->US->subregions->DE->apply_tax = false;
|
||||
$this->regions->US->subregions->DE->tax_rate = 0;
|
||||
$this->regions->US->subregions->DE->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->FL = new \stdClass();
|
||||
$this->regions->US->subregions->FL->apply_tax = false;
|
||||
$this->regions->US->subregions->FL->tax_rate = 6;
|
||||
$this->regions->US->subregions->FL->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->GA = new \stdClass();
|
||||
$this->regions->US->subregions->GA->apply_tax = false;
|
||||
$this->regions->US->subregions->GA->tax_rate = 4;
|
||||
$this->regions->US->subregions->GA->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->HI = new \stdClass();
|
||||
$this->regions->US->subregions->HI->apply_tax = false;
|
||||
$this->regions->US->subregions->HI->tax_rate = 4;
|
||||
$this->regions->US->subregions->HI->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->ID = new \stdClass();
|
||||
$this->regions->US->subregions->ID->apply_tax = false;
|
||||
$this->regions->US->subregions->ID->tax_rate = 6;
|
||||
$this->regions->US->subregions->ID->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->IL = new \stdClass();
|
||||
$this->regions->US->subregions->IL->apply_tax = false;
|
||||
$this->regions->US->subregions->IL->tax_rate = 6.25;
|
||||
$this->regions->US->subregions->IL->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->IN = new \stdClass();
|
||||
$this->regions->US->subregions->IN->apply_tax = false;
|
||||
$this->regions->US->subregions->IN->tax_rate = 7;
|
||||
$this->regions->US->subregions->IN->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->IA = new \stdClass();
|
||||
$this->regions->US->subregions->IA->apply_tax = false;
|
||||
$this->regions->US->subregions->IA->tax_rate = 6;
|
||||
$this->regions->US->subregions->IA->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->KS = new \stdClass();
|
||||
$this->regions->US->subregions->KS->apply_tax = false;
|
||||
$this->regions->US->subregions->KS->tax_rate = 6.5;
|
||||
$this->regions->US->subregions->KS->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->KY = new \stdClass();
|
||||
$this->regions->US->subregions->KY->apply_tax = false;
|
||||
$this->regions->US->subregions->KY->tax_rate = 6;
|
||||
$this->regions->US->subregions->KY->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->LA = new \stdClass();
|
||||
$this->regions->US->subregions->LA->apply_tax = false;
|
||||
$this->regions->US->subregions->LA->tax_rate = 4.45;
|
||||
$this->regions->US->subregions->LA->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->ME = new \stdClass();
|
||||
$this->regions->US->subregions->ME->apply_tax = false;
|
||||
$this->regions->US->subregions->ME->tax_rate = 5.5;
|
||||
$this->regions->US->subregions->ME->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->MD = new \stdClass();
|
||||
$this->regions->US->subregions->MD->apply_tax = false;
|
||||
$this->regions->US->subregions->MD->tax_rate = 6;
|
||||
$this->regions->US->subregions->MD->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->MA = new \stdClass();
|
||||
$this->regions->US->subregions->MA->apply_tax = false;
|
||||
$this->regions->US->subregions->MA->tax_rate = 6.25;
|
||||
$this->regions->US->subregions->MA->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->MI = new \stdClass();
|
||||
$this->regions->US->subregions->MI->apply_tax = false;
|
||||
$this->regions->US->subregions->MI->tax_rate = 6;
|
||||
$this->regions->US->subregions->MI->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->MN = new \stdClass();
|
||||
$this->regions->US->subregions->MN->apply_tax = false;
|
||||
$this->regions->US->subregions->MN->tax_rate = 6.875;
|
||||
$this->regions->US->subregions->MN->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->MS = new \stdClass();
|
||||
$this->regions->US->subregions->MS->apply_tax = false;
|
||||
$this->regions->US->subregions->MS->tax_rate = 7;
|
||||
$this->regions->US->subregions->MS->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->MO = new \stdClass();
|
||||
$this->regions->US->subregions->MO->apply_tax = false;
|
||||
$this->regions->US->subregions->MO->tax_rate = 4.225;
|
||||
$this->regions->US->subregions->MO->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->MT = new \stdClass();
|
||||
$this->regions->US->subregions->MT->apply_tax = false;
|
||||
$this->regions->US->subregions->MT->tax_rate = 0;
|
||||
$this->regions->US->subregions->MT->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->NE = new \stdClass();
|
||||
$this->regions->US->subregions->NE->apply_tax = false;
|
||||
$this->regions->US->subregions->NE->tax_rate = 5.5;
|
||||
$this->regions->US->subregions->NE->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->NV = new \stdClass();
|
||||
$this->regions->US->subregions->NV->apply_tax = false;
|
||||
$this->regions->US->subregions->NV->tax_rate = 6.85;
|
||||
$this->regions->US->subregions->NV->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->NH = new \stdClass();
|
||||
$this->regions->US->subregions->NH->apply_tax = false;
|
||||
$this->regions->US->subregions->NH->tax_rate = 0;
|
||||
$this->regions->US->subregions->NH->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->NJ = new \stdClass();
|
||||
$this->regions->US->subregions->NJ->apply_tax = false;
|
||||
$this->regions->US->subregions->NJ->tax_rate = 6.625;
|
||||
$this->regions->US->subregions->NJ->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->NM = new \stdClass();
|
||||
$this->regions->US->subregions->NM->apply_tax = false;
|
||||
$this->regions->US->subregions->NM->tax_rate = 5.125;
|
||||
$this->regions->US->subregions->NM->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->NY = new \stdClass();
|
||||
$this->regions->US->subregions->NY->apply_tax = false;
|
||||
$this->regions->US->subregions->NY->tax_rate = 4;
|
||||
$this->regions->US->subregions->NY->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->NC = new \stdClass();
|
||||
$this->regions->US->subregions->NC->apply_tax = false;
|
||||
$this->regions->US->subregions->NC->tax_rate = 4.75;
|
||||
$this->regions->US->subregions->NC->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->ND = new \stdClass();
|
||||
$this->regions->US->subregions->ND->apply_tax = false;
|
||||
$this->regions->US->subregions->ND->tax_rate = 5;
|
||||
$this->regions->US->subregions->ND->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->OH = new \stdClass();
|
||||
$this->regions->US->subregions->OH->apply_tax = false;
|
||||
$this->regions->US->subregions->OH->tax_rate = 5.75;
|
||||
$this->regions->US->subregions->OH->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->OK = new \stdClass();
|
||||
$this->regions->US->subregions->OK->apply_tax = false;
|
||||
$this->regions->US->subregions->OK->tax_rate = 4.5;
|
||||
$this->regions->US->subregions->OK->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->OR = new \stdClass();
|
||||
$this->regions->US->subregions->OR->apply_tax = false;
|
||||
$this->regions->US->subregions->OR->tax_rate = 0;
|
||||
$this->regions->US->subregions->OR->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->PA = new \stdClass();
|
||||
$this->regions->US->subregions->PA->apply_tax = false;
|
||||
$this->regions->US->subregions->PA->tax_rate = 6;
|
||||
$this->regions->US->subregions->PA->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->RI = new \stdClass();
|
||||
$this->regions->US->subregions->RI->apply_tax = false;
|
||||
$this->regions->US->subregions->RI->tax_rate = 7;
|
||||
$this->regions->US->subregions->RI->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->SC = new \stdClass();
|
||||
$this->regions->US->subregions->SC->apply_tax = false;
|
||||
$this->regions->US->subregions->SC->tax_rate = 6;
|
||||
$this->regions->US->subregions->SC->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->SD = new \stdClass();
|
||||
$this->regions->US->subregions->SD->apply_tax = false;
|
||||
$this->regions->US->subregions->SD->tax_rate = 4.5;
|
||||
$this->regions->US->subregions->SD->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->TN = new \stdClass();
|
||||
$this->regions->US->subregions->TN->apply_tax = false;
|
||||
$this->regions->US->subregions->TN->tax_rate = 7;
|
||||
$this->regions->US->subregions->TN->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->TX = new \stdClass();
|
||||
$this->regions->US->subregions->TX->apply_tax = false;
|
||||
$this->regions->US->subregions->TX->tax_rate = 6.25;
|
||||
$this->regions->US->subregions->TX->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->UT = new \stdClass();
|
||||
$this->regions->US->subregions->UT->apply_tax = false;
|
||||
$this->regions->US->subregions->UT->tax_rate = 5.95;
|
||||
$this->regions->US->subregions->UT->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->VT = new \stdClass();
|
||||
$this->regions->US->subregions->VT->apply_tax = false;
|
||||
$this->regions->US->subregions->VT->tax_rate = 6;
|
||||
$this->regions->US->subregions->VT->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->VA = new \stdClass();
|
||||
$this->regions->US->subregions->VA->apply_tax = false;
|
||||
$this->regions->US->subregions->VA->tax_rate = 5.3;
|
||||
$this->regions->US->subregions->VA->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->WA = new \stdClass();
|
||||
$this->regions->US->subregions->WA->apply_tax = false;
|
||||
$this->regions->US->subregions->WA->tax_rate = 6.5;
|
||||
$this->regions->US->subregions->WA->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->WV = new \stdClass();
|
||||
$this->regions->US->subregions->WV->apply_tax = false;
|
||||
$this->regions->US->subregions->WV->tax_rate = 6;
|
||||
$this->regions->US->subregions->WV->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->WI = new \stdClass();
|
||||
$this->regions->US->subregions->WI->apply_tax = false;
|
||||
$this->regions->US->subregions->WI->tax_rate = 5;
|
||||
$this->regions->US->subregions->WI->tax_name = 'Sales Tax';
|
||||
$this->regions->US->subregions->WY = new \stdClass();
|
||||
$this->regions->US->subregions->WY->apply_tax = false;
|
||||
$this->regions->US->subregions->WY->tax_rate = 4;
|
||||
$this->regions->US->subregions->WY->tax_name = 'Sales Tax';
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create the EU member countries
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
private function euSubRegions(): self
|
||||
{
|
||||
|
||||
$this->regions->EU->subregions = new \stdClass();
|
||||
|
||||
$this->regions->EU->subregions->AT = new \stdClass();
|
||||
$this->regions->EU->subregions->AT->vat_rate = 21;
|
||||
$this->regions->EU->subregions->AT->reduced_vat_rate = 11;
|
||||
$this->regions->EU->subregions->AT->tax_rate = 21;
|
||||
$this->regions->EU->subregions->AT->tax_name = 'USt';
|
||||
$this->regions->EU->subregions->AT->reduced_tax_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->tax_rate = 21;
|
||||
$this->regions->EU->subregions->BE->tax_name = 'BTW';
|
||||
$this->regions->EU->subregions->BE->reduced_tax_rate = 6;
|
||||
$this->regions->EU->subregions->BE->apply_tax = false;
|
||||
|
||||
$this->regions->EU->subregions->BG = new \stdClass();
|
||||
$this->regions->EU->subregions->BG->vat_rate = 20;
|
||||
$this->regions->EU->subregions->BG->reduced_vat_rate = 9;
|
||||
$this->regions->EU->subregions->BG->tax_rate = 20;
|
||||
$this->regions->EU->subregions->BG->tax_name = 'НДС';
|
||||
$this->regions->EU->subregions->BG->reduced_tax_rate = 9;
|
||||
$this->regions->EU->subregions->BG->apply_tax = false;
|
||||
|
||||
$this->regions->EU->subregions->CY = new \stdClass();
|
||||
$this->regions->EU->subregions->CY->vat_rate = 19;
|
||||
$this->regions->EU->subregions->CY->reduced_vat_rate = 9;
|
||||
$this->regions->EU->subregions->CY->tax_rate = 19;
|
||||
$this->regions->EU->subregions->CY->tax_name = 'ΦΠΑ';
|
||||
$this->regions->EU->subregions->CY->reduced_tax_rate = 9;
|
||||
$this->regions->EU->subregions->CY->apply_tax = false;
|
||||
|
||||
$this->regions->EU->subregions->CZ = new \stdClass();
|
||||
$this->regions->EU->subregions->CZ->vat_rate = 21;
|
||||
$this->regions->EU->subregions->CZ->reduced_vat_rate = 15;
|
||||
$this->regions->EU->subregions->CZ->tax_rate = 21;
|
||||
$this->regions->EU->subregions->CZ->tax_name = 'DPH';
|
||||
$this->regions->EU->subregions->CZ->reduced_tax_rate = 15;
|
||||
$this->regions->EU->subregions->CZ->apply_tax = false;
|
||||
|
||||
$this->regions->EU->subregions->DE = new \stdClass();
|
||||
$this->regions->EU->subregions->DE->vat_rate = 19;
|
||||
$this->regions->EU->subregions->DE->reduced_vat_rate = 7;
|
||||
$this->regions->EU->subregions->DE->tax_rate = 19;
|
||||
$this->regions->EU->subregions->DE->tax_name = 'MwSt';
|
||||
$this->regions->EU->subregions->DE->reduced_tax_rate = 7;
|
||||
$this->regions->EU->subregions->DE->apply_tax = false;
|
||||
|
||||
$this->regions->EU->subregions->DK = new \stdClass();
|
||||
$this->regions->EU->subregions->DK->vat_rate = 25;
|
||||
$this->regions->EU->subregions->DK->reduced_vat_rate = 0;
|
||||
$this->regions->EU->subregions->DK->tax_rate = 25;
|
||||
$this->regions->EU->subregions->DK->reduced_tax_rate = 0;
|
||||
$this->regions->EU->subregions->DK->apply_tax = false;
|
||||
|
||||
$this->regions->EU->subregions->EE = new \stdClass();
|
||||
$this->regions->EU->subregions->EE->vat_rate = 20;
|
||||
$this->regions->EU->subregions->EE->reduced_vat_rate = 9;
|
||||
$this->regions->EU->subregions->EE->tax_rate = 20;
|
||||
$this->regions->EU->subregions->EE->tax_name = 'KM';
|
||||
$this->regions->EU->subregions->EE->reduced_tax_rate = 9;
|
||||
$this->regions->EU->subregions->EE->apply_tax = false;
|
||||
|
||||
$this->regions->EU->subregions->ES = new \stdClass();
|
||||
$this->regions->EU->subregions->ES->vat_rate = 21;
|
||||
$this->regions->EU->subregions->ES->reduced_vat_rate = 10;
|
||||
$this->regions->EU->subregions->ES->tax_rate = 21;
|
||||
$this->regions->EU->subregions->ES->tax_name = 'IVA';
|
||||
$this->regions->EU->subregions->ES->reduced_tax_rate = 10;
|
||||
$this->regions->EU->subregions->ES->apply_tax = false;
|
||||
|
||||
$this->regions->EU->subregions->FI = new \stdClass();
|
||||
$this->regions->EU->subregions->FI->vat_rate = 24;
|
||||
$this->regions->EU->subregions->FI->reduced_vat_rate = 14;
|
||||
$this->regions->EU->subregions->FI->tax_rate = 24;
|
||||
$this->regions->EU->subregions->FI->tax_name = 'ALV';
|
||||
$this->regions->EU->subregions->FI->reduced_tax_rate = 14;
|
||||
$this->regions->EU->subregions->FI->apply_tax = false;
|
||||
|
||||
$this->regions->EU->subregions->FR = new \stdClass();
|
||||
$this->regions->EU->subregions->FR->vat_rate = 20;
|
||||
$this->regions->EU->subregions->FR->reduced_vat_rate = 5.5;
|
||||
$this->regions->EU->subregions->FR->tax_rate = 20;
|
||||
$this->regions->EU->subregions->FR->tax_name = 'TVA';
|
||||
$this->regions->EU->subregions->FR->reduced_tax_rate = 5.5;
|
||||
$this->regions->EU->subregions->FR->apply_tax = false;
|
||||
|
||||
// $this->regions->EU->subregions->GB = new \stdClass();
|
||||
// $this->regions->EU->subregions->GB->vat_rate = 20;
|
||||
// $this->regions->EU->subregions->GB->reduced_vat_rate = 0;
|
||||
// $this->regions->EU->subregions->GB->tax_rate = 20;
|
||||
// $this->regions->EU->subregions->GB->reduced_tax_rate = 0;
|
||||
// $this->regions->EU->subregions->GB->apply_tax = false;
|
||||
|
||||
$this->regions->EU->subregions->GR = new \stdClass();
|
||||
$this->regions->EU->subregions->GR->vat_rate = 24;
|
||||
$this->regions->EU->subregions->GR->reduced_vat_rate = 13;
|
||||
$this->regions->EU->subregions->GR->tax_rate = 24;
|
||||
$this->regions->EU->subregions->GR->tax_name = 'ΦΠΑ';
|
||||
$this->regions->EU->subregions->GR->reduced_tax_rate = 13;
|
||||
$this->regions->EU->subregions->GR->apply_tax = false;
|
||||
|
||||
$this->regions->EU->subregions->HR = new \stdClass();
|
||||
$this->regions->EU->subregions->HR->vat_rate = 25;
|
||||
$this->regions->EU->subregions->HR->reduced_vat_rate = 5;
|
||||
$this->regions->EU->subregions->HR->tax_rate = 25;
|
||||
$this->regions->EU->subregions->HR->tax_name = 'PDV';
|
||||
$this->regions->EU->subregions->HR->reduced_tax_rate = 5;
|
||||
$this->regions->EU->subregions->HR->apply_tax = false;
|
||||
|
||||
$this->regions->EU->subregions->HU = new \stdClass();
|
||||
$this->regions->EU->subregions->HU->vat_rate = 27;
|
||||
$this->regions->EU->subregions->HU->reduced_vat_rate = 5;
|
||||
$this->regions->EU->subregions->HU->tax_rate = 27;
|
||||
$this->regions->EU->subregions->HU->tax_name = 'ÁFA';
|
||||
$this->regions->EU->subregions->HU->reduced_tax_rate = 5;
|
||||
$this->regions->EU->subregions->HU->apply_tax = false;
|
||||
|
||||
$this->regions->EU->subregions->IE = new \stdClass();
|
||||
$this->regions->EU->subregions->IE->vat_rate = 23;
|
||||
$this->regions->EU->subregions->IE->reduced_vat_rate = 0;
|
||||
$this->regions->EU->subregions->IE->tax_rate = 23;
|
||||
$this->regions->EU->subregions->IE->tax_name = 'VAT';
|
||||
$this->regions->EU->subregions->IE->reduced_tax_rate = 0;
|
||||
$this->regions->EU->subregions->IE->apply_tax = false;
|
||||
|
||||
$this->regions->EU->subregions->IT = new \stdClass();
|
||||
$this->regions->EU->subregions->IT->vat_rate = 22;
|
||||
$this->regions->EU->subregions->IT->reduced_vat_rate = 10;
|
||||
$this->regions->EU->subregions->IT->tax_rate = 22;
|
||||
$this->regions->EU->subregions->IT->tax_name = 'IVA';
|
||||
$this->regions->EU->subregions->IT->reduced_tax_rate = 10;
|
||||
$this->regions->EU->subregions->IT->apply_tax = false;
|
||||
|
||||
$this->regions->EU->subregions->LT = new \stdClass();
|
||||
$this->regions->EU->subregions->LT->vat_rate = 21;
|
||||
$this->regions->EU->subregions->LT->reduced_vat_rate = 9;
|
||||
$this->regions->EU->subregions->LT->tax_rate = 21;
|
||||
$this->regions->EU->subregions->LT->tax_name = 'PVM';
|
||||
$this->regions->EU->subregions->LT->reduced_tax_rate = 9;
|
||||
$this->regions->EU->subregions->LT->apply_tax = false;
|
||||
|
||||
$this->regions->EU->subregions->LU = new \stdClass();
|
||||
$this->regions->EU->subregions->LU->vat_rate = 17;
|
||||
$this->regions->EU->subregions->LU->reduced_vat_rate = 3;
|
||||
$this->regions->EU->subregions->LU->tax_rate = 17;
|
||||
$this->regions->EU->subregions->LU->tax_name = 'TVA';
|
||||
$this->regions->EU->subregions->LU->reduced_tax_rate = 3;
|
||||
$this->regions->EU->subregions->LU->apply_tax = false;
|
||||
|
||||
$this->regions->EU->subregions->LV = new \stdClass();
|
||||
$this->regions->EU->subregions->LV->vat_rate = 21;
|
||||
$this->regions->EU->subregions->LV->reduced_vat_rate = 12;
|
||||
$this->regions->EU->subregions->LV->tax_rate = 21;
|
||||
$this->regions->EU->subregions->LV->tax_name = 'PVN';
|
||||
$this->regions->EU->subregions->LV->reduced_tax_rate = 12;
|
||||
$this->regions->EU->subregions->LV->apply_tax = false;
|
||||
|
||||
$this->regions->EU->subregions->MT = new \stdClass();
|
||||
$this->regions->EU->subregions->MT->vat_rate = 18;
|
||||
$this->regions->EU->subregions->MT->reduced_vat_rate = 5;
|
||||
$this->regions->EU->subregions->MT->tax_rate = 18;
|
||||
$this->regions->EU->subregions->MT->tax_name = 'VAT';
|
||||
$this->regions->EU->subregions->MT->reduced_tax_rate = 5;
|
||||
$this->regions->EU->subregions->MT->apply_tax = false;
|
||||
|
||||
$this->regions->EU->subregions->NL = new \stdClass();
|
||||
$this->regions->EU->subregions->NL->vat_rate = 21;
|
||||
$this->regions->EU->subregions->NL->reduced_vat_rate = 9;
|
||||
$this->regions->EU->subregions->NL->tax_rate = 21;
|
||||
$this->regions->EU->subregions->NL->tax_name = 'BTW';
|
||||
$this->regions->EU->subregions->NL->reduced_tax_rate = 9;
|
||||
$this->regions->EU->subregions->NL->apply_tax = false;
|
||||
|
||||
$this->regions->EU->subregions->PT = new \stdClass();
|
||||
$this->regions->EU->subregions->PT->vat_rate = 23;
|
||||
$this->regions->EU->subregions->PT->reduced_vat_rate = 6;
|
||||
$this->regions->EU->subregions->PT->tax_rate = 23;
|
||||
$this->regions->EU->subregions->PT->tax_name = 'IVA';
|
||||
$this->regions->EU->subregions->PT->reduced_tax_rate = 6;
|
||||
$this->regions->EU->subregions->PT->apply_tax = false;
|
||||
|
||||
$this->regions->EU->subregions->RO = new \stdClass();
|
||||
$this->regions->EU->subregions->RO->vat_rate = 19;
|
||||
$this->regions->EU->subregions->RO->reduced_vat_rate = 5;
|
||||
$this->regions->EU->subregions->RO->tax_rate = 19;
|
||||
$this->regions->EU->subregions->RO->tax_name = 'TVA';
|
||||
$this->regions->EU->subregions->RO->reduced_tax_rate = 5;
|
||||
$this->regions->EU->subregions->RO->apply_tax = false;
|
||||
|
||||
$this->regions->EU->subregions->SE = new \stdClass();
|
||||
$this->regions->EU->subregions->SE->vat_rate = 25;
|
||||
$this->regions->EU->subregions->SE->reduced_vat_rate = 12;
|
||||
$this->regions->EU->subregions->SE->tax_rate = 25;
|
||||
$this->regions->EU->subregions->SE->tax_name = 'Moms';
|
||||
$this->regions->EU->subregions->SE->reduced_tax_rate = 12;
|
||||
$this->regions->EU->subregions->SE->apply_tax = false;
|
||||
|
||||
$this->regions->EU->subregions->SI = new \stdClass();
|
||||
$this->regions->EU->subregions->SI->vat_rate = 22;
|
||||
$this->regions->EU->subregions->SI->reduced_vat_rate = 9.5;
|
||||
$this->regions->EU->subregions->SI->tax_rate = 22;
|
||||
$this->regions->EU->subregions->SI->tax_name = 'DDV';
|
||||
$this->regions->EU->subregions->SI->reduced_tax_rate = 9.5;
|
||||
$this->regions->EU->subregions->SI->apply_tax = false;
|
||||
|
||||
$this->regions->EU->subregions->SK = new \stdClass();
|
||||
$this->regions->EU->subregions->SK->vat_rate = 20;
|
||||
$this->regions->EU->subregions->SK->reduced_vat_rate = 10;
|
||||
$this->regions->EU->subregions->SK->tax_rate = 20;
|
||||
$this->regions->EU->subregions->SK->tax_name = 'DPH';
|
||||
$this->regions->EU->subregions->SK->reduced_tax_rate = 10;
|
||||
$this->regions->EU->subregions->SK->apply_tax = false;
|
||||
|
||||
return $this;
|
||||
|
@ -11,71 +11,53 @@
|
||||
|
||||
namespace App\DataMapper\Tax\US;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Models\Product;
|
||||
use App\DataMapper\Tax\BaseRule;
|
||||
use App\DataMapper\Tax\RuleInterface;
|
||||
use App\DataMapper\Tax\ZipTax\Response;
|
||||
use App\Models\Product;
|
||||
|
||||
class Rule implements RuleInterface
|
||||
/**
|
||||
* The rules apply US => US taxes using the tax calculator.
|
||||
*
|
||||
* US => Foreign taxes we check the product types still for exemptions, and we all back to the client country tax rate.
|
||||
*/
|
||||
class Rule extends BaseRule implements RuleInterface
|
||||
{
|
||||
|
||||
public string $tax_name1 = '';
|
||||
public float $tax_rate1 = 0;
|
||||
|
||||
public string $tax_name2 = '';
|
||||
public float $tax_rate2 = 0;
|
||||
/** @var string $seller_region */
|
||||
public string $seller_region = 'US';
|
||||
|
||||
public string $tax_name3 = '';
|
||||
public float $tax_rate3 = 0;
|
||||
/**
|
||||
* Initializes the rules and builds any required data.
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function init(): self
|
||||
{
|
||||
$this->calculateRates();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public ?Client $client;
|
||||
|
||||
public ?Response $tax_data;
|
||||
|
||||
public function __construct()
|
||||
/**
|
||||
* Override tax class, we use this when we do not modify the input taxes
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function override(): self
|
||||
{
|
||||
}
|
||||
|
||||
public function override()
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setTaxData(Response $tax_data): self
|
||||
{
|
||||
$this->tax_data = $tax_data;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setClient(Client $client):self
|
||||
{
|
||||
$this->client = $client;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function tax($type): self
|
||||
{
|
||||
|
||||
if ($this->client->is_tax_exempt) {
|
||||
return $this->taxExempt();
|
||||
}
|
||||
else if($this->client->company->tax_data->regions->US->tax_all_subregions || $this->client->company->tax_data->regions->US->subregions->{$this->tax_data->geoState}->apply_tax){
|
||||
|
||||
$this->taxByType($type);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
return $this;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the correct tax rate based on the product type.
|
||||
*
|
||||
* @param mixed $product_tax_type
|
||||
* @return self
|
||||
*/
|
||||
public function taxByType($product_tax_type): self
|
||||
{
|
||||
|
||||
match($product_tax_type){
|
||||
match($product_tax_type) {
|
||||
Product::PRODUCT_TYPE_EXEMPT => $this->taxExempt(),
|
||||
Product::PRODUCT_TYPE_DIGITAL => $this->taxDigital(),
|
||||
Product::PRODUCT_TYPE_SERVICE => $this->taxService(),
|
||||
@ -88,7 +70,12 @@ class Rule implements RuleInterface
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the tax as exempt (0)
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function taxExempt(): self
|
||||
{
|
||||
$this->tax_name1 = '';
|
||||
@ -96,37 +83,64 @@ class Rule implements RuleInterface
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the tax rate for a digital product
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function taxDigital(): self
|
||||
{
|
||||
$this->default();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the tax rate for a service product
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function taxService(): self
|
||||
{
|
||||
if($this->tax_data->txbService == 'Y')
|
||||
if($this->tax_data->txbService == 'Y') {
|
||||
$this->default();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the tax rate for a shipping product
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function taxShipping(): self
|
||||
{
|
||||
if($this->tax_data->txbFreight == 'Y')
|
||||
if($this->tax_data->txbFreight == 'Y') {
|
||||
$this->default();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the tax rate for a physical product
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function taxPhysical(): self
|
||||
{
|
||||
$this->default();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the tax rate for an undefined product uses the default tax rate for the client county
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function default(): self
|
||||
{
|
||||
|
||||
@ -135,19 +149,24 @@ class Rule implements RuleInterface
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the tax rate for a reduced tax product
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function taxReduced(): self
|
||||
{
|
||||
$this->default();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function init(): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the tax rates to be applied
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function calculateRates(): self
|
||||
{
|
||||
return $this;
|
||||
|
@ -57,7 +57,7 @@ class Response
|
||||
* ];
|
||||
*
|
||||
*/
|
||||
public string $seller_region = "";
|
||||
public string $seller_subregion = "";
|
||||
//US
|
||||
|
||||
public string $geoPostalCode = "";
|
||||
|
@ -108,7 +108,6 @@ region:
|
||||
tax_all: false
|
||||
vat_threshold: 10000
|
||||
has_sales_above_threshold: false
|
||||
seller_region: DE
|
||||
subregions:
|
||||
AT:
|
||||
vat: 21
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -38,7 +38,11 @@ class BaseExport
|
||||
$this->client_description = $client->present()->name;
|
||||
return $query->where('client_id', $this->input['client_id']);
|
||||
}
|
||||
elseif(isset($this->input['clients']) && count($this->input['clients']) > 0) {
|
||||
|
||||
$this->client_description = 'Multiple Clients';
|
||||
return $query->whereIn('client_id', $this->input['clients']);
|
||||
}
|
||||
return $query;
|
||||
}
|
||||
|
||||
@ -87,6 +91,10 @@ class BaseExport
|
||||
$this->start_date = (new \Carbon\Carbon('-6 months'))->firstOfQuarter()->format('Y-m-d');
|
||||
$this->end_date = (new \Carbon\Carbon('-6 months'))->lastOfQuarter()->format('Y-m-d');
|
||||
return $query->whereBetween($this->date_key, [(new \Carbon\Carbon('-6 months'))->firstOfQuarter(), (new \Carbon\Carbon('-6 months'))->lastOfQuarter()])->orderBy($this->date_key, 'ASC');
|
||||
case 'last365_days':
|
||||
$this->start_date = now()->startOfDay()->subDays(365)->format('Y-m-d');
|
||||
$this->end_date = now()->startOfDay()->format('Y-m-d');
|
||||
return $query->whereBetween($this->date_key, [now()->subDays(365), now()])->orderBy($this->date_key, 'ASC');
|
||||
case 'this_year':
|
||||
$this->start_date = now()->startOfYear()->format('Y-m-d');
|
||||
$this->end_date = now()->format('Y-m-d');
|
||||
@ -102,7 +110,7 @@ class BaseExport
|
||||
}
|
||||
}
|
||||
|
||||
protected function buildHeader() :array
|
||||
public function buildHeader() :array
|
||||
{
|
||||
$header = [];
|
||||
|
||||
|
@ -97,8 +97,6 @@ class ProductSalesExport extends BaseExport
|
||||
}
|
||||
|
||||
//insert the header
|
||||
$this->csv->insertOne($this->buildHeader());
|
||||
|
||||
$query = Invoice::query()
|
||||
->withTrashed()
|
||||
->where('company_id', $this->company->id)
|
||||
@ -109,6 +107,8 @@ class ProductSalesExport extends BaseExport
|
||||
|
||||
$query = $this->filterByClients($query);
|
||||
|
||||
$this->csv->insertOne($this->buildHeader());
|
||||
|
||||
$query->cursor()
|
||||
->each(function ($invoice) {
|
||||
foreach ($invoice->line_items as $item) {
|
||||
|
@ -22,7 +22,7 @@ class PaymentFilters extends QueryFilters
|
||||
/**
|
||||
* Filter based on search text.
|
||||
*
|
||||
* @param string query filter
|
||||
* @param string $filter
|
||||
* @return Builder
|
||||
* @deprecated
|
||||
*/
|
||||
@ -35,6 +35,8 @@ class PaymentFilters extends QueryFilters
|
||||
return $this->builder->where(function ($query) use ($filter) {
|
||||
$query->where('amount', 'like', '%'.$filter.'%')
|
||||
->orWhere('date', 'like', '%'.$filter.'%')
|
||||
->orWhere('number','like', '%'.$filter.'%')
|
||||
->owWhere('transaction_reference', 'like', '%'.$filter.'%')
|
||||
->orWhere('custom_value1', 'like', '%'.$filter.'%')
|
||||
->orWhere('custom_value2', 'like', '%'.$filter.'%')
|
||||
->orWhere('custom_value3', 'like', '%'.$filter.'%')
|
||||
@ -55,7 +57,7 @@ class PaymentFilters extends QueryFilters
|
||||
* - partially refunded
|
||||
* - refunded
|
||||
*
|
||||
* @param string client_status The payment status as seen by the client
|
||||
* @param string $value The payment status as seen by the client
|
||||
* @return Builder
|
||||
*/
|
||||
public function client_status(string $value = ''): Builder
|
||||
|
@ -54,7 +54,9 @@ class InvoiceItemSum
|
||||
'SI', // Slovenia
|
||||
'SK', // Slovakia
|
||||
|
||||
'US', //USA
|
||||
'US', // USA
|
||||
|
||||
'AU', // Australia
|
||||
];
|
||||
|
||||
protected $invoice;
|
||||
@ -200,7 +202,7 @@ class InvoiceItemSum
|
||||
*/
|
||||
private function calcTaxesAutomatically(): self
|
||||
{
|
||||
$this->rule->tax($this->item->tax_id ?? null);
|
||||
$this->rule->tax($this->item);
|
||||
|
||||
$this->item->tax_name1 = $this->rule->tax_name1;
|
||||
$this->item->tax_rate1 = $this->rule->tax_rate1;
|
||||
|
@ -274,6 +274,7 @@ class TaskController extends BaseController
|
||||
$old_task = json_decode(json_encode($task));
|
||||
|
||||
$task = $this->task_repo->save($request->all(), $task);
|
||||
|
||||
$task = $this->task_repo->triggeredActions($request, $task);
|
||||
|
||||
if ($task->status_order != $old_task->status_order) {
|
||||
|
@ -736,4 +736,18 @@ class UserController extends BaseController
|
||||
return $this->itemResponse($user->fresh());
|
||||
|
||||
}
|
||||
|
||||
public function disconnectOauth(DisconnectUserMailerRequest $request, User $user)
|
||||
{
|
||||
$user->oauth_user_id = null;
|
||||
$user->oauth_provider_id = null;
|
||||
$user->oauth_user_token_expiry = null;
|
||||
$user->oauth_user_token = null;
|
||||
$user->oauth_user_refresh_token = null;
|
||||
$user->save();
|
||||
|
||||
return $this->itemResponse($user->fresh());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ class UpdateTaskRequest extends Request
|
||||
public function prepareForValidation()
|
||||
{
|
||||
$input = $this->decodePrimaryKeys($this->all());
|
||||
|
||||
|
||||
if (array_key_exists('status_id', $input) && is_string($input['status_id'])) {
|
||||
$input['status_id'] = $this->decodePrimaryKey($input['status_id']);
|
||||
}
|
||||
|
@ -45,6 +45,8 @@ class StoreSchedulerRequest extends Request
|
||||
'parameters.end_date' => ['bail', 'sometimes', 'date:Y-m-d', 'required_if:parameters.date_rate,custom', 'after_or_equal:parameters.start_date'],
|
||||
'parameters.entity' => ['bail', 'sometimes', 'string', 'in:invoice,credit,quote,purchase_order'],
|
||||
'parameters.entity_id' => ['bail', 'sometimes', 'string'],
|
||||
'parameters.report_name' => ['bail','sometimes', 'string', 'required_if:template,email_report', 'in:ar_summary_report,ar_detail_report,tax_summary_report,user_sales_report,client_sales_report,client_balance_report,product_sales_report'],
|
||||
'parameters.date_key' => ['bail','sometimes', 'string'],
|
||||
];
|
||||
|
||||
return $rules;
|
||||
|
@ -40,6 +40,10 @@ class UpdateSchedulerRequest extends Request
|
||||
'parameters.date_range' => 'bail|sometimes|string|in:last7_days,last30_days,last365_days,this_month,last_month,this_quarter,last_quarter,this_year,last_year,custom',
|
||||
'parameters.start_date' => ['bail', 'sometimes', 'date:Y-m-d', 'required_if:parameters.date_rate,custom'],
|
||||
'parameters.end_date' => ['bail', 'sometimes', 'date:Y-m-d', 'required_if:parameters.date_rate,custom', 'after_or_equal:parameters.start_date'],
|
||||
'parameters.entity' => ['bail', 'sometimes', 'string', 'in:invoice,credit,quote,purchase_order'],
|
||||
'parameters.entity_id' => ['bail', 'sometimes', 'string'],
|
||||
'parameters.report_name' => ['bail','sometimes', 'string', 'required_if:template,email_report', 'in:ar_summary_report,ar_detail_report,tax_summary_report,user_sales_report,client_sales_report,client_balance_report,product_sales_report'],
|
||||
'parameters.date_key' => ['bail','sometimes', 'string'],
|
||||
];
|
||||
|
||||
return $rules;
|
||||
|
@ -28,7 +28,8 @@ class BlackListRule implements Rule
|
||||
'dataservices.space',
|
||||
'karenkey.com',
|
||||
'sharklasers.com',
|
||||
'100072641.help'
|
||||
'100072641.help',
|
||||
'yandex.com',
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -426,7 +426,9 @@ class BaseImport
|
||||
$message = $ex->getMessage();
|
||||
} else {
|
||||
report($ex);
|
||||
$message = 'Unknown error';
|
||||
$message = 'Unknown error ';
|
||||
nlog($ex->getMessage());
|
||||
nlog($raw_invoice);
|
||||
}
|
||||
|
||||
$this->error_array['invoice'][] = [
|
||||
|
@ -11,24 +11,26 @@
|
||||
|
||||
namespace App\Import\Transformer;
|
||||
|
||||
use App\Factory\ExpenseCategoryFactory;
|
||||
use App\Factory\ProjectFactory;
|
||||
use App\Factory\VendorFactory;
|
||||
use App\Models\Quote;
|
||||
use App\Utils\Number;
|
||||
use App\Models\Client;
|
||||
use App\Models\ClientContact;
|
||||
use App\Models\Vendor;
|
||||
use App\Models\Country;
|
||||
use App\Models\Expense;
|
||||
use App\Models\ExpenseCategory;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\PaymentType;
|
||||
use App\Models\Product;
|
||||
use App\Models\Project;
|
||||
use App\Models\Quote;
|
||||
use App\Models\TaxRate;
|
||||
use App\Models\Vendor;
|
||||
use App\Utils\Number;
|
||||
use App\Models\PaymentType;
|
||||
use App\Models\ClientContact;
|
||||
use App\Factory\ClientFactory;
|
||||
use App\Factory\VendorFactory;
|
||||
use Illuminate\Support\Carbon;
|
||||
use App\Factory\ProjectFactory;
|
||||
use App\Models\ExpenseCategory;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use App\Repositories\ClientRepository;
|
||||
use App\Factory\ExpenseCategoryFactory;
|
||||
|
||||
/**
|
||||
* Class BaseTransformer.
|
||||
@ -129,7 +131,28 @@ class BaseTransformer
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
$client_repository = app()->make(ClientRepository::class);
|
||||
$client_repository->import_mode = true;
|
||||
|
||||
$client = $client_repository->save(
|
||||
[
|
||||
'name' => $client_name,
|
||||
'contacts' => [
|
||||
[
|
||||
'first_name' => $client_name,
|
||||
'email' => $client_email,
|
||||
],
|
||||
],
|
||||
],
|
||||
ClientFactory::create(
|
||||
$this->company->id,
|
||||
$this->company->owner()->id
|
||||
)
|
||||
);
|
||||
|
||||
$client_repository = null;
|
||||
|
||||
return $client->id;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
@ -249,9 +272,9 @@ class BaseTransformer
|
||||
/**
|
||||
* @param $email
|
||||
*
|
||||
* @return ?Contact
|
||||
* @return ?ClientContact
|
||||
*/
|
||||
public function getContact($email)
|
||||
public function getContact($email): ?ClientContact
|
||||
{
|
||||
$contact = ClientContact::where('company_id', $this->company->id)
|
||||
->whereRaw("LOWER(REPLACE(`email`, ' ' ,'')) = ?", [
|
||||
|
@ -61,8 +61,14 @@ class InvoiceTransformer extends BaseTransformer
|
||||
],
|
||||
];
|
||||
|
||||
$client_id =
|
||||
$this->getClient($this->getString($invoice_data, 'Name'), $this->getString($invoice_data, 'EmailRecipient'));
|
||||
$client_id = null;
|
||||
|
||||
if($this->hasClient($this->getString($invoice_data, 'Name') || $this->getContact($this->getString($invoice_data, 'EmailRecipient'))))
|
||||
{
|
||||
|
||||
$client_id = $this->getClient($this->getString($invoice_data, 'Name'), $this->getString($invoice_data, 'EmailRecipient'));
|
||||
|
||||
}
|
||||
|
||||
if ($client_id) {
|
||||
$transformed['client_id'] = $client_id;
|
||||
|
@ -161,7 +161,7 @@ class MatchBankTransactions implements ShouldQueue
|
||||
foreach($_expenses as $_expense) {
|
||||
|
||||
$expense = Expense::withTrashed()
|
||||
->where('id', $this->decodePrimaryKey($_expense))
|
||||
->where('id', $this->decodePrimaryKey($_expense))
|
||||
->where('company_id', $this->bt->company_id)
|
||||
->first();
|
||||
|
||||
|
@ -148,8 +148,8 @@ class CompanyExport implements ShouldQueue
|
||||
|
||||
$this->export_data['clients'] = $this->company->clients()->orderBy('number', 'DESC')->cursor()->map(function ($client) {
|
||||
$client = $this->transformArrayOfKeys($client, ['company_id', 'user_id', 'assigned_user_id', 'group_settings_id']);
|
||||
|
||||
return $client->makeVisible(['id','private_notes','user_id','company_id','last_login','hashed_id']);
|
||||
$client->tax_data = '';
|
||||
return $client->makeVisible(['id','private_notes','user_id','company_id','last_login','hashed_id'])->makeHidden(['is_tax_exempt','has_valid_vat_number']);
|
||||
})->all();
|
||||
|
||||
|
||||
@ -229,6 +229,7 @@ class CompanyExport implements ShouldQueue
|
||||
$this->export_data['invoices'] = $this->company->invoices()->orderBy('number', 'DESC')->cursor()->map(function ($invoice) {
|
||||
$invoice = $this->transformBasicEntities($invoice);
|
||||
$invoice = $this->transformArrayOfKeys($invoice, ['recurring_id','client_id', 'vendor_id', 'project_id', 'design_id', 'subscription_id','project_id']);
|
||||
$invoice->tax_data = '';
|
||||
|
||||
return $invoice->makeVisible(['id',
|
||||
'private_notes',
|
||||
|
@ -1338,7 +1338,8 @@ class CompanyImport implements ShouldQueue
|
||||
unset($obj_array[$un]);
|
||||
}
|
||||
|
||||
if ($class instanceof CompanyGateway) {
|
||||
if ($class == 'App\Models\CompanyGateway') {
|
||||
|
||||
if (Ninja::isHosted() && $obj_array['gateway_key'] == 'd14dd26a37cecc30fdd65700bfb55b23') {
|
||||
$obj_array['gateway_key'] = 'd14dd26a47cecc30fdd65700bfb67b34';
|
||||
}
|
||||
|
@ -162,6 +162,14 @@ use Laracasts\Presenter\PresentableTrait;
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Company> $companies
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CompanyUser> $company_users
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\User> $users
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\BankIntegration> $bank_integrations
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Company> $companies
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CompanyUser> $company_users
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\User> $users
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\BankIntegration> $bank_integrations
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Company> $companies
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CompanyUser> $company_users
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\User> $users
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class Account extends BaseModel
|
||||
|
@ -40,6 +40,8 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\BankSubaccount> $bank_subaccounts
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\BankSubaccount> $bank_subaccounts
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\BankSubaccount> $bank_subaccounts
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\BankSubaccount> $bank_subaccounts
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\BankSubaccount> $bank_subaccounts
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class BankAccount extends BaseModel
|
||||
|
@ -83,6 +83,8 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\BankTransaction> $transactions
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\BankTransaction> $transactions
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\BankTransaction> $transactions
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\BankTransaction> $transactions
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\BankTransaction> $transactions
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class BankIntegration extends BaseModel
|
||||
|
@ -308,6 +308,44 @@ use Laracasts\Presenter\PresentableTrait;
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\RecurringInvoice> $recurring_invoices
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\SystemLog> $system_logs
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Task> $tasks
|
||||
* @property int $has_valid_vat_number
|
||||
* @property string $leitweg_id
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Activity> $activities
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CompanyLedger> $company_ledger
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\ClientContact> $contacts
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Credit> $credits
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Expense> $expenses
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\ClientGatewayToken> $gateway_tokens
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Invoice> $invoices
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CompanyLedger> $ledger
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Payment> $payments
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\ClientContact> $primary_contact
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Project> $projects
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Quote> $quotes
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\RecurringExpense> $recurring_expenses
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\RecurringInvoice> $recurring_invoices
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\SystemLog> $system_logs
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Task> $tasks
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Client whereHasValidVatNumber($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Client whereLeitwegId($value)
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Activity> $activities
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CompanyLedger> $company_ledger
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\ClientContact> $contacts
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Credit> $credits
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Expense> $expenses
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\ClientGatewayToken> $gateway_tokens
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Invoice> $invoices
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CompanyLedger> $ledger
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Payment> $payments
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\ClientContact> $primary_contact
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Project> $projects
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Quote> $quotes
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\RecurringExpense> $recurring_expenses
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\RecurringInvoice> $recurring_invoices
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\SystemLog> $system_logs
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Task> $tasks
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class Client extends BaseModel implements HasLocalePreference
|
||||
|
@ -163,6 +163,16 @@ use Laracasts\Presenter\PresentableTrait;
|
||||
* @property-read \Illuminate\Notifications\DatabaseNotificationCollection<int, \Illuminate\Notifications\DatabaseNotification> $notifications
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\QuoteInvitation> $quote_invitations
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\RecurringInvoiceInvitation> $recurring_invoice_invitations
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CreditInvitation> $credit_invitations
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\InvoiceInvitation> $invoice_invitations
|
||||
* @property-read \Illuminate\Notifications\DatabaseNotificationCollection<int, \Illuminate\Notifications\DatabaseNotification> $notifications
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\QuoteInvitation> $quote_invitations
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\RecurringInvoiceInvitation> $recurring_invoice_invitations
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CreditInvitation> $credit_invitations
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\InvoiceInvitation> $invoice_invitations
|
||||
* @property-read \Illuminate\Notifications\DatabaseNotificationCollection<int, \Illuminate\Notifications\DatabaseNotification> $notifications
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\QuoteInvitation> $quote_invitations
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\RecurringInvoiceInvitation> $recurring_invoice_invitations
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class ClientContact extends Authenticatable implements HasLocalePreference
|
||||
|
@ -639,6 +639,99 @@ use Laracasts\Presenter\PresentableTrait;
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\User> $users
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Vendor> $vendors
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Webhook> $webhooks
|
||||
* @property int $tax_all_products
|
||||
* @property int $use_xinvoice
|
||||
* @property string $xinvoice_type
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Activity> $activities
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Activity> $all_activities
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $all_documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\BankIntegration> $bank_integrations
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\BankTransactionRule> $bank_transaction_rules
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\BankTransaction> $bank_transactions
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\ClientContact> $client_contacts
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\ClientGatewayToken> $client_gateway_tokens
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Client> $clients
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CompanyGateway> $company_gateways
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CompanyUser> $company_users
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\ClientContact> $contacts
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Credit> $credits
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Design> $designs
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\ExpenseCategory> $expense_categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Expense> $expenses
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\GroupSetting> $group_settings
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\GroupSetting> $groups
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Invoice> $invoices
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CompanyLedger> $ledger
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\PaymentTerm> $payment_terms
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Payment> $payments
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Product> $products
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Project> $projects
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\PurchaseOrder> $purchase_orders
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Quote> $quotes
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\RecurringExpense> $recurring_expenses
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\RecurringInvoice> $recurring_invoices
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Scheduler> $schedulers
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Subscription> $subscriptions
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\SystemLog> $system_log_relation
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\SystemLog> $system_logs
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Scheduler> $task_schedulers
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\TaskStatus> $task_statuses
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Task> $tasks
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\TaxRate> $tax_rates
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CompanyToken> $tokens
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CompanyToken> $tokens_hashed
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Design> $user_designs
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\PaymentTerm> $user_payment_terms
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\User> $users
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Vendor> $vendors
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Webhook> $webhooks
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Company whereUseXinvoice($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Company whereXinvoiceType($value)
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Activity> $activities
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Activity> $all_activities
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $all_documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\BankIntegration> $bank_integrations
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\BankTransactionRule> $bank_transaction_rules
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\BankTransaction> $bank_transactions
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\ClientContact> $client_contacts
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\ClientGatewayToken> $client_gateway_tokens
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Client> $clients
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CompanyGateway> $company_gateways
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CompanyUser> $company_users
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\ClientContact> $contacts
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Credit> $credits
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Design> $designs
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\ExpenseCategory> $expense_categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Expense> $expenses
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\GroupSetting> $group_settings
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\GroupSetting> $groups
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Invoice> $invoices
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CompanyLedger> $ledger
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\PaymentTerm> $payment_terms
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Payment> $payments
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Product> $products
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Project> $projects
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\PurchaseOrder> $purchase_orders
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Quote> $quotes
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\RecurringExpense> $recurring_expenses
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\RecurringInvoice> $recurring_invoices
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Scheduler> $schedulers
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Subscription> $subscriptions
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\SystemLog> $system_log_relation
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\SystemLog> $system_logs
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Scheduler> $task_schedulers
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\TaskStatus> $task_statuses
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Task> $tasks
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\TaxRate> $tax_rates
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CompanyToken> $tokens
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CompanyToken> $tokens_hashed
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Design> $user_designs
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\PaymentTerm> $user_payment_terms
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\User> $users
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Vendor> $vendors
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Webhook> $webhooks
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class Company extends BaseModel
|
||||
|
@ -100,6 +100,8 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\ClientGatewayToken> $client_gateway_tokens
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\ClientGatewayToken> $client_gateway_tokens
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\ClientGatewayToken> $client_gateway_tokens
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\ClientGatewayToken> $client_gateway_tokens
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\ClientGatewayToken> $client_gateway_tokens
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class CompanyGateway extends BaseModel
|
||||
|
@ -91,6 +91,12 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CompanyToken> $token
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CompanyToken> $tokens
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\User> $users
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CompanyToken> $token
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CompanyToken> $tokens
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\User> $users
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CompanyToken> $token
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CompanyToken> $tokens
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\User> $users
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class CompanyUser extends Pivot
|
||||
|
@ -241,6 +241,20 @@ use Laracasts\Presenter\PresentableTrait;
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CreditInvitation> $invitations
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Invoice> $invoices
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Payment> $payments
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Activity> $activities
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CompanyLedger> $company_ledger
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Backup> $history
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CreditInvitation> $invitations
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Invoice> $invoices
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Payment> $payments
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Activity> $activities
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CompanyLedger> $company_ledger
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Backup> $history
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CreditInvitation> $invitations
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Invoice> $invoices
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Payment> $payments
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class Credit extends BaseModel
|
||||
|
@ -138,6 +138,9 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \App\Models\BankTransaction|null $transaction
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class Expense extends BaseModel
|
||||
|
@ -36,6 +36,8 @@ namespace App\Models;
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\PaymentType> $payment_methods
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\PaymentType> $payment_methods
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\PaymentType> $payment_methods
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\PaymentType> $payment_methods
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\PaymentType> $payment_methods
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class GatewayType extends StaticModel
|
||||
|
@ -70,6 +70,10 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Client> $clients
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Client> $clients
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Client> $clients
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class GroupSetting extends StaticModel
|
||||
|
@ -277,6 +277,24 @@ use Laracasts\Presenter\PresentableTrait;
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\InvoiceInvitation> $invitations
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Payment> $payments
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Task> $tasks
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Activity> $activities
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CompanyLedger> $company_ledger
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Credit> $credits
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Expense> $expenses
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Backup> $history
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\InvoiceInvitation> $invitations
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Payment> $payments
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Task> $tasks
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Activity> $activities
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CompanyLedger> $company_ledger
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Credit> $credits
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Expense> $expenses
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Backup> $history
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\InvoiceInvitation> $invitations
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Payment> $payments
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Task> $tasks
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class Invoice extends BaseModel
|
||||
|
@ -172,6 +172,16 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Invoice> $invoices
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Paymentable> $paymentables
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CompanyLedger> $company_ledger
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Credit> $credits
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Invoice> $invoices
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Paymentable> $paymentables
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CompanyLedger> $company_ledger
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Credit> $credits
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Invoice> $invoices
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Paymentable> $paymentables
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class Payment extends BaseModel
|
||||
|
@ -106,6 +106,8 @@ use League\CommonMark\CommonMarkConverter;
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class Product extends BaseModel
|
||||
|
@ -88,6 +88,12 @@ use Laracasts\Presenter\PresentableTrait;
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Task> $tasks
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Task> $tasks
|
||||
* @property int|null $current_hours
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Task> $tasks
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Project whereCurrentHours($value)
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Task> $tasks
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class Project extends BaseModel
|
||||
|
@ -36,6 +36,8 @@ use App\Utils\Traits\MakesHash;
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class Proposal extends BaseModel
|
||||
|
@ -228,6 +228,18 @@ use Illuminate\Support\Facades\Storage;
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\PurchaseOrderInvitation> $invitations
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Invoice> $invoices
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Payment> $payments
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Activity> $activities
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Backup> $history
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\PurchaseOrderInvitation> $invitations
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Invoice> $invoices
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Payment> $payments
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Activity> $activities
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Backup> $history
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\PurchaseOrderInvitation> $invitations
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Invoice> $invoices
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Payment> $payments
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class PurchaseOrder extends BaseModel
|
||||
|
@ -213,6 +213,14 @@ use Laracasts\Presenter\PresentableTrait;
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Backup> $history
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\QuoteInvitation> $invitations
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Activity> $activities
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Backup> $history
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\QuoteInvitation> $invitations
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Activity> $activities
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Backup> $history
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\QuoteInvitation> $invitations
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class Quote extends BaseModel
|
||||
|
@ -147,6 +147,8 @@ use Illuminate\Support\Carbon;
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class RecurringExpense extends BaseModel
|
||||
|
@ -219,6 +219,16 @@ use Laracasts\Presenter\PresentableTrait;
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Backup> $history
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\RecurringInvoiceInvitation> $invitations
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Invoice> $invoices
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Activity> $activities
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Backup> $history
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\RecurringInvoiceInvitation> $invitations
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Invoice> $invoices
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Activity> $activities
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Backup> $history
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\RecurringInvoiceInvitation> $invitations
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Invoice> $invoices
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class RecurringInvoice extends BaseModel
|
||||
|
@ -211,6 +211,16 @@ use Laracasts\Presenter\PresentableTrait;
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Backup> $history
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\RecurringQuoteInvitation> $invitations
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Quote> $quotes
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Activity> $activities
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Backup> $history
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\RecurringQuoteInvitation> $invitations
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Quote> $quotes
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Activity> $activities
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Backup> $history
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\RecurringQuoteInvitation> $invitations
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Quote> $quotes
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class RecurringQuote extends BaseModel
|
||||
|
@ -76,6 +76,7 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Scheduler whereUserId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Scheduler withTrashed()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Scheduler withoutTrashed()
|
||||
* @property-read \App\Models\User $user
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class Scheduler extends BaseModel
|
||||
@ -122,6 +123,11 @@ class Scheduler extends BaseModel
|
||||
return $this->belongsTo(Company::class);
|
||||
}
|
||||
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* remainingCycles
|
||||
*
|
||||
|
@ -99,6 +99,8 @@ use Illuminate\Support\Carbon;
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class Task extends BaseModel
|
||||
|
@ -195,6 +195,20 @@ use Laracasts\Presenter\PresentableTrait;
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Notifications\DatabaseNotificationCollection<int, \Illuminate\Notifications\DatabaseNotification> $notifications
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CompanyToken> $tokens
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Client> $clients
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Company> $companies
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CompanyUser> $company_users
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\ClientContact> $contacts
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Notifications\DatabaseNotificationCollection<int, \Illuminate\Notifications\DatabaseNotification> $notifications
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CompanyToken> $tokens
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Client> $clients
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Company> $companies
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CompanyUser> $company_users
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\ClientContact> $contacts
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Notifications\DatabaseNotificationCollection<int, \Illuminate\Notifications\DatabaseNotification> $notifications
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CompanyToken> $tokens
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class User extends Authenticatable implements MustVerifyEmail
|
||||
@ -243,6 +257,7 @@ class User extends Authenticatable implements MustVerifyEmail
|
||||
'custom_value3',
|
||||
'custom_value4',
|
||||
'is_deleted',
|
||||
'oauth_user_token',
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -136,6 +136,14 @@ use Laracasts\Presenter\PresentableTrait;
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\VendorContact> $contacts
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\VendorContact> $primary_contact
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Activity> $activities
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\VendorContact> $contacts
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\VendorContact> $primary_contact
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Activity> $activities
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\VendorContact> $contacts
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\VendorContact> $primary_contact
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class Vendor extends BaseModel
|
||||
|
@ -126,6 +126,10 @@ use Laracasts\Presenter\PresentableTrait;
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\PurchaseOrderInvitation> $purchase_order_invitations
|
||||
* @property-read \Illuminate\Notifications\DatabaseNotificationCollection<int, \Illuminate\Notifications\DatabaseNotification> $notifications
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\PurchaseOrderInvitation> $purchase_order_invitations
|
||||
* @property-read \Illuminate\Notifications\DatabaseNotificationCollection<int, \Illuminate\Notifications\DatabaseNotification> $notifications
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\PurchaseOrderInvitation> $purchase_order_invitations
|
||||
* @property-read \Illuminate\Notifications\DatabaseNotificationCollection<int, \Illuminate\Notifications\DatabaseNotification> $notifications
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\PurchaseOrderInvitation> $purchase_order_invitations
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class VendorContact extends Authenticatable implements HasLocalePreference
|
||||
|
@ -35,7 +35,7 @@ class TaskRepository extends BaseRepository
|
||||
*
|
||||
* @return task|null task Object
|
||||
*/
|
||||
public function save(array $data, Task $task) : ?Task
|
||||
public function save(array $data, Task $task): ?Task
|
||||
{
|
||||
if ($task->id) {
|
||||
$this->new_task = false;
|
||||
@ -97,8 +97,12 @@ class TaskRepository extends BaseRepository
|
||||
} else {
|
||||
$time_log = [];
|
||||
}
|
||||
|
||||
$key_values = array_column($time_log, 0);
|
||||
array_multisort($key_values, SORT_ASC, $time_log);
|
||||
|
||||
array_multisort($time_log);
|
||||
// array_multisort($time_log);
|
||||
// ksort($time_log);
|
||||
|
||||
if (isset($data['action'])) {
|
||||
if ($data['action'] == 'start') {
|
||||
@ -118,8 +122,6 @@ class TaskRepository extends BaseRepository
|
||||
}
|
||||
|
||||
$task->time_log = json_encode($time_log);
|
||||
// $task->start_time = $task->start_time ?: $task->calcStartTime();
|
||||
// $task->duration = $task->calcDuration();
|
||||
|
||||
$task->saveQuietly();
|
||||
|
||||
@ -206,10 +208,12 @@ class TaskRepository extends BaseRepository
|
||||
|
||||
$last = end($log);
|
||||
|
||||
if (is_array($last) && $last[1] !== 0) {
|
||||
if (is_array($last) && $last[1] !== 0) { // this line is a disaster
|
||||
$new = [time(), 0];
|
||||
|
||||
$log = array_merge($log, [$new]);
|
||||
$task->time_log = json_encode($log);
|
||||
|
||||
$task->saveQuietly();
|
||||
}
|
||||
|
||||
@ -226,7 +230,7 @@ class TaskRepository extends BaseRepository
|
||||
$last[1] = time();
|
||||
|
||||
array_pop($log);
|
||||
$log = array_merge($log, [$last]);
|
||||
$log = array_merge($log, [$last]);//check at this point, it may be prepending here.
|
||||
|
||||
$task->time_log = json_encode($log);
|
||||
$task->saveQuietly();
|
||||
|
141
app/Services/Report/ARDetailReport.php
Normal file
141
app/Services/Report/ARDetailReport.php
Normal file
@ -0,0 +1,141 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Services\Report;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\Number;
|
||||
use App\Models\Client;
|
||||
use League\Csv\Writer;
|
||||
use App\Models\Company;
|
||||
use App\Models\Invoice;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Export\CSV\BaseExport;
|
||||
use App\Utils\Traits\MakesDates;
|
||||
use Illuminate\Support\Facades\App;
|
||||
|
||||
class ARDetailReport extends BaseExport
|
||||
{
|
||||
use MakesDates;
|
||||
//Date
|
||||
//Invoice #
|
||||
//Status
|
||||
//Customer
|
||||
//Age - Days
|
||||
//Amount
|
||||
//Balance
|
||||
|
||||
public Writer $csv;
|
||||
|
||||
public string $date_key = 'created_at';
|
||||
|
||||
public array $report_keys = [
|
||||
'date',
|
||||
'invoice_number',
|
||||
'status',
|
||||
'client_name',
|
||||
'client_number',
|
||||
'id_number',
|
||||
'age',
|
||||
'amount',
|
||||
'balance',
|
||||
];
|
||||
|
||||
/**
|
||||
@param array $input
|
||||
[
|
||||
'date_range',
|
||||
'start_date',
|
||||
'end_date',
|
||||
'clients',
|
||||
'client_id',
|
||||
]
|
||||
*/
|
||||
public function __construct(public Company $company, public array $input)
|
||||
{
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
MultiDB::setDb($this->company->db);
|
||||
App::forgetInstance('translator');
|
||||
App::setLocale($this->company->locale());
|
||||
$t = app('translator');
|
||||
$t->replace(Ninja::transformTranslations($this->company->settings));
|
||||
|
||||
$this->csv = Writer::createFromString();
|
||||
|
||||
$this->csv->insertOne([]);
|
||||
$this->csv->insertOne([]);
|
||||
$this->csv->insertOne([]);
|
||||
$this->csv->insertOne([]);
|
||||
$this->csv->insertOne([ctrans('texts.aged_receivable_detailed_report')]);
|
||||
$this->csv->insertOne([ctrans('texts.created_on'),' ',$this->translateDate(now()->format('Y-m-d'), $this->company->date_format(), $this->company->locale())]);
|
||||
|
||||
if (count($this->input['report_keys']) == 0) {
|
||||
$this->input['report_keys'] = $this->report_keys;
|
||||
}
|
||||
|
||||
$this->csv->insertOne($this->buildHeader());
|
||||
|
||||
$query = Invoice::query()
|
||||
->withTrashed()
|
||||
->where('company_id', $this->company->id)
|
||||
->where('is_deleted', 0)
|
||||
->where('balance', '>', 0)
|
||||
->orderBy('due_date', 'ASC')
|
||||
->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL]);
|
||||
|
||||
$query = $this->addDateRange($query);
|
||||
|
||||
$query = $this->filterByClients($query);
|
||||
|
||||
$this->csv->insertOne($this->buildHeader());
|
||||
|
||||
$query->cursor()
|
||||
->each(function ($invoice) {
|
||||
$this->csv->insertOne($this->buildRow($invoice));
|
||||
});
|
||||
|
||||
return $this->csv->toString();
|
||||
}
|
||||
|
||||
private function buildRow(Invoice $invoice): array
|
||||
{
|
||||
$client = $invoice->client;
|
||||
|
||||
return [
|
||||
$this->translateDate($invoice->due_date, $this->company->date_format(), $this->company->locale()),
|
||||
$invoice->number,
|
||||
$invoice->stringStatus($invoice->status_id),
|
||||
$client->present()->name(),
|
||||
$client->number,
|
||||
$client->id_number,
|
||||
Carbon::parse($invoice->due_date)->diffInDays(now()),
|
||||
Number::formatMoney($invoice->amount, $client),
|
||||
Number::formatMoney($invoice->balance, $client),
|
||||
];
|
||||
}
|
||||
|
||||
public function buildHeader() :array
|
||||
{
|
||||
$header = [];
|
||||
|
||||
foreach ($this->input['report_keys'] as $value) {
|
||||
|
||||
$header[] = ctrans("texts.{$value}");
|
||||
}
|
||||
|
||||
return $header;
|
||||
}
|
||||
|
||||
}
|
212
app/Services/Report/ARSummaryReport.php
Normal file
212
app/Services/Report/ARSummaryReport.php
Normal file
@ -0,0 +1,212 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Services\Report;
|
||||
|
||||
use App\Export\CSV\BaseExport;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\Client;
|
||||
use App\Models\Company;
|
||||
use App\Models\Invoice;
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\Number;
|
||||
use App\Utils\Traits\MakesDates;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use League\Csv\Writer;
|
||||
|
||||
class ARSummaryReport extends BaseExport
|
||||
{
|
||||
use MakesDates;
|
||||
|
||||
public Writer $csv;
|
||||
|
||||
public string $date_key = 'created_at';
|
||||
|
||||
public Client $client;
|
||||
|
||||
public array $report_keys = [
|
||||
'client_name',
|
||||
'client_number',
|
||||
'id_number',
|
||||
'current',
|
||||
'age_group_0',
|
||||
'age_group_30',
|
||||
'age_group_60',
|
||||
'age_group_90',
|
||||
'age_group_120',
|
||||
'total',
|
||||
];
|
||||
|
||||
/**
|
||||
@param array $input
|
||||
[
|
||||
'date_range',
|
||||
'start_date',
|
||||
'end_date',
|
||||
'clients',
|
||||
'client_id',
|
||||
]
|
||||
*/
|
||||
public function __construct(public Company $company, public array $input)
|
||||
{
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
MultiDB::setDb($this->company->db);
|
||||
App::forgetInstance('translator');
|
||||
App::setLocale($this->company->locale());
|
||||
$t = app('translator');
|
||||
$t->replace(Ninja::transformTranslations($this->company->settings));
|
||||
|
||||
$this->csv = Writer::createFromString();
|
||||
|
||||
$this->csv->insertOne([]);
|
||||
$this->csv->insertOne([]);
|
||||
$this->csv->insertOne([]);
|
||||
$this->csv->insertOne([]);
|
||||
$this->csv->insertOne([ctrans('texts.aged_receivable_summary_report')]);
|
||||
$this->csv->insertOne([ctrans('texts.created_on'),' ',$this->translateDate(now()->format('Y-m-d'), $this->company->date_format(), $this->company->locale())]);
|
||||
|
||||
if (count($this->input['report_keys']) == 0) {
|
||||
$this->input['report_keys'] = $this->report_keys;
|
||||
}
|
||||
|
||||
$this->csv->insertOne($this->buildHeader());
|
||||
|
||||
Client::query()
|
||||
->where('company_id', $this->company->id)
|
||||
->where('is_deleted', 0)
|
||||
->orderBy('balance', 'desc')
|
||||
->cursor()
|
||||
->each(function ($client) {
|
||||
|
||||
$this->csv->insertOne($this->buildRow($client));
|
||||
|
||||
});
|
||||
|
||||
return $this->csv->toString();
|
||||
}
|
||||
|
||||
private function buildRow(Client $client): array
|
||||
{
|
||||
$this->client = $client;
|
||||
|
||||
return [
|
||||
$this->client->present()->name(),
|
||||
$this->client->number,
|
||||
$this->client->id_number,
|
||||
$this->getCurrent(),
|
||||
$this->getAgingAmount('30'),
|
||||
$this->getAgingAmount('60'),
|
||||
$this->getAgingAmount('90'),
|
||||
$this->getAgingAmount('120'),
|
||||
$this->getAgingAmount('120+'),
|
||||
];
|
||||
}
|
||||
|
||||
private function getCurrent(): string
|
||||
{
|
||||
$amount = Invoice::withTrashed()
|
||||
->where('client_id', $this->client->id)
|
||||
->where('company_id', $this->client->company_id)
|
||||
->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL])
|
||||
->where('balance', '>', 0)
|
||||
->where('is_deleted', 0)
|
||||
->where('due_date', '<', now()->startOfDay())
|
||||
->sum('balance');
|
||||
|
||||
return Number::formatMoney($amount, $this->client);
|
||||
|
||||
}
|
||||
/**
|
||||
* Generate aging amount.
|
||||
*
|
||||
* @param mixed $range
|
||||
* @return string
|
||||
*/
|
||||
private function getAgingAmount($range)
|
||||
{
|
||||
$ranges = $this->calculateDateRanges($range);
|
||||
|
||||
$from = $ranges[0];
|
||||
$to = $ranges[1];
|
||||
|
||||
$amount = Invoice::withTrashed()
|
||||
->where('client_id', $this->client->id)
|
||||
->where('company_id', $this->client->company_id)
|
||||
->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL])
|
||||
->where('balance', '>', 0)
|
||||
->where('is_deleted', 0)
|
||||
->whereBetween('due_date', [$to, $from])
|
||||
->sum('balance');
|
||||
|
||||
return Number::formatMoney($amount, $this->client);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate date ranges for aging.
|
||||
*
|
||||
* @param mixed $range
|
||||
* @return array
|
||||
*/
|
||||
private function calculateDateRanges($range)
|
||||
{
|
||||
$ranges = [];
|
||||
|
||||
switch ($range) {
|
||||
case '30':
|
||||
$ranges[0] = now()->startOfDay();
|
||||
$ranges[1] = now()->startOfDay()->subDays(30);
|
||||
|
||||
return $ranges;
|
||||
case '60':
|
||||
$ranges[0] = now()->startOfDay()->subDays(30);
|
||||
$ranges[1] = now()->startOfDay()->subDays(60);
|
||||
|
||||
return $ranges;
|
||||
case '90':
|
||||
$ranges[0] = now()->startOfDay()->subDays(60);
|
||||
$ranges[1] = now()->startOfDay()->subDays(90);
|
||||
|
||||
return $ranges;
|
||||
case '120':
|
||||
$ranges[0] = now()->startOfDay()->subDays(90);
|
||||
$ranges[1] = now()->startOfDay()->subDays(120);
|
||||
|
||||
return $ranges;
|
||||
case '120+':
|
||||
$ranges[0] = now()->startOfDay()->subDays(120);
|
||||
$ranges[1] = now()->startOfDay()->subYears(20);
|
||||
|
||||
return $ranges;
|
||||
default:
|
||||
$ranges[0] = now()->startOfDay()->subDays(0);
|
||||
$ranges[1] = now()->subDays(30);
|
||||
|
||||
return $ranges;
|
||||
}
|
||||
}
|
||||
|
||||
public function buildHeader() :array
|
||||
{
|
||||
$header = [];
|
||||
|
||||
foreach ($this->input['report_keys'] as $value) {
|
||||
|
||||
$header[] = ctrans("texts.{$value}");
|
||||
}
|
||||
|
||||
return $header;
|
||||
}
|
||||
|
||||
}
|
121
app/Services/Report/ClientBalanceReport.php
Normal file
121
app/Services/Report/ClientBalanceReport.php
Normal file
@ -0,0 +1,121 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Services\Report;
|
||||
|
||||
use App\Utils\Ninja;
|
||||
use App\Models\Client;
|
||||
use League\Csv\Writer;
|
||||
use App\Models\Company;
|
||||
use App\Models\Invoice;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Export\CSV\BaseExport;
|
||||
use App\Utils\Traits\MakesDates;
|
||||
use Illuminate\Support\Facades\App;
|
||||
|
||||
class ClientBalanceReport extends BaseExport
|
||||
{
|
||||
use MakesDates;
|
||||
//Name
|
||||
//Invoice count
|
||||
//Amount
|
||||
//Amount with Tax
|
||||
public Writer $csv;
|
||||
|
||||
public string $date_key = 'created_at';
|
||||
|
||||
public array $report_keys = [
|
||||
'client_name',
|
||||
'client_number',
|
||||
'id_number',
|
||||
'invoice_balance',
|
||||
'credit_balance',
|
||||
];
|
||||
|
||||
/**
|
||||
@param array $input
|
||||
[
|
||||
'date_range',
|
||||
'start_date',
|
||||
'end_date',
|
||||
'clients',
|
||||
'client_id',
|
||||
]
|
||||
*/
|
||||
public function __construct(public Company $company, public array $input)
|
||||
{
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
MultiDB::setDb($this->company->db);
|
||||
App::forgetInstance('translator');
|
||||
App::setLocale($this->company->locale());
|
||||
$t = app('translator');
|
||||
$t->replace(Ninja::transformTranslations($this->company->settings));
|
||||
|
||||
$this->csv = Writer::createFromString();
|
||||
|
||||
$this->csv->insertOne([]);
|
||||
$this->csv->insertOne([]);
|
||||
$this->csv->insertOne([]);
|
||||
$this->csv->insertOne([]);
|
||||
$this->csv->insertOne([ctrans('texts.customer_balance_report')]);
|
||||
$this->csv->insertOne([ctrans('texts.created_on'),' ',$this->translateDate(now()->format('Y-m-d'), $this->company->date_format(), $this->company->locale())]);
|
||||
|
||||
if (count($this->input['report_keys']) == 0) {
|
||||
$this->input['report_keys'] = $this->report_keys;
|
||||
}
|
||||
|
||||
$this->csv->insertOne($this->buildHeader());
|
||||
|
||||
Client::query()
|
||||
->where('company_id', $this->company->id)
|
||||
->where('is_deleted', 0)
|
||||
->orderBy('balance', 'desc')
|
||||
->cursor()
|
||||
->each(function ($client){
|
||||
|
||||
$this->csv->insertOne($this->buildRow($client));
|
||||
|
||||
});
|
||||
|
||||
return $this->csv->toString();
|
||||
|
||||
}
|
||||
|
||||
public function buildHeader(): array
|
||||
{
|
||||
$headers = [];
|
||||
|
||||
foreach($this->report_keys as $key)
|
||||
$headers[] = ctrans("texts.{$key}");
|
||||
|
||||
return $headers;
|
||||
|
||||
}
|
||||
private function buildRow(Client $client): array
|
||||
{
|
||||
$query = Invoice::where('client_id', $client->id)
|
||||
->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL]);
|
||||
|
||||
$query = $this->addDateRange($query);
|
||||
|
||||
return [
|
||||
$client->present()->name(),
|
||||
$client->number,
|
||||
$client->id_number,
|
||||
$query->count(),
|
||||
$query->sum('balance'),
|
||||
$client->credit_balance,
|
||||
];
|
||||
}
|
||||
}
|
136
app/Services/Report/ClientSalesReport.php
Normal file
136
app/Services/Report/ClientSalesReport.php
Normal file
@ -0,0 +1,136 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Services\Report;
|
||||
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\Number;
|
||||
use App\Models\Client;
|
||||
use League\Csv\Writer;
|
||||
use App\Models\Company;
|
||||
use App\Models\Invoice;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Export\CSV\BaseExport;
|
||||
use App\Utils\Traits\MakesDates;
|
||||
use Illuminate\Support\Facades\App;
|
||||
|
||||
class ClientSalesReport extends BaseExport
|
||||
{
|
||||
use MakesDates;
|
||||
//Name
|
||||
//Invoice count
|
||||
//Amount
|
||||
//Amount with Tax
|
||||
|
||||
public Writer $csv;
|
||||
|
||||
public string $date_key = 'created_at';
|
||||
|
||||
public array $report_keys = [
|
||||
'client_name',
|
||||
'client_number',
|
||||
'id_number',
|
||||
'invoices',
|
||||
'amount',
|
||||
'balance',
|
||||
'total_taxes',
|
||||
'amount_paid',
|
||||
];
|
||||
|
||||
/**
|
||||
@param array $input
|
||||
[
|
||||
'date_range',
|
||||
'start_date',
|
||||
'end_date',
|
||||
'clients',
|
||||
'client_id',
|
||||
]
|
||||
*/
|
||||
public function __construct(public Company $company, public array $input)
|
||||
{
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
MultiDB::setDb($this->company->db);
|
||||
App::forgetInstance('translator');
|
||||
App::setLocale($this->company->locale());
|
||||
$t = app('translator');
|
||||
$t->replace(Ninja::transformTranslations($this->company->settings));
|
||||
|
||||
$this->csv = Writer::createFromString();
|
||||
|
||||
$this->csv->insertOne([]);
|
||||
$this->csv->insertOne([]);
|
||||
$this->csv->insertOne([]);
|
||||
$this->csv->insertOne([]);
|
||||
$this->csv->insertOne([ctrans('texts.client_sales_report')]);
|
||||
$this->csv->insertOne([ctrans('texts.created_on'),' ',$this->translateDate(now()->format('Y-m-d'), $this->company->date_format(), $this->company->locale())]);
|
||||
|
||||
if (count($this->input['report_keys']) == 0) {
|
||||
$this->input['report_keys'] = $this->report_keys;
|
||||
}
|
||||
|
||||
$this->csv->insertOne($this->buildHeader());
|
||||
|
||||
Client::query()
|
||||
->where('company_id', $this->company->id)
|
||||
->where('is_deleted', 0)
|
||||
->orderBy('balance', 'desc')
|
||||
->cursor()
|
||||
->each(function ($client) {
|
||||
|
||||
$this->csv->insertOne($this->buildRow($client));
|
||||
|
||||
});
|
||||
|
||||
return $this->csv->toString();
|
||||
|
||||
}
|
||||
|
||||
private function buildRow(Client $client): array
|
||||
{
|
||||
$query = Invoice::where('client_id', $client->id)
|
||||
->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL, Invoice::STATUS_PAID]);
|
||||
|
||||
$query = $this->addDateRange($query);
|
||||
|
||||
$amount = $query->sum('amount');
|
||||
$balance = $query->sum('balance');
|
||||
$paid = $amount-$balance;
|
||||
|
||||
return [
|
||||
$client->present()->name(),
|
||||
$client->number,
|
||||
$client->id_number,
|
||||
$query->count(),
|
||||
Number::formatMoney($amount, $client),
|
||||
Number::formatMoney($balance, $client),
|
||||
Number::formatMoney($query->sum('total_taxes'), $client),
|
||||
Number::formatMoney($amount-$balance, $client),
|
||||
|
||||
];
|
||||
}
|
||||
|
||||
public function buildHeader() :array
|
||||
{
|
||||
$header = [];
|
||||
|
||||
foreach ($this->input['report_keys'] as $value) {
|
||||
|
||||
$header[] = ctrans("texts.{$value}");
|
||||
}
|
||||
|
||||
return $header;
|
||||
}
|
||||
|
||||
}
|
135
app/Services/Report/TaxSummaryReport.php
Normal file
135
app/Services/Report/TaxSummaryReport.php
Normal file
@ -0,0 +1,135 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Services\Report;
|
||||
|
||||
use App\Export\CSV\BaseExport;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\Client;
|
||||
use App\Models\Company;
|
||||
use App\Models\Invoice;
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\Number;
|
||||
use App\Utils\Traits\MakesDates;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use League\Csv\Writer;
|
||||
|
||||
class TaxSummaryReport extends BaseExport
|
||||
{
|
||||
use MakesDates;
|
||||
//Name
|
||||
//Invoice count
|
||||
//Amount
|
||||
//Amount with Tax
|
||||
|
||||
public Writer $csv;
|
||||
|
||||
public string $date_key = 'created_at';
|
||||
|
||||
public array $report_keys = [
|
||||
'tax_name',
|
||||
// 'taxable_amount',
|
||||
'tax_amount',
|
||||
];
|
||||
|
||||
/**
|
||||
@param array $input
|
||||
[
|
||||
'date_range',
|
||||
'start_date',
|
||||
'end_date',
|
||||
'clients',
|
||||
'client_id',
|
||||
]
|
||||
*/
|
||||
public function __construct(public Company $company, public array $input)
|
||||
{
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
MultiDB::setDb($this->company->db);
|
||||
App::forgetInstance('translator');
|
||||
App::setLocale($this->company->locale());
|
||||
$t = app('translator');
|
||||
$t->replace(Ninja::transformTranslations($this->company->settings));
|
||||
|
||||
$this->csv = Writer::createFromString();
|
||||
|
||||
$this->csv->insertOne([]);
|
||||
$this->csv->insertOne([]);
|
||||
$this->csv->insertOne([]);
|
||||
$this->csv->insertOne([]);
|
||||
$this->csv->insertOne([ctrans('texts.tax_summary')]);
|
||||
$this->csv->insertOne([ctrans('texts.created_on'),' ',$this->translateDate(now()->format('Y-m-d'), $this->company->date_format(), $this->company->locale())]);
|
||||
|
||||
if (count($this->input['report_keys']) == 0) {
|
||||
$this->input['report_keys'] = $this->report_keys;
|
||||
}
|
||||
|
||||
$this->csv->insertOne($this->buildHeader());
|
||||
|
||||
$query = Invoice::query()
|
||||
->where('company_id', $this->company->id)
|
||||
->where('is_deleted', 0)
|
||||
->orderBy('balance', 'desc');
|
||||
|
||||
$query = $this->addDateRange($query);
|
||||
|
||||
$query = $this->filterByClients($query);
|
||||
$map = [];
|
||||
|
||||
foreach($query->cursor() as $invoice)
|
||||
{
|
||||
|
||||
$taxes = $invoice->calc()->getTaxMap();
|
||||
|
||||
foreach($taxes as $tax)
|
||||
{
|
||||
$key = $tax['name'];
|
||||
|
||||
if(!isset($map[$key])) {
|
||||
$map[$key]['tax_amount'] = 0;
|
||||
// $map[$key]['taxable_amount'] = 0;
|
||||
}
|
||||
|
||||
$map[$key]['tax_amount'] += $tax['total'];
|
||||
// $map[$key]['taxable_amount'] += $invoice->amount;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
foreach($map as $key => $value)
|
||||
{
|
||||
$this->csv->insertOne([$key, Number::formatMoney($value['tax_amount'], $this->company)]);
|
||||
// $this->csv->insertOne([$key, Number::formatMoney($value['taxable_amount'], $this->company), Number::formatMoney($value['tax_amount'], $this->company)]);
|
||||
}
|
||||
|
||||
|
||||
return $this->csv->toString();
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function buildHeader() :array
|
||||
{
|
||||
$header = [];
|
||||
|
||||
foreach ($this->input['report_keys'] as $value) {
|
||||
|
||||
$header[] = ctrans("texts.{$value}");
|
||||
}
|
||||
|
||||
return $header;
|
||||
}
|
||||
|
||||
}
|
120
app/Services/Report/UserSalesReport.php
Normal file
120
app/Services/Report/UserSalesReport.php
Normal file
@ -0,0 +1,120 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Services\Report;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\Number;
|
||||
use League\Csv\Writer;
|
||||
use App\Models\Company;
|
||||
use App\Models\Invoice;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Export\CSV\BaseExport;
|
||||
use App\Utils\Traits\MakesDates;
|
||||
use Illuminate\Support\Facades\App;
|
||||
|
||||
class UserSalesReport extends BaseExport
|
||||
{
|
||||
use MakesDates;
|
||||
//Name
|
||||
//Invoice count
|
||||
//Amount
|
||||
//Amount with Tax
|
||||
public Writer $csv;
|
||||
|
||||
public string $date_key = 'created_at';
|
||||
|
||||
public array $report_keys = [
|
||||
'name',
|
||||
'invoices',
|
||||
'invoice_amount',
|
||||
'total_taxes',
|
||||
];
|
||||
/**
|
||||
@param array $input
|
||||
[
|
||||
'date_range',
|
||||
'start_date',
|
||||
'end_date',
|
||||
'clients',
|
||||
'client_id',
|
||||
]
|
||||
*/
|
||||
public function __construct(public Company $company, public array $input)
|
||||
{
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
MultiDB::setDb($this->company->db);
|
||||
App::forgetInstance('translator');
|
||||
App::setLocale($this->company->locale());
|
||||
$t = app('translator');
|
||||
$t->replace(Ninja::transformTranslations($this->company->settings));
|
||||
|
||||
$this->csv = Writer::createFromString();
|
||||
|
||||
$query = Invoice::query()
|
||||
->withTrashed()
|
||||
->where('company_id', $this->company->id)
|
||||
->where('is_deleted', 0)
|
||||
->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL, Invoice::STATUS_PAID]);
|
||||
|
||||
$query = $this->addDateRange($query);
|
||||
|
||||
$query = $this->filterByClients($query);
|
||||
|
||||
$this->csv->insertOne([ctrans('texts.user_sales_report_header', ['client' => $this->client_description, 'start_date' => $this->start_date, 'end_date' => $this->end_date])]);
|
||||
|
||||
if (count($this->input['report_keys']) == 0) {
|
||||
$this->input['report_keys'] = $this->report_keys;
|
||||
}
|
||||
|
||||
$this->csv->insertOne($this->buildHeader());
|
||||
|
||||
$users = $this->company->users;
|
||||
|
||||
$report = $users->map(function ($user) use($query){
|
||||
|
||||
$new_query = $query;
|
||||
$new_query->where('user_id', $user->id);
|
||||
|
||||
return [
|
||||
$user->present()->name(),
|
||||
$new_query->count(),
|
||||
Number::formatMoney($new_query->sum('amount'), $this->company),
|
||||
Number::formatMoney($new_query->sum('total_taxes'), $this->company),
|
||||
];
|
||||
|
||||
})->toArray();
|
||||
|
||||
$key_values = array_column($report, 1);
|
||||
array_multisort($key_values, SORT_DESC, $report);
|
||||
|
||||
$this->csv->insertAll($report);
|
||||
|
||||
return $this->csv->toString();
|
||||
|
||||
}
|
||||
|
||||
public function buildHeader() :array
|
||||
{
|
||||
$header = [];
|
||||
|
||||
foreach ($this->input['report_keys'] as $value) {
|
||||
|
||||
$header[] = ctrans("texts.{$value}");
|
||||
}
|
||||
|
||||
return $header;
|
||||
}
|
||||
}
|
@ -27,7 +27,10 @@ class EmailRecord
|
||||
{
|
||||
$class = 'App\\Models\\' . Str::camel($this->scheduler->parameters['entity']);
|
||||
|
||||
$class::find($this->decodePrimaryKey($this->scheduler->parameters['entity_id']))->service()->sendEmail();
|
||||
$entity = $class::find($this->decodePrimaryKey($this->scheduler->parameters['entity_id']));
|
||||
|
||||
if($entity)
|
||||
$entity->service()->sendEmail();
|
||||
|
||||
$this->scheduler->forceDelete();
|
||||
}
|
||||
|
133
app/Services/Scheduler/EmailReport.php
Normal file
133
app/Services/Scheduler/EmailReport.php
Normal file
@ -0,0 +1,133 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Services\Scheduler;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Models\Scheduler;
|
||||
use App\Mail\DownloadReport;
|
||||
use App\Export\CSV\TaskExport;
|
||||
use App\Export\CSV\QuoteExport;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use App\Export\CSV\ClientExport;
|
||||
use App\Export\CSV\CreditExport;
|
||||
use App\Utils\Traits\MakesDates;
|
||||
use App\Export\CSV\ContactExport;
|
||||
use App\Export\CSV\ExpenseExport;
|
||||
use App\Export\CSV\InvoiceExport;
|
||||
use App\Export\CSV\PaymentExport;
|
||||
use App\Export\CSV\ProductExport;
|
||||
use App\Jobs\Mail\NinjaMailerJob;
|
||||
use App\Export\CSV\DocumentExport;
|
||||
use App\Export\CSV\QuoteItemExport;
|
||||
use App\Services\Report\ProfitLoss;
|
||||
use App\Jobs\Mail\NinjaMailerObject;
|
||||
use App\Export\CSV\InvoiceItemExport;
|
||||
use App\Export\CSV\ProductSalesExport;
|
||||
use App\Services\Report\ARDetailReport;
|
||||
use App\Services\Report\ARSummaryReport;
|
||||
use App\Services\Report\UserSalesReport;
|
||||
use App\Services\Report\TaxSummaryReport;
|
||||
use App\Export\CSV\RecurringInvoiceExport;
|
||||
use App\Services\Report\ClientSalesReport;
|
||||
use App\Services\Report\ClientBalanceReport;
|
||||
|
||||
class EmailReport
|
||||
{
|
||||
use MakesHash;
|
||||
use MakesDates;
|
||||
|
||||
private Client $client;
|
||||
|
||||
private bool $multiple_clients = false;
|
||||
|
||||
private string $file_name = 'file.csv';
|
||||
|
||||
public function __construct(public Scheduler $scheduler)
|
||||
{
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
|
||||
$start_end_dates = $this->calculateStartAndEndDates();
|
||||
$data = [];
|
||||
|
||||
$data = [
|
||||
'start_date' => $start_end_dates[0],
|
||||
'end_date' => $start_end_dates[1],
|
||||
'date_range' => 'custom',
|
||||
'client_id' => null,
|
||||
'report_keys' => []
|
||||
];
|
||||
|
||||
if (count($this->scheduler->parameters['clients']) >= 1) {
|
||||
$data['clients'] = $this->transformKeys($this->scheduler->parameters['clients']);
|
||||
}
|
||||
|
||||
$export = false;
|
||||
|
||||
match($this->scheduler->parameters['report_name'])
|
||||
{
|
||||
'product_sales_report' => $export = (new ProductSalesExport($this->scheduler->company, $data)),
|
||||
'email_ar_detailed_report' => $export = (new ARDetailReport($this->scheduler->company, $data)),
|
||||
'email_ar_summary_report' => $export = (new ARSummaryReport($this->scheduler->company, $data)),
|
||||
'email_tax_summary_report' => $export = (new TaxSummaryReport($this->scheduler->company, $data)),
|
||||
'email_client_balance_report' => $export = (new ClientBalanceReport($this->scheduler->company, $data)),
|
||||
'email_client_sales_report' => $export = (new ClientSalesReport($this->scheduler->company, $data)),
|
||||
'email_user_sales_report' => $export = (new UserSalesReport($this->scheduler->company, $data)),
|
||||
'clients' => $export = (new ClientExport($this->scheduler->company, $data)),
|
||||
'client_contacts' => $export = (new ContactExport($this->scheduler->company, $data)),
|
||||
'credits' => $export = (new CreditExport($this->scheduler->company, $data)),
|
||||
'documents' => $export = (new DocumentExport($this->scheduler->company, $data)),
|
||||
'expenses' => $export = (new ExpenseExport($this->scheduler->company, $data)),
|
||||
'invoices' => $export = (new InvoiceExport($this->scheduler->company, $data)),
|
||||
'invoice_items' => $export = (new InvoiceItemExport($this->scheduler->company, $data)),
|
||||
'quotes' => $export = (new QuoteExport($this->scheduler->company, $data)),
|
||||
'quote_items' => $export = (new QuoteItemExport($this->scheduler->company, $data)),
|
||||
'recurring_invoices' => $export = (new RecurringInvoiceExport($this->scheduler->company, $data)),
|
||||
'payments' => $export = (new PaymentExport($this->scheduler->company, $data)),
|
||||
'products' => $export = (new ProductExport($this->scheduler->company, $data)),
|
||||
'tasks' => $export = (new TaskExport($this->scheduler->company, $data)),
|
||||
'profitloss' => $export = (new ProfitLoss($this->scheduler->company, $data)),
|
||||
default => $export = false,
|
||||
};
|
||||
|
||||
if(!$export) {
|
||||
$this->cancelSchedule();
|
||||
return;
|
||||
}
|
||||
|
||||
$csv = $export->run();
|
||||
|
||||
//todo - potentially we send this to more than one user.
|
||||
|
||||
$nmo = new NinjaMailerObject;
|
||||
$nmo->mailable = new DownloadReport($this->scheduler->company, $csv, $this->file_name);
|
||||
$nmo->company = $this->scheduler->company;
|
||||
$nmo->settings = $this->scheduler->company->settings;
|
||||
$nmo->to_user = $this->scheduler->user;
|
||||
|
||||
NinjaMailerJob::dispatch($nmo);
|
||||
|
||||
//calculate next run dates;
|
||||
$this->scheduler->calculateNextRun();
|
||||
|
||||
}
|
||||
|
||||
private function cancelSchedule()
|
||||
{
|
||||
$this->scheduler->forceDelete();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -15,10 +15,12 @@ use App\Models\Client;
|
||||
use App\Models\Scheduler;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use App\DataMapper\Schedule\EmailStatement;
|
||||
use App\Utils\Traits\MakesDates;
|
||||
|
||||
class EmailStatementService
|
||||
{
|
||||
use MakesHash;
|
||||
use MakesDates;
|
||||
|
||||
private Client $client;
|
||||
|
||||
|
@ -12,8 +12,9 @@
|
||||
namespace App\Services\Scheduler;
|
||||
|
||||
use App\Models\Scheduler;
|
||||
use App\Utils\Traits\MakesDates;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use App\Utils\Traits\MakesDates;
|
||||
use App\Services\Scheduler\EmailReport;
|
||||
|
||||
class SchedulerService
|
||||
{
|
||||
@ -43,12 +44,16 @@ class SchedulerService
|
||||
(new EmailRecord($this->scheduler))->run();
|
||||
}
|
||||
|
||||
|
||||
private function email_statement()
|
||||
{
|
||||
(new EmailStatementService($this->scheduler))->run();
|
||||
}
|
||||
|
||||
private function email_report()
|
||||
{
|
||||
(new EmailReport($this->scheduler))->run();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the next run date of the scheduled task
|
||||
|
@ -11,9 +11,10 @@
|
||||
|
||||
namespace App\Utils\Traits;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use DateTime;
|
||||
use DateTimeZone;
|
||||
use Carbon\Carbon;
|
||||
use App\DataMapper\Schedule\EmailStatement;
|
||||
|
||||
/**
|
||||
* Class MakesDates.
|
||||
@ -112,4 +113,27 @@ trait MakesDates
|
||||
return 'Invalid date!';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start and end date of the statement
|
||||
*
|
||||
* @return array [$start_date, $end_date];
|
||||
*/
|
||||
public function calculateStartAndEndDates(): array
|
||||
{
|
||||
return match ($this->scheduler->parameters['date_range']) {
|
||||
EmailStatement::LAST7 => [now()->startOfDay()->subDays(7)->format('Y-m-d'), now()->startOfDay()->format('Y-m-d')],
|
||||
EmailStatement::LAST30 => [now()->startOfDay()->subDays(30)->format('Y-m-d'), now()->startOfDay()->format('Y-m-d')],
|
||||
EmailStatement::LAST365 => [now()->startOfDay()->subDays(365)->format('Y-m-d'), now()->startOfDay()->format('Y-m-d')],
|
||||
EmailStatement::THIS_MONTH => [now()->startOfDay()->firstOfMonth()->format('Y-m-d'), now()->startOfDay()->lastOfMonth()->format('Y-m-d')],
|
||||
EmailStatement::LAST_MONTH => [now()->startOfDay()->subMonthNoOverflow()->firstOfMonth()->format('Y-m-d'), now()->startOfDay()->subMonthNoOverflow()->lastOfMonth()->format('Y-m-d')],
|
||||
EmailStatement::THIS_QUARTER => [now()->startOfDay()->firstOfQuarter()->format('Y-m-d'), now()->startOfDay()->lastOfQuarter()->format('Y-m-d')],
|
||||
EmailStatement::LAST_QUARTER => [now()->startOfDay()->subQuarterNoOverflow()->firstOfQuarter()->format('Y-m-d'), now()->startOfDay()->subQuarterNoOverflow()->lastOfQuarter()->format('Y-m-d')],
|
||||
EmailStatement::THIS_YEAR => [now()->startOfDay()->firstOfYear()->format('Y-m-d'), now()->startOfDay()->lastOfYear()->format('Y-m-d')],
|
||||
EmailStatement::LAST_YEAR => [now()->startOfDay()->subYearNoOverflow()->firstOfYear()->format('Y-m-d'), now()->startOfDay()->subYearNoOverflow()->lastOfYear()->format('Y-m-d')],
|
||||
EmailStatement::CUSTOM_RANGE => [$this->scheduler->parameters['start_date'], $this->scheduler->parameters['end_date']],
|
||||
default => [now()->startOfDay()->firstOfMonth()->format('Y-m-d'), now()->startOfDay()->lastOfMonth()->format('Y-m-d')],
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -14,8 +14,8 @@ return [
|
||||
'require_https' => env('REQUIRE_HTTPS', true),
|
||||
'app_url' => rtrim(env('APP_URL', ''), '/'),
|
||||
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
|
||||
'app_version' => '5.5.103',
|
||||
'app_tag' => '5.5.103',
|
||||
'app_version' => '5.5.104',
|
||||
'app_tag' => '5.5.104',
|
||||
'minimum_client_version' => '5.0.16',
|
||||
'terms_version' => '1.0.1',
|
||||
'api_secret' => env('API_SECRET', ''),
|
||||
|
@ -1,9 +1,12 @@
|
||||
<?php
|
||||
|
||||
use App\Models\BankTransaction;
|
||||
use App\Utils\Ninja;
|
||||
use App\Models\Client;
|
||||
use App\Models\Company;
|
||||
use App\Models\Product;
|
||||
use App\Models\GatewayType;
|
||||
use App\Models\PaymentType;
|
||||
use App\Models\BankTransaction;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
@ -67,6 +70,172 @@ return new class extends Migration
|
||||
$product->save();
|
||||
});
|
||||
|
||||
|
||||
//payment types from 34
|
||||
|
||||
if(Ninja::isSelfHost()) {
|
||||
|
||||
$pt = PaymentType::find(34);
|
||||
|
||||
if(!$pt) {
|
||||
$type = new PaymentType();
|
||||
$type->id = 34;
|
||||
$type->name = 'Mollie Bank Transfer';
|
||||
$type->gateway_type_id = GatewayType::BANK_TRANSFER;
|
||||
$type->save();
|
||||
|
||||
}
|
||||
|
||||
$pt = PaymentType::find(35);
|
||||
|
||||
if(!$pt) {
|
||||
|
||||
$type = new PaymentType();
|
||||
$type->id = 35;
|
||||
$type->name = 'KBC/CBC';
|
||||
$type->gateway_type_id = GatewayType::KBC;
|
||||
$type->save();
|
||||
|
||||
}
|
||||
|
||||
$pt = PaymentType::find(36);
|
||||
|
||||
if(!$pt) {
|
||||
$type = new PaymentType();
|
||||
$type->id = 36;
|
||||
$type->name = 'Bancontact';
|
||||
$type->gateway_type_id = GatewayType::BANCONTACT;
|
||||
$type->save();
|
||||
|
||||
}
|
||||
|
||||
$pt = PaymentType::find(37);
|
||||
|
||||
if(!$pt) {
|
||||
|
||||
$type = new PaymentType();
|
||||
$type->id = 37;
|
||||
$type->name = 'iDEAL';
|
||||
$type->gateway_type_id = GatewayType::IDEAL;
|
||||
$type->save();
|
||||
|
||||
}
|
||||
|
||||
$pt = PaymentType::find(38);
|
||||
|
||||
if(!$pt) {
|
||||
$type = new PaymentType();
|
||||
$type->id = 38;
|
||||
$type->name = 'Hosted Page';
|
||||
$type->gateway_type_id = GatewayType::HOSTED_PAGE;
|
||||
$type->save();
|
||||
}
|
||||
|
||||
$pt = PaymentType::find(39);
|
||||
|
||||
if(!$pt) {
|
||||
$type = new PaymentType();
|
||||
$type->id = 39;
|
||||
$type->name = 'GiroPay';
|
||||
$type->gateway_type_id = GatewayType::GIROPAY;
|
||||
$type->save();
|
||||
}
|
||||
|
||||
$pt = PaymentType::find(40);
|
||||
|
||||
if(!$pt) {
|
||||
$type = new PaymentType();
|
||||
$type->id = 40;
|
||||
$type->name = 'Przelewy24';
|
||||
$type->gateway_type_id = GatewayType::PRZELEWY24;
|
||||
$type->save();
|
||||
}
|
||||
|
||||
$pt = PaymentType::find(41);
|
||||
|
||||
if(!$pt) {
|
||||
$type = new PaymentType();
|
||||
$type->id = 41;
|
||||
$type->name = 'EPS';
|
||||
$type->gateway_type_id = GatewayType::EPS;
|
||||
$type->save();
|
||||
}
|
||||
|
||||
$pt = PaymentType::find(42);
|
||||
|
||||
if(!$pt) {
|
||||
$type = new PaymentType();
|
||||
$type->id = 42;
|
||||
$type->name = 'Direct Debit';
|
||||
$type->gateway_type_id = GatewayType::DIRECT_DEBIT;
|
||||
|
||||
$type->save();
|
||||
}
|
||||
|
||||
$pt = PaymentType::find(43);
|
||||
|
||||
if(!$pt) {
|
||||
$type = new PaymentType();
|
||||
$type->id = 43;
|
||||
$type->name = 'BECS';
|
||||
$type->gateway_type_id = GatewayType::BECS;
|
||||
$type->save();
|
||||
}
|
||||
|
||||
$pt = PaymentType::find(44);
|
||||
|
||||
if(!$pt) {
|
||||
$type = new PaymentType();
|
||||
$type->id = 44;
|
||||
$type->name = 'ACSS';
|
||||
$type->gateway_type_id = GatewayType::ACSS;
|
||||
|
||||
$type->save();
|
||||
}
|
||||
|
||||
$pt = PaymentType::find(45);
|
||||
|
||||
if(!$pt) {
|
||||
$type = new PaymentType();
|
||||
$type->id = PaymentType::INSTANT_BANK_PAY;
|
||||
$type->name = 'Instant Bank Pay';
|
||||
$type->gateway_type_id = GatewayType::INSTANT_BANK_PAY;
|
||||
|
||||
$type->save();
|
||||
}
|
||||
|
||||
$pt = PaymentType::find(47);
|
||||
|
||||
if (!$pt) {
|
||||
$type = new PaymentType();
|
||||
$type->id = 47;
|
||||
$type->name = 'Klarna';
|
||||
$type->gateway_type_id = GatewayType::KLARNA;
|
||||
$type->save();
|
||||
}
|
||||
|
||||
|
||||
$pt = PaymentType::find(48);
|
||||
|
||||
if (!$pt) {
|
||||
$type = new PaymentType();
|
||||
$type->id = 48;
|
||||
$type->name = 'Interac E-Transfer';
|
||||
$type->save();
|
||||
}
|
||||
|
||||
$gt = GatewayType::find(23);
|
||||
|
||||
if (!$gt) {
|
||||
$type = new GatewayType();
|
||||
$type->id = 23;
|
||||
$type->alias = 'klarna';
|
||||
$type->name = 'Klarna';
|
||||
$type->save();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -5032,6 +5032,14 @@ $LANG = array(
|
||||
'quote_product_columns' => 'Quote Product Columns',
|
||||
'vendors' => 'Vendors',
|
||||
'product_sales' => 'Product Sales',
|
||||
'user_sales_report_header' => 'User sales report for client/s :client from :start_date to :end_date',
|
||||
'client_balance_report' => 'Customer balance report',
|
||||
'client_sales_report' => 'Customer sales report',
|
||||
'user_sales_report' => 'User sales report',
|
||||
'aged_receivable_detailed_report' => 'Aged Receivable Detailed Report',
|
||||
'aged_receivable_summary_report' => 'Aged Receivable Summary Report',
|
||||
'taxable_amount' => 'Taxable Amount',
|
||||
'tax_summary' => 'Tax Summary',
|
||||
);
|
||||
|
||||
|
||||
|
@ -332,6 +332,7 @@ Route::group(['middleware' => ['throttle:api', 'api_db', 'token_auth', 'locale']
|
||||
Route::post('users/bulk', [UserController::class, 'bulk'])->name('users.bulk')->middleware('password_protected');
|
||||
Route::post('/users/{user}/invite', [UserController::class, 'invite'])->middleware('password_protected');
|
||||
Route::post('/users/{user}/disconnect_mailer', [UserController::class, 'disconnectOauthMailer']);
|
||||
Route::post('/users/{user}/disconnect_oauth', [UserController::class, 'disconnectOauth']);
|
||||
Route::post('/user/{user}/reconfirm', [UserController::class, 'reconfirm']);
|
||||
|
||||
Route::resource('webhooks', WebhookController::class);
|
||||
|
@ -77,6 +77,7 @@ class BankTransactionTest extends TestCase
|
||||
|
||||
$this->assertEquals($this->expense->refresh()->transaction_id, $bt->id);
|
||||
$this->assertEquals($this->expense->hashed_id, $bt->refresh()->expense_id);
|
||||
$this->assertEquals($bt->id, $this->expense->transaction_id);
|
||||
$this->assertEquals($this->vendor->id, $bt->vendor_id);
|
||||
$this->assertEquals(BankTransaction::STATUS_CONVERTED, $bt->status_id);
|
||||
|
||||
|
203
tests/Feature/Export/ArDetailReportTest.php
Normal file
203
tests/Feature/Export/ArDetailReportTest.php
Normal file
@ -0,0 +1,203 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace Tests\Feature\Export;
|
||||
|
||||
use App\DataMapper\CompanySettings;
|
||||
use App\Factory\InvoiceItemFactory;
|
||||
use App\Models\Account;
|
||||
use App\Models\Client;
|
||||
use App\Models\Company;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\User;
|
||||
use App\Services\Report\ARDetailReport;
|
||||
use App\Services\Report\UserSalesReport;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
class ARDetailReportTest extends TestCase
|
||||
{
|
||||
use MakesHash;
|
||||
|
||||
public $faker;
|
||||
|
||||
protected function setUp() :void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->faker = \Faker\Factory::create();
|
||||
|
||||
$this->withoutMiddleware(
|
||||
ThrottleRequests::class
|
||||
);
|
||||
|
||||
$this->withoutExceptionHandling();
|
||||
}
|
||||
|
||||
public $company;
|
||||
|
||||
public $user;
|
||||
|
||||
public $payload;
|
||||
|
||||
public $account;
|
||||
|
||||
public $client;
|
||||
|
||||
/**
|
||||
* start_date - Y-m-d
|
||||
end_date - Y-m-d
|
||||
date_range -
|
||||
all
|
||||
last7
|
||||
last30
|
||||
this_month
|
||||
last_month
|
||||
this_quarter
|
||||
last_quarter
|
||||
this_year
|
||||
custom
|
||||
is_income_billed - true = Invoiced || false = Payments
|
||||
expense_billed - true = Expensed || false = Expenses marked as paid
|
||||
include_tax - true tax_included || false - tax_excluded
|
||||
*/
|
||||
private function buildData()
|
||||
{
|
||||
$this->account = Account::factory()->create([
|
||||
'hosted_client_count' => 1000,
|
||||
'hosted_company_count' => 1000,
|
||||
]);
|
||||
|
||||
$this->account->num_users = 3;
|
||||
$this->account->save();
|
||||
|
||||
$this->user = User::factory()->create([
|
||||
'account_id' => $this->account->id,
|
||||
'confirmation_code' => 'xyz123',
|
||||
'email' => $this->faker->unique()->safeEmail(),
|
||||
]);
|
||||
|
||||
$settings = CompanySettings::defaults();
|
||||
$settings->client_online_payment_notification = false;
|
||||
$settings->client_manual_payment_notification = false;
|
||||
|
||||
$this->company = Company::factory()->create([
|
||||
'account_id' => $this->account->id,
|
||||
'settings' => $settings,
|
||||
]);
|
||||
|
||||
$this->company->settings = $settings;
|
||||
$this->company->save();
|
||||
|
||||
$this->payload = [
|
||||
'start_date' => '2000-01-01',
|
||||
'end_date' => '2030-01-11',
|
||||
'date_range' => 'custom',
|
||||
'is_income_billed' => true,
|
||||
'include_tax' => false,
|
||||
];
|
||||
|
||||
$this->client = Client::factory()->create([
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $this->company->id,
|
||||
'is_deleted' => 0,
|
||||
]);
|
||||
}
|
||||
|
||||
public function testUserSalesInstance()
|
||||
{
|
||||
$this->buildData();
|
||||
|
||||
$pl = new ARDetailReport($this->company, $this->payload);
|
||||
|
||||
$this->assertInstanceOf(ARDetailReport::class, $pl);
|
||||
|
||||
$this->account->delete();
|
||||
}
|
||||
|
||||
public function testSimpleReport()
|
||||
{
|
||||
$this->buildData();
|
||||
|
||||
|
||||
$this->payload = [
|
||||
'start_date' => '2000-01-01',
|
||||
'end_date' => '2030-01-11',
|
||||
'date_range' => 'custom',
|
||||
'client_id' => $this->client->id,
|
||||
'report_keys' => []
|
||||
];
|
||||
|
||||
$i = Invoice::factory()->create([
|
||||
'client_id' => $this->client->id,
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $this->company->id,
|
||||
'amount' => 0,
|
||||
'balance' => 0,
|
||||
'status_id' => 2,
|
||||
'total_taxes' => 1,
|
||||
'date' => now()->format('Y-m-d'),
|
||||
'terms' => 'nada',
|
||||
'discount' => 0,
|
||||
'tax_rate1' => 0,
|
||||
'tax_rate2' => 0,
|
||||
'tax_rate3' => 0,
|
||||
'tax_name1' => '',
|
||||
'tax_name2' => '',
|
||||
'tax_name3' => '',
|
||||
'uses_inclusive_taxes' => false,
|
||||
'line_items' => $this->buildLineItems(),
|
||||
]);
|
||||
|
||||
$i = $i->calc()->getInvoice();
|
||||
|
||||
$pl = new ARDetailReport($this->company, $this->payload);
|
||||
$response = $pl->run();
|
||||
|
||||
$this->assertIsString($response);
|
||||
|
||||
$this->account->delete();
|
||||
}
|
||||
|
||||
|
||||
private function buildLineItems()
|
||||
{
|
||||
$line_items = [];
|
||||
|
||||
$item = InvoiceItemFactory::create();
|
||||
$item->quantity = 1;
|
||||
$item->cost = 10;
|
||||
$item->product_key = 'test';
|
||||
$item->notes = 'test_product';
|
||||
// $item->task_id = $this->encodePrimaryKey($this->task->id);
|
||||
// $item->expense_id = $this->encodePrimaryKey($this->expense->id);
|
||||
|
||||
$line_items[] = $item;
|
||||
|
||||
|
||||
$item = InvoiceItemFactory::create();
|
||||
$item->quantity = 1;
|
||||
$item->cost = 10;
|
||||
$item->product_key = 'pumpkin';
|
||||
$item->notes = 'test_pumpkin';
|
||||
// $item->task_id = $this->encodePrimaryKey($this->task->id);
|
||||
// $item->expense_id = $this->encodePrimaryKey($this->expense->id);
|
||||
|
||||
$line_items[] = $item;
|
||||
|
||||
|
||||
return $line_items;
|
||||
}
|
||||
}
|
203
tests/Feature/Export/ArSummaryReportTest.php
Normal file
203
tests/Feature/Export/ArSummaryReportTest.php
Normal file
@ -0,0 +1,203 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace Tests\Feature\Export;
|
||||
|
||||
use App\DataMapper\CompanySettings;
|
||||
use App\Factory\InvoiceItemFactory;
|
||||
use App\Models\Account;
|
||||
use App\Models\Client;
|
||||
use App\Models\Company;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\User;
|
||||
use App\Services\Report\ARDetailReport;
|
||||
use App\Services\Report\ARSummaryReport;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
class ARSummaryReportTest extends TestCase
|
||||
{
|
||||
use MakesHash;
|
||||
|
||||
public $faker;
|
||||
|
||||
protected function setUp() :void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->faker = \Faker\Factory::create();
|
||||
|
||||
$this->withoutMiddleware(
|
||||
ThrottleRequests::class
|
||||
);
|
||||
|
||||
$this->withoutExceptionHandling();
|
||||
}
|
||||
|
||||
public $company;
|
||||
|
||||
public $user;
|
||||
|
||||
public $payload;
|
||||
|
||||
public $account;
|
||||
|
||||
public $client;
|
||||
|
||||
/**
|
||||
* start_date - Y-m-d
|
||||
end_date - Y-m-d
|
||||
date_range -
|
||||
all
|
||||
last7
|
||||
last30
|
||||
this_month
|
||||
last_month
|
||||
this_quarter
|
||||
last_quarter
|
||||
this_year
|
||||
custom
|
||||
is_income_billed - true = Invoiced || false = Payments
|
||||
expense_billed - true = Expensed || false = Expenses marked as paid
|
||||
include_tax - true tax_included || false - tax_excluded
|
||||
*/
|
||||
private function buildData()
|
||||
{
|
||||
$this->account = Account::factory()->create([
|
||||
'hosted_client_count' => 1000,
|
||||
'hosted_company_count' => 1000,
|
||||
]);
|
||||
|
||||
$this->account->num_users = 3;
|
||||
$this->account->save();
|
||||
|
||||
$this->user = User::factory()->create([
|
||||
'account_id' => $this->account->id,
|
||||
'confirmation_code' => 'xyz123',
|
||||
'email' => $this->faker->unique()->safeEmail(),
|
||||
]);
|
||||
|
||||
$settings = CompanySettings::defaults();
|
||||
$settings->client_online_payment_notification = false;
|
||||
$settings->client_manual_payment_notification = false;
|
||||
|
||||
$this->company = Company::factory()->create([
|
||||
'account_id' => $this->account->id,
|
||||
'settings' => $settings,
|
||||
]);
|
||||
|
||||
$this->company->settings = $settings;
|
||||
$this->company->save();
|
||||
|
||||
$this->payload = [
|
||||
'start_date' => '2000-01-01',
|
||||
'end_date' => '2030-01-11',
|
||||
'date_range' => 'custom',
|
||||
'is_income_billed' => true,
|
||||
'include_tax' => false,
|
||||
];
|
||||
|
||||
$this->client = Client::factory()->create([
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $this->company->id,
|
||||
'is_deleted' => 0,
|
||||
]);
|
||||
}
|
||||
|
||||
public function testUserSalesInstance()
|
||||
{
|
||||
$this->buildData();
|
||||
|
||||
$pl = new ARSummaryReport($this->company, $this->payload);
|
||||
|
||||
$this->assertInstanceOf(ARSummaryReport::class, $pl);
|
||||
|
||||
$this->account->delete();
|
||||
}
|
||||
|
||||
public function testSimpleReport()
|
||||
{
|
||||
$this->buildData();
|
||||
|
||||
|
||||
$this->payload = [
|
||||
'start_date' => '2000-01-01',
|
||||
'end_date' => '2030-01-11',
|
||||
'date_range' => 'custom',
|
||||
'client_id' => $this->client->id,
|
||||
'report_keys' => []
|
||||
];
|
||||
|
||||
$i = Invoice::factory()->create([
|
||||
'client_id' => $this->client->id,
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $this->company->id,
|
||||
'amount' => 0,
|
||||
'balance' => 0,
|
||||
'status_id' => 2,
|
||||
'total_taxes' => 1,
|
||||
'date' => now()->format('Y-m-d'),
|
||||
'terms' => 'nada',
|
||||
'discount' => 0,
|
||||
'tax_rate1' => 0,
|
||||
'tax_rate2' => 0,
|
||||
'tax_rate3' => 0,
|
||||
'tax_name1' => '',
|
||||
'tax_name2' => '',
|
||||
'tax_name3' => '',
|
||||
'uses_inclusive_taxes' => false,
|
||||
'line_items' => $this->buildLineItems(),
|
||||
]);
|
||||
|
||||
$i = $i->calc()->getInvoice();
|
||||
|
||||
$pl = new ARSummaryReport($this->company, $this->payload);
|
||||
$response = $pl->run();
|
||||
|
||||
$this->assertIsString($response);
|
||||
|
||||
$this->account->delete();
|
||||
}
|
||||
|
||||
|
||||
private function buildLineItems()
|
||||
{
|
||||
$line_items = [];
|
||||
|
||||
$item = InvoiceItemFactory::create();
|
||||
$item->quantity = 1;
|
||||
$item->cost = 10;
|
||||
$item->product_key = 'test';
|
||||
$item->notes = 'test_product';
|
||||
// $item->task_id = $this->encodePrimaryKey($this->task->id);
|
||||
// $item->expense_id = $this->encodePrimaryKey($this->expense->id);
|
||||
|
||||
$line_items[] = $item;
|
||||
|
||||
|
||||
$item = InvoiceItemFactory::create();
|
||||
$item->quantity = 1;
|
||||
$item->cost = 10;
|
||||
$item->product_key = 'pumpkin';
|
||||
$item->notes = 'test_pumpkin';
|
||||
// $item->task_id = $this->encodePrimaryKey($this->task->id);
|
||||
// $item->expense_id = $this->encodePrimaryKey($this->expense->id);
|
||||
|
||||
$line_items[] = $item;
|
||||
|
||||
|
||||
return $line_items;
|
||||
}
|
||||
}
|
203
tests/Feature/Export/ClientBalanceReportTest.php
Normal file
203
tests/Feature/Export/ClientBalanceReportTest.php
Normal file
@ -0,0 +1,203 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace Tests\Feature\Export;
|
||||
|
||||
use App\DataMapper\CompanySettings;
|
||||
use App\Factory\InvoiceItemFactory;
|
||||
use App\Models\Account;
|
||||
use App\Models\Client;
|
||||
use App\Models\Company;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\User;
|
||||
use App\Services\Report\ARSummaryReport;
|
||||
use App\Services\Report\ClientBalanceReport;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
class ClientBalanceReportTest extends TestCase
|
||||
{
|
||||
use MakesHash;
|
||||
|
||||
public $faker;
|
||||
|
||||
protected function setUp() :void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->faker = \Faker\Factory::create();
|
||||
|
||||
$this->withoutMiddleware(
|
||||
ThrottleRequests::class
|
||||
);
|
||||
|
||||
$this->withoutExceptionHandling();
|
||||
}
|
||||
|
||||
public $company;
|
||||
|
||||
public $user;
|
||||
|
||||
public $payload;
|
||||
|
||||
public $account;
|
||||
|
||||
public $client;
|
||||
|
||||
/**
|
||||
* start_date - Y-m-d
|
||||
end_date - Y-m-d
|
||||
date_range -
|
||||
all
|
||||
last7
|
||||
last30
|
||||
this_month
|
||||
last_month
|
||||
this_quarter
|
||||
last_quarter
|
||||
this_year
|
||||
custom
|
||||
is_income_billed - true = Invoiced || false = Payments
|
||||
expense_billed - true = Expensed || false = Expenses marked as paid
|
||||
include_tax - true tax_included || false - tax_excluded
|
||||
*/
|
||||
private function buildData()
|
||||
{
|
||||
$this->account = Account::factory()->create([
|
||||
'hosted_client_count' => 1000,
|
||||
'hosted_company_count' => 1000,
|
||||
]);
|
||||
|
||||
$this->account->num_users = 3;
|
||||
$this->account->save();
|
||||
|
||||
$this->user = User::factory()->create([
|
||||
'account_id' => $this->account->id,
|
||||
'confirmation_code' => 'xyz123',
|
||||
'email' => $this->faker->unique()->safeEmail(),
|
||||
]);
|
||||
|
||||
$settings = CompanySettings::defaults();
|
||||
$settings->client_online_payment_notification = false;
|
||||
$settings->client_manual_payment_notification = false;
|
||||
|
||||
$this->company = Company::factory()->create([
|
||||
'account_id' => $this->account->id,
|
||||
'settings' => $settings,
|
||||
]);
|
||||
|
||||
$this->company->settings = $settings;
|
||||
$this->company->save();
|
||||
|
||||
$this->payload = [
|
||||
'start_date' => '2000-01-01',
|
||||
'end_date' => '2030-01-11',
|
||||
'date_range' => 'custom',
|
||||
'is_income_billed' => true,
|
||||
'include_tax' => false,
|
||||
];
|
||||
|
||||
$this->client = Client::factory()->create([
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $this->company->id,
|
||||
'is_deleted' => 0,
|
||||
]);
|
||||
}
|
||||
|
||||
public function testUserSalesInstance()
|
||||
{
|
||||
$this->buildData();
|
||||
|
||||
$pl = new ClientBalanceReport($this->company, $this->payload);
|
||||
|
||||
$this->assertInstanceOf(ClientBalanceReport::class, $pl);
|
||||
|
||||
$this->account->delete();
|
||||
}
|
||||
|
||||
public function testSimpleReport()
|
||||
{
|
||||
$this->buildData();
|
||||
|
||||
|
||||
$this->payload = [
|
||||
'start_date' => '2000-01-01',
|
||||
'end_date' => '2030-01-11',
|
||||
'date_range' => 'custom',
|
||||
'client_id' => $this->client->id,
|
||||
'report_keys' => []
|
||||
];
|
||||
|
||||
$i = Invoice::factory()->create([
|
||||
'client_id' => $this->client->id,
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $this->company->id,
|
||||
'amount' => 0,
|
||||
'balance' => 0,
|
||||
'status_id' => 2,
|
||||
'total_taxes' => 1,
|
||||
'date' => now()->format('Y-m-d'),
|
||||
'terms' => 'nada',
|
||||
'discount' => 0,
|
||||
'tax_rate1' => 0,
|
||||
'tax_rate2' => 0,
|
||||
'tax_rate3' => 0,
|
||||
'tax_name1' => '',
|
||||
'tax_name2' => '',
|
||||
'tax_name3' => '',
|
||||
'uses_inclusive_taxes' => false,
|
||||
'line_items' => $this->buildLineItems(),
|
||||
]);
|
||||
|
||||
$i = $i->calc()->getInvoice();
|
||||
|
||||
$pl = new ClientBalanceReport($this->company, $this->payload);
|
||||
$response = $pl->run();
|
||||
|
||||
$this->assertIsString($response);
|
||||
|
||||
$this->account->delete();
|
||||
}
|
||||
|
||||
|
||||
private function buildLineItems()
|
||||
{
|
||||
$line_items = [];
|
||||
|
||||
$item = InvoiceItemFactory::create();
|
||||
$item->quantity = 1;
|
||||
$item->cost = 10;
|
||||
$item->product_key = 'test';
|
||||
$item->notes = 'test_product';
|
||||
// $item->task_id = $this->encodePrimaryKey($this->task->id);
|
||||
// $item->expense_id = $this->encodePrimaryKey($this->expense->id);
|
||||
|
||||
$line_items[] = $item;
|
||||
|
||||
|
||||
$item = InvoiceItemFactory::create();
|
||||
$item->quantity = 1;
|
||||
$item->cost = 10;
|
||||
$item->product_key = 'pumpkin';
|
||||
$item->notes = 'test_pumpkin';
|
||||
// $item->task_id = $this->encodePrimaryKey($this->task->id);
|
||||
// $item->expense_id = $this->encodePrimaryKey($this->expense->id);
|
||||
|
||||
$line_items[] = $item;
|
||||
|
||||
|
||||
return $line_items;
|
||||
}
|
||||
}
|
203
tests/Feature/Export/ClientSalesReportTest.php
Normal file
203
tests/Feature/Export/ClientSalesReportTest.php
Normal file
@ -0,0 +1,203 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace Tests\Feature\Export;
|
||||
|
||||
use Tests\TestCase;
|
||||
use App\Models\User;
|
||||
use App\Models\Client;
|
||||
use App\Models\Account;
|
||||
use App\Models\Company;
|
||||
use App\Models\Invoice;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use App\DataMapper\CompanySettings;
|
||||
use App\Factory\InvoiceItemFactory;
|
||||
use App\Services\Report\ClientSalesReport;
|
||||
use App\Services\Report\ClientBalanceReport;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
class ClientSalesReportTest extends TestCase
|
||||
{
|
||||
use MakesHash;
|
||||
|
||||
public $faker;
|
||||
|
||||
protected function setUp() :void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->faker = \Faker\Factory::create();
|
||||
|
||||
$this->withoutMiddleware(
|
||||
ThrottleRequests::class
|
||||
);
|
||||
|
||||
$this->withoutExceptionHandling();
|
||||
}
|
||||
|
||||
public $company;
|
||||
|
||||
public $user;
|
||||
|
||||
public $payload;
|
||||
|
||||
public $account;
|
||||
|
||||
public $client;
|
||||
|
||||
/**
|
||||
* start_date - Y-m-d
|
||||
end_date - Y-m-d
|
||||
date_range -
|
||||
all
|
||||
last7
|
||||
last30
|
||||
this_month
|
||||
last_month
|
||||
this_quarter
|
||||
last_quarter
|
||||
this_year
|
||||
custom
|
||||
is_income_billed - true = Invoiced || false = Payments
|
||||
expense_billed - true = Expensed || false = Expenses marked as paid
|
||||
include_tax - true tax_included || false - tax_excluded
|
||||
*/
|
||||
private function buildData()
|
||||
{
|
||||
$this->account = Account::factory()->create([
|
||||
'hosted_client_count' => 1000,
|
||||
'hosted_company_count' => 1000,
|
||||
]);
|
||||
|
||||
$this->account->num_users = 3;
|
||||
$this->account->save();
|
||||
|
||||
$this->user = User::factory()->create([
|
||||
'account_id' => $this->account->id,
|
||||
'confirmation_code' => 'xyz123',
|
||||
'email' => $this->faker->unique()->safeEmail(),
|
||||
]);
|
||||
|
||||
$settings = CompanySettings::defaults();
|
||||
$settings->client_online_payment_notification = false;
|
||||
$settings->client_manual_payment_notification = false;
|
||||
|
||||
$this->company = Company::factory()->create([
|
||||
'account_id' => $this->account->id,
|
||||
'settings' => $settings,
|
||||
]);
|
||||
|
||||
$this->company->settings = $settings;
|
||||
$this->company->save();
|
||||
|
||||
$this->payload = [
|
||||
'start_date' => '2000-01-01',
|
||||
'end_date' => '2030-01-11',
|
||||
'date_range' => 'custom',
|
||||
'is_income_billed' => true,
|
||||
'include_tax' => false,
|
||||
];
|
||||
|
||||
$this->client = Client::factory()->create([
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $this->company->id,
|
||||
'is_deleted' => 0,
|
||||
]);
|
||||
}
|
||||
|
||||
public function testUserSalesInstance()
|
||||
{
|
||||
$this->buildData();
|
||||
|
||||
$pl = new ClientSalesReport($this->company, $this->payload);
|
||||
|
||||
$this->assertInstanceOf(ClientSalesReport::class, $pl);
|
||||
|
||||
$this->account->delete();
|
||||
}
|
||||
|
||||
public function testSimpleReport()
|
||||
{
|
||||
$this->buildData();
|
||||
|
||||
|
||||
$this->payload = [
|
||||
'start_date' => '2000-01-01',
|
||||
'end_date' => '2030-01-11',
|
||||
'date_range' => 'custom',
|
||||
'client_id' => $this->client->id,
|
||||
'report_keys' => []
|
||||
];
|
||||
|
||||
$i = Invoice::factory()->create([
|
||||
'client_id' => $this->client->id,
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $this->company->id,
|
||||
'amount' => 0,
|
||||
'balance' => 0,
|
||||
'status_id' => 2,
|
||||
'total_taxes' => 1,
|
||||
'date' => now()->format('Y-m-d'),
|
||||
'terms' => 'nada',
|
||||
'discount' => 0,
|
||||
'tax_rate1' => 0,
|
||||
'tax_rate2' => 0,
|
||||
'tax_rate3' => 0,
|
||||
'tax_name1' => '',
|
||||
'tax_name2' => '',
|
||||
'tax_name3' => '',
|
||||
'uses_inclusive_taxes' => false,
|
||||
'line_items' => $this->buildLineItems(),
|
||||
]);
|
||||
|
||||
$i = $i->calc()->getInvoice();
|
||||
|
||||
$pl = new ClientSalesReport($this->company, $this->payload);
|
||||
$response = $pl->run();
|
||||
|
||||
$this->assertIsString($response);
|
||||
|
||||
$this->account->delete();
|
||||
}
|
||||
|
||||
|
||||
private function buildLineItems()
|
||||
{
|
||||
$line_items = [];
|
||||
|
||||
$item = InvoiceItemFactory::create();
|
||||
$item->quantity = 1;
|
||||
$item->cost = 10;
|
||||
$item->product_key = 'test';
|
||||
$item->notes = 'test_product';
|
||||
// $item->task_id = $this->encodePrimaryKey($this->task->id);
|
||||
// $item->expense_id = $this->encodePrimaryKey($this->expense->id);
|
||||
|
||||
$line_items[] = $item;
|
||||
|
||||
|
||||
$item = InvoiceItemFactory::create();
|
||||
$item->quantity = 1;
|
||||
$item->cost = 10;
|
||||
$item->product_key = 'pumpkin';
|
||||
$item->notes = 'test_pumpkin';
|
||||
// $item->task_id = $this->encodePrimaryKey($this->task->id);
|
||||
// $item->expense_id = $this->encodePrimaryKey($this->expense->id);
|
||||
|
||||
$line_items[] = $item;
|
||||
|
||||
|
||||
return $line_items;
|
||||
}
|
||||
}
|
203
tests/Feature/Export/TaxSummaryReportTest.php
Normal file
203
tests/Feature/Export/TaxSummaryReportTest.php
Normal file
@ -0,0 +1,203 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace Tests\Feature\Export;
|
||||
|
||||
use App\DataMapper\CompanySettings;
|
||||
use App\Factory\InvoiceItemFactory;
|
||||
use App\Models\Account;
|
||||
use App\Models\Client;
|
||||
use App\Models\Company;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\User;
|
||||
use App\Services\Report\ARDetailReport;
|
||||
use App\Services\Report\TaxSummaryReport;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
class TaxSummaryReportTest extends TestCase
|
||||
{
|
||||
use MakesHash;
|
||||
|
||||
public $faker;
|
||||
|
||||
protected function setUp() :void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->faker = \Faker\Factory::create();
|
||||
|
||||
$this->withoutMiddleware(
|
||||
ThrottleRequests::class
|
||||
);
|
||||
|
||||
$this->withoutExceptionHandling();
|
||||
}
|
||||
|
||||
public $company;
|
||||
|
||||
public $user;
|
||||
|
||||
public $payload;
|
||||
|
||||
public $account;
|
||||
|
||||
public $client;
|
||||
|
||||
/**
|
||||
* start_date - Y-m-d
|
||||
end_date - Y-m-d
|
||||
date_range -
|
||||
all
|
||||
last7
|
||||
last30
|
||||
this_month
|
||||
last_month
|
||||
this_quarter
|
||||
last_quarter
|
||||
this_year
|
||||
custom
|
||||
is_income_billed - true = Invoiced || false = Payments
|
||||
expense_billed - true = Expensed || false = Expenses marked as paid
|
||||
include_tax - true tax_included || false - tax_excluded
|
||||
*/
|
||||
private function buildData()
|
||||
{
|
||||
$this->account = Account::factory()->create([
|
||||
'hosted_client_count' => 1000,
|
||||
'hosted_company_count' => 1000,
|
||||
]);
|
||||
|
||||
$this->account->num_users = 3;
|
||||
$this->account->save();
|
||||
|
||||
$this->user = User::factory()->create([
|
||||
'account_id' => $this->account->id,
|
||||
'confirmation_code' => 'xyz123',
|
||||
'email' => $this->faker->unique()->safeEmail(),
|
||||
]);
|
||||
|
||||
$settings = CompanySettings::defaults();
|
||||
$settings->client_online_payment_notification = false;
|
||||
$settings->client_manual_payment_notification = false;
|
||||
|
||||
$this->company = Company::factory()->create([
|
||||
'account_id' => $this->account->id,
|
||||
'settings' => $settings,
|
||||
]);
|
||||
|
||||
$this->company->settings = $settings;
|
||||
$this->company->save();
|
||||
|
||||
$this->payload = [
|
||||
'start_date' => '2000-01-01',
|
||||
'end_date' => '2030-01-11',
|
||||
'date_range' => 'custom',
|
||||
'is_income_billed' => true,
|
||||
'include_tax' => false,
|
||||
];
|
||||
|
||||
$this->client = Client::factory()->create([
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $this->company->id,
|
||||
'is_deleted' => 0,
|
||||
]);
|
||||
}
|
||||
|
||||
public function testUserSalesInstance()
|
||||
{
|
||||
$this->buildData();
|
||||
|
||||
$pl = new TaxSummaryReport($this->company, $this->payload);
|
||||
|
||||
$this->assertInstanceOf(TaxSummaryReport::class, $pl);
|
||||
|
||||
$this->account->delete();
|
||||
}
|
||||
|
||||
public function testSimpleReport()
|
||||
{
|
||||
$this->buildData();
|
||||
|
||||
|
||||
$this->payload = [
|
||||
'start_date' => '2000-01-01',
|
||||
'end_date' => '2030-01-11',
|
||||
'date_range' => 'custom',
|
||||
'client_id' => $this->client->id,
|
||||
'report_keys' => []
|
||||
];
|
||||
|
||||
$i = Invoice::factory()->create([
|
||||
'client_id' => $this->client->id,
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $this->company->id,
|
||||
'amount' => 0,
|
||||
'balance' => 0,
|
||||
'status_id' => 2,
|
||||
'total_taxes' => 1,
|
||||
'date' => now()->format('Y-m-d'),
|
||||
'terms' => 'nada',
|
||||
'discount' => 0,
|
||||
'tax_rate1' => 10,
|
||||
'tax_rate2' => 17.5,
|
||||
'tax_rate3' => 5,
|
||||
'tax_name1' => 'GST',
|
||||
'tax_name2' => 'VAT',
|
||||
'tax_name3' => 'CA Sales Tax',
|
||||
'uses_inclusive_taxes' => false,
|
||||
'line_items' => $this->buildLineItems(),
|
||||
]);
|
||||
|
||||
$i = $i->calc()->getInvoice();
|
||||
|
||||
$pl = new TaxSummaryReport($this->company, $this->payload);
|
||||
$response = $pl->run();
|
||||
|
||||
$this->assertIsString($response);
|
||||
|
||||
$this->account->delete();
|
||||
}
|
||||
|
||||
|
||||
private function buildLineItems()
|
||||
{
|
||||
$line_items = [];
|
||||
|
||||
$item = InvoiceItemFactory::create();
|
||||
$item->quantity = 1;
|
||||
$item->cost = 10;
|
||||
$item->product_key = 'test';
|
||||
$item->notes = 'test_product';
|
||||
// $item->task_id = $this->encodePrimaryKey($this->task->id);
|
||||
// $item->expense_id = $this->encodePrimaryKey($this->expense->id);
|
||||
|
||||
$line_items[] = $item;
|
||||
|
||||
|
||||
$item = InvoiceItemFactory::create();
|
||||
$item->quantity = 1;
|
||||
$item->cost = 10;
|
||||
$item->product_key = 'pumpkin';
|
||||
$item->notes = 'test_pumpkin';
|
||||
// $item->task_id = $this->encodePrimaryKey($this->task->id);
|
||||
// $item->expense_id = $this->encodePrimaryKey($this->expense->id);
|
||||
|
||||
$line_items[] = $item;
|
||||
|
||||
|
||||
return $line_items;
|
||||
}
|
||||
}
|
203
tests/Feature/Export/UserSalesReportTest.php
Normal file
203
tests/Feature/Export/UserSalesReportTest.php
Normal file
@ -0,0 +1,203 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace Tests\Feature\Export;
|
||||
|
||||
use App\DataMapper\CompanySettings;
|
||||
use App\Export\CSV\ProductSalesExport;
|
||||
use App\Factory\InvoiceItemFactory;
|
||||
use App\Models\Account;
|
||||
use App\Models\Client;
|
||||
use App\Models\Company;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\User;
|
||||
use App\Services\Report\UserSalesReport;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
class UserSalesReportTest extends TestCase
|
||||
{
|
||||
use MakesHash;
|
||||
|
||||
public $faker;
|
||||
|
||||
protected function setUp() :void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->faker = \Faker\Factory::create();
|
||||
|
||||
$this->withoutMiddleware(
|
||||
ThrottleRequests::class
|
||||
);
|
||||
|
||||
$this->withoutExceptionHandling();
|
||||
}
|
||||
|
||||
public $company;
|
||||
|
||||
public $user;
|
||||
|
||||
public $payload;
|
||||
|
||||
public $account;
|
||||
|
||||
public $client;
|
||||
|
||||
/**
|
||||
* start_date - Y-m-d
|
||||
end_date - Y-m-d
|
||||
date_range -
|
||||
all
|
||||
last7
|
||||
last30
|
||||
this_month
|
||||
last_month
|
||||
this_quarter
|
||||
last_quarter
|
||||
this_year
|
||||
custom
|
||||
is_income_billed - true = Invoiced || false = Payments
|
||||
expense_billed - true = Expensed || false = Expenses marked as paid
|
||||
include_tax - true tax_included || false - tax_excluded
|
||||
*/
|
||||
private function buildData()
|
||||
{
|
||||
$this->account = Account::factory()->create([
|
||||
'hosted_client_count' => 1000,
|
||||
'hosted_company_count' => 1000,
|
||||
]);
|
||||
|
||||
$this->account->num_users = 3;
|
||||
$this->account->save();
|
||||
|
||||
$this->user = User::factory()->create([
|
||||
'account_id' => $this->account->id,
|
||||
'confirmation_code' => 'xyz123',
|
||||
'email' => $this->faker->unique()->safeEmail(),
|
||||
]);
|
||||
|
||||
$settings = CompanySettings::defaults();
|
||||
$settings->client_online_payment_notification = false;
|
||||
$settings->client_manual_payment_notification = false;
|
||||
|
||||
$this->company = Company::factory()->create([
|
||||
'account_id' => $this->account->id,
|
||||
'settings' => $settings,
|
||||
]);
|
||||
|
||||
$this->company->settings = $settings;
|
||||
$this->company->save();
|
||||
|
||||
$this->payload = [
|
||||
'start_date' => '2000-01-01',
|
||||
'end_date' => '2030-01-11',
|
||||
'date_range' => 'custom',
|
||||
'is_income_billed' => true,
|
||||
'include_tax' => false,
|
||||
];
|
||||
|
||||
$this->client = Client::factory()->create([
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $this->company->id,
|
||||
'is_deleted' => 0,
|
||||
]);
|
||||
}
|
||||
|
||||
public function testUserSalesInstance()
|
||||
{
|
||||
$this->buildData();
|
||||
|
||||
$pl = new UserSalesReport($this->company, $this->payload);
|
||||
|
||||
$this->assertInstanceOf(UserSalesReport::class, $pl);
|
||||
|
||||
$this->account->delete();
|
||||
}
|
||||
|
||||
public function testSimpleReport()
|
||||
{
|
||||
$this->buildData();
|
||||
|
||||
|
||||
$this->payload = [
|
||||
'start_date' => '2000-01-01',
|
||||
'end_date' => '2030-01-11',
|
||||
'date_range' => 'custom',
|
||||
'client_id' => $this->client->id,
|
||||
'report_keys' => []
|
||||
];
|
||||
|
||||
$i = Invoice::factory()->create([
|
||||
'client_id' => $this->client->id,
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $this->company->id,
|
||||
'amount' => 0,
|
||||
'balance' => 0,
|
||||
'status_id' => 2,
|
||||
'total_taxes' => 1,
|
||||
'date' => now()->format('Y-m-d'),
|
||||
'terms' => 'nada',
|
||||
'discount' => 0,
|
||||
'tax_rate1' => 0,
|
||||
'tax_rate2' => 0,
|
||||
'tax_rate3' => 0,
|
||||
'tax_name1' => '',
|
||||
'tax_name2' => '',
|
||||
'tax_name3' => '',
|
||||
'uses_inclusive_taxes' => false,
|
||||
'line_items' => $this->buildLineItems(),
|
||||
]);
|
||||
|
||||
$i = $i->calc()->getInvoice();
|
||||
|
||||
$pl = new UserSalesReport($this->company, $this->payload);
|
||||
$response = $pl->run();
|
||||
|
||||
$this->assertIsString($response);
|
||||
|
||||
$this->account->delete();
|
||||
}
|
||||
|
||||
|
||||
private function buildLineItems()
|
||||
{
|
||||
$line_items = [];
|
||||
|
||||
$item = InvoiceItemFactory::create();
|
||||
$item->quantity = 1;
|
||||
$item->cost = 10;
|
||||
$item->product_key = 'test';
|
||||
$item->notes = 'test_product';
|
||||
// $item->task_id = $this->encodePrimaryKey($this->task->id);
|
||||
// $item->expense_id = $this->encodePrimaryKey($this->expense->id);
|
||||
|
||||
$line_items[] = $item;
|
||||
|
||||
|
||||
$item = InvoiceItemFactory::create();
|
||||
$item->quantity = 1;
|
||||
$item->cost = 10;
|
||||
$item->product_key = 'pumpkin';
|
||||
$item->notes = 'test_pumpkin';
|
||||
// $item->task_id = $this->encodePrimaryKey($this->task->id);
|
||||
// $item->expense_id = $this->encodePrimaryKey($this->expense->id);
|
||||
|
||||
$line_items[] = $item;
|
||||
|
||||
|
||||
return $line_items;
|
||||
}
|
||||
}
|
@ -96,7 +96,7 @@ class BaseTransformerTest extends TestCase
|
||||
$this->assertEquals($client->id, $base_transformer->getClient('magic', 'null'));
|
||||
$this->assertEquals($client->id, $base_transformer->getClient('nomagic', 'test@gmail.com'));
|
||||
$this->assertEquals($client->id, $base_transformer->getClient(null, 'test@gmail.com'));
|
||||
$this->assertNull($base_transformer->getClient('null', 'notest@gmail.com'));
|
||||
$this->assertNotNull($base_transformer->getClient('null', 'notest@gmail.com'));
|
||||
|
||||
$this->assertEquals($client->id, $base_transformer->getClientId(' magic'));
|
||||
$this->assertEquals($client->id, $base_transformer->getClientId('Magic '));
|
||||
|
@ -122,6 +122,7 @@ class Invoice2GoTest extends TestCase
|
||||
|
||||
$this->assertInstanceOf(Client::class, $client);
|
||||
$this->assertEquals('840', $client->country_id);
|
||||
$this->assertEquals('wade@projectx.net', $client->contacts->first()->email);
|
||||
$this->assertEquals('2584 Sesame Street', $client->address1);
|
||||
|
||||
$this->assertTrue($base_transformer->hasInvoice('1'));
|
||||
|
@ -22,10 +22,11 @@ use App\Factory\SchedulerFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use App\DataMapper\Schedule\EmailStatement;
|
||||
use App\Services\Scheduler\SchedulerService;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Illuminate\Foundation\Testing\WithoutEvents;
|
||||
use App\Services\Scheduler\EmailStatementService;
|
||||
use App\Services\Scheduler\EmailReport;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||
|
||||
/**
|
||||
@ -37,6 +38,7 @@ class SchedulerTest extends TestCase
|
||||
use MakesHash;
|
||||
use MockAccountData;
|
||||
use WithoutEvents;
|
||||
use DatabaseTransactions;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
@ -53,8 +55,198 @@ class SchedulerTest extends TestCase
|
||||
$this->withoutMiddleware(
|
||||
ThrottleRequests::class
|
||||
);
|
||||
|
||||
// $this->withoutExceptionHandling();
|
||||
}
|
||||
|
||||
|
||||
public function testReportValidationRules()
|
||||
{
|
||||
$data = [
|
||||
'name' => 'A test product sales scheduler',
|
||||
'frequency_id' => RecurringInvoice::FREQUENCY_MONTHLY,
|
||||
'next_run' => now()->format('Y-m-d'),
|
||||
'template' => 'email_report',
|
||||
'parameters' => [
|
||||
'date_range' => EmailStatement::LAST_MONTH,
|
||||
'clients' => [],
|
||||
'report_keys' => [],
|
||||
'client_id' => $this->client->hashed_id,
|
||||
'report_name' => '',
|
||||
],
|
||||
];
|
||||
|
||||
$response = false;
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->postJson('/api/v1/task_schedulers', $data);
|
||||
|
||||
$response->assertStatus(422);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function testProductSalesReportGenerationOneClientSeparateParam()
|
||||
{
|
||||
$data = [
|
||||
'name' => 'A test product sales scheduler',
|
||||
'frequency_id' => RecurringInvoice::FREQUENCY_MONTHLY,
|
||||
'next_run' => now()->format('Y-m-d'),
|
||||
'template' => 'email_report',
|
||||
'parameters' => [
|
||||
'date_range' => EmailStatement::LAST_MONTH,
|
||||
'clients' => [],
|
||||
'report_keys' => [],
|
||||
'client_id' => $this->client->hashed_id,
|
||||
'report_name' => 'product_sales_report',
|
||||
|
||||
],
|
||||
];
|
||||
|
||||
$response = false;
|
||||
|
||||
try {
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->postJson('/api/v1/task_schedulers', $data);
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
catch(\Exception $e){
|
||||
nlog($e->getMessage());
|
||||
}
|
||||
|
||||
$arr = $response->json();
|
||||
|
||||
$id = $this->decodePrimaryKey($arr['data']['id']);
|
||||
$scheduler = Scheduler::find($id);
|
||||
$user = $scheduler->user;
|
||||
$user->email = "{rand(5,555555}@gmail.com";
|
||||
$user->save();
|
||||
|
||||
$this->assertNotNull($scheduler);
|
||||
|
||||
$export = (new EmailReport($scheduler))->run();
|
||||
|
||||
$this->assertEquals(now()->addMonth()->format('Y-m-d'), $scheduler->next_run->format('Y-m-d'));
|
||||
|
||||
}
|
||||
|
||||
public function testProductSalesReportGenerationOneClient()
|
||||
{
|
||||
$data = [
|
||||
'name' => 'A test product sales scheduler',
|
||||
'frequency_id' => RecurringInvoice::FREQUENCY_MONTHLY,
|
||||
'next_run' => now()->format('Y-m-d'),
|
||||
'template' => 'email_report',
|
||||
'parameters' => [
|
||||
'date_range' => EmailStatement::LAST_MONTH,
|
||||
'clients' => [$this->client->hashed_id],
|
||||
'report_keys' => [],
|
||||
'client_id' => null,
|
||||
'report_name' => 'product_sales_report',
|
||||
],
|
||||
];
|
||||
|
||||
$response = false;
|
||||
|
||||
try {
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->postJson('/api/v1/task_schedulers', $data);
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
catch(\Exception $e){
|
||||
nlog($e->getMessage());
|
||||
}
|
||||
|
||||
$arr = $response->json();
|
||||
|
||||
$id = $this->decodePrimaryKey($arr['data']['id']);
|
||||
$scheduler = Scheduler::find($id);
|
||||
$user = $scheduler->user;
|
||||
$user->email = "{rand(5,555555}@gmail.com";
|
||||
$user->save();
|
||||
|
||||
$this->assertNotNull($scheduler);
|
||||
|
||||
$export = (new EmailReport($scheduler))->run();
|
||||
|
||||
$this->assertEquals(now()->addMonth()->format('Y-m-d'), $scheduler->next_run->format('Y-m-d'));
|
||||
|
||||
}
|
||||
|
||||
public function testProductSalesReportGeneration()
|
||||
{
|
||||
$data = [
|
||||
'name' => 'A test product sales scheduler',
|
||||
'frequency_id' => RecurringInvoice::FREQUENCY_MONTHLY,
|
||||
'next_run' => now()->format('Y-m-d'),
|
||||
'template' => 'email_report',
|
||||
'parameters' => [
|
||||
'date_range' => EmailStatement::LAST_MONTH,
|
||||
'clients' => [],
|
||||
'report_keys' => [],
|
||||
'client_id' => null,
|
||||
'report_name' => 'product_sales_report',
|
||||
],
|
||||
];
|
||||
|
||||
$response = false;
|
||||
|
||||
try {
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->postJson('/api/v1/task_schedulers', $data);
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
catch(\Exception $e){
|
||||
nlog($e->getMessage());
|
||||
}
|
||||
|
||||
$arr = $response->json();
|
||||
|
||||
$id = $this->decodePrimaryKey($arr['data']['id']);
|
||||
$scheduler = Scheduler::find($id);
|
||||
|
||||
$this->assertNotNull($scheduler);
|
||||
|
||||
$export = (new EmailReport($scheduler))->run();
|
||||
|
||||
$this->assertEquals(now()->addMonth()->format('Y-m-d'), $scheduler->next_run->format('Y-m-d'));
|
||||
|
||||
}
|
||||
|
||||
public function testProductSalesReportStore()
|
||||
{
|
||||
$data = [
|
||||
'name' => 'A test product sales scheduler',
|
||||
'frequency_id' => RecurringInvoice::FREQUENCY_MONTHLY,
|
||||
'next_run' => now()->format('Y-m-d'),
|
||||
'template' => 'email_report',
|
||||
'parameters' => [
|
||||
'date_range' => EmailStatement::LAST_MONTH,
|
||||
'clients' => [],
|
||||
'report_name' => 'product_sales_report',
|
||||
],
|
||||
];
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->postJson('/api/v1/task_schedulers', $data);
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
|
||||
|
||||
public function testSchedulerGet3()
|
||||
{
|
||||
|
||||
@ -539,6 +731,7 @@ class SchedulerTest extends TestCase
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
|
||||
|
||||
public function testDeleteSchedule()
|
||||
{
|
||||
$data = [
|
||||
|
@ -99,6 +99,134 @@ class TaskApiTest extends TestCase
|
||||
}
|
||||
}
|
||||
|
||||
public function testMultiSortArray()
|
||||
{
|
||||
|
||||
$logs = [
|
||||
[1680035007,1680036807,"",true],
|
||||
];
|
||||
|
||||
$key_values = array_column($logs, 0);
|
||||
array_multisort($key_values, SORT_ASC, $logs);
|
||||
|
||||
$start = $logs[0];
|
||||
|
||||
$this->assertEquals(1680035007, $start[0]);
|
||||
|
||||
$logs = [
|
||||
];
|
||||
|
||||
$key_values = array_column($logs, 0);
|
||||
array_multisort($key_values, SORT_ASC, $logs);
|
||||
|
||||
$this->assertIsArray($logs);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public function testKsortPerformance()
|
||||
{
|
||||
$logs = [
|
||||
[1680035007,1680036807,"",true],
|
||||
[1681156840,1681158000,"",true],
|
||||
[1680302433,1680387960,"",true],
|
||||
[1680715620,1680722820,"",true],
|
||||
[1,1680737460,"",true]
|
||||
];
|
||||
|
||||
$key_values = array_column($logs, 0);
|
||||
array_multisort($key_values, SORT_ASC, $logs);
|
||||
|
||||
$start = $logs[0];
|
||||
|
||||
$this->assertEquals(1, $start[0]);
|
||||
|
||||
}
|
||||
|
||||
public function testStartStopSanity()
|
||||
{
|
||||
|
||||
$task = Task::factory()->create([
|
||||
'client_id' => $this->client->id,
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $this->company->id,
|
||||
'description' => 'Test Task',
|
||||
'time_log' => '[[1681165417,1681165432,"sumtin",true],[1681165446,0]]',
|
||||
]);
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->putJson("/api/v1/tasks/{$task->hashed_id}?stop=true");
|
||||
|
||||
$response->assertStatus(200);
|
||||
|
||||
}
|
||||
|
||||
public function testStoppingTaskWithDescription()
|
||||
{
|
||||
$task = Task::factory()->create([
|
||||
'client_id' => $this->client->id,
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $this->company->id,
|
||||
'description' => 'Test Task',
|
||||
'time_log' => '[[1681165417,1681165432,"sumtin",true],[1681165446,0]]',
|
||||
]);
|
||||
|
||||
$task_repo = new \App\Repositories\TaskRepository();
|
||||
|
||||
$task = $task_repo->stop($task);
|
||||
|
||||
$log = json_decode($task->time_log);
|
||||
|
||||
$last = end($log);
|
||||
|
||||
$this->assertNotEquals(0, $last[1]);
|
||||
$this->assertCount(2, $last);
|
||||
}
|
||||
|
||||
public function testMultiDimensionArrayOfTimes()
|
||||
{
|
||||
$logs = [
|
||||
'[[1680302433,1680387960,"",true]]',
|
||||
'[[1680715620,1680722820,"",true],[1680729660,1680737460,"",true]]',
|
||||
'[[1681156840,1681158000,"",true]]',
|
||||
'[[1680035007,1680036807,"",true]]',
|
||||
];
|
||||
|
||||
foreach($logs as $log)
|
||||
{
|
||||
$this->assertTrue($this->checkTimeLog(json_decode($log)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function testArrayOfTimes()
|
||||
{
|
||||
$logs = [
|
||||
"[[1675275148,1675277829]]",
|
||||
"[[1675375200,1675384200],[1676074247,1676074266]]",
|
||||
"[[1675443600,1675461600],[1676053305,1676055950],[1676063112,1676067834]]",
|
||||
"[[1676068200,1676070900]]",
|
||||
"[[1678134638,1678156238]]",
|
||||
"[[1678132800,1678134582],[1678134727,1678136801]]",
|
||||
"[[1678343569,1678344469]]",
|
||||
"[[1678744339,1678755139]]",
|
||||
"[[1678894860,1678906620]]",
|
||||
"[[1679339870,1679341672]]",
|
||||
"[[1680547478,1680547482]]",
|
||||
"[[1681156881,0]]",
|
||||
];
|
||||
|
||||
foreach($logs as $log)
|
||||
{
|
||||
$this->assertTrue($this->checkTimeLog(json_decode($log)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function testTimeLogChecker1()
|
||||
{
|
||||
$log = [
|
||||
|
@ -11,13 +11,15 @@
|
||||
|
||||
namespace Tests\Unit;
|
||||
|
||||
use Tests\TestCase;
|
||||
use App\Models\Invoice;
|
||||
use Tests\MockAccountData;
|
||||
use App\DataMapper\InvoiceItem;
|
||||
use App\Factory\InvoiceFactory;
|
||||
use App\Factory\InvoiceItemFactory;
|
||||
use App\Helpers\Invoice\InvoiceSum;
|
||||
use App\Helpers\Invoice\InvoiceSumInclusive;
|
||||
use App\Models\Invoice;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Tests\MockAccountData;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* @test
|
||||
@ -47,6 +49,32 @@ class InvoiceTest extends TestCase
|
||||
$this->invoice_calc = new InvoiceSum($this->invoice);
|
||||
}
|
||||
|
||||
public function testRoundingWithLargeUnitCostPrecision()
|
||||
{
|
||||
$invoice = InvoiceFactory::create($this->company->id, $this->user->id);
|
||||
$invoice->client_id = $this->client->id;
|
||||
$invoice->uses_inclusive_taxes = false;
|
||||
|
||||
$line_items = [];
|
||||
|
||||
$line_item = new InvoiceItem;
|
||||
$line_item->quantity = 1;
|
||||
$line_item->cost = 82.6446;
|
||||
$line_item->tax_rate1 = 21;
|
||||
$line_item->tax_name1 = 'Test';
|
||||
$line_item->product_key = 'Test';
|
||||
$line_item->notes = 'Test';
|
||||
$line_items[] = $line_item;
|
||||
|
||||
$invoice->line_items = $line_items;
|
||||
$invoice->save();
|
||||
|
||||
$invoice = $invoice->calc()->getInvoice();
|
||||
|
||||
$this->assertEquals(100, $invoice->amount);
|
||||
|
||||
}
|
||||
|
||||
public function testInclusiveRounding()
|
||||
{
|
||||
$this->invoice->line_items = [];
|
||||
|
@ -15,6 +15,7 @@ use Tests\TestCase;
|
||||
use App\Models\Client;
|
||||
use App\Models\Company;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Product;
|
||||
use Tests\MockAccountData;
|
||||
use App\DataMapper\Tax\DE\Rule;
|
||||
use App\DataMapper\Tax\TaxModel;
|
||||
@ -44,13 +45,88 @@ class EuTaxTest extends TestCase
|
||||
$this->makeTestData();
|
||||
}
|
||||
|
||||
|
||||
public function testEuToUsTaxCalculation()
|
||||
{
|
||||
|
||||
$settings = CompanySettings::defaults();
|
||||
$settings->country_id = '276'; // germany
|
||||
|
||||
$tax_data = new TaxModel();
|
||||
$tax_data->seller_subregion = 'DE';
|
||||
$tax_data->regions->EU->has_sales_above_threshold = false;
|
||||
$tax_data->regions->EU->tax_all_subregions = true;
|
||||
$tax_data->regions->US->tax_all_subregions = true;
|
||||
$tax_data->regions->US->has_sales_above_threshold = 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,
|
||||
'is_tax_exempt' => false,
|
||||
'tax_data' => new Response([
|
||||
'geoState' => 'CA',
|
||||
'taxSales' => 0.07,
|
||||
]),
|
||||
]);
|
||||
|
||||
$invoice = Invoice::factory()->create([
|
||||
'company_id' => $company->id,
|
||||
'client_id' => $client->id,
|
||||
'status_id' => 1,
|
||||
'user_id' => $this->user->id,
|
||||
'uses_inclusive_taxes' => false,
|
||||
'discount' => 0,
|
||||
'line_items' => [
|
||||
[
|
||||
'product_key' => 'Test',
|
||||
'notes' => 'Test',
|
||||
'cost' => 100,
|
||||
'quantity' => 1,
|
||||
'tax_name1' => '',
|
||||
'tax_rate1' => 0,
|
||||
'tax_name2' => '',
|
||||
'tax_rate2' => 0,
|
||||
'tax_name3' => '',
|
||||
'tax_rate3' => 0,
|
||||
'type_id' => '1',
|
||||
'tax_id' => Product::PRODUCT_TYPE_PHYSICAL,
|
||||
],
|
||||
],
|
||||
'tax_rate1' => 0,
|
||||
'tax_rate2' => 0,
|
||||
'tax_rate3' => 0,
|
||||
'tax_name1' => '',
|
||||
'tax_name2' => '',
|
||||
'tax_name3' => '',
|
||||
'tax_data' => new Response([
|
||||
'geoState' => 'CA',
|
||||
'taxSales' => 0.07,
|
||||
]),
|
||||
]);
|
||||
|
||||
$invoice = $invoice->calc()->getInvoice()->service()->markSent()->save();
|
||||
|
||||
$this->assertEquals(107, $invoice->amount);
|
||||
|
||||
}
|
||||
|
||||
|
||||
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_subregions = true;
|
||||
@ -114,7 +190,6 @@ class EuTaxTest extends TestCase
|
||||
$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_subregions = true;
|
||||
@ -179,7 +254,6 @@ class EuTaxTest extends TestCase
|
||||
$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_subregions = true;
|
||||
@ -246,7 +320,6 @@ class EuTaxTest extends TestCase
|
||||
$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_subregions = true;
|
||||
@ -269,17 +342,16 @@ class EuTaxTest extends TestCase
|
||||
$process->setClient($client);
|
||||
$process->init();
|
||||
|
||||
$this->assertEquals('DE', $process->vendor_country_code);
|
||||
|
||||
$this->assertEquals('DE', $process->client_country_code);
|
||||
$this->assertEquals('EU', $process->seller_region);
|
||||
$this->assertEquals('DE', $process->client_subregion);
|
||||
|
||||
$this->assertFalse($client->has_valid_vat_number);
|
||||
|
||||
$this->assertInstanceOf(Rule::class, $process);
|
||||
|
||||
$this->assertEquals(19, $process->vat_rate);
|
||||
$this->assertEquals(19, $process->tax_rate);
|
||||
|
||||
$this->assertEquals(7, $process->reduced_vat_rate);
|
||||
$this->assertEquals(7, $process->reduced_tax_rate);
|
||||
|
||||
|
||||
}
|
||||
@ -291,7 +363,6 @@ class EuTaxTest extends TestCase
|
||||
$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_subregions = true;
|
||||
@ -316,17 +387,17 @@ class EuTaxTest extends TestCase
|
||||
$process->init();
|
||||
|
||||
|
||||
$this->assertEquals('DE', $process->vendor_country_code);
|
||||
$this->assertEquals('EU', $process->seller_region);
|
||||
|
||||
$this->assertEquals('BE', $process->client_country_code);
|
||||
$this->assertEquals('BE', $process->client_subregion);
|
||||
|
||||
$this->assertFalse($client->has_valid_vat_number);
|
||||
|
||||
$this->assertInstanceOf(Rule::class, $process);
|
||||
|
||||
$this->assertEquals(21, $process->vat_rate);
|
||||
$this->assertEquals(21, $process->tax_rate);
|
||||
|
||||
$this->assertEquals(6, $process->reduced_vat_rate);
|
||||
$this->assertEquals(6, $process->reduced_tax_rate);
|
||||
|
||||
|
||||
}
|
||||
@ -337,11 +408,18 @@ class EuTaxTest extends TestCase
|
||||
$settings = CompanySettings::defaults();
|
||||
$settings->country_id = '276'; // germany
|
||||
|
||||
$tax_data = new TaxModel();
|
||||
$tax_data->seller_subregion = 'DE';
|
||||
$tax_data->regions->EU->has_sales_above_threshold = true;
|
||||
$tax_data->regions->EU->tax_all_subregions = true;
|
||||
|
||||
$company = Company::factory()->create([
|
||||
'account_id' => $this->account->id,
|
||||
'settings' => $settings
|
||||
'settings' => $settings,
|
||||
'tax_data' => $tax_data,
|
||||
]);
|
||||
|
||||
|
||||
$client = Client::factory()->create([
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $company->id,
|
||||
@ -351,24 +429,27 @@ class EuTaxTest extends TestCase
|
||||
]);
|
||||
|
||||
$process = new Rule();
|
||||
$process->setTaxData(new Response([
|
||||
'geoState' => 'CA',
|
||||
]));
|
||||
$process->setClient($client);
|
||||
$process->init();
|
||||
|
||||
$this->assertEquals('DE', $process->vendor_country_code);
|
||||
$this->assertEquals('EU', $process->seller_region);
|
||||
|
||||
$this->assertEquals('US', $process->client_country_code);
|
||||
$this->assertEquals('CA', $process->client_subregion);
|
||||
|
||||
$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);
|
||||
$this->assertEquals(0, $process->tax_rate);
|
||||
|
||||
$this->assertEquals(0, $process->reduced_tax_rate);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function testSubThresholdCorrectRate()
|
||||
{
|
||||
|
||||
@ -376,7 +457,6 @@ class EuTaxTest extends TestCase
|
||||
$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_subregions = true;
|
||||
@ -404,9 +484,9 @@ class EuTaxTest extends TestCase
|
||||
|
||||
$this->assertFalse($client->has_valid_vat_number);
|
||||
|
||||
$this->assertEquals(19, $process->vat_rate);
|
||||
$this->assertEquals(19, $process->tax_rate);
|
||||
|
||||
$this->assertEquals(7, $process->reduced_vat_rate);
|
||||
$this->assertEquals(7, $process->reduced_tax_rate);
|
||||
|
||||
}
|
||||
|
||||
@ -418,7 +498,6 @@ class EuTaxTest extends TestCase
|
||||
$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_subregions = true;
|
||||
@ -446,9 +525,9 @@ class EuTaxTest extends TestCase
|
||||
|
||||
$this->assertTrue($client->has_valid_vat_number);
|
||||
|
||||
$this->assertEquals(19, $process->vat_rate);
|
||||
$this->assertEquals(19, $process->tax_rate);
|
||||
|
||||
$this->assertEquals(7, $process->reduced_vat_rate);
|
||||
$this->assertEquals(7, $process->reduced_tax_rate);
|
||||
|
||||
}
|
||||
|
||||
@ -459,7 +538,6 @@ class EuTaxTest extends TestCase
|
||||
$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_subregions = true;
|
||||
@ -487,9 +565,9 @@ class EuTaxTest extends TestCase
|
||||
|
||||
$this->assertTrue($client->has_valid_vat_number);
|
||||
|
||||
$this->assertEquals(0, $process->vat_rate);
|
||||
$this->assertEquals(0, $process->tax_rate);
|
||||
|
||||
$this->assertEquals(0, $process->reduced_vat_rate);
|
||||
$this->assertEquals(0, $process->reduced_tax_rate);
|
||||
|
||||
}
|
||||
|
||||
@ -499,7 +577,6 @@ class EuTaxTest extends TestCase
|
||||
$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_subregions = true;
|
||||
@ -528,9 +605,9 @@ class EuTaxTest extends TestCase
|
||||
|
||||
$this->assertTrue($client->is_tax_exempt);
|
||||
|
||||
$this->assertEquals(0, $process->vat_rate);
|
||||
$this->assertEquals(0, $process->tax_rate);
|
||||
|
||||
$this->assertEquals(0, $process->reduced_vat_rate);
|
||||
$this->assertEquals(0, $process->reduced_tax_rate);
|
||||
|
||||
}
|
||||
|
||||
@ -540,7 +617,6 @@ class EuTaxTest extends TestCase
|
||||
$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_subregions = true;
|
||||
@ -569,9 +645,9 @@ class EuTaxTest extends TestCase
|
||||
|
||||
$this->assertTrue($client->is_tax_exempt);
|
||||
|
||||
$this->assertEquals(0, $process->vat_rate);
|
||||
$this->assertEquals(0, $process->tax_rate);
|
||||
|
||||
$this->assertEquals(0, $process->reduced_vat_rate);
|
||||
$this->assertEquals(0, $process->reduced_tax_rate);
|
||||
|
||||
}
|
||||
|
||||
@ -581,8 +657,6 @@ class EuTaxTest extends TestCase
|
||||
$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_subregions = true;
|
||||
|
||||
@ -603,6 +677,7 @@ class EuTaxTest extends TestCase
|
||||
]);
|
||||
|
||||
$process = new Rule();
|
||||
$process->setTaxData(new Response([]));
|
||||
$process->setClient($client);
|
||||
$process->init();
|
||||
|
||||
@ -610,9 +685,9 @@ class EuTaxTest extends TestCase
|
||||
|
||||
$this->assertTrue($client->is_tax_exempt);
|
||||
|
||||
$this->assertEquals(0, $process->vat_rate);
|
||||
$this->assertEquals(0, $process->tax_rate);
|
||||
|
||||
$this->assertEquals(0, $process->reduced_vat_rate);
|
||||
$this->assertEquals(0, $process->reduced_tax_rate);
|
||||
|
||||
}
|
||||
|
||||
|
@ -94,7 +94,6 @@ class SumTaxTest extends TestCase
|
||||
|
||||
|
||||
$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_subregions = true;
|
||||
@ -145,7 +144,6 @@ class SumTaxTest extends TestCase
|
||||
|
||||
|
||||
$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_subregions = true;
|
||||
|
@ -15,6 +15,7 @@ use Tests\TestCase;
|
||||
use App\Models\Client;
|
||||
use App\Models\Company;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Product;
|
||||
use Tests\MockAccountData;
|
||||
use App\DataMapper\Tax\DE\Rule;
|
||||
use App\DataMapper\Tax\TaxModel;
|
||||
@ -88,7 +89,6 @@ class UsTaxTest extends TestCase
|
||||
$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_subregions = true;
|
||||
@ -146,6 +146,209 @@ class UsTaxTest extends TestCase
|
||||
return $invoice;
|
||||
}
|
||||
|
||||
public function testForeignTaxesEnabledWithExemptProduct()
|
||||
{
|
||||
$settings = CompanySettings::defaults();
|
||||
$settings->country_id = '840'; // germany
|
||||
|
||||
$tax_data = new TaxModel();
|
||||
$tax_data->seller_subregion = 'CA';
|
||||
$tax_data->regions->US->has_sales_above_threshold = true;
|
||||
$tax_data->regions->US->tax_all_subregions = true;
|
||||
$tax_data->regions->EU->has_sales_above_threshold = true;
|
||||
$tax_data->regions->EU->tax_all_subregions = true;
|
||||
$tax_data->regions->EU->subregions->DE->tax_rate = 21;
|
||||
|
||||
$company = Company::factory()->create([
|
||||
'account_id' => $this->account->id,
|
||||
'settings' => $settings,
|
||||
'tax_data' => $tax_data,
|
||||
'calculate_taxes' => true,
|
||||
]);
|
||||
|
||||
$client = Client::factory()->create([
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $company->id,
|
||||
'country_id' => 276,
|
||||
'shipping_country_id' => 276,
|
||||
'has_valid_vat_number' => false,
|
||||
'postal_code' => 'xx',
|
||||
]);
|
||||
|
||||
$invoice = Invoice::factory()->create([
|
||||
'company_id' => $company->id,
|
||||
'client_id' => $client->id,
|
||||
'status_id' => 1,
|
||||
'user_id' => $this->user->id,
|
||||
'uses_inclusive_taxes' => false,
|
||||
'discount' => 0,
|
||||
'line_items' => [
|
||||
[
|
||||
'product_key' => 'Test',
|
||||
'notes' => 'Test',
|
||||
'cost' => 100,
|
||||
'quantity' => 1,
|
||||
'tax_name1' => '',
|
||||
'tax_rate1' => 0,
|
||||
'tax_name2' => '',
|
||||
'tax_rate2' => 0,
|
||||
'tax_name3' => '',
|
||||
'tax_rate3' => 0,
|
||||
'type_id' => '1',
|
||||
'tax_id' => Product::PRODUCT_TYPE_EXEMPT,
|
||||
],
|
||||
],
|
||||
'tax_rate1' => 0,
|
||||
'tax_rate2' => 0,
|
||||
'tax_rate3' => 0,
|
||||
'tax_name1' => '',
|
||||
'tax_name2' => '',
|
||||
'tax_name3' => '',
|
||||
'tax_data' => new Response($this->mock_response),
|
||||
]);
|
||||
|
||||
$invoice = $invoice->calc()->getInvoice()->service()->markSent()->save();
|
||||
|
||||
$this->assertEquals(100, $invoice->amount);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function testForeignTaxesDisabled()
|
||||
{
|
||||
$settings = CompanySettings::defaults();
|
||||
$settings->country_id = '840'; // germany
|
||||
|
||||
$tax_data = new TaxModel();
|
||||
$tax_data->seller_subregion = 'CA';
|
||||
$tax_data->regions->US->has_sales_above_threshold = true;
|
||||
$tax_data->regions->US->tax_all_subregions = true;
|
||||
$tax_data->regions->EU->has_sales_above_threshold = true;
|
||||
$tax_data->regions->EU->tax_all_subregions = false;
|
||||
$tax_data->regions->EU->subregions->DE->tax_rate = 21;
|
||||
|
||||
$company = Company::factory()->create([
|
||||
'account_id' => $this->account->id,
|
||||
'settings' => $settings,
|
||||
'tax_data' => $tax_data,
|
||||
'calculate_taxes' => true,
|
||||
]);
|
||||
|
||||
$client = Client::factory()->create([
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $company->id,
|
||||
'country_id' => 276,
|
||||
'shipping_country_id' => 276,
|
||||
'has_valid_vat_number' => false,
|
||||
'postal_code' => 'xx',
|
||||
]);
|
||||
|
||||
$invoice = Invoice::factory()->create([
|
||||
'company_id' => $company->id,
|
||||
'client_id' => $client->id,
|
||||
'status_id' => 1,
|
||||
'user_id' => $this->user->id,
|
||||
'uses_inclusive_taxes' => false,
|
||||
'discount' => 0,
|
||||
'line_items' => [
|
||||
[
|
||||
'product_key' => 'Test',
|
||||
'notes' => 'Test',
|
||||
'cost' => 100,
|
||||
'quantity' => 1,
|
||||
'tax_name1' => '',
|
||||
'tax_rate1' => 0,
|
||||
'tax_name2' => '',
|
||||
'tax_rate2' => 0,
|
||||
'tax_name3' => '',
|
||||
'tax_rate3' => 0,
|
||||
'type_id' => '1',
|
||||
'tax_id' => Product::PRODUCT_TYPE_PHYSICAL,
|
||||
],
|
||||
],
|
||||
'tax_rate1' => 0,
|
||||
'tax_rate2' => 0,
|
||||
'tax_rate3' => 0,
|
||||
'tax_name1' => '',
|
||||
'tax_name2' => '',
|
||||
'tax_name3' => '',
|
||||
'tax_data' => new Response($this->mock_response),
|
||||
]);
|
||||
|
||||
$invoice = $invoice->calc()->getInvoice()->service()->markSent()->save();
|
||||
|
||||
$this->assertEquals(100, $invoice->amount);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function testForeignTaxesEnabled()
|
||||
{
|
||||
$settings = CompanySettings::defaults();
|
||||
$settings->country_id = '840'; // germany
|
||||
|
||||
$tax_data = new TaxModel();
|
||||
$tax_data->seller_subregion = 'CA';
|
||||
$tax_data->regions->US->has_sales_above_threshold = true;
|
||||
$tax_data->regions->US->tax_all_subregions = true;
|
||||
$tax_data->regions->EU->has_sales_above_threshold = true;
|
||||
$tax_data->regions->EU->tax_all_subregions = true;
|
||||
$tax_data->regions->EU->subregions->DE->tax_rate = 21;
|
||||
|
||||
$company = Company::factory()->create([
|
||||
'account_id' => $this->account->id,
|
||||
'settings' => $settings,
|
||||
'tax_data' => $tax_data,
|
||||
'calculate_taxes' => true,
|
||||
]);
|
||||
|
||||
$client = Client::factory()->create([
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $company->id,
|
||||
'country_id' => 276,
|
||||
'shipping_country_id' => 276,
|
||||
'has_valid_vat_number' => false,
|
||||
'postal_code' => 'xx',
|
||||
]);
|
||||
|
||||
$invoice = Invoice::factory()->create([
|
||||
'company_id' => $company->id,
|
||||
'client_id' => $client->id,
|
||||
'status_id' => 1,
|
||||
'user_id' => $this->user->id,
|
||||
'uses_inclusive_taxes' => false,
|
||||
'discount' => 0,
|
||||
'line_items' => [
|
||||
[
|
||||
'product_key' => 'Test',
|
||||
'notes' => 'Test',
|
||||
'cost' => 100,
|
||||
'quantity' => 1,
|
||||
'tax_name1' => '',
|
||||
'tax_rate1' => 0,
|
||||
'tax_name2' => '',
|
||||
'tax_rate2' => 0,
|
||||
'tax_name3' => '',
|
||||
'tax_rate3' => 0,
|
||||
'type_id' => '1',
|
||||
'tax_id' => Product::PRODUCT_TYPE_PHYSICAL,
|
||||
],
|
||||
],
|
||||
'tax_rate1' => 0,
|
||||
'tax_rate2' => 0,
|
||||
'tax_rate3' => 0,
|
||||
'tax_name1' => '',
|
||||
'tax_name2' => '',
|
||||
'tax_name3' => '',
|
||||
'tax_data' => new Response($this->mock_response),
|
||||
]);
|
||||
|
||||
$invoice = $invoice->calc()->getInvoice()->service()->markSent()->save();
|
||||
|
||||
$this->assertEquals(121, $invoice->amount);
|
||||
|
||||
}
|
||||
|
||||
public function testCompanyTaxAllOffButTaxUSRegion()
|
||||
{
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user