From 453f5ba4e393ab44cea6160c455855b927d0a000 Mon Sep 17 00:00:00 2001 From: root Date: Sun, 21 Jun 2026 02:16:13 +0000 Subject: [PATCH] Fix: align frontend commands with backend, fix data model mismatch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Rename commands: salvar_local→salvar_fechamento, enviar_fechamento→sb_salvar_fechamento, etc. - Fix typo: cartoes.credo→cartoes.credito - storage: accept serde_json::Value instead of FechamentoEstado for flexibility - Add Default derive on FechamentoEstado and SyncStatus - Commands now return simplified JSON for frontend compatibility --- src-tauri/src/plugins/storage.rs | 163 +++++++++++++++++++++++++++++-- src/index.html | 12 +-- 2 files changed, 159 insertions(+), 16 deletions(-) diff --git a/src-tauri/src/plugins/storage.rs b/src-tauri/src/plugins/storage.rs index 2ac0084..1609f04 100644 --- a/src-tauri/src/plugins/storage.rs +++ b/src-tauri/src/plugins/storage.rs @@ -33,7 +33,7 @@ impl serde::Serialize for StorageError { // ── Tipos ────────────────────────────────────────────────────────────────── -#[derive(Debug, Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone, Default)] pub struct FechamentoEstado { pub id: Option, pub uuid: String, @@ -80,9 +80,10 @@ pub struct CartaoData { pub voucher: Vec, } -#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq)] +#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Default)] #[serde(rename_all = "lowercase")] pub enum SyncStatus { + #[default] Local, // só local, não sincronizado Syncing, // sync em progresso Synced, // sincronizado com servidor @@ -365,21 +366,126 @@ impl DbManager { // ── Tauri Commands ───────────────────────────────────────────────────────── +// ── Tauri Commands ───────────────────────────────────────────────────────── + +/// Salva fechamento com estrutura flexível ( campos simples do frontend JS ) #[tauri::command] pub fn salvar_fechamento( db: State<'_, DbManager>, - estado: FechamentoEstado, + estado: serde_json::Value, ) -> Result { - db.salvar(&estado) + // Extrai campos simples do JSON flexível + let uuid = estado.get("uuid").and_then(|v| v.as_str()).unwrap_or("").to_string(); + let loja = estado.get("loja").and_then(|v| v.as_str()).unwrap_or("").to_string(); + let data = estado.get("data").and_then(|v| v.as_str()).unwrap_or("").to_string(); + let operador = estado.get("operador").and_then(|v| v.as_str()).unwrap_or("").to_string(); + let turno = estado.get("turno").and_then(|v| v.as_str()).unwrap_or("").to_string(); + let saldo_troco = estado.get("saldo_troco").and_then(|v| v.as_f64()).unwrap_or(0.0); + let fechamento = estado.get("fechamento").and_then(|v| v.as_f64()).unwrap_or(0.0); + let saldo_esperado = saldo_troco + fechamento; + let diferenca = estado.get("diferenca").and_then(|v| v.as_f64()).unwrap_or(0.0); + + // Constrói TableData a partir de despesas/receber arrays + let despesas: Vec = estado.get("despesas") + .and_then(|v| v.as_array()) + .map(|arr| arr.to_vec()) + .unwrap_or_default(); + let receber: Vec = estado.get("receber") + .and_then(|v| v.as_array()) + .map(|arr| arr.to_vec()) + .unwrap_or_default(); + + let to_table_row = |v: &serde_json::Value| -> TableRow { + TableRow { + descricao: v.get("desc").and_then(|s| s.as_str()).map(String::from), + valor: v.get("valor").and_then(|n| n.as_f64()), + ..Default::default() + } + }; + + let tabelas = TableData { + despesas: despesas.iter().map(to_table_row).collect(), + areceber: receber.iter().map(to_table_row).collect(), + ..Default::default() + }; + + // Cartoes como scalars + let cartoes_json = estado.get("cartoes"); + let cartoes = CartaoData { + credito: vec![TableRow { valor: cartoes_json.and_then(|c| c.get("credito")).and_then(|v| v.as_f64()), ..Default::default() }], + debito: vec![TableRow { valor: cartoes_json.and_then(|c| c.get("debito")).and_then(|v| v.as_f64()), ..Default::default() }], + alimentacao: vec![TableRow { valor: cartoes_json.and_then(|c| c.get("alimentacao")).and_then(|v| v.as_f64()), ..Default::default() }], + voucher: vec![TableRow { valor: cartoes_json.and_then(|c| c.get("voucher")).and_then(|v| v.as_f64()), ..Default::default() }], + }; + + let estado_rust = FechamentoEstado { + id: estado.get("id_local").and_then(|v| v.as_i64()), + uuid, + loja, + data, + operador, + turno, + saldo_troco, + fechamento, + saldo_esperado, + tabelas, + cartoes, + sync_status: SyncStatus::Local, + ..Default::default() + }; + + db.salvar(&estado_rust) } +/// Carrega rascunho e devolve estrutura simples para o frontend #[tauri::command] pub fn carregar_rascunho( db: State<'_, DbManager>, loja: String, data: String, -) -> Result, StorageError> { - db.carregar_rascunho(&loja, &data) +) -> Result, StorageError> { + match db.carregar_rascunho(&loja, &data)? { + Some(e) => { + // Simplifica para formato que o frontend espera + let total_sangrias: f64 = e.tabelas.sangrias.iter().filter_map(|r| r.valor).sum(); + let total_despesas: f64 = e.tabelas.despesas.iter().filter_map(|r| r.valor).sum(); + let total_receber: f64 = e.tabelas.areceber.iter().filter_map(|r| r.valor).sum(); + let despesa_rows: Vec<_> = e.tabelas.despesas.iter().filter_map(|r| { + r.descricao.as_ref().map(|d| serde_json::json!({"desc": d, "valor": r.valor})) + }).collect(); + let receber_rows: Vec<_> = e.tabelas.areceber.iter().filter_map(|r| { + r.descricao.as_ref().map(|d| serde_json::json!({"desc": d, "valor": r.valor})) + }).collect(); + + Ok(Some(serde_json::json!({ + "id_local": e.id, + "uuid": e.uuid, + "loja": e.loja, + "data": e.data, + "operador": e.operador, + "turno": e.turno, + "saldo_troco": e.saldo_troco, + "fechamento": e.fechamento, + "saldo_esperado": e.saldo_esperado, + "diferenca": e.fechamento - e.saldo_esperado, + "despesas": despesa_rows, + "total_sangrias": total_sangrias, + "total_despesas": total_despesas, + "vales": 0.0, + "cartoes": { + "credito": e.cartoes.credito.iter().find_map(|r| r.valor).unwrap_or(0.0), + "debito": e.cartoes.debito.iter().find_map(|r| r.valor).unwrap_or(0.0), + "alimentacao": e.cartoes.alimentacao.iter().find_map(|r| r.valor).unwrap_or(0.0), + "voucher": e.cartoes.voucher.iter().find_map(|r| r.valor).unwrap_or(0.0), + "cancelamentos": 0.0, + }, + "receber": receber_rows, + "observacoes": "", + "sync_status": "local", + }))) + } + None => Ok(None), + } } #[tauri::command] @@ -387,16 +493,53 @@ pub fn listar_fechamentos( db: State<'_, DbManager>, loja: String, limite: Option, -) -> Result, StorageError> { - db.listar(&loja, limite.unwrap_or(50)) +) -> Result, StorageError> { + let rows = db.listar(&loja, limite.unwrap_or(50))?; + Ok(rows.into_iter().map(|e| serde_json::json!({ + "id": e.id, + "uuid": e.uuid, + "data": e.data, + "operador": e.operador, + "turno": e.turno, + "saldo_esperado": e.saldo_esperado, + "sync_status": format!("{:?}", e.sync_status).to_lowercase(), + })).collect()) } #[tauri::command] pub fn buscar_fechamento_por_id( db: State<'_, DbManager>, id: i64, -) -> Result, StorageError> { - db.buscar_por_id(id) +) -> Result, StorageError> { + match db.buscar_por_id(id)? { + Some(e) => Ok(Some(serde_json::json!({ + "id_local": e.id, + "uuid": e.uuid, + "loja": e.loja, + "data": e.data, + "operador": e.operador, + "turno": e.turno, + "saldo_troco": e.saldo_troco, + "fechamento": e.fechamento, + "saldo_esperado": e.saldo_esperado, + "diferenca": e.fechamento - e.saldo_esperado, + "despesas": e.tabelas.despesas.iter().filter_map(|r| r.descricao.as_ref().map(|d| serde_json::json!({"desc": d, "valor": r.valor}))).collect::>(), + "total_sangrias": e.tabelas.sangrias.iter().filter_map(|r| r.valor).sum::(), + "total_despesas": e.tabelas.despesas.iter().filter_map(|r| r.valor).sum::(), + "vales": 0.0, + "cartoes": { + "credito": e.cartoes.credito.iter().find_map(|r| r.valor).unwrap_or(0.0), + "debito": e.cartoes.debito.iter().find_map(|r| r.valor).unwrap_or(0.0), + "alimentacao": e.cartoes.alimentacao.iter().find_map(|r| r.valor).unwrap_or(0.0), + "voucher": e.cartoes.voucher.iter().find_map(|r| r.valor).unwrap_or(0.0), + "cancelamentos": 0.0, + }, + "receber": e.tabelas.areceber.iter().filter_map(|r| r.descricao.as_ref().map(|d| serde_json::json!({"desc": d, "valor": r.valor}))).collect::>(), + "observacoes": "", + "sync_status": format!("{:?}", e.sync_status).to_lowercase(), + }))), + None => Ok(None), + } } #[tauri::command] diff --git a/src/index.html b/src/index.html index 5e7f1d8..b598d71 100644 --- a/src/index.html +++ b/src/index.html @@ -613,7 +613,7 @@ function calcular() { estado.total_despesas = estado.despesas.filter(d => !d.desc.includes('Sangria')).reduce((s,d) => s+d.valor, 0); estado.vales = parseFloat(val('f-vales')) || 0; estado.cartoes = { - credo: parseFloat(val('f-credito')) || 0, + credito: parseFloat(val('f-credito')) || 0, debito: parseFloat(val('f-debito')) || 0, alimentacao: parseFloat(val('f-alimentacao')) || 0, voucher: parseFloat(val('f-voucher')) || 0, @@ -642,7 +642,7 @@ function updateBadges() { async function salvarRascunho(silent = false) { calcular(); try { - const result = await invokeSafe('salvar_local', { estado: JSON.stringify(estado) }); + const result = await invokeSafe('salvar_fechamento', { estado }); estado.id_local = result.id; estado.uuid = result.uuid; if (!silent) toast('Rascunho salvo (local)', 'success'); @@ -689,7 +689,7 @@ async function enviarFechamento() { if (!estado.loja || !estado.data) { toast('Loja e data so obrigatorios', 'error'); return; } showLoad('Enviando ao servidor…'); try { - await invokeSafe('enviar_fechamento', { estado: JSON.stringify(estado) }); + await invokeSafe('sb_salvar_fechamento', { estado }); toast('Enviado com sucesso!', 'success'); atualizarSyncBadge('synced'); } catch(e) { toast(`Erro ao enviar: ${e}`, 'error'); } @@ -739,7 +739,7 @@ async function imprimirAgora() { document.getElementById('modal-print').classList.remove('show'); showLoad('Imprimindo…'); try { - await invokeSafe('imprimir_fechamento', { estado: JSON.stringify(estado) }); + await invokeSafe('imprimir_recibo', { estado }); toast('Impresso com sucesso!', 'success'); } catch(e) { toast(`Erro na impressao: ${e}`, 'error'); } hideLoad(); @@ -755,7 +755,7 @@ async function listarRecentes() { if (!loja) { toast('Selecione a loja primeiro', 'error'); return; } showLoad('Carregando recentes…'); try { - const lista = await invokeSafe('listar_recentes', { loja, limite: 20 }); + const lista = await invokeSafe('sb_listar_recentes', { loja, limite: 20 }); const html = lista.map(r => ` ${r.data}${r.operador||'—'}${r.turno}º @@ -785,7 +785,7 @@ async function selecionarRecente(id) { document.getElementById('modal-recentes')?.classList.remove('show'); showLoad('Carregando…'); try { - const r = await invokeSafe('buscar_fechamento', { id }); + const r = await invokeSafe('buscar_fechamento_por_id', { id }); Object.assign(estado, r); document.getElementById('f-saldo-troco').value = r.saldo_troco || ''; document.getElementById('f-fechamento').value = r.fechamento || '';