feat: integrate barcode scanning functionality in 'Almoxarifado' for improved product search and registration, along with image upload support for enhanced inventory management

This commit is contained in:
2025-12-21 09:07:03 -03:00
parent fdbecff4fa
commit e4ffc1ae2a
10 changed files with 1656 additions and 37 deletions

View File

@@ -55,7 +55,8 @@ export const listarMateriais = query({
materiais = materiais.filter(
(m) =>
m.codigo.toLowerCase().includes(buscaLower) ||
m.nome.toLowerCase().includes(buscaLower)
m.nome.toLowerCase().includes(buscaLower) ||
(m.codigoBarras && m.codigoBarras.toLowerCase().includes(buscaLower))
);
}
@@ -81,6 +82,30 @@ export const obterMaterial = query({
}
});
export const buscarMaterialPorCodigoBarras = query({
args: { codigoBarras: v.string() },
handler: async (ctx, args) => {
const usuario = await getCurrentUserFunction(ctx);
if (!usuario) return null;
try {
await ctx.runQuery(internal.permissoesAcoes.assertPermissaoAcaoAtual, {
recurso: 'almoxarifado',
acao: 'listar'
});
} catch {
return null;
}
const material = await ctx.db
.query('materiais')
.withIndex('by_codigoBarras', (q) => q.eq('codigoBarras', args.codigoBarras))
.first();
return material ?? null;
}
});
export const listarMovimentacoes = query({
args: {
materialId: v.optional(v.id('materiais')),
@@ -595,7 +620,10 @@ export const criarMaterial = mutation({
estoqueMaximo: v.optional(v.number()),
estoqueAtual: v.optional(v.number()),
localizacao: v.optional(v.string()),
fornecedor: v.optional(v.string())
fornecedor: v.optional(v.string()),
codigoBarras: v.optional(v.string()),
imagemUrl: v.optional(v.string()),
imagemBase64: v.optional(v.string())
},
handler: async (ctx, args) => {
await ctx.runQuery(internal.permissoesAcoes.assertPermissaoAcaoAtual, {
@@ -613,6 +641,18 @@ export const criarMaterial = mutation({
throw new Error('Código do material já existe');
}
// Verificar se código de barras já existe (se fornecido)
if (args.codigoBarras) {
const codigoBarrasExistente = await ctx.db
.query('materiais')
.withIndex('by_codigoBarras', (q) => q.eq('codigoBarras', args.codigoBarras))
.first();
if (codigoBarrasExistente) {
throw new Error('Código de barras já está cadastrado para outro material');
}
}
const usuario = await getCurrentUserFunction(ctx);
if (!usuario) throw new Error('Usuário não autenticado');
@@ -650,6 +690,9 @@ export const editarMaterial = mutation({
estoqueMaximo: v.optional(v.number()),
localizacao: v.optional(v.string()),
fornecedor: v.optional(v.string()),
codigoBarras: v.optional(v.string()),
imagemUrl: v.optional(v.string()),
imagemBase64: v.optional(v.string()),
ativo: v.optional(v.boolean())
},
handler: async (ctx, args) => {
@@ -673,6 +716,18 @@ export const editarMaterial = mutation({
}
}
// Verificar se código de barras já existe (se foi alterado)
if (args.codigoBarras && args.codigoBarras !== material.codigoBarras) {
const codigoBarrasExistente = await ctx.db
.query('materiais')
.withIndex('by_codigoBarras', (q) => q.eq('codigoBarras', args.codigoBarras))
.first();
if (codigoBarrasExistente) {
throw new Error('Código de barras já está cadastrado para outro material');
}
}
const dadosAnteriores = { ...material };
const dadosNovos: Partial<Doc<'materiais'>> & { atualizadoEm: number } = {
atualizadoEm: Date.now()
@@ -688,6 +743,9 @@ export const editarMaterial = mutation({
if (args.estoqueMaximo !== undefined) dadosNovos.estoqueMaximo = args.estoqueMaximo;
if (args.localizacao !== undefined) dadosNovos.localizacao = args.localizacao;
if (args.fornecedor !== undefined) dadosNovos.fornecedor = args.fornecedor;
if (args.codigoBarras !== undefined) dadosNovos.codigoBarras = args.codigoBarras;
if (args.imagemUrl !== undefined) dadosNovos.imagemUrl = args.imagemUrl;
if (args.imagemBase64 !== undefined) dadosNovos.imagemBase64 = args.imagemBase64;
if (args.ativo !== undefined) dadosNovos.ativo = args.ativo;
await ctx.db.patch(args.id, dadosNovos);