Sari la conținut

Operare zilnică

După ce un client e activ, fluxul operațional zilnic se învârte în jurul facturilor electronice din SFS (SIA „e-Factura”) și al task-urilor fiscale recurente. ASYDATA sincronizează automat facturile, le împinge ca carduri în Telegram, ține o aprobare internă separată de SFS și permite semnarea MSign cu auto-postare la SFS. Pagina descrie pas cu pas actorii și automatizările.

Corespondentul vizual (swimlane) e pe board-ul FigJam: ASYDATA pe Figma.

  • ASYDATA (System) — worker-ul de polling e-Factură + WebApi.
  • SFS / e-Factura (SPV) — sursa facturilor electronice.
  • Firma de contabilitate — responsabilul care aprobă/semnează din Telegram sau din aplicație.
  • Telegram — canalul unde apare cardul facturii.
  • MSign — semnătura electronică, cu auto-postare la SFS.

Un worker rulează periodic (interval TimeSpan.FromMinutes(20), deci ~20 min) pentru fiecare firmă cu credențiale SFS active. Logica de sincronizare e în EfacturaService.SyncInvoicesAsync (asydata-app-backend-dotnet/src/Asy.Infrastructure/Efactura/EfacturaService.cs):

  1. Discovery — SearchInvoices. Caută la SFS după ActorRole (1 = furnizor/seller, 2 = cumpărător/buyer) și după codurile de status, deduplicând pe (Seria, Number) și păstrând statusul cel mai avansat.
  2. Conținut — GetInvoicesBySeriaNumber. Aduce XML-ul brut, parsat cu EfacturaXmlParser (supplier, buyer, linii, TVA).
  3. Upsert PartnerMaster. Partenerul se caută/creează după IDNO, cu PartnerRelationship și conturi contabile implicite (incoming: Db 521.1; outgoing: Db 221.1 / Cr 611.1).
  4. Salvare fișiere în MinIO. XML ({firmId}/{seria}-{number}.xml) și PDF din GetInvoicesContentForPrint ({firmId}/{seria}-{number}.pdf). Cheile se păstrează pe Invoice.EFacturaXmlObjectKey / EFacturaPdfObjectKey.
  5. Creează Invoice (asydata-app-backend-dotnet/src/Asy.Domain/Invoicing/Invoice.cs), cu Direction (Incoming/Outgoing), EFacturaSfsStatus (codul brut SFS), EFacturaStatus (enum mapat) și ImportedFromSpvAt.

Invoice.EFacturaSfsStatus păstrează codul exact din SPV. Înțelesurile (din documentația modulului și din cod):

CodÎnțelesObservații
1Semnat de furnizorfacturile emise apar semnate de furnizor
3Acceptatcumpărătorul a acceptat
4Anulatstatus „prioritar” — câștigă la deduplicare; Invoice.Status = Cancelled
6Arhivat
7Trimisciclu lung — facturile primite în acest status declanșează cardul Telegram
8Semnat de cumpărătorla ciclu scurt, status informativ
10Transportat

Sincronizarea nu apelează direct Telegram. Pentru o factură primită relevantă, Invoice.RaiseEFacturaReceived(...) ridică un eveniment de domeniu care trece prin outbox → Kafka firm.events → consumeri (Telegram, web push). Consumerul Telegram postează un card cu butoane. Vezi flux event-driven și integrarea Telegram.

Butoanele cardului (renderate de EfacturaCardRenderer):

  • Aprobă / Respinge (approve / decline) — doar dacă factura nu e ciclu scurt.
  • Vezi PDF (pdf) și Vezi atașamentul (attach, dacă există).
  • Semnează (MSign) — buton URL (nu callback), spre endpoint-ul care inițiază semnarea.
  • Plătește (queue) — pune plata în coadă.

Aprobarea internă e separată de statusul SFS. Responsabilul apasă Aprobă/Respinge în card, iar serviciul apelează Invoice.ApproveInternally(...) / Invoice.RejectInternally(...):

InternalApprovalStatusÎnțeles
Pendingtocmai primită — așteaptă decizia responsabilului
Approvedaprobată intern → poate fi apoi semnată (MSign) la SFS
Rejectedrespinsă intern

Când factura aprobată se semnează prin MSign, cererea de semnătură (MsignRequest, asydata-app-backend-dotnet/src/Asy.Domain/Msign/MsignRequest.cs) primește un PostBackTarget de forma efactura:postinvoices:<actorRole>. La succesul callback-ului MSign:

  1. XML-ul semnat se postează automat la SFS prin PostInvoices (actor role furnizor 1 pentru outgoing, cumpărător 2 pentru incoming).
  2. Invoice.EFacturaStatus trece spre SentToEFactura/Accepted, EFacturaRef se completează, iar EFacturaSignedByName se setează din certificat.
  3. Răspunsul SFS se salvează în MsignRequest.PostBackResult pentru audit.

Când statusul SFS al unei facturi se schimbă în afara aplicației (semnat/respins/anulat în portalul SPV), o sincronizare ulterioară apelează Invoice.RaiseEFacturaStatusChanged() → eveniment → consumerul Telegram re-editează cardul existent (nu trimite un mesaj nou).

Separat de facturi, munca lunară (declarații fiscale, raportări) se materializează din reguli recurente. RecurringTaskRule (asydata-app-backend-dotnet/src/Asy.Domain/Tasks/RecurringTaskRule.cs) definește o regulă per client, cu Frequency (RecurringFrequency { Daily, Weekly, Monthly }), DayOfMonth, TimeOfDay (implicit 09:00), Timezone ("Europe/Chisinau").

Serviciul RecurringTaskRulesService (asydata-app-backend-dotnet/src/Asy.Infrastructure/Tasks/RecurringTaskRulesService.cs) generează câte un TaskItem la fiecare rulare (copiind titlu, descriere, prioritate, asignați impliciți), apoi actualizează LastRunAt, LastGeneratedTaskId, TotalGeneratedCount și recalculează NextRunAt.

Task-ul rezultat (asydata-app-backend-dotnet/src/Asy.Domain/Tasks/TaskItem.cs) parcurge:

TaskItemStatusÎnțeles
Todode făcut (implicit la creare)
Doingîn lucru
PendingReviewașteaptă revizuire (când RequiresReview)
Donefinalizat
Cancelledanulat

Prioritatea e TaskItemPriority { Low, Normal, High, Urgent }.