feat: implement barcode search configuration in 'Almoxarifado', integrating multiple external APIs for enhanced product information retrieval and improving user experience with new modals for data handling
This commit is contained in:
166
packages/backend/convex/configuracaoBuscaCodigoBarras.ts
Normal file
166
packages/backend/convex/configuracaoBuscaCodigoBarras.ts
Normal file
@@ -0,0 +1,166 @@
|
||||
import { v } from 'convex/values';
|
||||
import { mutation, query, internalQuery } from './_generated/server';
|
||||
import { encryptSMTPPassword } from './auth/utils';
|
||||
import { registrarAtividade } from './logsAtividades';
|
||||
|
||||
/**
|
||||
* Obter configuração de busca de código de barras ativa (credenciais mascaradas)
|
||||
*/
|
||||
export const obterConfigBuscaCodigoBarras = query({
|
||||
args: {},
|
||||
handler: async (ctx) => {
|
||||
const config = await ctx.db
|
||||
.query('configuracaoBuscaCodigoBarras')
|
||||
.withIndex('by_ativo', (q) => q.eq('ativo', true))
|
||||
.first();
|
||||
|
||||
if (!config) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Retornar config com credenciais mascaradas
|
||||
return {
|
||||
_id: config._id,
|
||||
// GS1 Brasil
|
||||
gs1BrasilClientId: config.gs1BrasilClientId || '',
|
||||
gs1BrasilClientSecret: '********', // Mascarar
|
||||
gs1BrasilTokenUrl: config.gs1BrasilTokenUrl || '',
|
||||
gs1BrasilApiUrl: config.gs1BrasilApiUrl || '',
|
||||
gs1BrasilAtivo: config.gs1BrasilAtivo,
|
||||
// Bluesoft Cosmo
|
||||
bluesoftApiKey: '********', // Mascarar
|
||||
bluesoftApiUrl: config.bluesoftApiUrl || '',
|
||||
bluesoftAtivo: config.bluesoftAtivo,
|
||||
// Product-Search.net
|
||||
productSearchApiKey: '********', // Mascarar
|
||||
productSearchApiUrl: config.productSearchApiUrl || '',
|
||||
productSearchAtivo: config.productSearchAtivo,
|
||||
ativo: config.ativo,
|
||||
atualizadoEm: config.atualizadoEm
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Salvar configuração de busca de código de barras
|
||||
*/
|
||||
export const salvarConfigBuscaCodigoBarras = mutation({
|
||||
args: {
|
||||
// GS1 Brasil
|
||||
gs1BrasilClientId: v.optional(v.string()),
|
||||
gs1BrasilClientSecret: v.optional(v.string()),
|
||||
gs1BrasilTokenUrl: v.optional(v.string()),
|
||||
gs1BrasilApiUrl: v.optional(v.string()),
|
||||
gs1BrasilAtivo: v.boolean(),
|
||||
// Bluesoft Cosmo
|
||||
bluesoftApiKey: v.optional(v.string()),
|
||||
bluesoftApiUrl: v.optional(v.string()),
|
||||
bluesoftAtivo: v.boolean(),
|
||||
// Product-Search.net
|
||||
productSearchApiKey: v.optional(v.string()),
|
||||
productSearchApiUrl: v.optional(v.string()),
|
||||
productSearchAtivo: v.boolean(),
|
||||
configuradoPorId: v.id('usuarios')
|
||||
},
|
||||
returns: v.union(
|
||||
v.object({ sucesso: v.literal(true), configId: v.id('configuracaoBuscaCodigoBarras') }),
|
||||
v.object({ sucesso: v.literal(false), erro: v.string() })
|
||||
),
|
||||
handler: async (ctx, args) => {
|
||||
// Buscar config ativa anterior para manter credenciais se não fornecidas
|
||||
const configAtiva = await ctx.db
|
||||
.query('configuracaoBuscaCodigoBarras')
|
||||
.withIndex('by_ativo', (q) => q.eq('ativo', true))
|
||||
.first();
|
||||
|
||||
// Determinar credenciais: usar novas se fornecidas, senão manter as atuais
|
||||
let gs1BrasilClientSecret: string | undefined;
|
||||
if (args.gs1BrasilClientSecret && args.gs1BrasilClientSecret.trim().length > 0) {
|
||||
// Nova credencial fornecida, criptografar
|
||||
gs1BrasilClientSecret = await encryptSMTPPassword(args.gs1BrasilClientSecret);
|
||||
} else if (configAtiva?.gs1BrasilClientSecret) {
|
||||
// Credencial não fornecida, manter a atual
|
||||
gs1BrasilClientSecret = configAtiva.gs1BrasilClientSecret;
|
||||
}
|
||||
|
||||
let bluesoftApiKey: string | undefined;
|
||||
if (args.bluesoftApiKey && args.bluesoftApiKey.trim().length > 0) {
|
||||
bluesoftApiKey = await encryptSMTPPassword(args.bluesoftApiKey);
|
||||
} else if (configAtiva?.bluesoftApiKey) {
|
||||
bluesoftApiKey = configAtiva.bluesoftApiKey;
|
||||
}
|
||||
|
||||
let productSearchApiKey: string | undefined;
|
||||
if (args.productSearchApiKey && args.productSearchApiKey.trim().length > 0) {
|
||||
productSearchApiKey = await encryptSMTPPassword(args.productSearchApiKey);
|
||||
} else if (configAtiva?.productSearchApiKey) {
|
||||
productSearchApiKey = configAtiva.productSearchApiKey;
|
||||
}
|
||||
|
||||
// Desativar config anterior
|
||||
const configsAntigas = await ctx.db
|
||||
.query('configuracaoBuscaCodigoBarras')
|
||||
.withIndex('by_ativo', (q) => q.eq('ativo', true))
|
||||
.collect();
|
||||
|
||||
for (const config of configsAntigas) {
|
||||
await ctx.db.patch(config._id, { ativo: false });
|
||||
}
|
||||
|
||||
// Criar nova config
|
||||
const configId = await ctx.db.insert('configuracaoBuscaCodigoBarras', {
|
||||
gs1BrasilClientId: args.gs1BrasilClientId || undefined,
|
||||
gs1BrasilClientSecret,
|
||||
gs1BrasilTokenUrl: args.gs1BrasilTokenUrl || undefined,
|
||||
gs1BrasilApiUrl: args.gs1BrasilApiUrl || undefined,
|
||||
gs1BrasilAtivo: args.gs1BrasilAtivo,
|
||||
bluesoftApiKey,
|
||||
bluesoftApiUrl: args.bluesoftApiUrl || undefined,
|
||||
bluesoftAtivo: args.bluesoftAtivo,
|
||||
productSearchApiKey,
|
||||
productSearchApiUrl: args.productSearchApiUrl || undefined,
|
||||
productSearchAtivo: args.productSearchAtivo,
|
||||
ativo: true,
|
||||
configuradoPor: args.configuradoPorId,
|
||||
atualizadoEm: Date.now()
|
||||
});
|
||||
|
||||
// Log de atividade
|
||||
await registrarAtividade(
|
||||
ctx,
|
||||
args.configuradoPorId,
|
||||
'configurar',
|
||||
'buscaCodigoBarras',
|
||||
JSON.stringify({
|
||||
gs1BrasilAtivo: args.gs1BrasilAtivo,
|
||||
bluesoftAtivo: args.bluesoftAtivo,
|
||||
productSearchAtivo: args.productSearchAtivo
|
||||
}),
|
||||
configId
|
||||
);
|
||||
|
||||
return { sucesso: true as const, configId };
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Obter configuração de busca de código de barras (internal query)
|
||||
* Usado pela action de busca para obter credenciais descriptografadas
|
||||
*/
|
||||
export const obterConfigBuscaCodigoBarrasInternal = internalQuery({
|
||||
args: {},
|
||||
handler: async (ctx) => {
|
||||
const config = await ctx.db
|
||||
.query('configuracaoBuscaCodigoBarras')
|
||||
.withIndex('by_ativo', (q) => q.eq('ativo', true))
|
||||
.first();
|
||||
|
||||
if (!config) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Retornar config completa (para uso interno)
|
||||
return config;
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user