Working on e_invoicing Spain

This commit is contained in:
David Bomba 2023-04-21 09:11:31 +10:00
parent d06fa55f31
commit 3cff7827df
5 changed files with 331 additions and 4 deletions

View File

@ -36,7 +36,7 @@ class PaymentFilters extends QueryFilters
$query->where('amount', 'like', '%'.$filter.'%') $query->where('amount', 'like', '%'.$filter.'%')
->orWhere('date', 'like', '%'.$filter.'%') ->orWhere('date', 'like', '%'.$filter.'%')
->orWhere('number','like', '%'.$filter.'%') ->orWhere('number','like', '%'.$filter.'%')
->owWhere('transaction_reference', 'like', '%'.$filter.'%') ->orWhere('transaction_reference', 'like', '%'.$filter.'%')
->orWhere('custom_value1', 'like', '%'.$filter.'%') ->orWhere('custom_value1', 'like', '%'.$filter.'%')
->orWhere('custom_value2', 'like', '%'.$filter.'%') ->orWhere('custom_value2', 'like', '%'.$filter.'%')
->orWhere('custom_value3', 'like', '%'.$filter.'%') ->orWhere('custom_value3', 'like', '%'.$filter.'%')

View File

@ -98,7 +98,6 @@ use Laracasts\Presenter\PresentableTrait;
* @property string|null $matomo_url * @property string|null $matomo_url
* @property int|null $matomo_id * @property int|null $matomo_id
* @property bool $enable_e_invoice * @property bool $enable_e_invoice
* @property string $e_invoice_type
* @property int $enabled_expense_tax_rates * @property int $enabled_expense_tax_rates
* @property int $invoice_task_project * @property int $invoice_task_project
* @property int $report_include_deleted * @property int $report_include_deleted

View File

@ -0,0 +1,270 @@
<?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\Invoice\EInvoice;
use App\Models\Client;
use App\Models\Invoice;
use josemmo\Facturae\Facturae;
use App\Services\AbstractService;
use josemmo\Facturae\FacturaeItem;
use josemmo\Facturae\FacturaeParty;
class Facturae extends AbstractService
{
// Facturae::SCHEMA_3_2 Invoice Format 3.2
// Facturae::SCHEMA_3_2_1 Invoice Format 3.2.1
// Facturae::SCHEMA_3_2_2 Invoice Format 3.2.2
// Facturae::ISSUER_SELLER Provider (issuer)
// Facturae::ISSUER_BUYER Recipient (receiver)
// Facturae::ISSUER_THIRD_PARTY Third
// Facturae::PRECISION_LINE Line level accuracy
// Facturae::PRECISION_INVOICE Invoice level accuracy
// CorrectiveDetails::METHOD_FULL Full rectification
// CorrectiveDetails::METHOD_DIFFERENCES Rectification for differences
// CorrectiveDetails::METHOD_VOLUME_DISCOUNT Rectification for discount by volume of operations during a period
// CorrectiveDetails::METHOD_AEAT_AUTHORIZED Authorized by the Tax Agency
// FacturaePayment::TYPE_CASH Cash
// FacturaePayment::TYPE_DEBIT Domiciled receipt
// FacturaePayment::TYPE_RECEIPT Receipt
// FacturaePayment::TYPE_TRANSFER Transfer
// FacturaePayment::TYPE_ACCEPTED_BILL_OF_EXCHANGE Letter Accepted
// FacturaePayment::TYPE_DOCUMENTARY_CREDIT Letter of credit
// FacturaePayment::TYPE_CONTRACT_AWARD contract award
// FacturaePayment::TYPE_BILL_OF_EXCHANGE Bill of exchange
// FacturaePayment::TYPE_TRANSFERABLE_IOU I will pay to order
// FacturaePayment::TYPE_IOU I Will Pay Not To Order
// FacturaePayment::TYPE_CHEQUE Check
// FacturaePayment::TYPE_REIMBURSEMENT Replacement
// FacturaePayment::TYPE_SPECIAL specials
// FacturaePayment::TYPE_SETOFF Compensation
// FacturaePayment::TYPE_POSTGIRO Money order
// FacturaePayment::TYPE_CERTIFIED_CHEQUE conformed check
// FacturaePayment::TYPE_BANKERS_DRAFT Bank check
// FacturaePayment::TYPE_CASH_ON_DELIVERY Cash on delivery
// FacturaePayment::TYPE_CARD Payment by card
// Facturae::TAX_IVA Value Added Tax
// Facturae::TAX_IPSI Tax on production, services and imports
// Facturae::TAX_IGIC General indirect tax of the Canary Islands
// Facturae::TAX_IRPF Personal Income Tax
// Facturae::TAX_OTHER Other
// Facturae::TAX_ITPAJD Transfer tax and stamp duty
// Facturae::TAX_IE Special taxes
// Facturae::TAX_RA Customs rent
// Facturae::TAX_IGTECM General tax on business traffic that is applied in Ceuta and Melilla
// Facturae::TAX_IECDPCAC Special tax on fuels derived from petroleum in the Autonomous Community of the Canary Islands
// Facturae::TAX_IIIMAB Tax on facilities that affect the environment in the Balearic Islands
// Facturae::TAX_ICIO Tax on constructions, facilities and works
// Facturae::TAX_IMVDN Municipal tax on unoccupied homes in Navarra
// Facturae::TAX_IMSN Municipal tax on plots in Navarra
// Facturae::TAX_IMGSN Municipal tax on luxury expenses in Navarra
// Facturae::TAX_IMPN Municipal tax on advertising in Navarra
// Facturae::TAX_REIVA Special VAT regime for travel agencies
// Facturae::TAX_REIGIC Special IGIC regime: for travel agencies
// Facturae::TAX_REIPSI Special IPSI regime for travel agencies
// Facturae::TAX_IPS Taxes on insurance premiums
// Facturae::TAX_RLEA Surcharge intended to finance the liquidation functions of insurance entities
// Facturae::TAX_IVPEE Tax on the value of electricity production
// Facturae::TAX_IPCNG Tax on the production of spent nuclear fuel and radioactive waste resulting from the generation of nuclear power
// Facturae::TAX_IACNG Tax on the storage of spent nuclear fuel and radioactive waste in centralized facilities
// Facturae::TAX_IDEC Tax on Deposits in Credit Institutions
// Facturae::TAX_ILTCAC Tax on tobacco products in the Autonomous Community of the Canary Islands
// Facturae::TAX_IGFEI Tax on Fluorinated Greenhouse Gases
// Facturae::TAX_IRNR Non-Resident Income Tax
// Facturae::TAX_ISS Corporate tax
// FacturaeItem::SPECIAL_TAXABLE_EVENT_EXEMPT Subject and exempt operation
// FacturaeItem::SPECIAL_TAXABLE_EVENT_NON_SUBJECT Operation not subject
// FacturaeCentre::ROLE_CONTABLE
// eitherFacturaeCentre::ROLE_FISCAL Accounting Office
// FacturaeCentre::ROLE_GESTOR
// eitherFacturaeCentre::ROLE_RECEPTOR managing body
// FacturaeCentre::ROLE_TRAMITADOR
// eitherFacturaeCentre::ROLE_PAGADOR processing unit
// FacturaeCentre::ROLE_PROPONENTE proposing body
// FacturaeCentre::ROLE_B2B_FISCAL Fiscal receiver in FACeB2B
// FacturaeCentre::ROLE_B2B_PAYER Payer in FACeB2B
// FacturaeCentre::ROLE_B2B_BUYER Buyer at FACeB2B
// FacturaeCentre::ROLE_B2B_COLLECTOR Collector at FACeB2B
// FacturaeCentre::ROLE_B2B_SELLER Seller at FACeB2B
// FacturaeCentre::ROLE_B2B_PAYMENT_RECEIVER Payment recipient in FACeB2B
// FacturaeCentre::ROLE_B2B_COLLECTION_RECEIVER Collection receiver in FACeB2B
// FacturaeCentre::ROLE_B2B_ISSUER Issuer in FACeB2B
public function __construct(public Invoice $invoice)
{
}
public function run()
{
$fac = new Facturae();
$fac->setNumber('', $this->invoice->number);
$fac->setIssueDate($this->invoice->date);
$fac->setBuyer($this->buildBuyer());
$fac->setSeller($this->buildSeller());
$fac = $this->buildItems($fac);
}
private function buildItems(Facturae $fac): Facturae
{
foreach($this->invoice->line_items as $item)
{
$fac->addItem(new FacturaeItem([
'description' => $item->notes,
'quantity' => $item->quantity,
'unitPrice' => $item->cost,
'discountsAndRebates' => $item->discount,
'charges' => 0,
'taxes' => $this->buildRatesForItem($item),
'specialTaxableEvent' => FacturaeItem::SPECIAL_TAXABLE_EVENT_NON_SUBJECT,
'specialTaxableEventReason' => '',
'specialTaxableEventReasonDescription' => '',
]));
}
return $fac;
}
private function buildRatesForItem(\stdClass $item): array
{
$data = [];
if (strlen($item->tax_name1) > 1) {
$data[] = [$this->resolveTaxCode($item->tax_name1) => $item->tax_rate1];
}
if (strlen($item->tax_name2) > 1) {
$data[] = [$this->resolveTaxCode($item->tax_name2) => $item->tax_rate2];
}
if (strlen($item->tax_name3) > 1) {
$data[] = [$this->resolveTaxCode($item->tax_name3) => $item->tax_rate3];
}
return $data;
}
private function resolveTaxCode(string $tax_name)
{
return match (strtoupper($tax_name)) {
'IVA' => Facturae::TAX_IVA,
'IPSI' => Facturae::TAX_IPSI,
'IGIC' => Facturae::TAX_IGIC,
'IRPF' => Facturae::TAX_IRPF,
'IRNR' => Facturae::TAX_IRNR,
'ISS' => Facturae::TAX_ISS,
'REIVA' => Facturae::TAX_REIVA,
'REIGIC' => Facturae::TAX_REIGIC,
'REIPSI' => Facturae::TAX_REIPSI,
'IPS' => Facturae::TAX_IPS,
'RLEA' => Facturae::TAX_RLEA,
'IVPEE' => Facturae::TAX_IVPEE,
'IPCNG' => Facturae::TAX_IPCNG,
'IACNG' => Facturae::TAX_IACNG,
'IDEC' => Facturae::TAX_IDEC,
'ILTCAC' => Facturae::TAX_ILTCAC,
'IGFEI' => Facturae::TAX_IGFEI,
'ISS' => Facturae::TAX_ISS,
'IMGSN' => Facturae::TAX_IMGSN,
'IMSN' => Facturae::TAX_IMSN,
'IMPN' => Facturae::TAX_IMPN,
'IIIMAB' => Facturae::TAX_IIIMAB,
'ICIO' => Facturae::TAX_ICIO,
'IECDPCAC' => Facturae::TAX_IECDPCAC,
'IGTECM' => Facturae::TAX_IGTECM,
'IE' => Facturae::TAX_IE,
'RA' => Facturae::TAX_RA,
'ITPAJD' => Facturae::TAX_ITPAJD,
'OTHER' => Facturae::TAX_OTHER,
'IMVDN' => Facturae::TAX_IMVDN,
default => Facturae::TAX_IVA,
};
}
private function buildSeller(): FacturaeParty
{
$company = $this->invoice->company;
$seller = new FacturaeParty([
"isLegalEntity" => true, // Se asume true si se omite
"taxNumber" => $company->settings->vat_number,
"name" => $company->present()->name(),
"address" => $company->settings->address1,
"postCode" => $company->settings->postal_code,
"town" => $company->settings->city,
"province" => $company->settings->state,
"countryCode" => $company->country()->iso_3166_3, // Se asume España si se omite
"book" => "0", // Libro
"merchantRegister" => "RG", // Registro Mercantil
"sheet" => "1", // Hoja
"folio" => "2", // Folio
"section" => "3", // Sección
"volume" => "4", // Tomo
"email" => $company->settings->email,
"phone" => $company->settings->phone,
"fax" => "",
"website" => $company->settings->website,
"contactPeople" => $company->owner()->present()->name(),
// "cnoCnae" => "04647", // Clasif. Nacional de Act. Económicas
// "ineTownCode" => "280796" // Cód. de municipio del INE
]);
return $seller;
}
private function buildBuyer(): FacturaeParty
{
$buyer = new FacturaeParty([
"isLegalEntity" => $this->invoice->client->has_valid_vat_number,
"taxNumber" => $this->invoice->client->vat_number,
"name" => $this->invoice->client->present()->name(),
"firstSurname" => $this->invoice->client->present()->first_name(),
"lastSurname" => $this->invoice->client->present()->last_name(),
"address" => $this->invoice->client->address1,
"postCode" => $this->invoice->client->postal_code,
"town" => $this->invoice->client->city,
"province" => $this->invoice->client->state,
"countryCode" => $this->invoice->client->country->iso_3166_3, // Se asume España si se omite
"email" => $this->invoice->client->present()->email(),
"phone" => $this->invoice->client->present()->phone(),
"fax" => "",
"website" => $this->invoice->client->present()->website(),
"contactPeople" => $this->invoice->client->present()->first_name()." ".$this->invoice->client->present()->last_name(),
// "cnoCnae" => "04791", // Clasif. Nacional de Act. Económicas
// "ineTownCode" => "280796" // Cód. de municipio del INE
]);
return $buyer;
}
}

View File

@ -53,9 +53,11 @@
"halaxa/json-machine": "^0.7.0", "halaxa/json-machine": "^0.7.0",
"hashids/hashids": "^4.0", "hashids/hashids": "^4.0",
"hedii/laravel-gelf-logger": "^7.0", "hedii/laravel-gelf-logger": "^7.0",
"horstoeko/zugferd": "^1",
"imdhemy/laravel-purchases": "^1.7", "imdhemy/laravel-purchases": "^1.7",
"intervention/image": "^2.5", "intervention/image": "^2.5",
"invoiceninja/inspector": "^1.0", "invoiceninja/inspector": "^1.0",
"josemmo/facturae-php": "^1.7",
"laracasts/presenter": "^0.2.1", "laracasts/presenter": "^0.2.1",
"laravel/framework": "^9.3", "laravel/framework": "^9.3",
"laravel/slack-notification-channel": "^2.2", "laravel/slack-notification-channel": "^2.2",
@ -91,7 +93,6 @@
"turbo124/predis": "1.1.11", "turbo124/predis": "1.1.11",
"twilio/sdk": "^6.40", "twilio/sdk": "^6.40",
"webpatser/laravel-countries": "dev-master#75992ad", "webpatser/laravel-countries": "dev-master#75992ad",
"horstoeko/zugferd":"^1",
"wepay/php-sdk": "^0.3" "wepay/php-sdk": "^0.3"
}, },
"require-dev": { "require-dev": {

59
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "732ddc1c902c8a5a0412d8424df2ba6a", "content-hash": "7482363bb2c3f9f8fb07bbd3d517597b",
"packages": [ "packages": [
{ {
"name": "adrienrn/php-mimetyper", "name": "adrienrn/php-mimetyper",
@ -4026,6 +4026,63 @@
], ],
"time": "2023-02-17T17:40:48+00:00" "time": "2023-02-17T17:40:48+00:00"
}, },
{
"name": "josemmo/facturae-php",
"version": "v1.7.6",
"source": {
"type": "git",
"url": "https://github.com/josemmo/Facturae-PHP.git",
"reference": "fb876dd4b4515e0cd85b1be61f676bfee9a80f65"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/josemmo/Facturae-PHP/zipball/fb876dd4b4515e0cd85b1be61f676bfee9a80f65",
"reference": "fb876dd4b4515e0cd85b1be61f676bfee9a80f65",
"shasum": ""
},
"require": {
"php": ">=5.6"
},
"require-dev": {
"symfony/phpunit-bridge": "*"
},
"suggest": {
"ext-curl": "For communicating with remote TSA Servers and SOAP Web Services",
"ext-fileinfo": "For getting MIME types when using FacturaeFile",
"ext-openssl": "For signing and timestamping both invoices and SOAP requests",
"lib-libxml": "For parsing SOAP XML responses for FACe and FACeB2B"
},
"type": "library",
"autoload": {
"psr-4": {
"josemmo\\Facturae\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "josemmo",
"email": "josemmo@pm.me",
"homepage": "https://github.com/josemmo"
}
],
"description": "Librería para la generación, firma y envío de facturas electrónicas",
"homepage": "https://github.com/josemmo/Facturae-PHP",
"keywords": [
"face",
"faceb2b",
"facturae",
"xades"
],
"support": {
"issues": "https://github.com/josemmo/Facturae-PHP/issues",
"source": "https://github.com/josemmo/Facturae-PHP/tree/v1.7.6"
},
"time": "2023-03-25T10:09:02+00:00"
},
{ {
"name": "khanamiryan/qrcode-detector-decoder", "name": "khanamiryan/qrcode-detector-decoder",
"version": "1.0.6", "version": "1.0.6",