db); nlog("trying"); $model = $this->entity::withTrashed()->find($this->id); if (isset($model->backup->guid) && is_string($model->backup->guid)) { nlog("already sent!"); return; } if ($model->company->account->is_flagged) { nlog("Bad Actor"); return; //Bad Actor present. } $model = $model->service()->markSent()->save(); /** Concrete implementation current linked to Storecove only */ $p = new Peppol($model); $p->run(); $identifiers = $p->gateway->mutator->setClientRoutingCode()->getStorecoveMeta(); $result = $storecove->build($model)->getResult(); if (count($result['errors']) > 0) { nlog($result); return $result['errors']; } $payload = [ 'legal_entity_id' => $model->company->legal_entity_id, "idempotencyGuid" => \Illuminate\Support\Str::uuid(), 'document' => [ 'document_type' => 'invoice', 'invoice' => $result['document'], ], 'tenant_id' => $model->company->company_key, 'routing' => $identifiers['routing'], 'account_key' => $model->company->account->key, 'e_invoicing_token' => $model->company->account->e_invoicing_token, ]; //Self Hosted Sending Code Path if (Ninja::isSelfHost() && ($model instanceof Invoice) && $model->company->peppolSendingEnabled()) { $r = Http::withHeaders([...$this->getHeaders(), 'X-EInvoice-Token' => $model->company->account->e_invoicing_token]) ->post(config('ninja.hosted_ninja_url')."/api/einvoice/submission", $payload); if ($r->successful()) { if ($r->hasHeader('X-EINVOICE-QUOTA')) { $account = $model->company->account; $account->e_invoice_quota = (int) $r->header('X-EINVOICE-QUOTA'); $account->save(); } nlog("Model {$model->number} was successfully sent for third party processing via hosted Invoice Ninja"); $data = $r->json(); return $this->writeActivity($model, Activity::EINVOICE_DELIVERY_SUCCESS, $data['guid']); } if ($r->failed()) { nlog("Model {$model->number} failed to be accepted by invoice ninja, error follows:"); nlog($r->json()); $this->writeActivity($model, Activity::EINVOICE_DELIVERY_FAILURE, data_get($r->json(), 'errors.0.details', 'Unhandled error, check logs')); } } elseif (Ninja::isSelfHost()) { return; } //Run this check outside of the next loop as it will never send otherwise. if ($model->company->account->e_invoice_quota == 0 && $model->company->legal_entity_id) { $key = "e_invoice_quota_exhausted_{$model->company->account->key}"; if (! Cache::has($key)) { $mo = new EmailObject(); $mo->subject = ctrans('texts.notification_no_credits'); $mo->body = ctrans('texts.notification_no_credits_text'); $mo->text_body = ctrans('texts.notification_no_credits_text'); $mo->company_key = $model->company->company_key; $mo->html_template = 'email.template.generic'; $mo->to = [new Address($model->company->account->owner()->email, $model->company->account->owner()->name())]; $mo->email_template_body = 'notification_no_credits'; $mo->email_template_subject = 'notification_no_credits_text'; Email::dispatch($mo, $model->company); Cache::put($key, true, now()->addHours(24)); } return; } //Hosted Sending Code Path. if (($model instanceof Invoice) && $model->company->peppolSendingEnabled()) { if ($model->company->account->e_invoice_quota <= config('ninja.e_invoice_quota_warning')) { $key = "e_invoice_quota_low_{$model->company->account->key}"; if (! Cache::has($key)) { $mo = new EmailObject(); $mo->subject = ctrans('texts.notification_credits_low'); $mo->body = ctrans('texts.notification_credits_low_text'); $mo->text_body = ctrans('texts.notification_credits_low_text'); $mo->company_key = $model->company->company_key; $mo->html_template = 'email.template.generic'; $mo->to = [new Address($model->company->account->owner()->email, $model->company->account->owner()->name())]; $mo->email_template_body = 'notification_credits_low'; $mo->email_template_subject = 'notification_credits_low_text'; Email::dispatch($mo, $model->company); Cache::put($key, true, now()->addHours(24)); } } $sc = new \App\Services\EDocument\Gateway\Storecove\Storecove(); $r = $sc->sendJsonDocument($payload); // Successful send - update quota! if (is_string($r)) { $account = $model->company->account; $account->decrement('e_invoice_quota', 1); $account->refresh(); EInvoicingLog::create([ 'tenant_id' => $model->company->company_key, 'direction' => 'sent', 'legal_entity_id' => $model->company->legal_entity_id, 'notes' => $r, 'counter' => -1, ]); if ($account->e_invoice_quota == 0 && class_exists(\Modules\Admin\Jobs\Account\SuspendESendReceive::class)) { \Modules\Admin\Jobs\Account\SuspendESendReceive::dispatch($account->key); } return $this->writeActivity($model, Activity::EINVOICE_DELIVERY_SUCCESS, $r); } if ($r->failed()) { nlog("Model {$model->number} failed to be accepted by invoice ninja, error follows:"); $notes = data_get($r->json(), 'errors.0.details', 'Unhandled errors, check logs'); return $this->writeActivity($model, Activity::EINVOICE_DELIVERY_FAILURE, $notes); } } } private function writeActivity($model, int $activity_id, string $notes = '') { $activity = new Activity(); $activity->user_id = $model->user_id; $activity->client_id = $model->client_id ?? $model->vendor_id; $activity->company_id = $model->company_id; $activity->account_id = $model->company->account_id; $activity->activity_type_id = $activity_id; $activity->invoice_id = $model->id; $activity->notes = str_replace('"', '', $notes); $activity->is_system = true; $activity->save(); if ($activity_id == Activity::EINVOICE_DELIVERY_SUCCESS) { $backup = ($model->backup && is_object($model->backup)) ? $model->backup : new \stdClass(); $backup->guid = str_replace('"', '', $notes); $model->backup = $backup; $model->saveQuietly(); } } /** * Self hosted request headers * * **/ private function getHeaders(): array { return [ 'X-API-SELF-HOST-TOKEN' => config('ninja.license_key'), "X-Requested-With" => "XMLHttpRequest", "Content-Type" => "application/json", ]; } public function failed($exception = null) { if ($exception) { nlog("EXCEPTION:: SENDEDOCUMENT::"); nlog($exception->getMessage()); } // config(['queue.failed.driver' => null]); } public function middleware() { return [(new WithoutOverlapping($this->entity.$this->id.$this->db))->releaseAfter(60)->expireAfter(60)]; } }