diff --git a/app/Models/Account.php b/app/Models/Account.php index 58ae8bd431..124c4419b7 100644 --- a/app/Models/Account.php +++ b/app/Models/Account.php @@ -39,6 +39,7 @@ use Laracasts\Presenter\PresentableTrait; * @property string|null $plan_expires * @property string|null $user_agent * @property string|null $key + * @property string|null $e_invoice_token * @property int|null $payment_id * @property int $default_company_id * @property string|null $trial_started @@ -71,6 +72,7 @@ use Laracasts\Presenter\PresentableTrait; * @property string|null $account_sms_verification_number * @property bool $account_sms_verified * @property string|null $bank_integration_account_id + * @property string|null $e_invoicing_token * @property bool $is_trial * @property int $e_invoice_quota * @property-read int|null $bank_integrations_count diff --git a/app/Models/Client.php b/app/Models/Client.php index d79d9dcf40..c5866c8949 100644 --- a/app/Models/Client.php +++ b/app/Models/Client.php @@ -37,6 +37,7 @@ use Illuminate\Contracts\Translation\HasLocalePreference; * @property int $id * @property int $company_id * @property int $user_id + * @property int|null $location_id * @property int|null $assigned_user_id * @property string|null $name * @property string|null $website @@ -86,7 +87,11 @@ use Illuminate\Contracts\Translation\HasLocalePreference; * @property-read \App\Models\User $user * @property-read \App\Models\Company $company * @property-read \App\Models\Country|null $country + * @property-read \App\Models\Country|null $shipping_country + * @property-read \App\Models\Industry|null $industry + * @property-read \App\Models\Size|null $size * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $locations * @property-read \Illuminate\Database\Eloquent\Collection $company_ledger * @property-read \Illuminate\Database\Eloquent\Collection $contacts * @property-read \Illuminate\Database\Eloquent\Collection $credits diff --git a/app/Models/Company.php b/app/Models/Company.php index 12548843e0..d104f82432 100644 --- a/app/Models/Company.php +++ b/app/Models/Company.php @@ -93,6 +93,7 @@ use Laracasts\Presenter\PresentableTrait; * @property bool $markdown_enabled * @property bool $use_comma_as_decimal_place * @property bool $report_include_drafts + * @property bool $invoice_task_project_header * @property array|null $client_registration_fields * @property bool $convert_rate_to_client * @property bool $markdown_email_enabled @@ -129,11 +130,15 @@ use Laracasts\Presenter\PresentableTrait; * @property int|null $smtp_port * @property string|null $smtp_encryption * @property string|null $smtp_local_domain + * @property boolean $invoice_task_item_description * @property \App\DataMapper\QuickbooksSettings|null $quickbooks * @property boolean $smtp_verify_peer + * @property object|null $origin_tax_data * @property int|null $legal_entity_id * @property-read \App\Models\Account $account * @property-read \Illuminate\Database\Eloquent\Collection $activities + * @property-read \Illuminate\Database\Eloquent\Collection $locations + * @property-read \Illuminate\Database\Eloquent\Collection $verifactu_logs * @property-read int|null $activities_count * @property-read \Illuminate\Database\Eloquent\Collection $all_activities * @property-read int|null $all_activities_count diff --git a/app/Models/Credit.php b/app/Models/Credit.php index eb878cc149..6405c09384 100644 --- a/app/Models/Credit.php +++ b/app/Models/Credit.php @@ -91,6 +91,9 @@ use Illuminate\Database\Eloquent\SoftDeletes; * @property string|null $reminder2_sent * @property string|null $reminder3_sent * @property string|null $reminder_last_sent + * @property object|null $tax_data + * @property object|null $e_invoice + * @property int|null $location_id * @property float $paid_to_date * @property int|null $subscription_id * @property \Illuminate\Database\Eloquent\Collection $activities @@ -118,6 +121,7 @@ use Illuminate\Database\Eloquent\SoftDeletes; * @property \App\Models\Client $client * @property \App\Models\Vendor|null $vendor * @property-read mixed $pivot + * @property-read \App\Models\Location|null $location * @property-read \Illuminate\Database\Eloquent\Collection $activities * @property-read \Illuminate\Database\Eloquent\Collection $company_ledger * @property-read \Illuminate\Database\Eloquent\Collection $documents diff --git a/app/Models/Design.php b/app/Models/Design.php index 10aaa24baf..74304e7cb0 100644 --- a/app/Models/Design.php +++ b/app/Models/Design.php @@ -26,6 +26,7 @@ use Illuminate\Database\Eloquent\SoftDeletes; * @property object|null $design * @property bool $is_deleted * @property bool $is_template + * @property string|null $entities * @property int|null $created_at * @property int|null $updated_at * @property int|null $deleted_at diff --git a/app/Models/Expense.php b/app/Models/Expense.php index 824a2bf792..a91e580d24 100644 --- a/app/Models/Expense.php +++ b/app/Models/Expense.php @@ -74,6 +74,7 @@ use Illuminate\Database\Eloquent\SoftDeletes; * @property-read int|null $documents_count * @property-read mixed $hashed_id * @property-read \App\Models\PaymentType|null $payment_type + * @property-read \App\Models\Currency|null $invoice_currency * @property-read \App\Models\Project|null $project * @property-read \App\Models\PurchaseOrder|null $purchase_order * @property-read \App\Models\User $user diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php index c0a3fe8b60..3d28584b02 100644 --- a/app/Models/Invoice.php +++ b/app/Models/Invoice.php @@ -38,6 +38,7 @@ use App\Utils\Number; * @property object|null $e_invoice * @property int $client_id * @property int $user_id + * @property int|null $location_id * @property int|null $assigned_user_id * @property int $company_id * @property int $status_id @@ -125,6 +126,9 @@ use App\Utils\Number; * @property-read int|null $tasks_count * @property-read \App\Models\User $user * @property-read \App\Models\Vendor|null $vendor + * @property-read \App\Models\Location|null $location + * @property-read \App\Models\Quote|null $quote + * @property-read \Illuminate\Database\Eloquent\Collection $verifactu_logs * @property-read \Illuminate\Database\Eloquent\Collection $activities * @property-read \Illuminate\Database\Eloquent\Collection $company_ledger * @property-read \Illuminate\Database\Eloquent\Collection $credits diff --git a/app/Models/Location.php b/app/Models/Location.php index d637d6ca58..6392bd99ab 100644 --- a/app/Models/Location.php +++ b/app/Models/Location.php @@ -22,6 +22,8 @@ use Illuminate\Database\Eloquent\SoftDeletes; * @property int $id * @property int $company_id * @property int $user_id + * @property int $client_id + * @property int $vendor_id * @property int|null $assigned_user_id * @property string|null $name * @property string|null $website diff --git a/app/Models/Project.php b/app/Models/Project.php index ea47e6ef63..99dbccefc8 100644 --- a/app/Models/Project.php +++ b/app/Models/Project.php @@ -31,6 +31,7 @@ use Laracasts\Presenter\PresentableTrait; * @property bool $is_deleted * @property string|null $number * @property string $color + * @property int|null $current_hours * @property-read \App\Models\Client|null $client * @property-read \App\Models\Company $company * @property-read int|null $documents_count @@ -53,6 +54,10 @@ use Laracasts\Presenter\PresentableTrait; * @method static \Illuminate\Database\Eloquent\Builder|Project withoutTrashed() * @property-read \Illuminate\Database\Eloquent\Collection $documents * @property-read \Illuminate\Database\Eloquent\Collection $tasks + * @property-read \Illuminate\Database\Eloquent\Collection $invoices + * @property-read \Illuminate\Database\Eloquent\Collection $quotes + * @property-read \Illuminate\Database\Eloquent\Collection $expenses + * * @mixin \Eloquent */ class Project extends BaseModel diff --git a/app/Models/PurchaseOrder.php b/app/Models/PurchaseOrder.php index dc4c7000d4..0e7b94b406 100644 --- a/app/Models/PurchaseOrder.php +++ b/app/Models/PurchaseOrder.php @@ -59,6 +59,7 @@ use App\Events\PurchaseOrder\PurchaseOrderWasEmailed; * @property float $tax_rate3 * @property float $total_taxes * @property bool $uses_inclusive_taxes + * @property int|null $location_id * @property string|null $reminder1_sent * @property string|null $reminder2_sent * @property string|null $reminder3_sent @@ -100,6 +101,10 @@ use App\Events\PurchaseOrder\PurchaseOrderWasEmailed; * @property \App\Models\User $user * @property \App\Models\Vendor $vendor * @property \App\Models\PurchaseOrderInvitation $invitation + * @property \App\Models\Currency|null $currency + * @property \App\Models\Location|null $location + * @property object|null $tax_data + * @property object|null $e_invoice * @method static \Illuminate\Database\Eloquent\Builder|PurchaseOrder exclude($columns) * @method static \Database\Factories\PurchaseOrderFactory factory($count = null, $state = []) * @method static \Illuminate\Database\Eloquent\Builder|PurchaseOrder filter(\App\Filters\QueryFilters $filters) diff --git a/app/Models/Quote.php b/app/Models/Quote.php index cceffd59fc..8dc31bf291 100644 --- a/app/Models/Quote.php +++ b/app/Models/Quote.php @@ -81,6 +81,7 @@ use Illuminate\Database\Eloquent\SoftDeletes; * @property int $custom_surcharge_tax2 * @property int $custom_surcharge_tax3 * @property int $custom_surcharge_tax4 + * @property int|null $location_id * @property float $exchange_rate * @property float $amount * @property float $balance @@ -94,6 +95,9 @@ use Illuminate\Database\Eloquent\SoftDeletes; * @property string|null $reminder2_sent * @property string|null $reminder3_sent * @property string|null $reminder_last_sent + * @property int|null $location_id + * @property object|null $tax_data + * @property object|null $e_invoice * @property float $paid_to_date * @property int|null $subscription_id * @property \App\Models\User|null $assigned_user @@ -110,6 +114,7 @@ use Illuminate\Database\Eloquent\SoftDeletes; * @property-read \App\Models\Project|null $project * @property-read \App\Models\User $user * @property-read \App\Models\Vendor|null $vendor + * @property-read \App\Models\Location|null $location * @property-read \Illuminate\Database\Eloquent\Collection $activities * @property-read \Illuminate\Database\Eloquent\Collection $documents * @property-read \Illuminate\Database\Eloquent\Collection $history diff --git a/app/Models/RecurringInvoice.php b/app/Models/RecurringInvoice.php index 3745cdb4ee..26ff7510eb 100644 --- a/app/Models/RecurringInvoice.php +++ b/app/Models/RecurringInvoice.php @@ -83,6 +83,7 @@ use App\Models\Presenters\RecurringInvoicePresenter; * @property bool $custom_surcharge_tax3 * @property bool $custom_surcharge_tax4 * @property string|null $due_date_days + * @property int|null $location_id * @property string|null $partial_due_date * @property float $exchange_rate * @property float $paid_to_date @@ -108,6 +109,7 @@ use App\Models\Presenters\RecurringInvoicePresenter; * @property-read \App\Models\Subscription|null $subscription * @property-read \App\Models\User $user * @property-read \App\Models\Vendor|null $vendor + * @property-read \App\Models\Location|null $location * @method static \Illuminate\Database\Eloquent\Builder|BaseModel exclude($columns) * @method static \Database\Factories\RecurringInvoiceFactory factory($count = null, $state = []) * @method static \Illuminate\Database\Eloquent\Builder|RecurringInvoice filter(\App\Filters\QueryFilters $filters) diff --git a/app/Models/Subscription.php b/app/Models/Subscription.php index 14081ca9f3..f034c21009 100644 --- a/app/Models/Subscription.php +++ b/app/Models/Subscription.php @@ -57,6 +57,7 @@ use Illuminate\Database\Eloquent\SoftDeletes; * @property int $use_inventory_management * @property string|null $optional_product_ids * @property string|null $optional_recurring_product_ids + * @property string|null $steps * @property-read \App\Models\Company $company * @property-read mixed $hashed_id * @property-read \App\Models\GroupSetting|null $group_settings diff --git a/app/Models/Vendor.php b/app/Models/Vendor.php index 5726239f58..5714d1b51b 100644 --- a/app/Models/Vendor.php +++ b/app/Models/Vendor.php @@ -54,6 +54,7 @@ use Illuminate\Database\Eloquent\SoftDeletes; * @property string|null $custom_value4 * @property string|null $vendor_hash * @property string|null $public_notes + * @property string|null $classification * @property string|null $id_number * @property int|null $language_id * @property int|null $last_login @@ -71,6 +72,7 @@ use Illuminate\Database\Eloquent\SoftDeletes; * @property-read \Illuminate\Database\Eloquent\Collection $primary_contact * @property-read int|null $primary_contact_count * @property-read \App\Models\User $user + * @property-read \App\Models\Language|null $language * @method static \Illuminate\Database\Eloquent\Builder|BaseModel exclude($columns) * @method static \Database\Factories\VendorFactory factory($count = null, $state = []) * @method static \Illuminate\Database\Eloquent\Builder|Vendor filter(\App\Filters\QueryFilters $filters) @@ -85,6 +87,7 @@ use Illuminate\Database\Eloquent\SoftDeletes; * @property-read \Illuminate\Database\Eloquent\Collection $contacts * @property-read \Illuminate\Database\Eloquent\Collection $documents * @property-read \Illuminate\Database\Eloquent\Collection $primary_contact + * @property-read \Illuminate\Database\Eloquent\Collection $locations * @mixin \Eloquent */ class Vendor extends BaseModel diff --git a/app/Models/VerifactuLog.php b/app/Models/VerifactuLog.php index 4cdecdaa8f..d1e5c0dbc0 100644 --- a/app/Models/VerifactuLog.php +++ b/app/Models/VerifactuLog.php @@ -1,9 +1,19 @@ state); + return \App\Services\EDocument\Standards\Verifactu\Models\Invoice::unserialize($this->state); } } diff --git a/app/Services/EDocument/Standards/Validation/Verifactu/InvoiceValidator.php b/app/Services/EDocument/Standards/Validation/Verifactu/InvoiceValidator.php index ff785c923d..427151a766 100644 --- a/app/Services/EDocument/Standards/Validation/Verifactu/InvoiceValidator.php +++ b/app/Services/EDocument/Standards/Validation/Verifactu/InvoiceValidator.php @@ -74,40 +74,10 @@ class InvoiceValidator $errors[] = "Invalid FechaHoraHusoGenRegistro format. Expected: YYYY-MM-DDTHH:MM:SS+HH:MM, Got: {$fechaHora}"; } - // Validate FechaExpedicionFactura format (YYYY-MM-DD) - if ($invoice->getIdFactura() && method_exists($invoice->getIdFactura(), 'getFechaExpedicionFactura')) { - $fecha = $invoice->getIdFactura()->getFechaExpedicionFactura(); - if ($fecha && !preg_match('/^\d{4}-\d{2}-\d{2}$/', $fecha)) { - $errors[] = "Invalid FechaExpedicionFactura format. Expected: YYYY-MM-DD, Got: {$fecha}"; - } - } return $errors; } - /** - * Validate invoice numbers - */ - private function validateInvoiceNumbers(Invoice $invoice): array - { - $errors = []; - - if ($invoice->getIdFactura() && method_exists($invoice->getIdFactura(), 'getNumSerieFactura')) { - $numero = $invoice->getIdFactura()->getNumSerieFactura(); - - // Check for common problematic patterns - if (str_contains($numero, 'TEST') && strlen($numero) < 10) { - $errors[] = "Test invoice numbers should be at least 10 characters long"; - } - - // Check for special characters that might cause issues - if (preg_match('/[^A-Za-z0-9\-_]/', $numero)) { - $errors[] = "Invoice number contains invalid characters. Only letters, numbers, hyphens and underscores allowed"; - } - } - - return $errors; - } /** * Validate amounts @@ -145,18 +115,18 @@ class InvoiceValidator $errors = []; // Check if desglose exists and has valid tax rates - if ($invoice->getDesglose()) { - $desglose = $invoice->getDesglose(); + // if ($invoice->getDesglose()) { + // $desglose = $invoice->getDesglose(); - // Validate tax rates are standard Spanish rates - $validRates = [0, 4, 10, 21]; + // // Validate tax rates are standard Spanish rates + // $validRates = [0, 4, 10, 21]; - // This would need to be implemented based on your Desglose structure - // $taxRate = $desglose->getTipoImpositivo(); - // if (!in_array($taxRate, $validRates)) { - // $errors[] = "Invalid tax rate: {$taxRate}. Valid rates are: " . implode(', ', $validRates); - // } - } + // // This would need to be implemented based on your Desglose structure + // // $taxRate = $desglose->getTipoImpositivo(); + // // if (!in_array($taxRate, $validRates)) { + // // $errors[] = "Invalid tax rate: {$taxRate}. Valid rates are: " . implode(', ', $validRates); + // // } + // } return $errors; } diff --git a/app/Services/EDocument/Standards/Validation/XsltDocumentValidator.php b/app/Services/EDocument/Standards/Validation/XsltDocumentValidator.php index 55443592ca..d0895aee61 100644 --- a/app/Services/EDocument/Standards/Validation/XsltDocumentValidator.php +++ b/app/Services/EDocument/Standards/Validation/XsltDocumentValidator.php @@ -26,7 +26,7 @@ class XsltDocumentValidator // private string $peppol_stylesheetx = 'Services/EDocument/Standards/Validation/Peppol/Stylesheets/ubl_stylesheet.xslt'; // private string $peppol_stylesheet = 'Services/EDocument/Standards/Validation/Peppol/Stylesheets/ci_to_ubl_stylesheet.xslt'; - private array $errors = []; + public array $errors = []; public function __construct(public string $xml_document) { diff --git a/app/Services/EDocument/Standards/Verifactu.php b/app/Services/EDocument/Standards/Verifactu.php index d325ce9390..750a98ff60 100644 --- a/app/Services/EDocument/Standards/Verifactu.php +++ b/app/Services/EDocument/Standards/Verifactu.php @@ -60,7 +60,7 @@ class Verifactu extends AbstractService if($v_logs->count() >= 1){ $v_log = $v_logs->first(); $huella = $v_log->hash; - $document = InvoiceModification::fromInvoice($this->invoice, $v_log->deserialize()); + $document = InvoiceModification::createFromInvoice($document->getInvoice(), $v_log->deserialize()); } //3. cancelled => RegistroAnulacion @@ -69,6 +69,8 @@ class Verifactu extends AbstractService $document->setHuella($new_huella); $soapXml = $document->toSoapEnvelope(); + + return $this; } diff --git a/app/Services/EDocument/Standards/Verifactu/AeatClient.php b/app/Services/EDocument/Standards/Verifactu/AeatClient.php index 857713a479..2b4dac73ad 100644 --- a/app/Services/EDocument/Standards/Verifactu/AeatClient.php +++ b/app/Services/EDocument/Standards/Verifactu/AeatClient.php @@ -74,14 +74,7 @@ class AeatClient nlog($parsedResponse); - if($parsedResponse['success']){ - - //write the success activity - } - else { - //handle the failure - } - + return $parsedResponse; } } \ No newline at end of file diff --git a/app/Services/EDocument/Standards/Verifactu/Models/Encadenamiento.php b/app/Services/EDocument/Standards/Verifactu/Models/Encadenamiento.php index 4b87b0b436..58a0ccd545 100644 --- a/app/Services/EDocument/Standards/Verifactu/Models/Encadenamiento.php +++ b/app/Services/EDocument/Standards/Verifactu/Models/Encadenamiento.php @@ -7,8 +7,8 @@ use App\Services\EDocument\Standards\Verifactu\Models\RegistroAnterior; class Encadenamiento extends BaseXmlModel { protected ?string $primerRegistro = null; - protected ?EncadenamientoFacturaAnterior $registroAnterior = null; - protected ?EncadenamientoFacturaAnterior $registroPosterior = null; + protected ?RegistroAnterior $registroAnterior = null; + protected ?RegistroAnterior $registroPosterior = null; public function toXml(\DOMDocument $doc): \DOMElement { @@ -55,7 +55,7 @@ class Encadenamiento extends BaseXmlModel // Handle RegistroAnterior $registroAnterior = $element->getElementsByTagNameNS(self::XML_NAMESPACE, 'RegistroAnterior')->item(0); if ($registroAnterior) { - $encadenamiento->setRegistroAnterior(EncadenamientoFacturaAnterior::fromDOMElement($registroAnterior)); + $encadenamiento->setRegistroAnterior(RegistroAnterior::fromDOMElement($registroAnterior)); } return $encadenamiento; @@ -78,7 +78,7 @@ class Encadenamiento extends BaseXmlModel // Handle RegistroAnterior $registroAnterior = $element->getElementsByTagNameNS(self::XML_NAMESPACE, 'RegistroAnterior')->item(0); if ($registroAnterior) { - $encadenamiento->setRegistroAnterior(EncadenamientoFacturaAnterior::fromDOMElement($registroAnterior)); + $encadenamiento->setRegistroAnterior(RegistroAnterior::fromDOMElement($registroAnterior)); } return $encadenamiento; @@ -109,109 +109,14 @@ class Encadenamiento extends BaseXmlModel return $this; } - public function getRegistroPosterior(): ?EncadenamientoFacturaAnterior + public function getRegistroPosterior(): ?RegistroAnterior { return $this->registroPosterior; } - public function setRegistroPosterior(?EncadenamientoFacturaAnterior $registroPosterior): self + public function setRegistroPosterior(?RegistroAnterior $registroPosterior): self { $this->registroPosterior = $registroPosterior; return $this; } -} - -class EncadenamientoFacturaAnterior extends BaseXmlModel -{ - protected string $idEmisorFactura; - protected string $numSerieFactura; - protected string $fechaExpedicionFactura; - protected string $huella; - - public function toXml(\DOMDocument $doc): \DOMElement - { - $root = $this->createElement($doc, 'RegistroAnterior'); - - $root->appendChild($this->createElement($doc, 'IDEmisorFactura', $this->idEmisorFactura)); - $root->appendChild($this->createElement($doc, 'NumSerieFactura', $this->numSerieFactura)); - $root->appendChild($this->createElement($doc, 'FechaExpedicionFactura', $this->fechaExpedicionFactura)); - $root->appendChild($this->createElement($doc, 'Huella', $this->huella)); - - return $root; - } - - public static function fromDOMElement(\DOMElement $element): self - { - $registroAnterior = new self(); - - // Handle IDEmisorFactura - $idEmisorFactura = $element->getElementsByTagNameNS(self::XML_NAMESPACE, 'IDEmisorFactura')->item(0); - if ($idEmisorFactura) { - $registroAnterior->setIdEmisorFactura($idEmisorFactura->nodeValue); - } - - // Handle NumSerieFactura - $numSerieFactura = $element->getElementsByTagNameNS(self::XML_NAMESPACE, 'NumSerieFactura')->item(0); - if ($numSerieFactura) { - $registroAnterior->setNumSerieFactura($numSerieFactura->nodeValue); - } - - // Handle FechaExpedicionFactura - $fechaExpedicionFactura = $element->getElementsByTagNameNS(self::XML_NAMESPACE, 'FechaExpedicionFactura')->item(0); - if ($fechaExpedicionFactura) { - $registroAnterior->setFechaExpedicionFactura($fechaExpedicionFactura->nodeValue); - } - - // Handle Huella - $huella = $element->getElementsByTagNameNS(self::XML_NAMESPACE, 'Huella')->item(0); - if ($huella) { - $registroAnterior->setHuella($huella->nodeValue); - } - - return $registroAnterior; - } - - public function getIdEmisorFactura(): string - { - return $this->idEmisorFactura; - } - - public function setIdEmisorFactura(string $idEmisorFactura): self - { - $this->idEmisorFactura = $idEmisorFactura; - return $this; - } - - public function getNumSerieFactura(): string - { - return $this->numSerieFactura; - } - - public function setNumSerieFactura(string $numSerieFactura): self - { - $this->numSerieFactura = $numSerieFactura; - return $this; - } - - public function getFechaExpedicionFactura(): string - { - return $this->fechaExpedicionFactura; - } - - public function setFechaExpedicionFactura(string $fechaExpedicionFactura): self - { - $this->fechaExpedicionFactura = $fechaExpedicionFactura; - return $this; - } - - public function getHuella(): string - { - return $this->huella; - } - - public function setHuella(string $huella): self - { - $this->huella = $huella; - return $this; - } } \ No newline at end of file diff --git a/app/Services/EDocument/Standards/Verifactu/Models/InvoiceModification.php b/app/Services/EDocument/Standards/Verifactu/Models/InvoiceModification.php index 5b7d9c57bc..df74cb386c 100644 --- a/app/Services/EDocument/Standards/Verifactu/Models/InvoiceModification.php +++ b/app/Services/EDocument/Standards/Verifactu/Models/InvoiceModification.php @@ -284,66 +284,66 @@ class InvoiceModification extends BaseXmlModel implements XmlModelInterface /** * Create a proper RegistroAlta structure from the RegistroModificacion data */ - private function createRegistroAltaFromModificacion(\DOMDocument $doc): \DOMElement - { - $registroAlta = $doc->createElementNS(self::XML_NAMESPACE, self::XML_NAMESPACE_PREFIX . ':RegistroAlta'); + // private function createRegistroAltaFromModificacion(\DOMDocument $doc): \DOMElement + // { + // $registroAlta = $doc->createElementNS(self::XML_NAMESPACE, self::XML_NAMESPACE_PREFIX . ':RegistroAlta'); - // Add IDVersion - $registroAlta->appendChild($this->createElement($doc, 'IDVersion', $this->registroModificacion->getIdVersion())); + // // Add IDVersion + // $registroAlta->appendChild($this->createElement($doc, 'IDVersion', $this->registroModificacion->getIdVersion())); - // Create IDFactura structure - $idFactura = $doc->createElementNS(self::XML_NAMESPACE, self::XML_NAMESPACE_PREFIX . ':IDFactura'); - $idFactura->appendChild($this->createElement($doc, 'IDEmisorFactura', $this->registroModificacion->getTercero()?->getNif() ?? 'B12345678')); - $idFactura->appendChild($this->createElement($doc, 'NumSerieFactura', $this->registroModificacion->getIdFactura())); - $idFactura->appendChild($this->createElement($doc, 'FechaExpedicionFactura', '2025-01-01')); - $registroAlta->appendChild($idFactura); + // // Create IDFactura structure + // $idFactura = $doc->createElementNS(self::XML_NAMESPACE, self::XML_NAMESPACE_PREFIX . ':IDFactura'); + // $idFactura->appendChild($this->createElement($doc, 'IDEmisorFactura', $this->registroModificacion->getTercero()?->getNif() ?? 'B12345678')); + // $idFactura->appendChild($this->createElement($doc, 'NumSerieFactura', $this->registroModificacion->getIdFactura())); + // $idFactura->appendChild($this->createElement($doc, 'FechaExpedicionFactura', '2025-01-01')); + // $registroAlta->appendChild($idFactura); - // Add other required elements - if ($this->registroModificacion->getRefExterna()) { - $registroAlta->appendChild($this->createElement($doc, 'RefExterna', $this->registroModificacion->getRefExterna())); - } + // // Add other required elements + // if ($this->registroModificacion->getRefExterna()) { + // $registroAlta->appendChild($this->createElement($doc, 'RefExterna', $this->registroModificacion->getRefExterna())); + // } - $registroAlta->appendChild($this->createElement($doc, 'NombreRazonEmisor', $this->registroModificacion->getNombreRazonEmisor())); - $registroAlta->appendChild($this->createElement($doc, 'TipoFactura', $this->registroModificacion->getTipoFactura())); - $registroAlta->appendChild($this->createElement($doc, 'DescripcionOperacion', $this->registroModificacion->getDescripcionOperacion())); + // $registroAlta->appendChild($this->createElement($doc, 'NombreRazonEmisor', $this->registroModificacion->getNombreRazonEmisor())); + // $registroAlta->appendChild($this->createElement($doc, 'TipoFactura', $this->registroModificacion->getTipoFactura())); + // $registroAlta->appendChild($this->createElement($doc, 'DescripcionOperacion', $this->registroModificacion->getDescripcionOperacion())); - // Add Desglose - $desglose = $doc->createElementNS(self::XML_NAMESPACE, self::XML_NAMESPACE_PREFIX . ':Desglose'); - $desgloseFactura = $doc->createElementNS(self::XML_NAMESPACE, self::XML_NAMESPACE_PREFIX . ':DesgloseFactura'); - $desgloseFactura->appendChild($this->createElement($doc, 'Impuesto', '01')); - $desgloseFactura->appendChild($this->createElement($doc, 'ClaveRegimen', '01')); - $desgloseFactura->appendChild($this->createElement($doc, 'CalificacionOperacion', 'S1')); - $desgloseFactura->appendChild($this->createElement($doc, 'TipoImpositivo', '21')); - $desgloseFactura->appendChild($this->createElement($doc, 'BaseImponibleOimporteNoSujeto', '100.00')); - $desgloseFactura->appendChild($this->createElement($doc, 'CuotaRepercutida', '21.00')); - $desglose->appendChild($desgloseFactura); - $registroAlta->appendChild($desglose); + // // Add Desglose + // $desglose = $doc->createElementNS(self::XML_NAMESPACE, self::XML_NAMESPACE_PREFIX . ':Desglose'); + // $desgloseFactura = $doc->createElementNS(self::XML_NAMESPACE, self::XML_NAMESPACE_PREFIX . ':DesgloseFactura'); + // $desgloseFactura->appendChild($this->createElement($doc, 'Impuesto', '01')); + // $desgloseFactura->appendChild($this->createElement($doc, 'ClaveRegimen', '01')); + // $desgloseFactura->appendChild($this->createElement($doc, 'CalificacionOperacion', 'S1')); + // $desgloseFactura->appendChild($this->createElement($doc, 'TipoImpositivo', '21')); + // $desgloseFactura->appendChild($this->createElement($doc, 'BaseImponibleOimporteNoSujeto', '100.00')); + // $desgloseFactura->appendChild($this->createElement($doc, 'CuotaRepercutida', '21.00')); + // $desglose->appendChild($desgloseFactura); + // $registroAlta->appendChild($desglose); - $registroAlta->appendChild($this->createElement($doc, 'CuotaTotal', $this->registroModificacion->getCuotaTotal())); - $registroAlta->appendChild($this->createElement($doc, 'ImporteTotal', $this->registroModificacion->getImporteTotal())); + // $registroAlta->appendChild($this->createElement($doc, 'CuotaTotal', $this->registroModificacion->getCuotaTotal())); + // $registroAlta->appendChild($this->createElement($doc, 'ImporteTotal', $this->registroModificacion->getImporteTotal())); - // Add Encadenamiento - $encadenamiento = $doc->createElementNS(self::XML_NAMESPACE, self::XML_NAMESPACE_PREFIX . ':Encadenamiento'); - $encadenamiento->appendChild($this->createElement($doc, 'PrimerRegistro', 'S')); - $registroAlta->appendChild($encadenamiento); + // // Add Encadenamiento + // $encadenamiento = $doc->createElementNS(self::XML_NAMESPACE, self::XML_NAMESPACE_PREFIX . ':Encadenamiento'); + // $encadenamiento->appendChild($this->createElement($doc, 'PrimerRegistro', 'S')); + // $registroAlta->appendChild($encadenamiento); - // Add SistemaInformatico - $sistemaInformatico = $doc->createElementNS(self::XML_NAMESPACE, self::XML_NAMESPACE_PREFIX . ':SistemaInformatico'); - $sistemaInformatico->appendChild($this->createElement($doc, 'NombreRazon', 'Test System')); - $sistemaInformatico->appendChild($this->createElement($doc, 'NIF', 'B12345678')); - $sistemaInformatico->appendChild($this->createElement($doc, 'NombreSistemaInformatico', 'Test Software')); - $sistemaInformatico->appendChild($this->createElement($doc, 'IdSistemaInformatico', '01')); - $sistemaInformatico->appendChild($this->createElement($doc, 'Version', '1.0')); - $sistemaInformatico->appendChild($this->createElement($doc, 'NumeroInstalacion', '001')); - $sistemaInformatico->appendChild($this->createElement($doc, 'TipoUsoPosibleSoloVerifactu', 'S')); - $sistemaInformatico->appendChild($this->createElement($doc, 'TipoUsoPosibleMultiOT', 'S')); - $sistemaInformatico->appendChild($this->createElement($doc, 'IndicadorMultiplesOT', 'S')); - $registroAlta->appendChild($sistemaInformatico); + // // Add SistemaInformatico + // $sistemaInformatico = $doc->createElementNS(self::XML_NAMESPACE, self::XML_NAMESPACE_PREFIX . ':SistemaInformatico'); + // $sistemaInformatico->appendChild($this->createElement($doc, 'NombreRazon', 'Test System')); + // $sistemaInformatico->appendChild($this->createElement($doc, 'NIF', 'B12345678')); + // $sistemaInformatico->appendChild($this->createElement($doc, 'NombreSistemaInformatico', 'Test Software')); + // $sistemaInformatico->appendChild($this->createElement($doc, 'IdSistemaInformatico', '01')); + // $sistemaInformatico->appendChild($this->createElement($doc, 'Version', '1.0')); + // $sistemaInformatico->appendChild($this->createElement($doc, 'NumeroInstalacion', '001')); + // $sistemaInformatico->appendChild($this->createElement($doc, 'TipoUsoPosibleSoloVerifactu', 'S')); + // $sistemaInformatico->appendChild($this->createElement($doc, 'TipoUsoPosibleMultiOT', 'S')); + // $sistemaInformatico->appendChild($this->createElement($doc, 'IndicadorMultiplesOT', 'S')); + // $registroAlta->appendChild($sistemaInformatico); - $registroAlta->appendChild($this->createElement($doc, 'FechaHoraHusoGenRegistro', $this->registroModificacion->getFechaHoraHusoGenRegistro())); - $registroAlta->appendChild($this->createElement($doc, 'TipoHuella', $this->registroModificacion->getTipoHuella())); - $registroAlta->appendChild($this->createElement($doc, 'Huella', $this->registroModificacion->getHuella())); + // $registroAlta->appendChild($this->createElement($doc, 'FechaHoraHusoGenRegistro', $this->registroModificacion->getFechaHoraHusoGenRegistro())); + // $registroAlta->appendChild($this->createElement($doc, 'TipoHuella', $this->registroModificacion->getTipoHuella())); + // $registroAlta->appendChild($this->createElement($doc, 'Huella', $this->registroModificacion->getHuella())); - return $registroAlta; - } + // return $registroAlta; + // } } \ No newline at end of file diff --git a/app/Services/EDocument/Standards/Verifactu/RegistroAlta.php b/app/Services/EDocument/Standards/Verifactu/RegistroAlta.php index cdf98864c8..9fd562905f 100644 --- a/app/Services/EDocument/Standards/Verifactu/RegistroAlta.php +++ b/app/Services/EDocument/Standards/Verifactu/RegistroAlta.php @@ -103,7 +103,6 @@ class RegistroAlta { // Get the previous invoice log - /** @var ?VerifactuLog $v_log */ $this->v_log = $this->company->verifactu_logs()->first(); $this->current_timestamp = now()->setTimezone('Europe/Madrid')->format('Y-m-d\TH:i:s'); @@ -171,10 +170,10 @@ class RegistroAlta if($this->v_log){ $registro_anterior = new RegistroAnterior(); - $registro_anterior->setIDEmisorFactura($v_log->nif); - $registro_anterior->setNumSerieFactura($v_log->invoice_number); - $registro_anterior->setFechaExpedicionFactura($v_log->date->format('d-m-Y')); - $registro_anterior->setHuella($v_log->hash); + $registro_anterior->setIDEmisorFactura($this->v_log->nif); + $registro_anterior->setNumSerieFactura($this->v_log->invoice_number); + $registro_anterior->setFechaExpedicionFactura($this->v_log->date->format('d-m-Y')); + $registro_anterior->setHuella($this->v_log->hash); $encadenamiento->setRegistroAnterior($registro_anterior); @@ -206,6 +205,11 @@ class RegistroAlta return $this; } + public function getInvoice(): VerifactuInvoice + { + return $this->v_invoice; + } + private function calculateTaxType(string $tax_name): string { if(stripos($tax_name, 'iva') !== false) { diff --git a/app/Services/EDocument/Standards/Verifactu/ResponseProcessor.php b/app/Services/EDocument/Standards/Verifactu/ResponseProcessor.php index 10d72932fd..9dd1967f65 100644 --- a/app/Services/EDocument/Standards/Verifactu/ResponseProcessor.php +++ b/app/Services/EDocument/Standards/Verifactu/ResponseProcessor.php @@ -265,7 +265,8 @@ class ResponseProcessor $nodeList = $xpathObj->query($xpath); if ($nodeList && $nodeList->length > 0) { - return $nodeList->item(0); + $node = $nodeList->item(0); + return $node instanceof DOMElement ? $node : null; } return null; diff --git a/app/Services/Quickbooks/QuickbooksService.php b/app/Services/Quickbooks/QuickbooksService.php index 4afdef23d9..06affc3f40 100644 --- a/app/Services/Quickbooks/QuickbooksService.php +++ b/app/Services/Quickbooks/QuickbooksService.php @@ -97,38 +97,38 @@ class QuickbooksService return $this; } - private function checkDefaultAccounts(): self - { + // private function checkDefaultAccounts(): self + // { - $accountQuery = "SELECT * FROM Account WHERE AccountType IN ('Income', 'Cost of Goods Sold')"; + // $accountQuery = "SELECT * FROM Account WHERE AccountType IN ('Income', 'Cost of Goods Sold')"; - if (strlen($this->settings->default_income_account) == 0 || strlen($this->settings->default_expense_account) == 0) { + // if (strlen($this->settings->default_income_account) == 0 || strlen($this->settings->default_expense_account) == 0) { - nlog("Checking default accounts for company {$this->company->company_key}"); - $accounts = $this->sdk->Query($accountQuery); + // nlog("Checking default accounts for company {$this->company->company_key}"); + // $accounts = $this->sdk->Query($accountQuery); - $find_income_account = true; - $find_expense_account = true; + // $find_income_account = true; + // $find_expense_account = true; - foreach ($accounts as $account) { - if ($account->AccountType->value == 'Income' && $find_income_account) { - $this->settings->default_income_account = $account->Id->value; - $find_income_account = false; - } elseif ($account->AccountType->value == 'Cost of Goods Sold' && $find_expense_account) { - $this->settings->default_expense_account = $account->Id->value; - $find_expense_account = false; - } - } + // foreach ($accounts as $account) { + // if ($account->AccountType->value == 'Income' && $find_income_account) { + // $this->settings->default_income_account = $account->Id->value; + // $find_income_account = false; + // } elseif ($account->AccountType->value == 'Cost of Goods Sold' && $find_expense_account) { + // $this->settings->default_expense_account = $account->Id->value; + // $find_expense_account = false; + // } + // } - nlog($this->settings); + // nlog($this->settings); - $this->company->quickbooks->settings = $this->settings; - $this->company->save(); - } + // $this->company->quickbooks->settings = $this->settings; + // $this->company->save(); + // } - return $this; - } + // return $this; + // } private function checkToken(): self { diff --git a/app/Services/Quickbooks/Transformers/QuoteTransformer.php b/app/Services/Quickbooks/Transformers/QuoteTransformer.php index 28dd54c555..03d1f1ae88 100644 --- a/app/Services/Quickbooks/Transformers/QuoteTransformer.php +++ b/app/Services/Quickbooks/Transformers/QuoteTransformer.php @@ -130,25 +130,25 @@ class QuoteTransformer extends BaseTransformer } - private function getPayments(mixed $qb_data) - { - $payments = []; + // private function getPayments(mixed $qb_data) + // { + // $payments = []; - $qb_payments = data_get($qb_data, 'LinkedTxn', false) ?? []; + // $qb_payments = data_get($qb_data, 'LinkedTxn', false) ?? []; - if (!empty($qb_payments) && !isset($qb_payments[0])) { - $qb_payments = [$qb_payments]; - } + // if (!empty($qb_payments) && !isset($qb_payments[0])) { + // $qb_payments = [$qb_payments]; + // } - foreach ($qb_payments as $payment) { - if (data_get($payment, 'TxnType', false) == 'Payment') { - $payments[] = data_get($payment, 'TxnId', false); - } - } + // foreach ($qb_payments as $payment) { + // if (data_get($payment, 'TxnType', false) == 'Payment') { + // $payments[] = data_get($payment, 'TxnId', false); + // } + // } - return $payments; + // return $payments; - } + // } private function getLineItems(mixed $qb_data, array $tax_array) { diff --git a/app/Utils/HtmlEngine.php b/app/Utils/HtmlEngine.php index 1f90d30378..1f8b12a19d 100644 --- a/app/Utils/HtmlEngine.php +++ b/app/Utils/HtmlEngine.php @@ -757,7 +757,7 @@ class HtmlEngine if ($this->entity_string == 'invoice' && $this->entity->net_payments()->exists()) { $payment_list = '

'; - foreach ($this->entity->net_payments as $payment) { + foreach ($this->entity->net_payments as $payment) { //@phpstan-ignore-line $payment_list .= ctrans('texts.payment_subject') . ": " . $this->formatDate($payment->date, $this->client->date_format()) . " :: " . Number::formatMoney($payment->amount, $this->client) ." :: ". $payment->translatedType() . "
"; } diff --git a/composer.lock b/composer.lock index 47fca9d48a..0fd4ba831e 100644 --- a/composer.lock +++ b/composer.lock @@ -5384,16 +5384,16 @@ }, { "name": "laravel/octane", - "version": "v2.12.0", + "version": "v2.12.1", "source": { "type": "git", "url": "https://github.com/laravel/octane.git", - "reference": "d606f3dffc785032f11c23a017334c99800f2e40" + "reference": "4ca38b90d76f31b8c1e27873316c2db34450151c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/octane/zipball/d606f3dffc785032f11c23a017334c99800f2e40", - "reference": "d606f3dffc785032f11c23a017334c99800f2e40", + "url": "https://api.github.com/repos/laravel/octane/zipball/4ca38b90d76f31b8c1e27873316c2db34450151c", + "reference": "4ca38b90d76f31b8c1e27873316c2db34450151c", "shasum": "" }, "require": { @@ -5470,7 +5470,7 @@ "issues": "https://github.com/laravel/octane/issues", "source": "https://github.com/laravel/octane" }, - "time": "2025-07-18T15:50:14+00:00" + "time": "2025-07-25T15:03:05+00:00" }, { "name": "laravel/prompts", diff --git a/phpstan.neon b/phpstan.neon index 88abf4d150..ad438b6769 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -20,6 +20,7 @@ parameters: - 'app/PaymentDrivers/AuthorizePaymentDriver.php' - 'app/Http/Middleware/ThrottleRequestsWithPredis.php' - 'app/Utils/Traits/*' + - 'Modules/Accounting/*' universalObjectCratesClasses: - App\DataMapper\Tax\RuleInterface - App\DataMapper\FeesAndLimits diff --git a/tests/Feature/EInvoice/Verifactu/InvoiceCancellationTest.php b/tests/Feature/EInvoice/Verifactu/InvoiceCancellationTest.php index 0b2ca883fe..3b6bb2a5ab 100644 --- a/tests/Feature/EInvoice/Verifactu/InvoiceCancellationTest.php +++ b/tests/Feature/EInvoice/Verifactu/InvoiceCancellationTest.php @@ -155,7 +155,6 @@ class InvoiceCancellationTest extends TestCase $this->assertEquals('02', $cancellation->getEstado()); $this->assertEquals('Factura anulada por error', $cancellation->getDescripcionEstado()); - nlog($cancellation->toXmlString()); } public function testInvoiceCancellationXmlGeneration() diff --git a/tests/Feature/EInvoice/Verifactu/VerifactuFeatureTest.php b/tests/Feature/EInvoice/Verifactu/VerifactuFeatureTest.php index f7c49f4c9a..f2d1862b1a 100644 --- a/tests/Feature/EInvoice/Verifactu/VerifactuFeatureTest.php +++ b/tests/Feature/EInvoice/Verifactu/VerifactuFeatureTest.php @@ -127,7 +127,7 @@ class VerifactuFeatureTest extends TestCase $item = new InvoiceItem(); $item->product_key = '1234567890'; - $item->qty = 1; + $item->quantity = 1; $item->cost = 100; $item->notes = 'Test item'; $item->tax_name1 = 'IVA';