Ferramenta desktop em Python para atualização automatizada de preços e estoque de perfumes no ERP Bling.
Recebe uma planilha XLSX do fornecedor e um CSV exportado do Bling, cruza os dados por nome de perfume com algoritmo de matching fuzzy (Jaccard), calcula os preços finais aplicando câmbio e frete, suporta decomposição 1:N ("Vários num Só"), e exporta um CSV pronto para reimportação no Bling.
🆕 Novidades da Versão 2.1: Suporte completo a produtos compostos (1:N) com a janela "Vários num Só", botão de divisão automática "➗ Repartir Igualmente" com alerta de sobras, e orquestração de múltiplas reassociações para um único item do fornecedor.
- Visão Geral da Arquitetura
- Fluxo Completo de Processamento
- Funcionalidades
- Estrutura do Projeto
- Como Usar
- Colunas Esperadas
- Lógica de Preços
- Algoritmo de Matching
- Interface Gráfica — Classes e Janelas
- Histórico de Versões
O programa é dividido em dois arquivos com responsabilidades bem separadas:
interface_perfumaria.pyw → Tudo que o usuário VÊ e INTERAGE (Tkinter GUI, Popups, Modais)
logica_perfumaria.py → Tudo que o programa CALCULA e PROCESSA (Pandas, Jaccard, Preços)
A interface nunca faz cálculos de preço ou matching. A lógica nunca cria janelas ou exibe mensagens. A comunicação entre eles é feita via dicionários e callbacks.
No Windows, a extensão .pyw faz o Python rodar sem abrir a janela do terminal — só a interface gráfica aparece. Isso permite executar com duplo clique sem ver a tela preta do CMD.
O Tkinter (biblioteca gráfica do Python) é single-threaded: se o processamento pesado rodar na thread principal, a interface trava até terminar. Para resolver isso:
- O processamento roda numa thread separada (
threading.Thread) - A thread envia mensagens de log via
queue.Queue(fila thread-safe) - A thread principal drena a fila a cada 100ms via
root.after()e atualiza o log visual
Regra de ouro: NUNCA atualize widgets do Tkinter de uma thread secundária. Isso causa crashes aleatórios. Sempre use fila +
after().
O programa segue um pipeline linear com pontos de intervenção manual:
┌─────────────────┐ ┌─────────────────┐ ┌──────────────────────┐
│ 1. LER XLSX │ ──→ │ 2. LER CSV │ ──→ │ 3. PASSADA 1 │
│ (Fornecedor) │ │ (Bling) │ │ Matching Jaccard │
└─────────────────┘ └─────────────────┘ └──────────┬───────────┘
│
┌──────────────────────────────────┘
▼
┌─────────────────────┐ ┌──────────────────────────┐
│ 4. DETECÇÃO DE │ ──→ │ 5. PASSADA 2 │
│ CONFLITOS (N:1) │ │ Aplicar Preço/Estoque │
└─────────────────────┘ └──────────┬───────────────┘
│
┌────────────────────────────┘
▼
┌───────────────────────┐ ┌─────────────────────────┐
│ 6. REASSOCIAÇÃO │ ──→ │ 7. FILTRO DE VARIAÇÃO │
│ MANUAL (1:1 / 1:N) │ │ (pergunta individual) │
└───────────────────────┘ └──────────┬──────────────┘
│
┌──────────────────────────────┘
▼
┌───────────────────────┐ ┌──────────────────────┐
│ 8. PREVIEW │ ──→ │ 9. EXPORTAR CSV │
│ (conferência visual) │ │ (perfumes_atualizados│
└───────────────────────┘ │ .csv) │
└──────────────────────┘
- CSV do Bling: lido com
pandas.read_csv(), separador;, encodingutf-8-sig(ignora BOM) - XLSX do Fornecedor: lido com
pandas.read_excel(),dtype=strpara evitar conversões numéricas automáticas - O XLSX passa por detecção flexível de colunas — aceita variações de nome (ver seção Colunas Esperadas)
Para cada perfume do XLSX, busca o melhor candidato no CSV (ver seção Algoritmo de Matching).
Se 2+ produtos do XLSX apontam para o mesmo produto do CSV → conflito. Os itens conflitantes são removidos do mapeamento automático e enviados para a lista de "não encontrados", dando ao usuário a chance de resolvê-los manualmente na tela de reassociação.
Por que conflitos são perigosos? Se dois perfumes do XLSX apontam para o mesmo SKU no CSV, o último processado "esmaga" o preço do primeiro silenciosamente. O programa bloqueia isso.
Os preços/estoques são calculados e escritos no DataFrame do Pandas em memória — nenhum arquivo é salvo nesta etapa. Isso permite que o usuário revise tudo antes de gravar.
Se há produtos não encontrados (incluindo os conflitantes), o programa abre a janela de Reassociação:
- Lista de todos os itens pendentes com combobox filtrável.
- Associação 1:1: selecione diretamente o produto correspondente do CSV.
- Associação 1:N ("📦 Vários"): para itens como
"ZAKAT VARIOS"(composto por múltiplos perfumes), abra a janela de decomposição e associe N produtos individuais do CSV com suas quantidades.
Para cada produto cuja variação de preço é menor que o limite configurado (padrão R$10), o programa pergunta individualmente: "Deseja atualizar?". Isso evita alterações insignificantes que podem desalinhar com comparadores de preço.
Janela modal com tabela completa de todos os produtos que serão exportados (incluindo os decompostos de lote). Permite:
- Conferir cada match visualmente
- Trocar um match errado (duplo clique ou clique direito)
- Editar o valor diretamente (duplo clique na coluna "Preço Novo" / "Est. Novo")
- Desmarcar linhas com checkbox (☑/☐) para excluí-las da exportação
- Remover linhas via menu de contexto
Ao clicar "Confirmar e Exportar", o programa:
- Verifica se há produtos não associados (bloqueia no Modo Preço)
- Remove linhas desmarcadas (☐) do conjunto de exportação
- Grava somente as linhas alteradas no arquivo
perfumes_atualizados.csv
- Associação 1:N: Associa um único item do XLSX (ex:
"ZAKAT VARIOS"com 8 unidades) a múltiplos perfumes individuais no CSV do Bling (ex: 4 perfumes diferentes, 2 unidades de cada). - Divisão Automática ("➗ Repartir Igualmente"): Reparte a quantidade total do XLSX uniformemente entre os produtos adicionados.
- Gestão de Sobras / Restos: Se a divisão não for exata (ex: 9 unidades divididas entre 4 itens = 2 para cada), o sistema aplica a divisão inteira (2) e emite um alerta informando quantas unidades sobraram para alocação manual.
- Validação Dinâmica de Estoque: Valida em tempo real se a soma das quantidades atribuídas é menor ou igual ao estoque total do item do fornecedor.
- Importa CSV do Bling + XLSX do fornecedor
- Cruza produtos por nome usando matching fuzzy inteligente
- Aplica cotação do dólar e percentual de frete
- Calcula preço de compra, custo e venda (arredondado para terminar em
,90) - Exporta CSV atualizado para reimportação no Bling
- Atualiza somente a coluna Estoque do CSV
- Substitui a quantidade no processamento automático
- Soma quantidades na reassociação manual (incluindo itens decompostos)
- Requer coluna
Estoque (un)no XLSX
- Jaccard Scoring fuzzy-aware com threshold configurável
- Remoção automática de prefixos de fragrância (
Eau de Parfum,EDP,PERF, etc.) - Matching por prefixo e por similaridade de palavras (threshold 78%)
- Detecção e resolução de conflitos (2+ XLSX disputando 1 CSV → enviados para reassociação)
- Cobertura total: aceita match quando 100% das palavras do XLSX estão no CSV
- Remoção de códigos alfanuméricos para evitar falsos positivos
-
Janela de Preview modal antes de salvar — nada é gravado automaticamente
-
Tabela com: SKU, Nome XLSX, Descrição CSV, Preço Atual → Novo, Custo, GTIN
-
Checkboxes (☑/☐) por linha para marcar/desmarcar itens da exportação
-
Edição inline de preço/estoque com duplo clique na coluna de valor
-
Código de cores por variação de preço para produtos com GTIN/EAN:
Cor Condição Branco Preço não mudou 🟡 Amarelo 0 < Δ ≤ R$10🟠 Laranja R$10 < Δ < R$80🔴 Vermelho Δ ≥ R$80🔵 Azul Corrigido manualmente (reassociado / decomposto)
- Trocar match no Preview: duplo clique ou clique direito na linha
- Combobox filtrável com todos os produtos do CSV
- Botão "Ignorar e tentar novamente" — roda Jaccard excluindo candidatos já rejeitados
- Suporta múltiplas tentativas por produto
- Reassociação manual de produtos não encontrados e conflitantes
- Suporta associação simples (1:1) e decomposição em lote (1:N via botão 📦 Vários)
- Itens reassociados aparecem em azul no Preview com tag
REASSOC. - Funciona em ambos os modos (Preço e Estoque)
- Editar valor diretamente no preview (duplo clique no preço/estoque novo)
- Remover linha da exportação via menu de contexto
- Campo configurável "Avisar se variação < R$" (padrão: R$10)
- Para cada produto que se enquadra, pergunta individualmente: "Deseja atualizar?"
- Conflito N:1 no Preview: se duas linhas marcadas apontam para o mesmo produto CSV → botão Confirmar desabilitado (fica cinza) até desmarcar uma
- Produtos não associados (Modo Preço): exportação é bloqueada, exibindo lista de itens pendentes. O botão fica clicável para o usuário ver quais são, mas a exportação não prossegue
- Produtos não associados (Modo Estoque): são simplesmente ignorados, sem bloquear
- Remoção da lista fantasma: quando um produto é reassociado com sucesso, ele é removido da lista de "não encontrados" — evitando bloqueio indevido
- Processamento em thread separada — UI nunca trava
- Comunicação via
queue.Queuethread-safe - Diálogos sempre visíveis (
parent=self.root+lift()+focus_force()) - Layouts responsivos com garantia de ancoragem de botões no rodapé (
side=tk.BOTTOM) - Tratamento robusto de
NaNem células vazias do XLSX - Auto-instalação de dependências na primeira execução
AutoPreco Perfumes/
├── interface_perfumaria.pyw # Interface gráfica (Tkinter) — ponto de entrada e janelas visuais
├── logica_perfumaria.py # Toda a lógica de negócio: leitura, matching, cálculo, reambiguação
├── README.md # Documentação completa do projeto
├── .gitignore # Exclui .csv, .xlsx e arquivos temporários
└── prompt_transcrever_nota.md # Prompt auxiliar (referência)
| Arquivo | Responsabilidade |
|---|---|
logica_perfumaria.py |
Leitura de CSV/XLSX, normalização de texto, Jaccard scoring, mapeamento de colunas, detecção de conflitos, cálculo de preços, aplicação de reassociações simples e múltiplas, exportação do CSV final |
interface_perfumaria.pyw |
Janela principal (PerfumariaApp), preview modal (PreviewWindow), troca de match (TrocarMatchDialog), reassociação manual (ReassociarWindow) e decomposição em lote (VariosNumSoWindow) |
- Python 3.8+ instalado
- As dependências (
pandas,openpyxl) são instaladas automaticamente na primeira execução
# Duplo clique no arquivo .pyw (Windows) ou:
python interface_perfumaria.pyw- Selecionar CSV do Bling — exportado com as colunas de produtos
- Selecionar XLSX do Fornecedor — planilha com nomes, quantidades e valores
- Preencher parâmetros (modo preço):
- 💵 Cotação do dólar (deixe vazio se valores já estão em R$)
- 🚚 Percentual de frete (deixe vazio ou 0 para ignorar)
- 🔔 Limite de variação para alerta individual
- Clicar em "Processar"
- Resolver não encontrados:
- Para itens 1:1, escolha o produto no combobox.
- Para itens compostos (ex:
"ZAKAT VARIOS"), clique em "📦 Vários", adicione os perfumes, clique em "➗ Repartir Igualmente" e confirme.
- Responder filtro de variação — para variações pequenas, confirmar produto a produto
- Revisar o Preview — conferir cada linha, trocar matches errados, editar valores, marcar/desmarcar linhas
- Confirmar e Exportar — gera
perfumes_atualizados.csvna mesma pasta do CSV original
O sistema aceita variações de nome para cada coluna (mapeamento flexível):
| Coluna Interna | Apelidos Aceitos |
|---|---|
Nome do Perfume |
nome formatado (erp), produto, nome, perfume, description |
Quantidade (ml) |
quantidade, ml, volume, qty |
Valor Unitario |
valor unitário, valor unitario (us$), unit price, price, preco |
Estoque (un) (modo estoque) |
estoque, quantidade (un), unidades, stock, qtd estoque |
A comparação de nomes de colunas é case-insensitive e sem acentos — "Valor Unitário (US$)" bate com "valor unitario (us$)".
Colunas utilizadas (nomes padrão do Bling):
Descrição— nome do produtoCódigo— SKUPreço— preço de vendaPreço de Compra— preço de compraPreço de custo— preço de custoGTIN/EAN— código de barras (para alertas)Estoque— quantidade em estoque (modo estoque)Descrição do Produto no Fornecedor— descrição formatada
Preço de Compra = Valor Unitário (XLSX) × Cotação do Dólar
Preço de Custo = Preço de Compra × (1 + Frete%)
Preço de Venda = arredonda(Preço de Custo × 2) → termina em ,90
O preço final sempre termina em ,90 (precificação psicológica). A regra olha o dígito das unidades da parte inteira do valor calculado:
| Dígito das unidades | Direção | Exemplo |
|---|---|---|
< 5 |
Desce para o X9,90 anterior | 154,10 → 149,90 |
≥ 5 |
Sobe para o X9,90 seguinte | 158,77 → 159,90 |
O matching entre XLSX (fornecedor) e CSV (Bling) funciona em 2 passadas:
- Remove prefixos de fragrância (
Eau de Parfum,EDP,PERF,Cologne, etc.) - Normaliza texto (lowercase, remove acentos via decomposição Unicode NFKD)
- Remove códigos numéricos (tokens que começam com dígito:
2230,100M6173) - Filtra stopwords do domínio de perfumaria (
de,da,eau,ml,parfum, etc.) - Extrai palavras significativas — resultado é um SET (ordem não importa)
- Calcula Jaccard Score fuzzy contra todos os produtos do CSV (threshold 78% / prefixos)
- Se 2+ produtos do XLSX apontam para o mesmo CSV → conflito N:1
- Os itens conflitantes são enviados para a tela de Reassociação Manual
- Permite associação 1:1 direta ou decomposição 1:N via "Vários num Só"
A classe principal que gerencia toda a aplicação, orquestração de threads e logs.
Tabela modal com todos os produtos prontos para exportação. Suporta seleção com checkboxes, edição inline e menu de contexto.
Permite corrigir um match errado do algoritmo individualmente no preview.
Exibe lista de itens não encontrados / conflitantes. Apresenta o combobox individual e o botão "📦 Vários" por linha.
Janela modal dedicada a desmembrar um item do XLSX em múltiplos produtos do CSV:
- Adição/Remoção dinâmica de linhas (combo do CSV + campo de quantidade).
- Botão "➗ Repartir Igualmente" com cálculo de restos e pop-up informativo.
- Barra de status com totalizadores e validação contínua de estoque.
- Empacotamento de layout corrigido no rodapé (
side=tk.BOTTOM).
- ✨ Suporte a Associação 1:N ("Vários num Só"): Permite decompor um item do XLSX em múltiplos produtos do CSV do Bling.
- ➗ Divisão Automática de Quantidades: Novo botão "Repartir Igualmente" com tratamento inteligente de sobras/restos de divisão.
- 🎨 Correção de Layout em Telas Menores: Reestruturação do empacotamento (
pack) em modais para garantir visibilidade permanente dos botões no rodapé. - ⚡ Orquestração de Reassociações Múltiplas: Atualização da ponte de dados entre GUI e Engine de Cálculo para emitir N atualizações a partir de 1 registro.
- 📦 Suporte completo ao Modo Estoque.
- 🔍 Visualização avançada em Dark Mode com temas customizados.
- 🛡 Travas de segurança para conflitos N:1 e verificação de itens não associados.
Projeto interno de uso pessoal / comercial privado.