Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5e6f8b09a9 | |||
| 9ac4eb7042 | |||
| 2b8fa98ed7 | |||
| 77e927fef0 | |||
| 3f6b2ae6e4 | |||
| 35dcd27dda | |||
| bd867e8419 | |||
| da861ef964 | |||
| 8e642f2e0c | |||
| 7473db6b1f | |||
| 13489d58cf | |||
| 5ad8c1f395 | |||
| 103cd31e50 | |||
| 06783de4e2 | |||
| 11abac8daf | |||
| fea957dfb9 | |||
| 130b2b6da7 | |||
| b47d7766ad | |||
| 78fa778197 | |||
| 5e4340adca | |||
| c01133f39c |
@@ -36,10 +36,10 @@ fn load_config() -> (String, String) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Fallback: tenta variáveis de ambiente
|
// Fallback 3: chaves embedadas no binário (funciona em qualquer PC sem config)
|
||||||
(
|
(
|
||||||
std::env::var("SUPABASE_ANON_KEY").unwrap_or_default(),
|
"sb_publishable_NCUGwstslOvVt5JtGxKB9A_p-BERG57".to_string(),
|
||||||
std::env::var("SUPABASE_SERVICE_KEY").unwrap_or_default(),
|
"sb_secret_T6eHIKJDGaH53HMTG6UUKa_6ou6KfEW".to_string(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,6 +96,8 @@ fn main() {
|
|||||||
plugins::supabase::sb_carregar_rascunho,
|
plugins::supabase::sb_carregar_rascunho,
|
||||||
plugins::supabase::sb_listar_recentes,
|
plugins::supabase::sb_listar_recentes,
|
||||||
plugins::supabase::sb_buscar_por_id,
|
plugins::supabase::sb_buscar_por_id,
|
||||||
|
plugins::supabase::sb_buscar_por_uuid,
|
||||||
|
plugins::supabase::sb_atualizar_fechamento,
|
||||||
plugins::supabase::sb_salvar_listas,
|
plugins::supabase::sb_salvar_listas,
|
||||||
plugins::supabase::sb_carregar_listas,
|
plugins::supabase::sb_carregar_listas,
|
||||||
plugins::supabase::sb_online,
|
plugins::supabase::sb_online,
|
||||||
|
|||||||
@@ -127,6 +127,10 @@ pub struct ReciboData {
|
|||||||
pub cancelamentos_arr: Vec<ReciboLinha>,
|
pub cancelamentos_arr: Vec<ReciboLinha>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub observacoes: Option<String>,
|
pub observacoes: Option<String>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub clientes: i32,
|
||||||
|
#[serde(default)]
|
||||||
|
pub frango: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReciboData {
|
impl ReciboData {
|
||||||
@@ -318,8 +322,9 @@ impl ReciboData {
|
|||||||
out.extend(escpos::divider());
|
out.extend(escpos::divider());
|
||||||
|
|
||||||
// ── DIFERENÇA ──
|
// ── DIFERENÇA ──
|
||||||
|
// Diferença = total_fechamento - saldo_esperado - cancelamentos
|
||||||
out.extend(escpos::line_bold("DIFERENCA"));
|
out.extend(escpos::line_bold("DIFERENCA"));
|
||||||
let diff = self.diferenca;
|
let diff = self.fechamento - self.saldo_esperado - self.cancelamentos;
|
||||||
let diff_str = if diff >= 0.0 {
|
let diff_str = if diff >= 0.0 {
|
||||||
format!("+{}", self.fmt_money(diff))
|
format!("+{}", self.fmt_money(diff))
|
||||||
} else {
|
} else {
|
||||||
@@ -327,6 +332,12 @@ impl ReciboData {
|
|||||||
};
|
};
|
||||||
out.extend(escpos::title(&diff_str));
|
out.extend(escpos::title(&diff_str));
|
||||||
|
|
||||||
|
// ── CONTADORES ──
|
||||||
|
out.extend(escpos::line_bold("CONTADORES"));
|
||||||
|
out.extend(escpos::kv("Clientes:", &self.clientes.to_string()));
|
||||||
|
out.extend(escpos::kv("Frango Assado:", &self.frango.to_string()));
|
||||||
|
out.extend(escpos::divider());
|
||||||
|
|
||||||
// ── OBSERVAÇÕES ──
|
// ── OBSERVAÇÕES ──
|
||||||
if let Some(ref obs) = self.observacoes {
|
if let Some(ref obs) = self.observacoes {
|
||||||
if !obs.trim().is_empty() {
|
if !obs.trim().is_empty() {
|
||||||
|
|||||||
@@ -7,6 +7,29 @@ use std::time::Duration;
|
|||||||
use tauri::State;
|
use tauri::State;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
/// Remove acentos de uma string (ex: "União" → "Uniao")
|
||||||
|
fn sem_acento(s: &str) -> String {
|
||||||
|
s.replace("ã", "a")
|
||||||
|
.replace("á", "a")
|
||||||
|
.replace("à", "a")
|
||||||
|
.replace("â", "a")
|
||||||
|
.replace("é", "e")
|
||||||
|
.replace("è", "e")
|
||||||
|
.replace("ê", "e")
|
||||||
|
.replace("í", "i")
|
||||||
|
.replace("ì", "i")
|
||||||
|
.replace("î", "i")
|
||||||
|
.replace("õ", "o")
|
||||||
|
.replace("ó", "o")
|
||||||
|
.replace("ò", "o")
|
||||||
|
.replace("ô", "o")
|
||||||
|
.replace("ú", "u")
|
||||||
|
.replace("ù", "u")
|
||||||
|
.replace("û", "u")
|
||||||
|
.replace("ç", "c")
|
||||||
|
.replace("ñ", "n")
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub enum SupabaseError {
|
pub enum SupabaseError {
|
||||||
@@ -69,58 +92,75 @@ impl SupabaseClient {
|
|||||||
|
|
||||||
/// Salva/atualiza um fechamento na tabela `fechamentos_web`.
|
/// Salva/atualiza um fechamento na tabela `fechamentos_web`.
|
||||||
pub fn salvar_fechamento(&self, estado: &serde_json::Value) -> Result<Value, SupabaseError> {
|
pub fn salvar_fechamento(&self, estado: &serde_json::Value) -> Result<Value, SupabaseError> {
|
||||||
let uuid = estado
|
// Normaliza loja e turno para minúsculo (CHECK constraints do Postgres)
|
||||||
.get("uuid")
|
let loja = estado
|
||||||
|
.get("loja")
|
||||||
.and_then(|v| v.as_str())
|
.and_then(|v| v.as_str())
|
||||||
.unwrap_or("");
|
.map(|s| sem_acento(&s.to_lowercase()).replace(" ", "_"))
|
||||||
|
.unwrap_or_else(|| "uniao".to_string());
|
||||||
|
let data = estado.get("data").and_then(|v| v.as_str()).unwrap_or("");
|
||||||
|
let operador = estado.get("operador").and_then(|v| v.as_str()).unwrap_or("");
|
||||||
|
let id_fechamento = format!("{}_{}_{}", loja, data, operador)
|
||||||
|
.to_lowercase()
|
||||||
|
.replace(" ", "_");
|
||||||
|
let turno = estado
|
||||||
|
.get("turno")
|
||||||
|
.and_then(|v| v.as_str())
|
||||||
|
.map(|s| sem_acento(&s.to_lowercase()))
|
||||||
|
.unwrap_or_else(|| "manha".to_string());
|
||||||
|
|
||||||
let payload = serde_json::json!({
|
let payload = serde_json::json!({
|
||||||
"uuid": uuid,
|
"id_fechamento": id_fechamento,
|
||||||
"loja": estado["loja"],
|
"loja": loja,
|
||||||
"data": estado["data"],
|
"data": data,
|
||||||
"operador": estado["operador"],
|
"operador": operador,
|
||||||
"turno": estado["turno"],
|
"turno": turno,
|
||||||
"saldo_troco": estado["saldo_troco"],
|
"saldo_troco": estado.get("saldo_troco").and_then(|v| v.as_f64()).unwrap_or(0.0),
|
||||||
"saldo_esperado": estado["saldo_esperado"],
|
"saldo_credito": estado.get("credito").and_then(|v| v.as_f64()).unwrap_or(0.0),
|
||||||
"fechamento": estado["fechamento"],
|
"saldo_debito": estado.get("debito").and_then(|v| v.as_f64()).unwrap_or(0.0),
|
||||||
|
"saldo_alimentacao": estado.get("alimentacao").and_then(|v| v.as_f64()).unwrap_or(0.0),
|
||||||
|
"saldo_vales": estado.get("vales").and_then(|v| v.as_f64()).unwrap_or(0.0),
|
||||||
|
"saldo_areceber": estado.get("areceber").and_then(|v| v.as_f64()).unwrap_or(0.0),
|
||||||
|
"saldo_pixcnpj": estado.get("pixcnpj").and_then(|v| v.as_f64()).unwrap_or(0.0),
|
||||||
|
"fechamento_dinheiro": estado.get("fd").and_then(|v| v.as_f64()).unwrap_or(0.0),
|
||||||
|
"fechamento_cartoes": estado.get("fc").and_then(|v| v.as_f64()).unwrap_or(0.0),
|
||||||
|
"fechamento_areceber": estado.get("fr").and_then(|v| v.as_f64()).unwrap_or(0.0),
|
||||||
|
"total_sangrias": estado.get("total_sangrias").and_then(|v| v.as_f64()).unwrap_or(0.0),
|
||||||
|
"total_despesas": estado.get("total_despesas").and_then(|v| v.as_f64()).unwrap_or(0.0),
|
||||||
|
"total_cancelamentos": estado.get("total_cancelamentos").and_then(|v| v.as_f64()).unwrap_or(0.0),
|
||||||
|
"total_vales": estado.get("total_vales").and_then(|v| v.as_f64()).unwrap_or(0.0),
|
||||||
|
"total_pixcnpj": estado.get("total_pixcnpj").and_then(|v| v.as_f64()).unwrap_or(0.0),
|
||||||
|
"total_areceber": estado.get("total_areceber").and_then(|v| v.as_f64()).unwrap_or(0.0),
|
||||||
|
"total_cartao_credito": estado.get("total_cartao_credito").and_then(|v| v.as_f64()).unwrap_or(0.0),
|
||||||
|
"total_cartao_debito": estado.get("total_cartao_debito").and_then(|v| v.as_f64()).unwrap_or(0.0),
|
||||||
|
"total_cartao_alimentacao": estado.get("total_cartao_alimentacao").and_then(|v| v.as_f64()).unwrap_or(0.0),
|
||||||
|
"total_cartao_pix": estado.get("total_cartao_pix").and_then(|v| v.as_f64()).unwrap_or(0.0),
|
||||||
|
"saldo_esperado": estado.get("saldo_esperado").and_then(|v| v.as_f64()).unwrap_or(0.0),
|
||||||
"dados": estado,
|
"dados": estado,
|
||||||
"observacoes": "rascunho",
|
"observacoes": estado.get("observacoes").and_then(|v| v.as_str()).unwrap_or(""),
|
||||||
|
"clientes": estado.get("clientes").and_then(|v| v.as_i64()).unwrap_or(0),
|
||||||
|
"frango": estado.get("frango").and_then(|v| v.as_i64()).unwrap_or(0),
|
||||||
});
|
});
|
||||||
|
|
||||||
let _url = format!(
|
|
||||||
"{}/rest/v1/fechamentos_web?uuid=eq.{}&select=id",
|
|
||||||
self.base_url, uuid
|
|
||||||
);
|
|
||||||
|
|
||||||
// Upsert via POST com Prefer: resolution=merge-duplicates
|
// Upsert via POST com Prefer: resolution=merge-duplicates
|
||||||
let resp = self
|
let resp = self
|
||||||
.http
|
.http
|
||||||
.post(&format!("{}/rest/v1/rpc/upsert_fechamento", self.base_url))
|
.post(&format!("{}/rest/v1/fechamentos_web", self.base_url))
|
||||||
.headers(self.headers(true))
|
.headers(self.headers(true))
|
||||||
|
.header("Prefer", "resolution=merge-duplicates")
|
||||||
.json(&payload)
|
.json(&payload)
|
||||||
.send()?;
|
.send()?;
|
||||||
|
|
||||||
if resp.status().is_success() {
|
let status = resp.status();
|
||||||
Ok(serde_json::json!({ "ok": true, "uuid": uuid }))
|
if status.is_success() {
|
||||||
|
Ok(serde_json::json!({ "ok": true, "id_fechamento": id_fechamento }))
|
||||||
} else {
|
} else {
|
||||||
let body = resp.text().unwrap_or_default();
|
let body = resp.text().unwrap_or_default();
|
||||||
// Fallback: tenta POST direto na tabela
|
Err(SupabaseError::Api(format!(
|
||||||
let resp2 = self
|
"HTTP {}: {}",
|
||||||
.http
|
status.as_u16(),
|
||||||
.post(&format!("{}/rest/v1/fechamentos_web", self.base_url))
|
body
|
||||||
.headers(self.headers(true))
|
)))
|
||||||
.header("Prefer", "resolution=merge-duplicates")
|
|
||||||
.json(&payload)
|
|
||||||
.send()?;
|
|
||||||
if resp2.status().is_success() {
|
|
||||||
Ok(serde_json::json!({ "ok": true, "uuid": uuid }))
|
|
||||||
} else {
|
|
||||||
Err(SupabaseError::Api(format!(
|
|
||||||
"HTTP {}: {}",
|
|
||||||
resp2.status().as_u16(),
|
|
||||||
body
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,7 +193,59 @@ impl SupabaseClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lista fechamentos recentes de uma loja.
|
/// Busca um fechamento pelo UUID.
|
||||||
|
pub fn buscar_por_uuid(&self, uuid: &str) -> Result<Option<Value>, SupabaseError> {
|
||||||
|
let url = format!(
|
||||||
|
"{}/rest/v1/fechamentos_web?uuid=eq.{}&select=*",
|
||||||
|
self.base_url, uuid
|
||||||
|
);
|
||||||
|
|
||||||
|
let resp = self
|
||||||
|
.http
|
||||||
|
.get(&url)
|
||||||
|
.headers(self.headers(false))
|
||||||
|
.send()?;
|
||||||
|
|
||||||
|
if resp.status().is_success() {
|
||||||
|
let arr: Vec<Value> = resp.json()?;
|
||||||
|
Ok(arr.into_iter().next())
|
||||||
|
} else {
|
||||||
|
let status = resp.status();
|
||||||
|
let body = resp.text().unwrap_or_default();
|
||||||
|
Err(SupabaseError::Api(format!(
|
||||||
|
"HTTP {}: {}",
|
||||||
|
status.as_u16(),
|
||||||
|
body
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Atualiza campos específicos de um fechamento pelo UUID (PATCH).
|
||||||
|
pub fn atualizar_fechamento(&self, uuid: &str, updates: &serde_json::Value) -> Result<Value, SupabaseError> {
|
||||||
|
let url = format!(
|
||||||
|
"{}/rest/v1/fechamentos_web?uuid=eq.{}",
|
||||||
|
self.base_url, uuid
|
||||||
|
);
|
||||||
|
|
||||||
|
let resp = self
|
||||||
|
.http
|
||||||
|
.patch(&url)
|
||||||
|
.headers(self.headers(true))
|
||||||
|
.json(updates)
|
||||||
|
.send()?;
|
||||||
|
|
||||||
|
if resp.status().is_success() {
|
||||||
|
Ok(serde_json::json!({ "ok": true, "uuid": uuid }))
|
||||||
|
} else {
|
||||||
|
let status = resp.status();
|
||||||
|
let body = resp.text().unwrap_or_default();
|
||||||
|
Err(SupabaseError::Api(format!(
|
||||||
|
"HTTP {}: {}",
|
||||||
|
status.as_u16(),
|
||||||
|
body
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
pub fn listar_recentes(&self, loja: &str, limite: i64) -> Result<Vec<Value>, SupabaseError> {
|
pub fn listar_recentes(&self, loja: &str, limite: i64) -> Result<Vec<Value>, SupabaseError> {
|
||||||
let url = format!(
|
let url = format!(
|
||||||
"{}/rest/v1/fechamentos_web?loja=eq.{}&order=data.desc,atualizado_em.desc&limit={}&select=id,uuid,data,operador,turno,saldo_troco,saldo_esperado,fechamento,sync_status,observacoes,atualizado_em",
|
"{}/rest/v1/fechamentos_web?loja=eq.{}&order=data.desc,atualizado_em.desc&limit={}&select=id,uuid,data,operador,turno,saldo_troco,saldo_esperado,fechamento,sync_status,observacoes,atualizado_em",
|
||||||
@@ -322,6 +414,23 @@ pub fn sb_buscar_por_id(
|
|||||||
sb.buscar_por_id(id)
|
sb.buscar_por_id(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub fn sb_buscar_por_uuid(
|
||||||
|
sb: State<'_, SupabaseClient>,
|
||||||
|
uuid: String,
|
||||||
|
) -> Result<Option<serde_json::Value>, SupabaseError> {
|
||||||
|
sb.buscar_por_uuid(&uuid)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub fn sb_atualizar_fechamento(
|
||||||
|
sb: State<'_, SupabaseClient>,
|
||||||
|
uuid: String,
|
||||||
|
updates: serde_json::Value,
|
||||||
|
) -> Result<serde_json::Value, SupabaseError> {
|
||||||
|
sb.atualizar_fechamento(&uuid, &updates)
|
||||||
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn sb_salvar_listas(
|
pub fn sb_salvar_listas(
|
||||||
sb: State<'_, SupabaseClient>,
|
sb: State<'_, SupabaseClient>,
|
||||||
|
|||||||
+767
-307
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user