Notas do varejoRetail notesNotas del punto de venta
Um bloco de anotações por varejo: título, texto livre e até três anexos (foto, PDF, documento). O representante de vendas cria, edita e exclui notas; cada mudança é enviada ao backend por uma transação (NoteUploadAPI). A leitura é só do cache — as notas chegam embutidas no varejo dentro da visita — e a tela mostra a alteração na hora (otimista) até o backend reconciliar.
A notes pad per retail: title, free text and up to three attachments (photo, PDF, document). The sales rep creates, edits and deletes notes; each change is sent to the backend through one transaction (NoteUploadAPI). The read is cache-only — notes arrive embedded in the retail inside the visit — and the screen shows the change immediately (optimistic) until the backend reconciles.
Un bloc de anotaciones por punto de venta: título, texto libre y hasta tres adjuntos (foto, PDF, documento). El representante de ventas crea, edita y elimina notas; cada cambio se envía al backend por una transacción (NoteUploadAPI). La lectura es solo del caché — las notas llegan embebidas en el punto de venta dentro de la visita — y la pantalla muestra el cambio al instante (optimista) hasta que el backend reconcilia.
O que é e para que serveWhat it is and what it's forQué es y para qué sirve
As Notas são um caderno de anotações preso a um varejo. Servem para registrar o que aconteceu na relação com o ponto de venda — acordos, combinados, pendências, evidências — com título, texto e anexos. Cada nota pertence ao varejo (não a uma visita específica), então reaparece sempre que aquele varejo é aberto. Notes are a notepad attached to a retail. They record what happened in the relationship with the store — agreements, arrangements, pending items, evidence — with a title, text and attachments. Each note belongs to the retail (not to a specific visit), so it reappears whenever that retail is opened. Las Notas son un bloc de anotaciones ligado a un punto de venta. Sirven para registrar lo que pasó en la relación con la tienda — acuerdos, arreglos, pendientes, evidencias — con título, texto y adjuntos. Cada nota pertenece al punto de venta (no a una visita específica), por lo que reaparece cada vez que ese punto de venta se abre.
O que tem numa nota?What's in a note?¿Qué hay en una nota?
Título, texto livre e até três anexos (foto, PDF ou documento), além da data.Title, free text and up to three attachments (photo, PDF or document), plus the date.Título, texto libre y hasta tres adjuntos (foto, PDF o documento), además de la fecha.
O que posso fazer?What can I do?¿Qué puedo hacer?
Criar, editar e excluir notas. Cada mudança vai para o backend na hora.Create, edit and delete notes. Each change goes to the backend right away.Crear, editar y eliminar notas. Cada cambio va al backend al instante.
Aparece na hora?Shows instantly?¿Aparece al instante?
Sim. A alteração aparece na tela imediatamente e é confirmada quando o backend reconcilia (arraste para atualizar).Yes. The change appears on screen immediately and is confirmed once the backend reconciles (pull to refresh).Sí. El cambio aparece en pantalla de inmediato y se confirma cuando el backend reconcilia (deslice para actualizar).
Só no ChileChile onlySolo Chile A ferramenta Notas só aparece na grade de ferramentas do Chile (CL). Nos demais mercados a ferramenta não existe (ver Mercados). The Notes tool only shows in the Chile (CL) tools grid. In the other markets the tool doesn't exist (see Markets). La herramienta Notas solo aparece en la grilla de herramientas de Chile (CL). En los demás mercados la herramienta no existe (ver Mercados).
Como acessarHow to openCómo acceder
- Abra uma visitaOpen a visitAbra una visitaEntre no Detalhe da visita do varejo desejado.Go to the desired retail's Visit detail.Entre al Detalle de la visita del punto de venta deseado.
- Toque em "Notas"Tap "Notes"Toque "Notas"Na grade de ferramentas, toque na ferramenta Notas (presente só no Chile).In the tools grid, tap the Notes tool (present in Chile only).En la grilla de herramientas, toque la herramienta Notas (presente solo en Chile).
- A tela abreThe screen opensLa pantalla abreCom uma seta de voltar no topo, o cartão do varejo e a lista de notas. Arraste para baixo para atualizar.With a back arrow at the top, the retail card and the list of notes. Pull down to refresh.Con una flecha de volver arriba, la tarjeta del punto de venta y la lista de notas. Deslice hacia abajo para actualizar.
Estrutura da telaScreen structureEstructura de la pantalla
Uma coluna rolável, de cima para baixo:A single scrollable column, top to bottom:Una columna desplazable, de arriba a abajo:
- Data de sincronizaçãoSync dateFecha de sincronización
- A data da última sincronização das visitas (de onde as notas vêm).The last sync date of the visits (where the notes come from).La fecha de última sincronización de las visitas (de donde vienen las notas).
- Cartão do varejoRetail cardTarjeta del punto de venta
- Código do cliente e nome do varejo — só leitura.Customer code and retail name — read only.Código de cliente y nombre del punto de venta — solo lectura.
- Título "Notas""Notes" headingTítulo "Notas"
- O rótulo da seção, sobre a lista.The section label, above the list.La etiqueta de la sección, sobre la lista.
- Lista de notasNotes listLista de notas
- Um card por nota (mais recente primeiro): data, botões editar e excluir, título, texto e miniaturas dos anexos.One card per note (newest first): date, edit and delete buttons, title, text and attachment thumbnails.Un card por nota (más reciente primero): fecha, botones editar y eliminar, título, texto y miniaturas de los adjuntos.
- Estado vazioEmpty stateEstado vacío
- Se o varejo não tem notas, um card de estado vazio (ícone + título + subtítulo) aparece no lugar da lista.If the retail has no notes, an empty-state card (icon + title + subtitle) appears in place of the list.Si el punto de venta no tiene notas, un card de estado vacío (ícono + título + subtítulo) aparece en lugar de la lista.
- Botão de adicionarAdd buttonBotón de agregar
- Um botão circular + ("Nova nota") no fim, sempre visível, que abre o editor.A circular + button ("New note") at the end, always visible, that opens the editor.Un botón circular + ("Nueva nota") al final, siempre visible, que abre el editor.
Estados da notaNote statesEstados de la nota
Uma nota não tem "status" de negócio como um pedido. O que muda é a origem do que você vê na lista — o backend é a fonte, mas a tela sobrepõe as mudanças recém-feitas para você ver o resultado na hora:A note has no business "status" like an order. What changes is the origin of what you see in the list — the backend is the source, but the screen overlays your just-made changes so you see the result immediately:Una nota no tiene un "estado" de negocio como un pedido. Lo que cambia es el origen de lo que ves en la lista — el backend es la fuente, pero la pantalla superpone tus cambios recién hechos para que veas el resultado al instante:
- Do backendFrom backendDel backend
- A nota veio embutida no varejo, na última sincronização. É a lista "oficial".The note came embedded in the retail, in the last sync. This is the "official" list.La nota vino embebida en el punto de venta, en la última sincronización. Es la lista "oficial".
- Recém-enviadaJust sentRecién enviada
- Você criou/editou e o envio deu certo, mas a próxima sincronização ainda não trouxe a versão do backend. A tela mostra a sua versão (com os anexos locais) até reconciliar.You created/edited and the send succeeded, but the next sync hasn't brought the backend's version yet. The screen shows your version (with the local attachments) until it reconciles.Creaste/editaste y el envío tuvo éxito, pero la próxima sincronización aún no trajo la versión del backend. La pantalla muestra tu versión (con los adjuntos locales) hasta que reconcilia.
- ExcluídaDeletedEliminada
- Você excluiu e o envio deu certo. A nota some da lista na hora e continua oculta até a sincronização confirmar.You deleted and the send succeeded. The note disappears from the list at once and stays hidden until the sync confirms.Eliminaste y el envío tuvo éxito. La nota desaparece de la lista de inmediato y permanece oculta hasta que la sincronización confirma.
Ações: criar, editar, excluirActions: create, edit, deleteAcciones: crear, editar, eliminar
Todas as ações passam pelo mesmo envio ao backend. Anexos: até três por nota, vindos da câmera, da galeria ou de um arquivo (foto, PDF, documento ou planilha).All actions go through the same backend send. Attachments: up to three per note, from the camera, the gallery or a file (photo, PDF, document or spreadsheet).Todas las acciones pasan por el mismo envío al backend. Adjuntos: hasta tres por nota, desde la cámara, la galería o un archivo (foto, PDF, documento o planilla).
- CriarCreateCrear
- Toque no +. Preencha título e/ou texto e anexe arquivos. "Salvar" fica ativo se houver ao menos um dos três (título, texto ou anexo).Tap +. Fill title and/or text and attach files. "Save" is enabled if there's at least one of the three (title, text or attachment).Toque +. Complete título y/o texto y adjunte archivos. "Guardar" se habilita si hay al menos uno de los tres (título, texto o adjunto).
- EditarEditEditar
- Toque no lápis do card. O editor abre com título e texto preenchidos e os anexos atuais (as fotos já enviadas aparecem como miniaturas, só leitura). Salvar reenvia a nota com o mesmo identificador.Tap the card's pencil. The editor opens with title and text filled and the current attachments (already-sent photos show as read-only thumbnails). Saving resends the note with the same identifier.Toque el lápiz del card. El editor abre con título y texto completados y los adjuntos actuales (las fotos ya enviadas aparecen como miniaturas de solo lectura). Guardar reenvía la nota con el mismo identificador.
- ExcluirDeleteEliminar
- Toque na lixeira do card. Um modal pede confirmação; ao confirmar, a nota é enviada como excluída e some da lista.Tap the card's trash. A modal asks for confirmation; on confirm, the note is sent as deleted and disappears from the list.Toque el tacho del card. Un modal pide confirmación; al confirmar, la nota se envía como eliminada y desaparece de la lista.
Limite de anexosAttachment limitLímite de adjuntos São no máximo 3 anexos por nota. Atingido o limite, os botões de câmera/galeria/arquivo desabilitam e um aviso aparece se você insistir em adicionar arquivo. Up to 3 attachments per note. Once reached, the camera/gallery/file buttons disable and a notice appears if you try to add another file. Máximo 3 adjuntos por nota. Alcanzado el límite, los botones de cámara/galería/archivo se deshabilitan y aparece un aviso si intenta agregar otro archivo.
Arquitetura e fluxo de dadosArchitecture & data flowArquitectura y flujo de datos
Clean Architecture + Riverpod + Freezed + ObjectBox. Há dois fluxos distintos: a leitura (cache do próprio aggregate de Notas) e a escrita (criar/editar/excluir, via Dispatcher).Clean Architecture + Riverpod + Freezed + ObjectBox. There are two distinct flows: the read (cache of the Notes aggregate itself) and the write (create/edit/delete, via the Dispatcher).Clean Architecture + Riverpod + Freezed + ObjectBox. Hay dos flujos distintos: la lectura (caché del propio aggregate de Notas) y la escritura (crear/editar/eliminar, vía Dispatcher).
Leitura · cache + remoto no refreshRead · cache + remote on refreshLectura · caché + remoto en el refresh
As notas têm proto e pipeline próprios (NoteConectaRep.proto). O GetNotesUseCase lê o cache do agregado de Notas e recorta por conta com getCachedNotesForAccount. O sync inicial (DataSyncType.notes) e o pull-to-refresh populam esse cache pelo getNotes. Da feature de Visitas o Notifier só tira a identificação do varejo (nome, código, código fiscal):Notes have their own proto and pipeline (NoteConectaRep.proto). GetNotesUseCase reads the Notes aggregate cache and slices it per account with getCachedNotesForAccount. The initial sync (DataSyncType.notes) and pull-to-refresh populate that cache through getNotes. From the Visits feature the Notifier only takes the retail identity (name, code, tax code):Las notas tienen proto y pipeline propios (NoteConectaRep.proto). El GetNotesUseCase lee el caché del aggregate de Notas y lo recorta por cuenta con getCachedNotesForAccount. El sync inicial (DataSyncType.notes) y el pull-to-refresh poblan ese caché mediante getNotes. De la feature de Visitas el Notifier solo toma la identificación del punto de venta (nombre, código, código fiscal):
- NotesModelObjectBox · cache
- getCachedNotesNotesLocalDataSource
- toDomainNotesEntity · notesForAccountdomain
- getCachedNotesForAccountGetNotesUseCase
- _loadNotesNotifier + NotesState
- → UINotesPage
- _loadNotesNotifier + NotesState
- getCachedNotesForAccountGetNotesUseCase
- toDomainNotesEntity · notesForAccountdomain
- getCachedNotesNotesLocalDataSource
Escrita · criar/editar/excluir via DispatcherWrite · create/edit/delete via DispatcherEscritura · crear/editar/eliminar vía Dispatcher
A ação sai do editor/modal, o Notifier lê os arquivos como base64, monta o NotesDispatcherPayloadInput (entities cruas + isDeleted), o builder gera o envelope (DispatcherType.notes · NoteUploadAPI) e o submit despacha:The action leaves the editor/modal, the Notifier reads the files as base64, assembles the NotesDispatcherPayloadInput (raw entities + isDeleted), the builder produces the envelope (DispatcherType.notes · NoteUploadAPI) and submit dispatches:La acción sale del editor/modal, el Notifier lee los archivos como base64, arma el NotesDispatcherPayloadInput (entities crudas + isDeleted), el builder produce el sobre (DispatcherType.notes · NoteUploadAPI) y submit despacha:
- NoteEditorModalContent / NoteCardWidgetUI
- submitNote / deleteNoteNotesNotifier
- readAsBase64FileCaptureServiceanexos → base64
- build(input)BuildNotesDispatcherPayloadUseCase→ DispatcherEnvelope
- submit(envelope)SubmitNotesUseCase
- dispatchDispatcherOrchestratorNoteUploadAPI · batchApi
- submit(envelope)SubmitNotesUseCase
- build(input)BuildNotesDispatcherPayloadUseCase→ DispatcherEnvelope
- readAsBase64FileCaptureServiceanexos → base64
- submitNote / deleteNoteNotesNotifier
Otimismo + reconciliaçãoOptimism + reconciliationOptimismo + reconciliación
Após o envio dar certo, o Notifier não reescreve o cache; ele guarda a nota num overlay local (pendingNotes) ou marca o id em deletedIds, e o State combina isso com backendNotes no getter displayItems. O refresh() re-busca as visitas do remoto e, para cada pendência cujo id já voltou do backend, descarta o overlay e apaga os arquivos locais. É por isso que a UI muda "na hora" sem esperar a sincronização.
After a successful send, the Notifier does not rewrite the cache; it keeps the note in a local overlay (pendingNotes) or marks the id in deletedIds, and the State merges that with backendNotes in the displayItems getter. refresh() re-fetches visits from remote and, for each pending whose id already returned from the backend, drops the overlay and deletes the local files. That's why the UI changes "instantly" without waiting for the sync.
Tras un envío exitoso, el Notifier no reescribe el caché; guarda la nota en un overlay local (pendingNotes) o marca el id en deletedIds, y el State combina eso con backendNotes en el getter displayItems. refresh() re-busca las visitas del remoto y, por cada pendiente cuyo id ya volvió del backend, descarta el overlay y borra los archivos locales. Por eso la UI cambia "al instante" sin esperar la sincronización.
Modelo de dadosData modelModelo de datos
A nota existe em quatro representações — Proto (wire gRPC) → DTO (Freezed) → Model (ObjectBox) → Entity (domínio) — ligadas por mappers, com cache write-through. A nota tem proto, DTO, Model e Entity próprios, no agregado Notes: NotesEntity carrega o lastSyncAt uma única vez e a lista de NoteEntity (§21). Cada nota carrega o accountSfid do varejo dono — no wire é o retailerId, o mesmo nome que o NoteUploadAPI já usa na escrita. O campo é opcional por semântica: vazio significa nota sem varejo, e o notesForAccount nunca a devolve num recorte por conta. É essa folga que deixa a estrutura pronta para notas não ligadas a varejo, sem tocar no contrato de Visitas — de onde Account.notes foi removido.A note exists in four representations — Proto (gRPC wire) → DTO (Freezed) → Model (ObjectBox) → Entity (domain) — linked by mappers, with cache write-through. The note has its own proto, DTO, Model and Entity, in the Notes aggregate: NotesEntity carries lastSyncAt once plus the list of NoteEntity (§21). Each note carries the owning retail's accountSfid — on the wire it is retailerId, the same name NoteUploadAPI already uses on the write side. The field is semantically optional: empty means a note with no retail, and notesForAccount never returns it in a per-account slice. That slack is what leaves the structure ready for notes not tied to a retail, without touching the Visits contract — where Account.notes was removed.Una nota existe en cuatro representaciones — Proto (wire gRPC) → DTO (Freezed) → Model (ObjectBox) → Entity (dominio) — unidas por mappers, con cache write-through. La nota tiene proto, DTO, Model y Entity propios, en el aggregate Notes: NotesEntity lleva el lastSyncAt una sola vez y la lista de NoteEntity (§21). Cada nota lleva el accountSfid del punto de venta dueño — en el wire es el retailerId, el mismo nombre que el NoteUploadAPI ya usa en la escritura. El campo es opcional por semántica: vacío significa nota sin punto de venta, y el notesForAccount nunca la devuelve en un recorte por cuenta. Esa holgura deja la estructura lista para notas no ligadas a un punto de venta, sin tocar el contrato de Visitas — de donde Account.notes fue eliminado.
A escrita (criar/editar/excluir) não usa nenhuma dessas quatro representações: o Notifier monta um NotesDispatcherPayloadInput com a NoteEntity crua + anexos em base64 e o builder serializa o JSON da transação (ver UseCases). A seguir, na ordem: o proto de origem, as estruturas campo-a-campo por camada, e os mappers. ¹ não se aplica aqui (os campos do proto não são optional).The write (create/edit/delete) uses none of these four representations: the Notifier assembles a NotesDispatcherPayloadInput with the raw NoteEntity + base64 attachments and the builder serializes the transaction JSON (see UseCases). Next, in order: the origin proto, the field-by-field structures per layer, and the mappers. ¹ doesn't apply here (the proto fields aren't optional).La escritura (crear/editar/eliminar) no usa ninguna de esas cuatro representaciones: el Notifier arma un NotesDispatcherPayloadInput con la NoteEntity cruda + adjuntos en base64 y el builder serializa el JSON de la transacción (ver UseCases). A continuación, en orden: el proto de origen, las estructuras campo a campo por capa, y los mappers. ¹ no aplica aquí (los campos del proto no son optional).
Proto
A nota vem do seu próprio proto — NoteConectaRep.proto · proto3. A escrita continua saindo pelo Dispatcher (ver UseCases), não por esse serviço.The note comes from its own proto — NoteConectaRep.proto · proto3. Writes still go out through the Dispatcher (see UseCases), not through this service.La nota viene de su propio proto — NoteConectaRep.proto · proto3. La escritura sigue saliendo por el Dispatcher (ver UseCases), no por este servicio.
getNotesunary · leituraunary · readunary · lecturarpc getNotes(NoteRequest) returns (NoteReply)
Request em lote por locationHierarchySfid, resolvido no repository (§25) — não por conta, para a tela abrir offline depois do sync. O recorte por conta é em memória.Batch request by locationHierarchySfid, resolved in the repository (§25) — not per account, so the screen opens offline after the sync. The per-account slice happens in memory.Request en lote por locationHierarchySfid, resuelto en el repository (§25) — no por cuenta, para que la pantalla abra offline después del sync. El recorte por cuenta es en memoria.
NoteReplyrepeated Note noteList = 1 — a lista vem plana e cada nota traz o retailerId do varejo dono. O lastSyncAt não trafega: nenhum proto do projeto o declara, porque ele é o instante em que este device buscou com sucesso, não um dado do backend — o mapper de fronteira o estampa com DateTimeUtils.now() (§21). O detalhe campo-a-campo de Note e NoteAttachment está nas Estruturas de dados abaixo.the list comes flat and each note carries the owning retail's retailerId. lastSyncAt never travels: no proto in the project declares it, because it is the moment this device fetched successfully, not backend data — the boundary mapper stamps it with DateTimeUtils.now() (§21). The field-by-field detail of Note and NoteAttachment is in Data structures below.la lista viene plana y cada nota trae el retailerId del punto de venta dueño. El lastSyncAt no viaja: ningún proto del proyecto lo declara, porque es el instante en que este device buscó con éxito, no un dato del backend — el mapper de frontera lo estampa con DateTimeUtils.now() (§21). El detalle campo a campo de Note y NoteAttachment está en Estructuras de datos abajo.
Estruturas de dadosData structuresEstructuras de datos
Um dropdown por estrutura, aninhados pela hierarquia. Cada tabela tem uma coluna por camada — Proto · DTO · Model · Entity; o texto em azul marca onde o tipo (ou nome) primeiro muda lendo Proto→DTO→Model→Entity.One dropdown per structure, nested by hierarchy. Each table has one column per layer — Proto · DTO · Model · Entity; the blue text marks where the type (or name) first changes reading Proto→DTO→Model→Entity.Un dropdown por estructura, anidados por jerarquía. Cada tabla tiene una columna por capa — Proto · DTO · Model · Entity; el texto en azul marca dónde primero cambia el tipo (o nombre) leyendo Proto→DTO→Model→Entity.
Note NoteReply.noteList[] 7 camposfieldscampos
Campo Proto DTO Model Entity idstring String noteIdString accountSfidretailerIdString String String titlestring String String String texttextPreviewString String String createdAtstring String? DateTime?DateTime? updatedAtstring String? DateTime?DateTime? attachmentsrepeated NoteAttachment List<…DTO> ToMany<…Model>List<…Entity> NoteAttachment Note.attachments[] 3 camposfieldscampos
Campo Proto DTO Model Entity fileUrlstring String String String fileNamestring String String String fileTypestring String String String
NoteEntity tem ainda o getter hasAttachments (attachments.isNotEmpty). Defaults dos Freezed: title/text = "", attachments = lista vazia; datas nulas.NoteEntity also has the hasAttachments getter (attachments.isNotEmpty). Freezed defaults: title/text = "", attachments = empty list; dates null.NoteEntity tiene además el getter hasAttachments (attachments.isNotEmpty). Defaults de Freezed: title/text = "", attachments = lista vacía; fechas nulas.
Mappers
As cinco direções, para Note e NoteAttachment (extensions em note_mapper.dart / note_attachment_mapper.dart). As notas entram no fluxo por dentro do mapper de AccountData.The five directions, for Note and NoteAttachment (extensions in note_mapper.dart / note_attachment_mapper.dart). Notes enter the flow through the AccountData mapper.Las cinco direcciones, para Note y NoteAttachment (extensions en note_mapper.dart / note_attachment_mapper.dart). Las notas entran al flujo dentro del mapper de AccountData.
| DireçãoDirectionDirección | Note | NoteAttachment | NotaNoteNota |
|---|---|---|---|
| JSON → DTO | NoteDTOMapper.fromMap | NoteAttachmentDTOMapper.fromMap | lê map["textPreview"] → textreads map["textPreview"] → textlee map["textPreview"] → text |
| Proto → DTO | NoteProtoMapper.toDTO | NoteAttachmentProtoMapper.toDTO | textPreview → texttextPreview → texttextPreview → text |
| DTO → Entity | NoteDTOMapper.toDomain | NoteAttachmentDTOMapper.toDomain | parseia datas (DateTimeUtils.tryParse)parses dates (DateTimeUtils.tryParse)parsea fechas (DateTimeUtils.tryParse) |
| Entity → Model | NoteEntityMapper.toModel | NoteAttachmentEntityMapper.toModel | attachments → ToManyattachments → ToManyattachments → ToMany |
| Model → Entity | NoteModelMapper.toDomain | NoteAttachmentModelMapper.toDomain | datas já são DateTime?dates are already DateTime?fechas ya son DateTime? |
Os únicos deltasThe only deltasLos únicos deltas
- rename ·
textPreview(proto) →text(DTO/Model/Entity), aplicado notoDTOdo proto.rename ·textPreview(proto) →text(DTO/Model/Entity), applied in the proto'stoDTO.rename ·textPreview(proto) →text(DTO/Model/Entity), aplicado en eltoDTOdel proto. - parse de data ·
createdAt/updatedAt:String(proto/DTO) →DateTime?a partir do Model (parse viaDateTimeUtils.tryParsenoDTO→Entity; ObjectBox guardaDateTime).date parse ·createdAt/updatedAt:String(proto/DTO) →DateTime?from the Model on (parse viaDateTimeUtils.tryParseinDTO→Entity; ObjectBox storesDateTime).parse de fecha ·createdAt/updatedAt:String(proto/DTO) →DateTime?desde el Model (parse víaDateTimeUtils.tryParseenDTO→Entity; ObjectBox guardaDateTime). - relação ·
attachments:repeated NoteAttachment→ToMany<NoteAttachmentModel>no Model.relation ·attachments:repeated NoteAttachment→ToMany<NoteAttachmentModel>in the Model.relación ·attachments:repeated NoteAttachment→ToMany<NoteAttachmentModel>en el Model.
Repository
As Notas têm o seu NotesRepositoryImpl, com as 3 operações do padrão: getNotes (cache + fallback remoto), getCachedNotes e getCachedNotesForAccount (§28-A). O locationHierarchySfid é resolvido aqui, via currentResourceProvider (§25). A escrita das notas não passa por este repository — vai pelo Dispatcher (ver UseCases).Notes have their own NotesRepositoryImpl, with the 3 standard operations: getNotes (cache + remote fallback), getCachedNotes and getCachedNotesForAccount (§28-A). locationHierarchySfid is resolved here, via currentResourceProvider (§25). Note writes do not go through this repository — they go via the Dispatcher (see UseCases).Las Notas tienen su propio NotesRepositoryImpl, con las 3 operaciones del patrón: getNotes (caché + fallback remoto), getCachedNotes y getCachedNotesForAccount (§28-A). El locationHierarchySfid se resuelve aquí, vía currentResourceProvider (§25). La escritura de las notas no pasa por este repository — va por el Dispatcher (ver UseCases).
Um dropdown por método — assinatura, retorno e comportamento. As Notas usam estes três.One dropdown per method — signature, return and behavior. Notes use these three.Un dropdown por método — firma, retorno y comportamiento. Las Notas usan estos tres.
getCachedNotesForAccount({accountSfid}) local
RetornaReturnsDevuelve Result<List<NoteEntity>, Failure>
Fonte das Notas. Só cache: lê getCachedNotes() e recorta com NotesEntity.notesForAccount, comparando o accountSfid de cada nota. Nunca dispara remoto; lista vazia quando não há nota da conta.Notes' source. Cache only: reads getCachedNotes() and slices it with NotesEntity.notesForAccount, matching each note's accountSfid. Never triggers remote; empty list when the account has no note.Fuente de las Notas. Solo caché: lee getCachedNotes() y lo recorta con NotesEntity.notesForAccount, comparando el accountSfid de cada nota. Nunca dispara remoto; lista vacía cuando la cuenta no tiene notas.
getCachedNotesLastSyncAt() local
RetornaReturnsDevuelve Future<DateTime?>
O lastSyncAt do container NotesEntity, exibido no DataLoadInfo — o dado da própria feature, nunca o do Resource (§23).The NotesEntity container's lastSyncAt, shown in DataLoadInfo — the feature's own data, never the Resource's (§23).El lastSyncAt del container NotesEntity, mostrado en DataLoadInfo — el dato de la propia feature, nunca el del Resource (§23).
getNotes({source}) local | remote
RetornaReturnsDevuelve Result<NotesEntity, Failure>
Usado no sync inicial (DataSyncType.notes) e no pull-to-refresh com source: DataSourceType.remote: chama o getNotes e regrava o cache. Só as notas trafegam — a lista de visitas não é mais rebaixada para atualizar uma nota.Used on the initial sync (DataSyncType.notes) and on pull-to-refresh with source: DataSourceType.remote: calls getNotes and rewrites the cache. Only notes travel — the visit list is no longer re-downloaded to refresh a note.Usado en el sync inicial (DataSyncType.notes) y en el pull-to-refresh con source: DataSourceType.remote: llama al getNotes y regraba el caché. Solo las notas viajan — la lista de visitas ya no se vuelve a bajar para actualizar una nota.
Demais métodosOther methodsDemás métodosO NotesRepositoryImpl expõe só os métodos acima. As Notas ainda leem a visita num ponto: GetVisitsUseCase.getCachedByAccountSfid (que delega ao VisitRepositoryImpl.getCachedVisitByAccountSfid), para o nome/código/código fiscal do varejo no cabeçalho — o texto e os anexos vêm todos do agregado de Notas. Os demais métodos de visita estão em Visitas / Detalhe da visita.NotesRepositoryImpl exposes only the methods above. Notes still read the visit at one point: GetVisitsUseCase.getCachedByAccountSfid (which delegates to VisitRepositoryImpl.getCachedVisitByAccountSfid), for the retail name/code/tax code in the header — the text and attachments all come from the Notes aggregate. The remaining visit methods are in Visits / Visit detail.El NotesRepositoryImpl expone solo los métodos de arriba. Las Notas todavía leen la visita en un punto: GetVisitsUseCase.getCachedByAccountSfid (que delega al VisitRepositoryImpl.getCachedVisitByAccountSfid), para el nombre/código/código fiscal del punto de venta en el encabezado — el texto y los adjuntos vienen todos del aggregate de Notas. Los demás métodos de visita están en Visitas / Detalle de la visita.
Datasources
As Notas têm os 3 datasources próprios: mock (JSON de asset), local (ObjectBox) e remoto (gRPC). Os boxes são exclusivos — NotesModel, NoteModel e NoteAttachmentModel. A escrita das notas não usa datasource: sai pelo Dispatcher.Notes have their own 3 datasources: mock (asset JSON), local (ObjectBox) and remote (gRPC). The boxes are exclusive — NotesModel, NoteModel and NoteAttachmentModel. Note writes use no datasource: they go via the Dispatcher.Las Notas tienen sus 3 datasources propios: mock (JSON de asset), local (ObjectBox) y remoto (gRPC). Los boxes son exclusivos — NotesModel, NoteModel y NoteAttachmentModel. La escritura de las notas no usa datasource: sale por el Dispatcher.
Local NotesLocalDataSource ObjectBox
Envio / fluxo: leitura local via ObjectBox (box de NotesModel, com NoteModel/NoteAttachmentModel aninhados por ToMany) — sem rede; o sync inicial já populou o box. O saveNotes limpa os 3 boxes antes de regravar. Erro: falha de leitura vira CacheException.Sends / flow: local read via ObjectBox (NotesModel box, with NoteModel/NoteAttachmentModel nested by ToMany) — no network; the initial sync already populated the box. saveNotes clears the 3 boxes before rewriting. Error: a read failure becomes CacheException.Envío / flujo: lectura local vía ObjectBox (box de NotesModel, con NoteModel/NoteAttachmentModel anidados por ToMany) — sin red; el sync inicial ya pobló el box. El saveNotes limpia los 3 boxes antes de regrabar. Error: un fallo de lectura es CacheException.
getCachedNotes()
- RetornoReturnRetorno
NotesEntity?- ComportamentoBehaviorComportamiento
- o agregado de notas do box; o repository recorta por
accountSfid. Alimenta as Notas.the notes aggregate from the box; the repository slices it byaccountSfid. Feeds Notes.el agregado de notas del box; el repository lo recorta poraccountSfid. Alimenta las Notas.
getNotesLastSyncAt()
- RetornoReturnRetorno
DateTime?- ComportamentoBehaviorComportamiento
- o
lastSyncAtdo container, para oDataLoadInfo.the container'slastSyncAt, forDataLoadInfo.ellastSyncAtdel container, para elDataLoadInfo.
Remote NotesRemoteDataSource gRPC · só no refreshrefresh onlysolo en refresh
Envio / fluxo: getNotes por gRPC, disparado no sync inicial e no pull-to-refresh (via getNotes(source: remote)). Traz só as notas e regrava o cache. Erro: falha de rede propaga como Failure, o repository cai no cache e o refresh mantém o estado atual.Sends / flow: getNotes over gRPC, fired on the initial sync and on pull-to-refresh (via getNotes(source: remote)). Brings only the notes and rewrites the cache. Error: a network failure propagates as Failure, the repository falls back to cache and refresh keeps the current state.Envío / flujo: getNotes por gRPC, disparado en el sync inicial y en el pull-to-refresh (vía getNotes(source: remote)). Trae solo las notas y regraba el caché. Error: un fallo de red propaga como Failure, el repository cae al caché y el refresh mantiene el estado actual.
getNotes({locationHierarchySfid, dateReference, lastModifiedDate})
- RetornoReturnRetorno
NotesEntity- ComportamentoBehaviorComportamiento
- chama
getNotes; olocationHierarchySfidé resolvido no repository (§25).callsgetNotes;locationHierarchySfidis resolved in the repository (§25).llamagetNotes; ellocationHierarchySfidse resuelve en el repository (§25).
Enums e labelsEnums & labelsEnums y labels
As Notas não têm enum de dado próprio (a nota é texto livre). Os enums relevantes são o de gating (a ferramenta na grade) e o de transação (o canal de escrita), além dos enums de captura de arquivo reusados no editor.Notes have no data enum of their own (a note is free text). The relevant enums are the gating one (the tool in the grid) and the transaction one (the write channel), plus the file-capture enums reused in the editor.Las Notas no tienen enum de dato propio (la nota es texto libre). Los enums relevantes son el de gating (la herramienta en la grilla) y el de transacción (el canal de escritura), además de los enums de captura de archivo reutilizados en el editor.
ModuleDetailType · visitDetailToolNotes gating da ferramentatool gatinggating de la herramienta
| case | value | usouseuso |
|---|---|---|
visitDetailToolNotes | "notes" | a chave da ferramenta "Notas" na grade do Detalhe da visita; presente só na config do Chile. O visit_detail_tools_grid_widget mapeia esse case para AppRouter.goToNotes.the "Notes" tool key in the Visit detail grid; present only in Chile's config. visit_detail_tools_grid_widget maps this case to AppRouter.goToNotes.la clave de la herramienta "Notas" en la grilla del Detalle de la visita; presente solo en la config de Chile. visit_detail_tools_grid_widget mapea este case a AppRouter.goToNotes. |
DispatcherType · notes serviceName + mercadosmarketsmercados
| case | serviceName | destination | mercadosmarketsmercados |
|---|---|---|---|
notes | NoteUploadAPI | batchApi | CL |
Único canal de escrita das notas (criar/editar/excluir). O serviceName resolvido é NoteUploadAPI (sem prefixo Promo_). Lista completa dos DispatcherType no doc de arquitetura do Dispatcher.The only write channel for notes (create/edit/delete). The resolved serviceName is NoteUploadAPI (no Promo_ prefix). Full list of DispatcherType in the Dispatcher architecture doc.Único canal de escritura de las notas (crear/editar/eliminar). El serviceName resuelto es NoteUploadAPI (sin prefijo Promo_). Lista completa de DispatcherType en el doc de arquitectura del Dispatcher.
AllowedFileType 4 · tipos aceitos ao anexar arquivoaccepted types when attaching a filetipos aceptados al adjuntar archivo
| case | extensions |
|---|---|
image | jpg · jpeg · png · webp · heic |
pdf | |
document | doc · docx |
spreadsheet | xls · xlsx · csv |
Passados ao pickDocument do editor. A câmera e a galeria capturam imagem via CaptureSource.camera / CaptureSource.gallery.Passed to the editor's pickDocument. Camera and gallery capture an image via CaptureSource.camera / CaptureSource.gallery.Pasados al pickDocument del editor. La cámara y la galería capturan imagen vía CaptureSource.camera / CaptureSource.gallery.
UseCases
Um dropdown por UseCase; dentro, cada método com assinatura, o que retorna e uso.One dropdown per UseCase; inside, each method with its signature, what it returns and use.Un dropdown por UseCase; dentro, cada método con su firma, qué devuelve y uso.
LeituraReadLectura
GetNotesUseCase 3 métodos3 methods3 métodos
| MétodoMethodMétodo | RetornaReturnsDevuelve | UsoUseUso |
|---|---|---|
getCachedNotesForAccount({accountSfid}) | Result<List<NoteEntity>, Failure> | Fonte das Notas. Cache-only → repository.getCachedNotesForAccount. Alimenta o _load().Notes' source. Cache-only → repository.getCachedNotesForAccount. Feeds _load().Fuente de las Notas. Cache-only → repository.getCachedNotesForAccount. Alimenta el _load(). |
getCachedLastSyncAt() | Future<DateTime?> | o lastSyncAt das Notas para o DataLoadInfo (§23).Notes' lastSyncAt for DataLoadInfo (§23).el lastSyncAt de las Notas para el DataLoadInfo (§23). |
execute({source}) | Result<NotesEntity, Failure> | no refresh(), com source: remote — re-busca só as notas antes de recarregar. Também é o alvo do DataSyncType.notes.in refresh(), with source: remote — re-fetches only the notes before reloading. Also the DataSyncType.notes target.en el refresh(), con source: remote — re-busca solo las notas antes de recargar. También es el objetivo del DataSyncType.notes. |
EscritaWriteEscritura
BuildNotesDispatcherPayloadUseCase 1 · builder
| MétodoMethodMétodo | RetornaReturnsDevuelve | UsoUseUso |
|---|---|---|
build({input: NotesDispatcherPayloadInput}) | DispatcherEnvelope | implements DispatcherPayloadBuilder (§36). Toda construção wire mora aqui: deriva o resourceSfid (primary/secondary), normaliza o fileType dos anexos (sem ponto, minúsculo), renomeia text → textPreview e monta o array AccNoteData com id, retailerId (= accountSfid), title, isDeleted e os anexos em base64. Tipo fixo DispatcherType.notes; dateReference = formatDate(submittedAt); transactionReference = note.id.implements DispatcherPayloadBuilder (§36). All wire construction lives here: derives the resourceSfid (primary/secondary), normalizes the attachments' fileType (no dot, lowercase), renames text → textPreview and builds the AccNoteData array with id, retailerId (= accountSfid), title, isDeleted and the base64 attachments. Fixed type DispatcherType.notes; dateReference = formatDate(submittedAt); transactionReference = note.id.implements DispatcherPayloadBuilder (§36). Toda la construcción wire vive aquí: deriva el resourceSfid (primary/secondary), normaliza el fileType de los adjuntos (sin punto, minúscula), renombra text → textPreview y arma el array AccNoteData con id, retailerId (= accountSfid), title, isDeleted y los adjuntos en base64. Tipo fijo DispatcherType.notes; dateReference = formatDate(submittedAt); transactionReference = note.id. |
SubmitNotesUseCase 1 · transportetransporttransporte
| MétodoMethodMétodo | RetornaReturnsDevuelve | UsoUseUso |
|---|---|---|
submit({envelope}) | Result<DispatcherAck, Failure> | Delegate de transporte fino: encaminha o envelope ao DispatcherOrchestrator.dispatch (um único envelope por transação — sem Future.wait). Não decide DispatcherType (isso é do builder).Thin transport delegate: forwards the envelope to DispatcherOrchestrator.dispatch (a single envelope per transaction — no Future.wait). Doesn't decide DispatcherType (the builder does).Delegate de transporte fino: reenvía el sobre a DispatcherOrchestrator.dispatch (un único sobre por transacción — sin Future.wait). No decide DispatcherType (eso es del builder). |
Input cru + arquivosRaw input + filesInput crudo + archivosO NotesDispatcherPayloadInput (Freezed) carrega a NoteEntity crua, o accountSfid, a lista de NoteAttachmentUploadInput (fileName/fileType/base64 — I/O já resolvido pelo Notifier), o isDeleted, a ResourceEntity crua e o submittedAt: DateTime (relógio único; nunca data já formatada — §36).The NotesDispatcherPayloadInput (Freezed) carries the raw NoteEntity, the accountSfid, the list of NoteAttachmentUploadInput (fileName/fileType/base64 — I/O already resolved by the Notifier), the isDeleted, the raw ResourceEntity and submittedAt: DateTime (single clock; never a pre-formatted date — §36).El NotesDispatcherPayloadInput (Freezed) lleva la NoteEntity cruda, el accountSfid, la lista de NoteAttachmentUploadInput (fileName/fileType/base64 — I/O ya resuelto por el Notifier), el isDeleted, la ResourceEntity cruda y el submittedAt: DateTime (reloj único; nunca fecha ya formateada — §36).
Notifier & State
O NotesNotifier (@riverpod, family por accountSfid) é o cérebro da tela. O build() é magro (resolve UseCases/serviço, registra o onDispose de limpeza de arquivos e chama guardedBuild(() => _load(...)) — via mixin AsyncGuard). O State (NotesState, Freezed) é a fonte única de verdade: guarda as notas do backend, o overlay otimista e o lastSyncAt, e expõe o getter displayItems que combina tudo.The NotesNotifier (@riverpod, family by accountSfid) is the screen's brain. build() is thin (resolves UseCases/service, registers the file-cleanup onDispose and calls guardedBuild(() => _load(...)) — via the AsyncGuard mixin). The State (NotesState, Freezed) is the single source of truth: it holds the backend notes, the optimistic overlay and lastSyncAt, and exposes the displayItems getter that merges everything.El NotesNotifier (@riverpod, family por accountSfid) es el cerebro de la pantalla. build() es magro (resuelve UseCases/servicio, registra el onDispose de limpieza de archivos y llama guardedBuild(() => _load(...)) — vía el mixin AsyncGuard). El State (NotesState, Freezed) es la fuente única de verdad: guarda las notas del backend, el overlay optimista y lastSyncAt, y expone el getter displayItems que combina todo.
MétodosMethodsMétodos
build({accountSfid}) cache-only
RetornoReturnRetorno FutureOr<NotesState>
Chama _load(): busca a visita por accountSfid (cache-only) — ausente → CacheFailure — e monta o State com accountName/customerCode/taxCode, lastSyncAt e backendNotes = account.notes. Registra onDispose para apagar os arquivos locais rastreados.Calls _load(): fetches the visit by accountSfid (cache-only) — missing → CacheFailure — and assembles the State with accountName/customerCode/taxCode, lastSyncAt and backendNotes = account.notes. Registers onDispose to delete the tracked local files.Llama _load(): busca la visita por accountSfid (cache-only) — ausente → CacheFailure — y arma el State con accountName/customerCode/taxCode, lastSyncAt y backendNotes = account.notes. Registra onDispose para borrar los archivos locales rastreados.
refresh()
RetornoReturnRetorno Future<void>
Null-guard em state.value; re-busca as visitas do remoto (execute(source: remote)) e recarrega via runGuarded. Reconcilia o overlay: descarta as pendências cujo id já voltou do backend (apagando os arquivos locais) e limpa os deletedIds já refletidos. Não seta loading (§37).Null-guards state.value; re-fetches visits from remote (execute(source: remote)) and reloads via runGuarded. Reconciles the overlay: drops the pendings whose id already returned from the backend (deleting the local files) and clears the deletedIds already reflected. Doesn't set loading (§37).Null-guard en state.value; re-busca las visitas del remoto (execute(source: remote)) y recarga vía runGuarded. Reconcilia el overlay: descarta los pendientes cuyo id ya volvió del backend (borrando los archivos locales) y limpia los deletedIds ya reflejados. No setea loading (§37).
submitNote({id, title, text, files})
RetornoReturnRetorno Future<Failure?> · null = sucessonull = successnull = éxito
Cria (id null → gera note_<ms>) ou edita (id existente → preserva createdAt/attachments, seta updatedAt). Trima título/texto; se título, texto e arquivos vazios, apaga os arquivos e sai. Lê os arquivos como base64, monta o input, chama o builder e o submit. Em sucesso, adiciona/atualiza a PendingNote (overlay otimista) e rastreia os arquivos; em falha, apaga os arquivos e desliga isSubmitting.Creates (id null → generates note_<ms>) or edits (existing id → preserves createdAt/attachments, sets updatedAt). Trims title/text; if title, text and files are empty, deletes the files and exits. Reads the files as base64, assembles the input, calls the builder and submit. On success, adds/updates the PendingNote (optimistic overlay) and tracks the files; on failure, deletes the files and turns off isSubmitting.Crea (id null → genera note_<ms>) o edita (id existente → preserva createdAt/attachments, setea updatedAt). Trima título/texto; si título, texto y archivos vacíos, borra los archivos y sale. Lee los archivos como base64, arma el input, llama al builder y al submit. En éxito, agrega/actualiza la PendingNote (overlay optimista) y rastrea los archivos; en fallo, borra los archivos y apaga isSubmitting.
deleteNote({note})
RetornoReturnRetorno Future<Failure?>
Monta o input com isDeleted: true (sem anexos), chama builder + submit. Em sucesso, remove qualquer pendência do mesmo id (apagando arquivos) e adiciona o id a deletedIds — a nota some do displayItems na hora.Assembles the input with isDeleted: true (no attachments), calls builder + submit. On success, removes any pending with the same id (deleting files) and adds the id to deletedIds — the note disappears from displayItems at once.Arma el input con isDeleted: true (sin adjuntos), llama builder + submit. En éxito, remueve cualquier pendiente del mismo id (borrando archivos) y agrega el id a deletedIds — la nota desaparece del displayItems al instante.
State disponível para a PageState available to the PageState disponible para la Page
NotesState campos + gettersfields + getterscampos + getters
| campo | tipo | default |
|---|---|---|
accountSfid | String | required |
accountName | String | required |
accountCustomerCode | String | required |
accountTaxCode | String? | null |
lastSyncAt | DateTime? | null |
backendNotes | List<NoteEntity> | [] |
pendingNotes | List<PendingNote> | [] |
deletedIds | Set<String> | {} |
isSubmitting | bool | false |
Getters: displayItems (combina backendNotes + pendingNotes por id, remove os deletedIds, ordena por createdAt desc — cada item é um NoteDisplayItem com a note + os localFiles otimistas), visibleNotes (só as entities) e hasNotes. PendingNote/NoteDisplayItem são wrappers simples (nota + arquivos locais).Getters: displayItems (merges backendNotes + pendingNotes by id, removes the deletedIds, sorts by createdAt desc — each item is a NoteDisplayItem with the note + the optimistic localFiles), visibleNotes (entities only) and hasNotes. PendingNote/NoteDisplayItem are simple wrappers (note + local files).Getters: displayItems (combina backendNotes + pendingNotes por id, remueve los deletedIds, ordena por createdAt desc — cada item es un NoteDisplayItem con la note + los localFiles optimistas), visibleNotes (solo las entities) y hasNotes. PendingNote/NoteDisplayItem son wrappers simples (nota + archivos locales).
Page e widgetsPage & widgetsPage y widgets
A NotesPage (ConsumerWidget) recebe só o accountSfid (§17), observa notesProvider(accountSfid:) e monta os widgets numa coluna rolável com pull-to-refresh. Loading e erro são globais (asyncState.when); erro → FailureStateView com retry via ref.invalidate. Árvore de composição:NotesPage (ConsumerWidget) takes only accountSfid (§17), watches notesProvider(accountSfid:) and composes the widgets in a scrollable column with pull-to-refresh. Loading and error are global (asyncState.when); error → FailureStateView with retry via ref.invalidate. Composition tree:NotesPage (ConsumerWidget) recibe solo accountSfid (§17), observa notesProvider(accountSfid:) y compone los widgets en una columna desplazable con pull-to-refresh. Loading y error son globales (asyncState.when); error → FailureStateView con retry vía ref.invalidate. Árbol de composición:
- NotesPage
- AppPageShell displayBackButton
- CustomLoadingIndicator loading
- FailureStateView error → ref.invalidate
- _NotesBody → CustomPullToRefresh → Column data
- DataLoadInfo state.lastSyncAt
- AccountHeaderCard shared · código · nome
- NotesListWidget
- CustomText título "Notas"
- CustomEmptyState se sem notas
- NoteCardWidget por nota · data + editar + excluir + título + texto + anexos
- CustomFileThumbnail.remote anexo do backend (URL)
- CustomFileThumbnail anexo local otimista
- NoteEditorModalContent modal editar (widgets/modals/) → NoteEditorResult → submitNote
- ConectaModal.showConfirmation confirmar exclusão → deleteNote
- CustomAddButton + "Nova nota"
- NoteEditorModalContent modal criar → NoteEditorResult → submitNote
- AppPageShell displayBackButton
Editor (NoteEditorModalContent, ConsumerStatefulWidget): dois campos (CustomInput título máx. 80 · texto máx. 1000, 3–6 linhas), uma linha de três botões (câmera · galeria · arquivo) e as miniaturas (anexos existentes só leitura + arquivos locais removíveis). "Salvar" ativa com título, texto ou anexo. Usa uma sessão de captura própria; ao fechar sem salvar, faz cleanupSession. Retorna NoteEditorResult via AppRouter.backWithResult. Feedback de envio via ConectaNotice (§30). Modais/navegação ficam no widget (precisam de BuildContext); o envio mora no Notifier (§39).Editor (NoteEditorModalContent, ConsumerStatefulWidget): two fields (CustomInput title max 80 · text max 1000, 3–6 lines), a row of three buttons (camera · gallery · file) and the thumbnails (existing read-only attachments + removable local files). "Save" enables with title, text or attachment. Uses its own capture session; on closing without saving, it runs cleanupSession. Returns NoteEditorResult via AppRouter.backWithResult. Submit feedback via ConectaNotice (§30). Modals/navigation stay in the widget (they need BuildContext); the submit lives in the Notifier (§39).Editor (NoteEditorModalContent, ConsumerStatefulWidget): dos campos (CustomInput título máx. 80 · texto máx. 1000, 3–6 líneas), una fila de tres botones (cámara · galería · archivo) y las miniaturas (adjuntos existentes de solo lectura + archivos locales removibles). "Guardar" se habilita con título, texto o adjunto. Usa su propia sesión de captura; al cerrar sin guardar, ejecuta cleanupSession. Devuelve NoteEditorResult vía AppRouter.backWithResult. Feedback de envío vía ConectaNotice (§30). Modales/navegación quedan en el widget (necesitan BuildContext); el envío vive en el Notifier (§39).
Notas por mercadoMarket notesNotas por mercado
As Notas são dirigidas pelo End Market Configuration: a ferramenta só existe onde a config a declara na grade do Detalhe da visita. Hoje isso é só o Chile — e o canal de escrita DispatcherType.notes também está habilitado só para CL.Notes are driven by the End Market Configuration: the tool only exists where the config declares it in the Visit detail grid. Today that's only Chile — and the write channel DispatcherType.notes is also enabled for CL only.Las Notas son dirigidas por el End Market Configuration: la herramienta solo existe donde la config la declara en la grilla del Detalle de la visita. Hoy eso es solo Chile — y el canal de escritura DispatcherType.notes también está habilitado solo para CL.
ChileChileChile
Único mercado com a ferramenta Notas na grade do Detalhe da visita (chave EMC notes) e com o canal de escrita NoteUploadAPI habilitado. Os mocks (cl_real_notes.json/cl_notes.json) já trazem notas de exemplo — os mocks de visita não carregam mais nota alguma. O cartão do varejo mostra só o código do cliente e o nome (sem código fiscal).
Only market with the Notes tool in the Visit detail grid (EMC key notes) and with the NoteUploadAPI write channel enabled. The mocks (cl_real_notes.json/cl_notes.json) already carry sample notes — the visit mocks no longer carry any note. The retail card shows only the customer code and name (no tax code).
Único mercado con la herramienta Notas en la grilla del Detalle de la visita (clave EMC notes) y con el canal de escritura NoteUploadAPI habilitado. Los mocks (cl_real_notes.json/cl_notes.json) ya traen notas de ejemplo — los mocks de visita ya no llevan ninguna nota. La tarjeta del punto de venta muestra solo el código de cliente y el nombre (sin código fiscal).
BR · ZA · AR · PY · PE
A ferramenta não existe na grade desses mercados (chave notes ausente no EMC) e o DispatcherType.notes não os inclui. O NoteConectaRep.proto e as camadas de dado existem em todos os mercados — o que falta é o gating da UI, a habilitação da transação e o enabledMarkets do DataSyncType.notes (hoje só CL). Ativar em outro mercado seria adicionar a chave notes à grade do EMC e o mercado aos dois enums.
The tool doesn't exist in these markets' grids (notes key absent in the EMC) and DispatcherType.notes doesn't include them. NoteConectaRep.proto and the data layers exist in every market — what's missing is the UI gating, the transaction enablement and DataSyncType.notes' enabledMarkets (CL only today). Enabling in another market would mean adding the notes key to the EMC grid and the market to both enums.
La herramienta no existe en las grillas de esos mercados (clave notes ausente en el EMC) y DispatcherType.notes no los incluye. El NoteConectaRep.proto y las capas de dato existen en todos los mercados — lo que falta es el gating de la UI, la habilitación de la transacción y el enabledMarkets del DataSyncType.notes (hoy solo CL). Activar en otro mercado sería agregar la clave notes a la grilla del EMC y el mercado a los dos enums.