feat: Implement batch item removal and pedido splitting for pedidos, and add document management for atas.
This commit is contained in:
@@ -47,9 +47,7 @@ export const listByObjetoIds = query({
|
||||
links.push(...partial);
|
||||
}
|
||||
|
||||
const ataIds = Array.from(
|
||||
new Set(links.map((l) => l.ataId as Id<'atas'>))
|
||||
);
|
||||
const ataIds = Array.from(new Set(links.map((l) => l.ataId as Id<'atas'>)));
|
||||
|
||||
if (ataIds.length === 0) return [];
|
||||
|
||||
@@ -64,9 +62,9 @@ export const create = mutation({
|
||||
dataInicio: v.optional(v.string()),
|
||||
dataFim: v.optional(v.string()),
|
||||
empresaId: v.id('empresas'),
|
||||
pdf: v.optional(v.string()),
|
||||
pdf: v.optional(v.id('_storage')),
|
||||
numeroSei: v.string(),
|
||||
objetosIds: v.optional(v.array(v.id('objetos')))
|
||||
objetosIds: v.array(v.id('objetos'))
|
||||
},
|
||||
handler: async (ctx, args) => {
|
||||
const user = await getCurrentUserFunction(ctx);
|
||||
@@ -74,23 +72,22 @@ export const create = mutation({
|
||||
|
||||
const ataId = await ctx.db.insert('atas', {
|
||||
numero: args.numero,
|
||||
numeroSei: args.numeroSei,
|
||||
empresaId: args.empresaId,
|
||||
dataInicio: args.dataInicio,
|
||||
dataFim: args.dataFim,
|
||||
empresaId: args.empresaId,
|
||||
pdf: args.pdf,
|
||||
numeroSei: args.numeroSei,
|
||||
criadoPor: user._id,
|
||||
criadoEm: Date.now(),
|
||||
atualizadoEm: Date.now()
|
||||
});
|
||||
|
||||
if (args.objetosIds) {
|
||||
for (const objetoId of args.objetosIds) {
|
||||
await ctx.db.insert('atasObjetos', {
|
||||
ataId,
|
||||
objetoId
|
||||
});
|
||||
}
|
||||
// Vincular objetos
|
||||
for (const objetoId of args.objetosIds) {
|
||||
await ctx.db.insert('atasObjetos', {
|
||||
ataId,
|
||||
objetoId
|
||||
});
|
||||
}
|
||||
|
||||
return ataId;
|
||||
@@ -101,12 +98,12 @@ export const update = mutation({
|
||||
args: {
|
||||
id: v.id('atas'),
|
||||
numero: v.string(),
|
||||
numeroSei: v.string(),
|
||||
empresaId: v.id('empresas'),
|
||||
dataInicio: v.optional(v.string()),
|
||||
dataFim: v.optional(v.string()),
|
||||
empresaId: v.id('empresas'),
|
||||
pdf: v.optional(v.string()),
|
||||
numeroSei: v.string(),
|
||||
objetosIds: v.optional(v.array(v.id('objetos')))
|
||||
pdf: v.optional(v.id('_storage')),
|
||||
objetosIds: v.array(v.id('objetos'))
|
||||
},
|
||||
handler: async (ctx, args) => {
|
||||
const user = await getCurrentUserFunction(ctx);
|
||||
@@ -114,45 +111,42 @@ export const update = mutation({
|
||||
|
||||
await ctx.db.patch(args.id, {
|
||||
numero: args.numero,
|
||||
numeroSei: args.numeroSei,
|
||||
empresaId: args.empresaId,
|
||||
dataInicio: args.dataInicio,
|
||||
dataFim: args.dataFim,
|
||||
empresaId: args.empresaId,
|
||||
pdf: args.pdf,
|
||||
numeroSei: args.numeroSei,
|
||||
atualizadoEm: Date.now()
|
||||
});
|
||||
|
||||
if (args.objetosIds !== undefined) {
|
||||
// Remove existing links
|
||||
const existingLinks = await ctx.db
|
||||
.query('atasObjetos')
|
||||
.withIndex('by_ataId', (q) => q.eq('ataId', args.id))
|
||||
.collect();
|
||||
// Atualizar objetos vinculados
|
||||
// Primeiro remove todos os vínculos existentes
|
||||
const existingLinks = await ctx.db
|
||||
.query('atasObjetos')
|
||||
.withIndex('by_ataId', (q) => q.eq('ataId', args.id))
|
||||
.collect();
|
||||
|
||||
for (const link of existingLinks) {
|
||||
await ctx.db.delete(link._id);
|
||||
}
|
||||
for (const link of existingLinks) {
|
||||
await ctx.db.delete(link._id);
|
||||
}
|
||||
|
||||
// Add new links
|
||||
for (const objetoId of args.objetosIds) {
|
||||
await ctx.db.insert('atasObjetos', {
|
||||
ataId: args.id,
|
||||
objetoId
|
||||
});
|
||||
}
|
||||
// Adiciona os novos vínculos
|
||||
for (const objetoId of args.objetosIds) {
|
||||
await ctx.db.insert('atasObjetos', {
|
||||
ataId: args.id,
|
||||
objetoId
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const remove = mutation({
|
||||
args: {
|
||||
id: v.id('atas')
|
||||
},
|
||||
args: { id: v.id('atas') },
|
||||
handler: async (ctx, args) => {
|
||||
const user = await getCurrentUserFunction(ctx);
|
||||
if (!user) throw new Error('Unauthorized');
|
||||
|
||||
// Remove linked objects
|
||||
// Remover vínculos com objetos
|
||||
const links = await ctx.db
|
||||
.query('atasObjetos')
|
||||
.withIndex('by_ataId', (q) => q.eq('ataId', args.id))
|
||||
@@ -162,6 +156,79 @@ export const remove = mutation({
|
||||
await ctx.db.delete(link._id);
|
||||
}
|
||||
|
||||
// Remover documentos vinculados
|
||||
const docs = await ctx.db
|
||||
.query('atasDocumentos')
|
||||
.withIndex('by_ataId', (q) => q.eq('ataId', args.id))
|
||||
.collect();
|
||||
|
||||
for (const doc of docs) {
|
||||
await ctx.storage.delete(doc.storageId);
|
||||
await ctx.db.delete(doc._id);
|
||||
}
|
||||
|
||||
await ctx.db.delete(args.id);
|
||||
}
|
||||
});
|
||||
|
||||
export const generateUploadUrl = mutation({
|
||||
args: {},
|
||||
handler: async (ctx) => {
|
||||
return await ctx.storage.generateUploadUrl();
|
||||
}
|
||||
});
|
||||
|
||||
export const saveDocumento = mutation({
|
||||
args: {
|
||||
ataId: v.id('atas'),
|
||||
nome: v.string(),
|
||||
storageId: v.id('_storage'),
|
||||
tipo: v.string(),
|
||||
tamanho: v.number()
|
||||
},
|
||||
handler: async (ctx, args) => {
|
||||
const user = await getCurrentUserFunction(ctx);
|
||||
if (!user) throw new Error('Unauthorized');
|
||||
|
||||
return await ctx.db.insert('atasDocumentos', {
|
||||
ataId: args.ataId,
|
||||
nome: args.nome,
|
||||
storageId: args.storageId,
|
||||
tipo: args.tipo,
|
||||
tamanho: args.tamanho,
|
||||
criadoPor: user._id,
|
||||
criadoEm: Date.now()
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
export const removeDocumento = mutation({
|
||||
args: { id: v.id('atasDocumentos') },
|
||||
handler: async (ctx, args) => {
|
||||
const user = await getCurrentUserFunction(ctx);
|
||||
if (!user) throw new Error('Unauthorized');
|
||||
|
||||
const doc = await ctx.db.get(args.id);
|
||||
if (!doc) throw new Error('Documento não encontrado');
|
||||
|
||||
await ctx.storage.delete(doc.storageId);
|
||||
await ctx.db.delete(args.id);
|
||||
}
|
||||
});
|
||||
|
||||
export const getDocumentos = query({
|
||||
args: { ataId: v.id('atas') },
|
||||
handler: async (ctx, args) => {
|
||||
const docs = await ctx.db
|
||||
.query('atasDocumentos')
|
||||
.withIndex('by_ataId', (q) => q.eq('ataId', args.ataId))
|
||||
.collect();
|
||||
|
||||
return await Promise.all(
|
||||
docs.map(async (doc) => ({
|
||||
...doc,
|
||||
url: await ctx.storage.getUrl(doc.storageId)
|
||||
}))
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -238,9 +238,7 @@ export const checkExisting = query({
|
||||
.collect();
|
||||
|
||||
const matching = items.filter((i) =>
|
||||
itensFiltro.some(
|
||||
(f) => f.objetoId === i.objetoId && f.modalidade === i.modalidade
|
||||
)
|
||||
itensFiltro.some((f) => f.objetoId === i.objetoId && f.modalidade === i.modalidade)
|
||||
);
|
||||
|
||||
if (matching.length > 0) {
|
||||
@@ -513,6 +511,159 @@ export const removeItem = mutation({
|
||||
}
|
||||
});
|
||||
|
||||
export const removeItemsBatch = mutation({
|
||||
args: {
|
||||
itemIds: v.array(v.id('objetoItems'))
|
||||
},
|
||||
returns: v.null(),
|
||||
handler: async (ctx, args) => {
|
||||
const user = await getUsuarioAutenticado(ctx);
|
||||
|
||||
if (!user.funcionarioId) {
|
||||
throw new Error('Usuário não vinculado a um funcionário.');
|
||||
}
|
||||
|
||||
if (args.itemIds.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const firstItem = await ctx.db.get(args.itemIds[0]);
|
||||
if (!firstItem) {
|
||||
throw new Error('Item não encontrado.');
|
||||
}
|
||||
|
||||
const pedidoId = firstItem.pedidoId;
|
||||
const pedido = await ctx.db.get(pedidoId);
|
||||
if (!pedido) {
|
||||
throw new Error('Pedido não encontrado.');
|
||||
}
|
||||
|
||||
if (pedido.status !== 'em_rascunho' && pedido.status !== 'precisa_ajustes') {
|
||||
throw new Error(
|
||||
'Só é possível remover itens em pedidos em rascunho ou que precisam de ajustes.'
|
||||
);
|
||||
}
|
||||
|
||||
for (const itemId of args.itemIds) {
|
||||
const item = await ctx.db.get(itemId);
|
||||
if (!item) continue;
|
||||
|
||||
if (item.pedidoId !== pedidoId) {
|
||||
throw new Error('Todos os itens devem pertencer ao mesmo pedido.');
|
||||
}
|
||||
|
||||
if (item.adicionadoPor !== user.funcionarioId) {
|
||||
throw new Error('Você só pode remover itens que você adicionou.');
|
||||
}
|
||||
|
||||
await ctx.db.delete(itemId);
|
||||
|
||||
await ctx.db.insert('historicoPedidos', {
|
||||
pedidoId,
|
||||
usuarioId: user._id,
|
||||
acao: 'remocao_item',
|
||||
detalhes: JSON.stringify({
|
||||
objetoId: item.objetoId,
|
||||
valor: item.valorEstimado
|
||||
}),
|
||||
data: Date.now()
|
||||
});
|
||||
}
|
||||
|
||||
await ctx.db.patch(pedidoId, { atualizadoEm: Date.now() });
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
export const splitPedido = mutation({
|
||||
args: {
|
||||
pedidoId: v.id('pedidos'),
|
||||
itemIds: v.array(v.id('objetoItems')),
|
||||
numeroSei: v.optional(v.string())
|
||||
},
|
||||
returns: v.id('pedidos'),
|
||||
handler: async (ctx, args) => {
|
||||
const user = await getUsuarioAutenticado(ctx);
|
||||
|
||||
if (!user.funcionarioId) {
|
||||
throw new Error('Usuário não vinculado a um funcionário.');
|
||||
}
|
||||
|
||||
if (args.itemIds.length === 0) {
|
||||
throw new Error('Selecione ao menos um item para dividir o pedido.');
|
||||
}
|
||||
|
||||
const pedidoOriginal = await ctx.db.get(args.pedidoId);
|
||||
if (!pedidoOriginal) {
|
||||
throw new Error('Pedido não encontrado.');
|
||||
}
|
||||
|
||||
if (pedidoOriginal.status !== 'em_rascunho' && pedidoOriginal.status !== 'precisa_ajustes') {
|
||||
throw new Error('Só é possível dividir pedidos em rascunho ou que precisam de ajustes.');
|
||||
}
|
||||
|
||||
const itens = [];
|
||||
for (const itemId of args.itemIds) {
|
||||
const item = await ctx.db.get(itemId);
|
||||
if (!item) {
|
||||
continue;
|
||||
}
|
||||
if (item.pedidoId !== args.pedidoId) {
|
||||
throw new Error('Todos os itens devem pertencer ao mesmo pedido.');
|
||||
}
|
||||
if (item.adicionadoPor !== user.funcionarioId) {
|
||||
throw new Error('Você só pode mover itens que você adicionou.');
|
||||
}
|
||||
itens.push(item);
|
||||
}
|
||||
|
||||
if (itens.length === 0) {
|
||||
throw new Error('Nenhum dos itens selecionados pôde ser usado para divisão.');
|
||||
}
|
||||
|
||||
const novoPedidoId = await ctx.db.insert('pedidos', {
|
||||
numeroSei: args.numeroSei,
|
||||
status: 'em_rascunho',
|
||||
criadoPor: user._id,
|
||||
criadoEm: Date.now(),
|
||||
atualizadoEm: Date.now()
|
||||
});
|
||||
|
||||
for (const item of itens) {
|
||||
await ctx.db.patch(item._id, {
|
||||
pedidoId: novoPedidoId
|
||||
});
|
||||
}
|
||||
|
||||
await ctx.db.insert('historicoPedidos', {
|
||||
pedidoId: args.pedidoId,
|
||||
usuarioId: user._id,
|
||||
acao: 'divisao_pedido_origem',
|
||||
detalhes: JSON.stringify({
|
||||
itensMovidos: itens.map((i) => i._id),
|
||||
novoPedidoId
|
||||
}),
|
||||
data: Date.now()
|
||||
});
|
||||
|
||||
await ctx.db.insert('historicoPedidos', {
|
||||
pedidoId: novoPedidoId,
|
||||
usuarioId: user._id,
|
||||
acao: 'divisao_pedido_destino',
|
||||
detalhes: JSON.stringify({
|
||||
pedidoOriginalId: args.pedidoId,
|
||||
itensRecebidos: itens.map((i) => i._id)
|
||||
}),
|
||||
data: Date.now()
|
||||
});
|
||||
|
||||
await ctx.db.patch(args.pedidoId, { atualizadoEm: Date.now() });
|
||||
|
||||
return novoPedidoId;
|
||||
}
|
||||
});
|
||||
|
||||
export const updateItem = mutation({
|
||||
args: {
|
||||
itemId: v.id('objetoItems'),
|
||||
|
||||
@@ -7,7 +7,7 @@ export const atasTables = {
|
||||
dataInicio: v.optional(v.string()),
|
||||
dataFim: v.optional(v.string()),
|
||||
empresaId: v.id('empresas'),
|
||||
pdf: v.optional(v.string()), // storage ID
|
||||
pdf: v.optional(v.id('_storage')),
|
||||
numeroSei: v.string(),
|
||||
criadoPor: v.id('usuarios'),
|
||||
criadoEm: v.number(),
|
||||
@@ -22,5 +22,15 @@ export const atasTables = {
|
||||
objetoId: v.id('objetos')
|
||||
})
|
||||
.index('by_ataId', ['ataId'])
|
||||
.index('by_objetoId', ['objetoId'])
|
||||
.index('by_objetoId', ['objetoId']),
|
||||
|
||||
atasDocumentos: defineTable({
|
||||
ataId: v.id('atas'),
|
||||
nome: v.string(),
|
||||
storageId: v.id('_storage'),
|
||||
tipo: v.string(), // MIME type
|
||||
tamanho: v.number(), // bytes
|
||||
criadoPor: v.id('usuarios'),
|
||||
criadoEm: v.number()
|
||||
}).index('by_ataId', ['ataId'])
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user