Updates for factuare invoices

This commit is contained in:
David Bomba 2023-05-08 19:11:14 +10:00
parent 0f4113ca57
commit f2df6c2e79
6 changed files with 201 additions and 71 deletions

View File

@ -212,6 +212,9 @@ class FacturaEInvoice extends AbstractService
} }
if(count($data) == 0)
$data[Facturae::TAX_IVA] = 0;
return $data; return $data;
} }
@ -258,29 +261,30 @@ class FacturaEInvoice extends AbstractService
$company = $this->invoice->company; $company = $this->invoice->company;
$seller = new FacturaeParty([ $seller = new FacturaeParty([
"isLegalEntity" => true, // Se asume true si se omite "isLegalEntity" => true, // Se asume true si se omite
"taxNumber" => $company->settings->vat_number, "taxNumber" => $company->settings->vat_number,
"name" => $company->present()->name(), "name" => substr($company->present()->name(), 0, 40),
"address" => $company->settings->address1, "address" => substr($company->settings->address1, 0, 80),
"postCode" => $company->settings->postal_code, "postCode" => substr($this->invoice->client->postal_code, 0, 5),
"town" => $company->settings->city, "town" => substr($company->settings->city, 0, 50),
"province" => $company->settings->state, "province" => substr($company->settings->state, 0, 20),
"countryCode" => $company->country()->iso_3166_3, // Se asume España si se omite "countryCode" => $company->country()->iso_3166_3, // Se asume España si se omite
"book" => "0", // Libro "book" => "0", // Libro
"merchantRegister" => "RG", // Registro Mercantil "merchantRegister" => "RG", // Registro Mercantil
"sheet" => "1", // Hoja "sheet" => "1", // Hoja
"folio" => "2", // Folio "folio" => "2", // Folio
"section" => "3", // Sección "section" => "3", // Sección
"volume" => "4", // Tomo "volume" => "4", // Tomo
"email" => $company->settings->email, "email" => substr($company->settings->email, 0, 60),
"phone" => $company->settings->phone, "phone" => substr($company->settings->phone, 0, 15),
"fax" => "", "fax" => "",
"website" => $company->settings->website, "website" => substr($company->settings->website, 0, 50),
"contactPeople" => $company->owner()->present()->name(), "contactPeople" => substr($company->owner()->present()->name(), 0, 40),
// "cnoCnae" => "04647", // Clasif. Nacional de Act. Económicas // "cnoCnae" => "04647", // Clasif. Nacional de Act. Económicas
// "ineTownCode" => "280796" // Cód. de municipio del INE // "ineTownCode" => "280796" // Cód. de municipio del INE
]); ]);
$this->fac->setSeller($seller); $this->fac->setSeller($seller);
return $this; return $this;
@ -292,19 +296,19 @@ class FacturaEInvoice extends AbstractService
$buyer = new FacturaeParty([ $buyer = new FacturaeParty([
"isLegalEntity" => $this->invoice->client->has_valid_vat_number, "isLegalEntity" => $this->invoice->client->has_valid_vat_number,
"taxNumber" => $this->invoice->client->vat_number, "taxNumber" => $this->invoice->client->vat_number,
"name" => $this->invoice->client->present()->name(), "name" => substr($this->invoice->client->present()->name(),0, 40),
"firstSurname" => $this->invoice->client->present()->first_name(), "firstSurname" => substr($this->invoice->client->present()->first_name(),0, 40),
"lastSurname" => $this->invoice->client->present()->last_name(), "lastSurname" => substr($this->invoice->client->present()->last_name(),0, 40),
"address" => $this->invoice->client->address1, "address" => substr($this->invoice->client->address1,0, 80),
"postCode" => $this->invoice->client->postal_code, "postCode" => substr($this->invoice->client->postal_code,0,5),
"town" => $this->invoice->client->city, "town" => substr($this->invoice->client->city,0, 50),
"province" => $this->invoice->client->state, "province" => substr($this->invoice->client->state,0, 20),
"countryCode" => $this->invoice->client->country->iso_3166_3, // Se asume España si se omite "countryCode" => $this->invoice->client->country->iso_3166_3, // Se asume España si se omite
"email" => $this->invoice->client->present()->email(), "email" => substr($this->invoice->client->present()->email(),0, 60),
"phone" => $this->invoice->client->present()->phone(), "phone" => substr($this->invoice->client->present()->phone(),0, 15),
"fax" => "", "fax" => "",
"website" => substr($this->invoice->client->present()->website(), 0 ,60), "website" => substr($this->invoice->client->present()->website(), 0 ,60),
"contactPeople" => $this->invoice->client->present()->first_name()." ".$this->invoice->client->present()->last_name(), "contactPeople" => substr($this->invoice->client->present()->first_name()." ".$this->invoice->client->present()->last_name(), 0, 40),
// "cnoCnae" => "04791", // Clasif. Nacional de Act. Económicas // "cnoCnae" => "04791", // Clasif. Nacional de Act. Económicas
// "ineTownCode" => "280796" // Cód. de municipio del INE // "ineTownCode" => "280796" // Cód. de municipio del INE
]); ]);

View File

@ -16907,9 +16907,10 @@ components:
type: number type: number
example: 8.00 example: 8.00
line_items: line_items:
description: "Array of line items included in the invoice" type: array
type: object description: 'An array of objects which define the line items of the invoice'
example: "[{item1}, {item2}]" items:
$ref: '#/components/schemas/InvoiceItem'
discount: discount:
description: "The discount applied to the invoice" description: "The discount applied to the invoice"
type: number type: number
@ -17324,83 +17325,116 @@ components:
quantity: quantity:
type: integer type: integer
example: 1 example: 1
description: 'The quantity of the product offered for this line item'
cost: cost:
type: number type: number
format: float format: float
example: 10.00 example: 10.00
description: 'The cost of the product offered for this line item'
product_key: product_key:
type: string type: string
example: 'Product key' example: 'Product key'
description: 'The product key of the product offered for this line item (Referred to as Product in the product tab)'
product_cost: product_cost:
type: number type: number
format: float format: float
example: 10.00 example: 10.00
description: 'The cost of the product offered for this line item (Referred to as Cost in the product tab)'
notes: notes:
type: string type: string
example: 'Item notes' example: 'Item notes'
description: 'The notes/description for the product offered for this line item'
discount: discount:
type: number type: number
format: float format: float
example: 5.00 example: 5.00
description: 'The discount applied to the product offered for this line item'
is_amount_discount: is_amount_discount:
type: boolean type: boolean
example: false example: false
description: 'Indicates whether the discount applied to the product offered for this line item is a fixed amount or a percentage'
tax_name1: tax_name1:
type: string type: string
example: 'Tax name 1' example: 'GST'
description: 'The name of the first tax applied to the product offered for this line item'
tax_rate1: tax_rate1:
type: number type: number
format: float format: float
example: 10.00 example: 10.00
description: 'The rate of the first tax applied to the product offered for this line item'
tax_name2: tax_name2:
type: string type: string
example: 'Tax name 2' example: 'VAT'
description: 'The name of the second tax applied to the product offered for this line item'
tax_rate2: tax_rate2:
type: number type: number
format: float format: float
example: 5.00 example: 5.00
description: 'The rate of the second tax applied to the product offered for this line item'
tax_name3: tax_name3:
type: string type: string
example: 'Tax name 3' example: 'CA Sales Tax'
description: 'The name of the third tax applied to the product offered for this line item'
tax_rate3: tax_rate3:
type: number type: number
format: float format: float
example: 3.00 example: 3.00
description: 'The rate of the third tax applied to the product offered for this line item'
sort_id: sort_id:
type: string type: string
example: '0' example: '0'
description: 'Deprecated'
deprecated: true
line_total: line_total:
type: number type: number
format: float format: float
example: 10.00 example: 10.00
description: 'The total amount of the product offered for this line item'
readOnly: true
gross_line_total: gross_line_total:
type: number type: number
format: float format: float
example: 15.00 example: 15.00
description: 'The total amount of the product offered for this line item before discounts'
readOnly: true
tax_amount: tax_amount:
type: number type: number
format: float format: float
example: 1.00 example: 1.00
description: 'The total amount of tax applied to the product offered for this line item'
readOnly: true
date: date:
type: string type: string
format: date-time format: date-time
example: '2023-03-19T00:00:00Z' example: '2023-03-19T00:00:00Z'
description: 'Deprecated'
deprecated: true
custom_value1: custom_value1:
type: string type: string
example: 'Custom value 1' example: 'Custom value 1'
description: 'The first custom value of the product offered for this line item'
custom_value2: custom_value2:
type: string type: string
example: 'Custom value 2' example: 'Custom value 2'
description: 'The second custom value of the product offered for this line item'
custom_value3: custom_value3:
type: string type: string
example: 'Custom value 3' example: 'Custom value 3'
description: 'The third custom value of the product offered for this line item'
custom_value4: custom_value4:
type: string type: string
example: 'Custom value 4' example: 'Custom value 4'
description: 'The fourth custom value of the product offered for this line item'
type_id: type_id:
type: string type: string
example: '1' example: '1'
description: '1 = product, 2 = service, 3 unpaid gateway fee, 4 paid gateway fee, 5 late fee, 6 expense' description: '1 = product, 2 = service, 3 unpaid gateway fee, 4 paid gateway fee, 5 late fee, 6 expense'
default: '1'
tax_id:
type: string
example: '1'
default: '1'
description: 'The tax ID of the product: 1 product, 2 service, 3 digital, 4 shipping, 5 exempt, 5 reduced tax, 7 override, 8 zero rate, 9 reverse tax'
CompanyUser: CompanyUser:
properties: properties:
permissions: permissions:
@ -19431,17 +19465,17 @@ components:
cost: cost:
type: number type: number
format: double format: double
description: 'The cost of the product.' description: 'The cost of the product. (Your purchase price for this product)'
example: 10.0 example: 10.0
price: price:
type: number type: number
format: double format: double
description: 'The price of the product.' description: 'The price of the product that you are charging.'
example: 20.0 example: 20.0
quantity: quantity:
type: number type: number
format: double format: double
description: 'The quantity of the product.' description: 'The quantity of the product. (used as a default)'
example: 5.0 example: 5.0
tax_name1: tax_name1:
type: string type: string

View File

@ -73,9 +73,10 @@
type: number type: number
example: 8.00 example: 8.00
line_items: line_items:
description: "Array of line items included in the invoice" type: array
type: object description: 'An array of objects which define the line items of the invoice'
example: "[{item1}, {item2}]" items:
$ref: '#/components/schemas/InvoiceItem'
discount: discount:
description: "The discount applied to the invoice" description: "The discount applied to the invoice"
type: number type: number

View File

@ -4,80 +4,113 @@
quantity: quantity:
type: integer type: integer
example: 1 example: 1
description: 'The quantity of the product offered for this line item'
cost: cost:
type: number type: number
format: float format: float
example: 10.00 example: 10.00
description: 'The cost of the product offered for this line item'
product_key: product_key:
type: string type: string
example: 'Product key' example: 'Product key'
description: 'The product key of the product offered for this line item (Referred to as Product in the product tab)'
product_cost: product_cost:
type: number type: number
format: float format: float
example: 10.00 example: 10.00
description: 'The cost of the product offered for this line item (Referred to as Cost in the product tab)'
notes: notes:
type: string type: string
example: 'Item notes' example: 'Item notes'
description: 'The notes/description for the product offered for this line item'
discount: discount:
type: number type: number
format: float format: float
example: 5.00 example: 5.00
description: 'The discount applied to the product offered for this line item'
is_amount_discount: is_amount_discount:
type: boolean type: boolean
example: false example: false
description: 'Indicates whether the discount applied to the product offered for this line item is a fixed amount or a percentage'
tax_name1: tax_name1:
type: string type: string
example: 'Tax name 1' example: 'GST'
description: 'The name of the first tax applied to the product offered for this line item'
tax_rate1: tax_rate1:
type: number type: number
format: float format: float
example: 10.00 example: 10.00
description: 'The rate of the first tax applied to the product offered for this line item'
tax_name2: tax_name2:
type: string type: string
example: 'Tax name 2' example: 'VAT'
description: 'The name of the second tax applied to the product offered for this line item'
tax_rate2: tax_rate2:
type: number type: number
format: float format: float
example: 5.00 example: 5.00
description: 'The rate of the second tax applied to the product offered for this line item'
tax_name3: tax_name3:
type: string type: string
example: 'Tax name 3' example: 'CA Sales Tax'
description: 'The name of the third tax applied to the product offered for this line item'
tax_rate3: tax_rate3:
type: number type: number
format: float format: float
example: 3.00 example: 3.00
description: 'The rate of the third tax applied to the product offered for this line item'
sort_id: sort_id:
type: string type: string
example: '0' example: '0'
description: 'Deprecated'
deprecated: true
line_total: line_total:
type: number type: number
format: float format: float
example: 10.00 example: 10.00
description: 'The total amount of the product offered for this line item'
readOnly: true
gross_line_total: gross_line_total:
type: number type: number
format: float format: float
example: 15.00 example: 15.00
description: 'The total amount of the product offered for this line item before discounts'
readOnly: true
tax_amount: tax_amount:
type: number type: number
format: float format: float
example: 1.00 example: 1.00
description: 'The total amount of tax applied to the product offered for this line item'
readOnly: true
date: date:
type: string type: string
format: date-time format: date-time
example: '2023-03-19T00:00:00Z' example: '2023-03-19T00:00:00Z'
description: 'Deprecated'
deprecated: true
custom_value1: custom_value1:
type: string type: string
example: 'Custom value 1' example: 'Custom value 1'
description: 'The first custom value of the product offered for this line item'
custom_value2: custom_value2:
type: string type: string
example: 'Custom value 2' example: 'Custom value 2'
description: 'The second custom value of the product offered for this line item'
custom_value3: custom_value3:
type: string type: string
example: 'Custom value 3' example: 'Custom value 3'
description: 'The third custom value of the product offered for this line item'
custom_value4: custom_value4:
type: string type: string
example: 'Custom value 4' example: 'Custom value 4'
description: 'The fourth custom value of the product offered for this line item'
type_id: type_id:
type: string type: string
example: '1' example: '1'
description: '1 = product, 2 = service, 3 unpaid gateway fee, 4 paid gateway fee, 5 late fee, 6 expense' description: '1 = product, 2 = service, 3 unpaid gateway fee, 4 paid gateway fee, 5 late fee, 6 expense'
default: '1'
tax_id:
type: string
example: '1'
default: '1'
description: 'The tax ID of the product: 1 product, 2 service, 3 digital, 4 shipping, 5 exempt, 5 reduced tax, 7 override, 8 zero rate, 9 reverse tax'

View File

@ -55,17 +55,17 @@
cost: cost:
type: number type: number
format: double format: double
description: 'The cost of the product.' description: 'The cost of the product. (Your purchase price for this product)'
example: 10.0 example: 10.0
price: price:
type: number type: number
format: double format: double
description: 'The price of the product.' description: 'The price of the product that you are charging.'
example: 20.0 example: 20.0
quantity: quantity:
type: number type: number
format: double format: double
description: 'The quantity of the product.' description: 'The quantity of the product. (used as a default)'
example: 5.0 example: 5.0
tax_name1: tax_name1:
type: string type: string

View File

@ -13,8 +13,6 @@ namespace Tests\Feature\EInvoice;
use Tests\TestCase; use Tests\TestCase;
use Tests\MockAccountData; use Tests\MockAccountData;
use Http\Message\CookieJar;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
use App\Services\Invoice\EInvoice\FacturaEInvoice; use App\Services\Invoice\EInvoice\FacturaEInvoice;
use Illuminate\Routing\Middleware\ThrottleRequests; use Illuminate\Routing\Middleware\ThrottleRequests;
@ -51,29 +49,89 @@ class FacturaeTest extends TestCase
nlog($f->run()); nlog($f->run());
// $this->assertTrue($this->validateInvoiceXML($path)); $this->assertTrue($this->validateInvoiceXML($path));
} }
// private function validateInvoiceXML($path) { // protected function validateInvoiceXML($path, $validateSignature=false) {
// // Prepare file to upload
// if (function_exists('curl_file_create')) {
// $postFile = curl_file_create($path);
// } else {
// $postFile = "@" . realpath($path);
// }
// // Send upload request
// $ch = curl_init();
// curl_setopt_array($ch, array(
// CURLOPT_RETURNTRANSFER => true,
// CURLOPT_FOLLOWLOCATION => true,
// CURLOPT_URL => "http://plataforma.firma-e.com/VisualizadorFacturae/index2.jsp",
// CURLOPT_POST => 1,
// CURLOPT_POSTFIELDS => array(
// "referencia" => $postFile,
// "valContable" => "on",
// "valFirma" => $validateSignature ? "on" : "off",
// "aceptarCondiciones" => "on",
// "submit" => "Siguiente"
// ),
// CURLOPT_COOKIEJAR => base_path()."/cookie.txt"
// ));
// $res = curl_exec($ch);
// curl_close($ch);
// unset($ch);
// nlog($res);
// if (strpos($res, "window.open('facturae.jsp'") === false) {
// $this->expectException(\UnexpectedValueException::class);
// }
// // Fetch results
// $ch = curl_init();
// curl_setopt_array($ch, array(
// CURLOPT_RETURNTRANSFER => true,
// CURLOPT_FOLLOWLOCATION => true,
// CURLOPT_URL => "http://plataforma.firma-e.com/VisualizadorFacturae/facturae.jsp",
// CURLOPT_COOKIEFILE => base_path()."/cookie.txt"
// ));
// $res = curl_exec($ch);
// curl_close($ch);
// unset($ch);
// nlog($res);
// // Validate results
// $this->assertNotEmpty($res, 'Invalid Validator Response');
// $this->assertNotEmpty(strpos($res, 'euro_ok.png'), 'Invalid XML Format');
// if ($validateSignature) {
// $this->assertNotEmpty(strpos($res, '>Nivel de Firma Válido<'), 'Invalid Signature');
// }
// if (strpos($res, '>Sellos de Tiempo<') !== false) {
// $this->assertNotEmpty(strpos($res, '>XAdES_T<'), 'Invalid Timestamp');
// }
// }
// private function validateInvoiceXML($path)
// {
// $client = new \GuzzleHttp\Client(['cookies' => true]);
// $response = $client->request('POST', 'https://face.gob.es/api/v1/herramientas/validador',[
// 'multipart' => [
// [
// 'name' => 'validador[factura]',
// 'contents' => Storage::get($path),
// ],
// ]
// ]);
// $response = $client->request('POST', 'http://plataforma.firma-e.com/VisualizadorFacturae/facturae.jsp');
// $body = $response->getBody();
// $stringBody = (string) $body;
// echo print_r($stringBody,1);
// }
// $jar = (new \GuzzleHttp\Cookie\CookieJar())->toArray();
// echo print_r($jar);
// $response = Http::withCookies($jar, '.ninja.test')->attach(
// 'xmlFile',
// Storage::get($path),
// basename($path)
// )->post('https://viewer.facturadirecta.com/dp/viewer/upload.void'); // Instance of Guzzle/CookieJar
// echo print_r($jar);
// $response = Http::withCookies($jar, '.ninja.test')->post('https://viewer.facturadirecta.com/dp/viewer/viewer.void');
// echo print_r($response->body(), 1);
// }
} }