mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-09 20:52:56 +01:00
Updates for e-invoice signatures
This commit is contained in:
parent
913599334b
commit
7a88d631dc
@ -14,7 +14,6 @@ namespace App\DataMapper\Tax;
|
||||
use App\Models\Client;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Product;
|
||||
use App\DataMapper\Tax\TaxData;
|
||||
use App\DataProviders\USStates;
|
||||
use App\DataMapper\Tax\ZipTax\Response;
|
||||
|
||||
@ -147,21 +146,25 @@ class BaseRule implements RuleInterface
|
||||
|
||||
private function configTaxData(): self
|
||||
{
|
||||
|
||||
/* If the client Country is not in the region_codes, we force the company country onto the client? @TODO */
|
||||
if(!array_key_exists($this->client->country->iso_3166_2, $this->region_codes)) {
|
||||
$this->client->country_id = $this->invoice->company->settings->country_id;
|
||||
$this->client->saveQuietly();
|
||||
|
||||
nlog('Automatic tax calculations not supported for this country - defaulting to company country');
|
||||
}
|
||||
|
||||
/** Harvest the client_region */
|
||||
$this->client_region = $this->region_codes[$this->client->country->iso_3166_2];
|
||||
|
||||
/** If the tax data is already set and the invoice is marked as sent, do not adjust the rates */
|
||||
if($this->invoice->tax_data && $this->invoice->status_id > 1)
|
||||
return $this;
|
||||
|
||||
//determine if we are taxing locally or if we are taxing globally
|
||||
//Pass the client tax data into the invoice tax data object
|
||||
$tax_data = is_object($this->invoice->client->tax_data) ? $this->invoice->client->tax_data : new Response([]);
|
||||
|
||||
/** If no Origin / Destination has been set and the seller and client sub regions are not the same, force destination tax */
|
||||
if(strlen($this->invoice->tax_data?->originDestination) == 0 && $this->client->company->tax_data->seller_subregion != $this->client_subregion) {
|
||||
$tax_data->originDestination = "D";
|
||||
$tax_data->geoState = $this->client_subregion;
|
||||
@ -235,18 +238,21 @@ class BaseRule implements RuleInterface
|
||||
{
|
||||
|
||||
if ($this->client->is_tax_exempt) {
|
||||
return $this->taxExempt();
|
||||
|
||||
return $this->taxExempt($item);
|
||||
|
||||
} elseif($this->client_region == $this->seller_region && $this->isTaxableRegion()) {
|
||||
|
||||
$this->taxByType($item->tax_id);
|
||||
$this->taxByType($item);
|
||||
|
||||
return $this;
|
||||
|
||||
} elseif($this->isTaxableRegion()) { //other regions outside of US
|
||||
|
||||
match(intval($item->tax_id)) {
|
||||
Product::PRODUCT_TYPE_EXEMPT => $this->taxExempt(),
|
||||
Product::PRODUCT_TYPE_REDUCED_TAX => $this->taxReduced(),
|
||||
Product::PRODUCT_TYPE_OVERRIDE_TAX => $this->override(),
|
||||
Product::PRODUCT_TYPE_EXEMPT => $this->taxExempt($item),
|
||||
Product::PRODUCT_TYPE_REDUCED_TAX => $this->taxReduced($item),
|
||||
Product::PRODUCT_TYPE_OVERRIDE_TAX => $this->override($item),
|
||||
default => $this->defaultForeign(),
|
||||
};
|
||||
|
||||
@ -260,42 +266,42 @@ class BaseRule implements RuleInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function taxReduced(): self
|
||||
public function taxReduced($item): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function taxExempt(): self
|
||||
public function taxExempt($item): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function taxDigital(): self
|
||||
public function taxDigital($item): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function taxService(): self
|
||||
public function taxService($item): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function taxShipping(): self
|
||||
public function taxShipping($item): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function taxPhysical(): self
|
||||
public function taxPhysical($item): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function default(): self
|
||||
public function default($item): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function override(): self
|
||||
public function override($item): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
@ -56,27 +56,27 @@ class Rule extends BaseRule implements RuleInterface
|
||||
/**
|
||||
* Sets the correct tax rate based on the product type.
|
||||
*
|
||||
* @param mixed $product_tax_type
|
||||
* @param mixed $item
|
||||
* @return self
|
||||
*/
|
||||
public function taxByType($product_tax_type): self
|
||||
public function taxByType($item): self
|
||||
{
|
||||
|
||||
if ($this->client->is_tax_exempt) {
|
||||
return $this->taxExempt();
|
||||
return $this->taxExempt($item);
|
||||
}
|
||||
|
||||
match(intval($product_tax_type)){
|
||||
Product::PRODUCT_TYPE_EXEMPT => $this->taxExempt(),
|
||||
Product::PRODUCT_TYPE_DIGITAL => $this->taxDigital(),
|
||||
Product::PRODUCT_TYPE_SERVICE => $this->taxService(),
|
||||
Product::PRODUCT_TYPE_SHIPPING => $this->taxShipping(),
|
||||
Product::PRODUCT_TYPE_PHYSICAL => $this->taxPhysical(),
|
||||
Product::PRODUCT_TYPE_REDUCED_TAX => $this->taxReduced(),
|
||||
Product::PRODUCT_TYPE_OVERRIDE_TAX => $this->override(),
|
||||
Product::PRODUCT_TYPE_ZERO_RATED => $this->zeroRated(),
|
||||
Product::PRODUCT_TYPE_REVERSE_TAX => $this->reverseTax(),
|
||||
default => $this->default(),
|
||||
match(intval($item->tax_id)){
|
||||
Product::PRODUCT_TYPE_EXEMPT => $this->taxExempt($item),
|
||||
Product::PRODUCT_TYPE_DIGITAL => $this->taxDigital($item),
|
||||
Product::PRODUCT_TYPE_SERVICE => $this->taxService($item),
|
||||
Product::PRODUCT_TYPE_SHIPPING => $this->taxShipping($item),
|
||||
Product::PRODUCT_TYPE_PHYSICAL => $this->taxPhysical($item),
|
||||
Product::PRODUCT_TYPE_REDUCED_TAX => $this->taxReduced($item),
|
||||
Product::PRODUCT_TYPE_OVERRIDE_TAX => $this->override($item),
|
||||
Product::PRODUCT_TYPE_ZERO_RATED => $this->zeroRated($item),
|
||||
Product::PRODUCT_TYPE_REVERSE_TAX => $this->reverseTax($item),
|
||||
default => $this->default($item),
|
||||
};
|
||||
|
||||
return $this;
|
||||
@ -87,7 +87,7 @@ class Rule extends BaseRule implements RuleInterface
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function reverseTax(): self
|
||||
public function reverseTax($item): self
|
||||
{
|
||||
$this->tax_rate1 = 0;
|
||||
$this->tax_name1 = 'ermäßigte MwSt.';
|
||||
@ -100,7 +100,7 @@ class Rule extends BaseRule implements RuleInterface
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function taxReduced(): self
|
||||
public function taxReduced($item): self
|
||||
{
|
||||
$this->tax_rate1 = $this->reduced_tax_rate;
|
||||
$this->tax_name1 = 'ermäßigte MwSt.';
|
||||
@ -113,7 +113,7 @@ class Rule extends BaseRule implements RuleInterface
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function zeroRated(): self
|
||||
public function zeroRated($item): self
|
||||
{
|
||||
$this->tax_rate1 = 0;
|
||||
$this->tax_name1 = 'ermäßigte MwSt.';
|
||||
@ -127,7 +127,7 @@ class Rule extends BaseRule implements RuleInterface
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function taxExempt(): self
|
||||
public function taxExempt($item): self
|
||||
{
|
||||
$this->tax_name1 = '';
|
||||
$this->tax_rate1 = 0;
|
||||
@ -140,7 +140,7 @@ class Rule extends BaseRule implements RuleInterface
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function taxDigital(): self
|
||||
public function taxDigital($item): self
|
||||
{
|
||||
|
||||
$this->tax_rate1 = $this->tax_rate;
|
||||
@ -154,7 +154,7 @@ class Rule extends BaseRule implements RuleInterface
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function taxService(): self
|
||||
public function taxService($item): self
|
||||
{
|
||||
|
||||
$this->tax_rate1 = $this->tax_rate;
|
||||
@ -168,7 +168,7 @@ class Rule extends BaseRule implements RuleInterface
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function taxShipping(): self
|
||||
public function taxShipping($item): self
|
||||
{
|
||||
|
||||
$this->tax_rate1 = $this->tax_rate;
|
||||
@ -182,7 +182,7 @@ class Rule extends BaseRule implements RuleInterface
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function taxPhysical(): self
|
||||
public function taxPhysical($item): self
|
||||
{
|
||||
|
||||
$this->tax_rate1 = $this->tax_rate;
|
||||
@ -196,7 +196,7 @@ class Rule extends BaseRule implements RuleInterface
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function default(): self
|
||||
public function default($item): self
|
||||
{
|
||||
|
||||
$this->tax_name1 = '';
|
||||
@ -210,7 +210,7 @@ class Rule extends BaseRule implements RuleInterface
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function override(): self
|
||||
public function override($item): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
@ -15,25 +15,25 @@ interface RuleInterface
|
||||
{
|
||||
public function init();
|
||||
|
||||
public function tax($item = null);
|
||||
public function tax($item);
|
||||
|
||||
public function taxByType($type);
|
||||
|
||||
public function taxExempt();
|
||||
public function taxExempt($item);
|
||||
|
||||
public function taxDigital();
|
||||
public function taxDigital($item);
|
||||
|
||||
public function taxService();
|
||||
public function taxService($item);
|
||||
|
||||
public function taxShipping();
|
||||
public function taxShipping($item);
|
||||
|
||||
public function taxPhysical();
|
||||
public function taxPhysical($item);
|
||||
|
||||
public function taxReduced();
|
||||
public function taxReduced($item);
|
||||
|
||||
public function default();
|
||||
public function default($item);
|
||||
|
||||
public function override();
|
||||
public function override($item);
|
||||
|
||||
public function calculateRates();
|
||||
}
|
@ -41,32 +41,39 @@ class Rule extends BaseRule implements RuleInterface
|
||||
/**
|
||||
* Override tax class, we use this when we do not modify the input taxes
|
||||
*
|
||||
* @param mixed $item
|
||||
* @return self
|
||||
*/
|
||||
public function override(): self
|
||||
public function override($item): self
|
||||
{
|
||||
|
||||
$this->tax_rate1 = $item->tax_rate1;
|
||||
|
||||
$this->tax_name1 = $item->tax_name1;
|
||||
|
||||
return $this;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the correct tax rate based on the product type.
|
||||
*
|
||||
* @param mixed $product_tax_type
|
||||
* @param mixed $item
|
||||
* @return self
|
||||
*/
|
||||
public function taxByType($product_tax_type): self
|
||||
public function taxByType($item): self
|
||||
{
|
||||
|
||||
match(intval($product_tax_type)) {
|
||||
Product::PRODUCT_TYPE_EXEMPT => $this->taxExempt(),
|
||||
Product::PRODUCT_TYPE_DIGITAL => $this->taxDigital(),
|
||||
Product::PRODUCT_TYPE_SERVICE => $this->taxService(),
|
||||
Product::PRODUCT_TYPE_SHIPPING => $this->taxShipping(),
|
||||
Product::PRODUCT_TYPE_PHYSICAL => $this->taxPhysical(),
|
||||
Product::PRODUCT_TYPE_REDUCED_TAX => $this->taxReduced(),
|
||||
Product::PRODUCT_TYPE_OVERRIDE_TAX => $this->override(),
|
||||
Product::PRODUCT_TYPE_ZERO_RATED => $this->zeroRated(),
|
||||
default => $this->default(),
|
||||
match(intval($item->tax_id)) {
|
||||
Product::PRODUCT_TYPE_EXEMPT => $this->taxExempt($item),
|
||||
Product::PRODUCT_TYPE_DIGITAL => $this->taxDigital($item),
|
||||
Product::PRODUCT_TYPE_SERVICE => $this->taxService($item),
|
||||
Product::PRODUCT_TYPE_SHIPPING => $this->taxShipping($item),
|
||||
Product::PRODUCT_TYPE_PHYSICAL => $this->taxPhysical($item),
|
||||
Product::PRODUCT_TYPE_REDUCED_TAX => $this->taxReduced($item),
|
||||
Product::PRODUCT_TYPE_OVERRIDE_TAX => $this->override($item),
|
||||
Product::PRODUCT_TYPE_ZERO_RATED => $this->zeroRated($item),
|
||||
default => $this->default($item),
|
||||
};
|
||||
|
||||
return $this;
|
||||
@ -74,10 +81,11 @@ class Rule extends BaseRule implements RuleInterface
|
||||
|
||||
/**
|
||||
* Sets the tax as exempt (0)
|
||||
* @param mixed $item
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function taxExempt(): self
|
||||
public function taxExempt($item): self
|
||||
{
|
||||
$this->tax_name1 = '';
|
||||
$this->tax_rate1 = 0;
|
||||
@ -87,25 +95,27 @@ class Rule extends BaseRule implements RuleInterface
|
||||
|
||||
/**
|
||||
* Calculates the tax rate for a digital product
|
||||
* @param mixed $item
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function taxDigital(): self
|
||||
public function taxDigital($item): self
|
||||
{
|
||||
$this->default();
|
||||
$this->default($item);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the tax rate for a service product
|
||||
* @param mixed $item
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function taxService(): self
|
||||
public function taxService($item): self
|
||||
{
|
||||
if($this->tax_data?->txbService == 'Y') {
|
||||
$this->default();
|
||||
$this->default($item);
|
||||
}
|
||||
|
||||
return $this;
|
||||
@ -113,13 +123,14 @@ class Rule extends BaseRule implements RuleInterface
|
||||
|
||||
/**
|
||||
* Calculates the tax rate for a shipping product
|
||||
* @param mixed $item
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function taxShipping(): self
|
||||
public function taxShipping($item): self
|
||||
{
|
||||
if($this->tax_data?->txbFreight == 'Y') {
|
||||
$this->default();
|
||||
$this->default($item);
|
||||
}
|
||||
|
||||
return $this;
|
||||
@ -127,12 +138,13 @@ class Rule extends BaseRule implements RuleInterface
|
||||
|
||||
/**
|
||||
* Calculates the tax rate for a physical product
|
||||
* @param mixed $item
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function taxPhysical(): self
|
||||
public function taxPhysical($item): self
|
||||
{
|
||||
$this->default();
|
||||
$this->default($item);
|
||||
|
||||
return $this;
|
||||
}
|
||||
@ -142,10 +154,8 @@ class Rule extends BaseRule implements RuleInterface
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function default(): self
|
||||
public function default($item): self
|
||||
{
|
||||
nlog("default rate");
|
||||
nlog($this->tax_data);
|
||||
|
||||
if($this->tax_data?->stateSalesTax == 0) {
|
||||
|
||||
@ -172,7 +182,7 @@ nlog($this->tax_data);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function zeroRated(): self
|
||||
public function zeroRated($item): self
|
||||
{
|
||||
|
||||
$this->tax_rate1 = 0;
|
||||
@ -187,13 +197,25 @@ nlog($this->tax_data);
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function taxReduced(): self
|
||||
public function taxReduced($item): self
|
||||
{
|
||||
$this->default();
|
||||
$this->default($item);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the tax rate for a reverse tax product
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function reverseTax($item): self
|
||||
{
|
||||
$this->default($item);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the tax rates to be applied
|
||||
*
|
||||
@ -204,17 +226,4 @@ nlog($this->tax_data);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the tax rate for a reverse tax product
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function reverseTax(): self
|
||||
{
|
||||
$this->default();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -144,12 +144,8 @@ class InvoiceItemSum
|
||||
return $this;
|
||||
}
|
||||
|
||||
//should we be filtering by client country here? do we need to reflect at the company <=> client level?
|
||||
// if (in_array($this->client->country->iso_3166_2, $this->tax_jurisdictions)) { //only calculate for supported tax jurisdictions
|
||||
if (in_array($this->client->company->country()->iso_3166_2, $this->tax_jurisdictions)) { //only calculate for supported tax jurisdictions
|
||||
|
||||
nlog($this->client->company->country()->iso_3166_2);
|
||||
|
||||
$class = "App\DataMapper\Tax\\".$this->client->company->country()->iso_3166_2."\\Rule";
|
||||
|
||||
$this->rule = new $class();
|
||||
|
@ -41,6 +41,7 @@ use App\Utils\Traits\Uploadable;
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Str;
|
||||
use Turbo124\Beacon\Facades\LightLogs;
|
||||
|
||||
/**
|
||||
@ -417,6 +418,13 @@ class CompanyController extends BaseController
|
||||
$this->saveDocuments($request->input('documents'), $company, false);
|
||||
}
|
||||
|
||||
if($request->has('e_invoice_certificate')){
|
||||
|
||||
$company->e_invoice_certificate = base64_encode($request->file("e_invoice_certificate")->get());
|
||||
$company->save();
|
||||
|
||||
}
|
||||
|
||||
$this->uploadLogo($request->file('company_logo'), $company, $company);
|
||||
|
||||
return $this->itemResponse($company);
|
||||
|
@ -53,7 +53,8 @@ class UpdateCompanyRequest extends Request
|
||||
$rules['country_id'] = 'integer|nullable';
|
||||
$rules['work_email'] = 'email|nullable';
|
||||
$rules['matomo_id'] = 'nullable|integer';
|
||||
|
||||
$rules['e_invoice_certificate_passphrase'] = 'sometimes|nullable';
|
||||
$rules['e_invoice_certificate'] = 'sometimes|file|mimes:p12,pfx,pem,cer,crt,der,txt,p7b,spc,bin';
|
||||
// $rules['client_registration_fields'] = 'array';
|
||||
|
||||
if (isset($input['portal_mode']) && ($input['portal_mode'] == 'domain' || $input['portal_mode'] == 'iframe')) {
|
||||
|
@ -339,6 +339,7 @@ class Company extends BaseModel
|
||||
'notify_vendor_when_paid',
|
||||
'calculate_taxes',
|
||||
'tax_data',
|
||||
'e_invoice_certificate_passphrase',
|
||||
];
|
||||
|
||||
protected $hidden = [
|
||||
@ -357,6 +358,7 @@ class Company extends BaseModel
|
||||
'deleted_at' => 'timestamp',
|
||||
'client_registration_fields' => 'array',
|
||||
'tax_data' => 'object',
|
||||
'e_invoice_certificate_passphrase' => 'encrypted',
|
||||
];
|
||||
|
||||
protected $with = [];
|
||||
@ -365,7 +367,6 @@ class Company extends BaseModel
|
||||
self::ENTITY_RECURRING_INVOICE => 1,
|
||||
self::ENTITY_CREDIT => 2,
|
||||
self::ENTITY_QUOTE => 4,
|
||||
// @phpstan-ignore-next-line
|
||||
self::ENTITY_TASK => 8,
|
||||
self::ENTITY_EXPENSE => 16,
|
||||
self::ENTITY_PROJECT => 32,
|
||||
|
@ -199,6 +199,8 @@ class CompanyTransformer extends EntityTransformer
|
||||
'invoice_task_hours' => (bool) $company->invoice_task_hours,
|
||||
'calculate_taxes' => (bool) $company->calculate_taxes,
|
||||
'tax_data' => $company->tax_data ?: new \stdClass,
|
||||
'has_e_invoice_certificate' => $company->e_invoice_certificate ? true : false,
|
||||
'has_e_invoice_certificate_passphrase' => $company->e_invoice_certificate_passphrase ? true : false,
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('companies', function (Illuminate\Database\Schema\Blueprint $table) {
|
||||
$table->text('e_invoice_certificate')->nullable();
|
||||
$table->string('e_invoice_certificate_passphrase')->nullable();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
//
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue
Block a user