diff --git a/src/packages/administrativo/components/TPessoa/TPessoaTableFormSubview.tsx b/src/packages/administrativo/components/TPessoa/TPessoaTableFormSubview.tsx
index a756b94..04ad22f 100644
--- a/src/packages/administrativo/components/TPessoa/TPessoaTableFormSubview.tsx
+++ b/src/packages/administrativo/components/TPessoa/TPessoaTableFormSubview.tsx
@@ -64,7 +64,7 @@ export default function TPessoaTableFormSubview({ params, servico, selectedTPess
return (
-
+
-
diff --git a/src/packages/servicos/actions/TServicoPedido/HandleSelectTServicoTipoAction.ts b/src/packages/servicos/actions/TServicoPedido/HandleSelectTServicoTipoAction.ts
index 531d24b..c569337 100644
--- a/src/packages/servicos/actions/TServicoPedido/HandleSelectTServicoTipoAction.ts
+++ b/src/packages/servicos/actions/TServicoPedido/HandleSelectTServicoTipoAction.ts
@@ -1,8 +1,15 @@
-import HandleSelectTServicoTipoInterface from "./HandleSelectTServicoTipoInterface";
+
export default function HandleSelectTServicoTipoAction({ servico, emolumento, onOpenPessoaForm, onAddItem }: HandleSelectTServicoTipoInterface) {
- if (!servico || !emolumento) return;
+ if (!servico || !emolumento) {
+
+ return {
+ 'status': 422,
+ 'detail': 'Serviço e emolumento devem ser selecionados'
+ };
+
+ };
if (servico?.tipo_pessoa) {
diff --git a/src/packages/servicos/actions/TServicoPedido/PrepareTServicoItemPedidoPayload.ts b/src/packages/servicos/actions/TServicoPedido/PrepareTServicoItemPedidoPayload.ts
index 5f25e93..524e76b 100644
--- a/src/packages/servicos/actions/TServicoPedido/PrepareTServicoItemPedidoPayload.ts
+++ b/src/packages/servicos/actions/TServicoPedido/PrepareTServicoItemPedidoPayload.ts
@@ -6,7 +6,7 @@ export default function PrepareTServicoItemPedidoPayload(data: TServicoItemPedid
data.valor_documento = 0
// Verifica dados obrigatórios de serviço e emolumento
- if (!data?.emolumentoSelecionado?.emolumento_id || !data?.servicoSelecionado?.servico_tipo_id) {
+ if (!data?.emolumento?.emolumento_id || !data?.servico_tipo?.servico_tipo_id) {
return {
status: 400,
message: 'Dados informados inválidos: serviço ou emolumento não informado.'
@@ -14,7 +14,7 @@ export default function PrepareTServicoItemPedidoPayload(data: TServicoItemPedid
}
// Valida sistema_id (padrão 2, mas ainda assim precisa ser válido)
- if (!data?.emolumentoSelecionado.sistema_id || data.emolumentoSelecionado.sistema_id <= 0) {
+ if (!data?.emolumento.sistema_id || data.servico_tipo.sistema_id <= 0) {
return {
status: 400,
message: 'Sistema inválido ou não informado.'
@@ -30,10 +30,10 @@ export default function PrepareTServicoItemPedidoPayload(data: TServicoItemPedid
}
return {
- sistema_id: data.emolumentoSelecionado.sistema_id,
+ sistema_id: data.emolumento.sistema_id,
valor_documento: data.valor_documento,
quantidade: data.quantidade,
- emolumento_id: data.emolumentoSelecionado.emolumento_id,
+ emolumento_id: data.emolumento.emolumento_id,
};
}
diff --git a/src/packages/servicos/actions/TServicoPedido/PrepareTServicoItemPedidoResponseItem.ts b/src/packages/servicos/actions/TServicoPedido/PrepareTServicoItemPedidoResponseItem.ts
index dadf841..985c7ac 100644
--- a/src/packages/servicos/actions/TServicoPedido/PrepareTServicoItemPedidoResponseItem.ts
+++ b/src/packages/servicos/actions/TServicoPedido/PrepareTServicoItemPedidoResponseItem.ts
@@ -44,10 +44,10 @@ export function PrepareTServicoItemPedidoCalculoResponse(
const item: TServicoItemPedidoAddResponseInterface = {
emolumento_id: result.emolumento_id,
emolumento_item_id: result.emolumento_item_id ?? null,
- servico_tipo_id: data.servicoSelecionado.servico_tipo_id ?? 0,
- tipo_item: data.servicoSelecionado.tipo_item ?? "",
- descricao: data.servicoSelecionado.descricao ?? "",
- tabela: data.emolumentoSelecionado?.descricao ?? "",
+ servico_tipo_id: data.servico_tipo.servico_tipo_id ?? 0,
+ tipo_item: data.servico_tipo.tipo_item ?? "",
+ descricao: data.servico_tipo.descricao ?? "",
+ tabela: data.servico_tipo?.descricao ?? "",
situacao: "F",
qtd: 1,
valor: result.valor_total ?? 0,
diff --git a/src/packages/servicos/components/TServicoPedido/TServicoPedidoForm.tsx b/src/packages/servicos/components/TServicoPedido/TServicoPedidoForm.tsx
index 191117d..ef44577 100644
--- a/src/packages/servicos/components/TServicoPedido/TServicoPedidoForm.tsx
+++ b/src/packages/servicos/components/TServicoPedido/TServicoPedidoForm.tsx
@@ -1,6 +1,6 @@
'use client';
-import { CreditCard, Package, PlusIcon, UserSquare2 } from 'lucide-react';
+import { CreditCard, Package, UserSquare2 } from 'lucide-react';
import { useRouter } from 'next/navigation';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
@@ -38,9 +38,12 @@ import { useTServicoPedidoSaveHook } from '@/packages/servicos/hooks/TServicoPed
import { useTServicoPedidoShowHook } from '@/packages/servicos/hooks/TServicoPedido/useTServicoPedidoShowHook';
import { TServicoPedidoFormInterface } from '@/packages/servicos/interfaces/TServicoPedido/TServicoPedidoFormInterface';
import TServicoPedidoInterface from '@/packages/servicos/interfaces/TServicoPedido/TServicoPedidoInterface';
+import { FormatCPFCNPJForm } from '@/shared/actions/CPF/FormatCPFCNPJForm';
+import { UnmaskCPFCNPJForm } from '@/shared/actions/CPF/UnmaskCPFCNPJForm';
import { parseNumberInput } from '@/shared/actions/form/parseNumberInput';
import ConfirmDialog from '@/shared/components/confirmDialog/ConfirmDialog';
import LoadingButton from '@/shared/components/loadingButton/LoadingButton';
+import { useResponse } from '@/shared/components/response/ResponseContext';
import {
StepNavigator,
StepNavigatorRef,
@@ -58,6 +61,7 @@ export default function TServicoPedidoForm({ servico_pedido_id }: TServicoPedido
const { setValue, reset, watch } = form;
const [isSaving, setIsSaving] = useState(false);
+ const [isAdding, setIsAdding] = useState(false);
const [isPessoaFormOpen, setIsPessoaFormOpen] = useState(false);
const [isSaveConfirmOpen, setIsSaveConfirmOpen] = useState(false);
const [isCancelDialogOpen, setIsCancelDialogOpen] = useState(false)
@@ -72,6 +76,7 @@ export default function TServicoPedidoForm({ servico_pedido_id }: TServicoPedido
const handleCloseSaveConfirm = useCallback(() => setIsSaveConfirmOpen(false), []);
// Hooks
+ const { response, setResponse } = useResponse()
const { saveTServicoPedido } = useTServicoPedidoSaveHook();
const { showTServicoPedido } = useTServicoPedidoShowHook();
const { TServicoItemPedidoLocal, localAddTServicoItemPedido, setLocalTServicoItemPedido } = useTServicoItemPedidoLocalAddHook(setValue);
@@ -158,6 +163,8 @@ export default function TServicoPedidoForm({ servico_pedido_id }: TServicoPedido
const handleAddItemWithPessoa = useCallback(async (selectedTPessoa: any) => {
+ setIsAdding(true)
+
// Constroi um novo item
const newItem: TServicoSubviewInterface = await addTServicoItemPedido({
servico_tipo: selectedServicoTipo,
@@ -190,6 +197,8 @@ export default function TServicoPedidoForm({ servico_pedido_id }: TServicoPedido
// Atualiza os itens do formulário
form.setValue(`itens.${index}`, newItem);
+ setIsAdding(false)
+
}, [
addTServicoItemPedido,
selectedServicoTipo,
@@ -239,10 +248,12 @@ export default function TServicoPedidoForm({ servico_pedido_id }: TServicoPedido
// Controle de itens
const handleAddItemBasic = useCallback(async () => {
+ setIsAdding(true)
+
// Prepara e valida os dados de item do pedido
const payload = {
- servicoSelecionado: selectedServicoTipo,
- emolumentoSelecionado: selectedEmolumento
+ servico_tipo: selectedServicoTipo,
+ emolumento: selectedEmolumento
}
// Verifica se os dados foram criados corretamente
@@ -254,6 +265,8 @@ export default function TServicoPedidoForm({ servico_pedido_id }: TServicoPedido
// Se tiver um novo item, adiciona o mesmo na tela
if (newItem) localAddTServicoItemPedido(newItem);
+ setIsAdding(false)
+
}, [addTServicoItemPedido, selectedServicoTipo, selectedEmolumento, localAddTServicoItemPedido]);
// Habilita o formulário de pessoas
@@ -267,15 +280,42 @@ export default function TServicoPedidoForm({ servico_pedido_id }: TServicoPedido
// Adiciona o item a tabela e verifica se deve ou não montar a subview da linha da tabela
const handleSelectServicoTipo = useCallback(() => {
- HandleSelectTServicoTipoAction({
+ const response = HandleSelectTServicoTipoAction({
servico: selectedServicoTipo,
emolumento: selectedEmolumento,
onOpenPessoaForm: handleOpenPessoaForm,
onAddItem: handleAddItemBasic
})
+ // Verifica se existem erros
+ if (response?.status) {
+ setResponse(response)
+ }
+
}, [selectedServicoTipo, selectedEmolumento, handleOpenPessoaForm, handleAddItemBasic]);
+ // Cálculo automático dos totais
+ const calcularTotais = useCallback(() => {
+ if (!TServicoItemPedidoLocal || !TServicoItemPedidoLocal.length) {
+ setValue("valor_pedido", 0);
+ setValue("valor_pago", 0);
+ return;
+ }
+
+ const total = TServicoItemPedidoLocal.reduce((acc, item) => {
+ const valor = Number(item.valor_total ?? item.valor ?? 0);
+ return acc + valor;
+ }, 0);
+
+ setValue("valor_pedido", total, { shouldDirty: true });
+
+ // opcional: manter valor pago igual ao pedido
+ const valorPagoAtual = watch("valor_pago");
+ if (!valorPagoAtual || valorPagoAtual === 0) {
+ setValue("valor_pago", total, { shouldDirty: true });
+ }
+ }, [TServicoItemPedidoLocal, setValue, watch]);
+
// Dispara a busca do pedido
useEffect(() => {
@@ -297,6 +337,11 @@ export default function TServicoPedidoForm({ servico_pedido_id }: TServicoPedido
}, []);
+ // Monitora mudanças na lista de itens
+ useEffect(() => {
+ calcularTotais();
+ }, [TServicoItemPedidoLocal, calcularTotais]);
+
// Memoriza os dados para não renderizar novamente
const sections: StepSection[] = useMemo(() => [
{
@@ -375,8 +420,18 @@ export default function TServicoPedidoForm({ servico_pedido_id }: TServicoPedido
name="cpfcnpj_apresentante"
render={({ field }) => (
- CPF
-
+ CPF/CNPJ
+
+ {
+ const raw = UnmaskCPFCNPJForm(e.target.value);
+ field.onChange(raw);
+ }}
+ maxLength={14}
+ />
+
)}
@@ -403,8 +458,18 @@ export default function TServicoPedidoForm({ servico_pedido_id }: TServicoPedido
name="selo_pessoa_cpfcnpj"
render={({ field }) => (
- CPF
-
+ CPF/CNPJ
+
+ {
+ const raw = UnmaskCPFCNPJForm(e.target.value);
+ field.onChange(raw);
+ }}
+ maxLength={14}
+ />
+
)}
@@ -449,9 +514,12 @@ export default function TServicoPedidoForm({ servico_pedido_id }: TServicoPedido
/>
@@ -486,8 +554,17 @@ export default function TServicoPedidoForm({ servico_pedido_id }: TServicoPedido
name="pagador_cpfcnpj"
render={({ field }) => (
- CPF/CNPJ Requerente
-
+ CPF/CNPJ
+
+ {
+ const raw = UnmaskCPFCNPJForm(e.target.value);
+ field.onChange(raw);
+ }}
+ maxLength={14}
+ />
)}
@@ -502,7 +579,9 @@ export default function TServicoPedidoForm({ servico_pedido_id }: TServicoPedido
Valor do Pedido
field.onChange(parseNumberInput(e))} />
+ onChange={(e) => field.onChange(parseNumberInput(e))}
+ readOnly={true}
+ />
diff --git a/src/packages/servicos/hooks/TServicoItemPedido/useTServicoItemPedidoAddHook.ts b/src/packages/servicos/hooks/TServicoItemPedido/useTServicoItemPedidoAddHook.ts
index 273bdd8..6a87816 100644
--- a/src/packages/servicos/hooks/TServicoItemPedido/useTServicoItemPedidoAddHook.ts
+++ b/src/packages/servicos/hooks/TServicoItemPedido/useTServicoItemPedidoAddHook.ts
@@ -7,10 +7,13 @@ import { GCalculoServicoService } from '@/packages/administrativo/services/GCalc
import PrepareTServicoItemPedidoPayload from '@/packages/servicos/actions/TServicoPedido/PrepareTServicoItemPedidoPayload';
import TServicoItemPedidoAddInterface from '@/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoAddInterface';
import { default as TServicoItemPedidoIndexResponseInterface } from '@/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoAddResponseInterface';
+import { useResponse } from '@/shared/components/response/ResponseContext';
export const useTServicoItemPedidoAddHook = (setValue?: UseFormSetValue) => {
+ const { setResponse } = useResponse();
+
const [TServicoItemPedido, setTServicoItemPedido] = useState([]);
const addTServicoItemPedido = async (data: TServicoItemPedidoAddInterface) => {
@@ -18,6 +21,14 @@ export const useTServicoItemPedidoAddHook = (setValue?: UseFormSetValue({
resolver: zodResolver(TServicoPedidoFormSchema),
defaultValues: {
+ escrevente_id: 0,
+ apresentante: "",
+ cpfcnpj_apresentante: "",
+ selo_pessoa_nome: "",
+ selo_pessoa_cpfcnpj: "",
+ servico_tipo: null,
+ emolumento: null,
+ itens: [],
+ pagador_nome: "",
+ pagador_cpfcnpj: "",
+ valor_pedido: 0,
+ valor_pago: 0,
+ tipo_pagamento: null,
...defaults,
},
});
diff --git a/src/packages/servicos/hooks/TServicoPedido/useTServicoPedidoSaveHook.ts b/src/packages/servicos/hooks/TServicoPedido/useTServicoPedidoSaveHook.ts
index 6500b27..e72dd90 100644
--- a/src/packages/servicos/hooks/TServicoPedido/useTServicoPedidoSaveHook.ts
+++ b/src/packages/servicos/hooks/TServicoPedido/useTServicoPedidoSaveHook.ts
@@ -2,10 +2,9 @@
import { useState } from 'react';
-import { useResponse } from '@/shared/components/response/ResponseContext';
-
import TServicoPedidoInterface from '@/packages/servicos/interfaces/TServicoPedido/TServicoPedidoInterface';
import { TServicoPedidoSaveService } from '@/packages/servicos/services/TServicoPedido/TServicoPedidoSaveService';
+import { useResponse } from '@/shared/components/response/ResponseContext';
export const useTServicoPedidoSaveHook = () => {
@@ -17,6 +16,7 @@ export const useTServicoPedidoSaveHook = () => {
const [isOpen, setIsOpen] = useState(false);
const saveTServicoPedido = async (data: TServicoPedidoInterface) => {
+
const response = await TServicoPedidoSaveService(data);
// Armazena os dados da resposta
@@ -30,6 +30,7 @@ export const useTServicoPedidoSaveHook = () => {
// Retorna os valores de forma imediata
return response.data;
+
};
return { TServicoPedido, saveTServicoPedido, isOpen, setIsOpen };
diff --git a/src/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoAddInterface.ts b/src/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoAddInterface.ts
index 2c6ece1..1269f8f 100644
--- a/src/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoAddInterface.ts
+++ b/src/packages/servicos/interfaces/TServicoItemPedido/TServicoItemPedidoAddInterface.ts
@@ -2,8 +2,8 @@ import TServicoTipoInterface from "@/app/(protected)/(cadastros)/cadastros/_inte
import GEmolumentoInterface from "@/packages/administrativo/interfaces/GEmolumento/GEmolumentoInterface";
export default interface TServicoItemPedidoAddInterface {
- emolumentoSelecionado: GEmolumentoInterface;
- servicoSelecionado: TServicoTipoInterface;
+ emolumento: GEmolumentoInterface;
+ servico_tipo: TServicoTipoInterface;
sistema_id?: number;
valor_documento?: number;
quantidade?: number;
diff --git a/src/packages/servicos/schemas/TServicoPedido/TServicoPedidoFormSchema.ts b/src/packages/servicos/schemas/TServicoPedido/TServicoPedidoFormSchema.ts
index e17eb78..e9e92c4 100644
--- a/src/packages/servicos/schemas/TServicoPedido/TServicoPedidoFormSchema.ts
+++ b/src/packages/servicos/schemas/TServicoPedido/TServicoPedidoFormSchema.ts
@@ -5,39 +5,54 @@ export const TServicoPedidoFormSchema = z.object({
.number()
.int()
.positive("Escrevente é obrigatório."),
+
apresentante: z
.string()
- .optional(),
+ .min(1, "Apresentante é obrigatório."),
+
cpfcnpj_apresentante: z
.string()
- .optional(),
+ .min(1, "CPF/CNPJ do apresentante é obrigatório."),
+
selo_pessoa_nome: z
.string()
- .optional(),
+ .min(1, "Nome da pessoa do selo é obrigatório."),
+
selo_pessoa_cpfcnpj: z
.string()
- .optional(),
+ .min(1, "CPF/CNPJ da pessoa do selo é obrigatório."),
+
servico_tipo: z
.any()
.refine((v) => !!v, "Selecione um serviço."),
+
emolumento: z
.any()
.refine((v) => !!v, "Selecione um emolumento."),
- itens: z.array(z.any()).optional(),
- pagador_nome: z.string().optional(),
- pagador_cpfcnpj: z.string().optional(),
+
+ itens: z
+ .array(z.any())
+ .min(1, "Adicione ao menos um item ao pedido."),
+
+ pagador_nome: z
+ .string()
+ .min(1, "Nome do requerente é obrigatório."),
+
+ pagador_cpfcnpj: z
+ .string()
+ .min(1, "CPF/CNPJ do requerente é obrigatório."),
+
valor_pedido: z
.number()
- .nonnegative("Valor do pedido inválido.")
- .optional(),
+ .nonnegative("Valor do pedido inválido."),
+
valor_pago: z
.number()
- .nonnegative("Valor pago inválido.")
- .optional(),
+ .nonnegative("Valor pago inválido."),
+
tipo_pagamento: z
.any()
- .refine((v) => !!v, "Selecione a forma de pagamento.")
- .optional(),
+ .refine((v) => !!v, "Selecione a forma de pagamento."),
});
export type TServicoPedidoFormValues = z.infer;
\ No newline at end of file
diff --git a/src/shared/actions/CPF/FormatCPFCNPJForm.ts b/src/shared/actions/CPF/FormatCPFCNPJForm.ts
new file mode 100644
index 0000000..1fa91e1
--- /dev/null
+++ b/src/shared/actions/CPF/FormatCPFCNPJForm.ts
@@ -0,0 +1,25 @@
+import { UnmaskCPFCNPJForm } from "./UnmaskCPFCNPJForm";
+
+export function isCpf(value: string): boolean {
+ return UnmaskCPFCNPJForm(value).length <= 11;
+}
+
+export function FormatCPFCNPJForm(value: string = ''): string {
+ const digits = UnmaskCPFCNPJForm(value);
+
+ // CPF — 11 dígitos
+ if (digits.length <= 11) {
+ return digits
+ .replace(/^(\d{3})(\d)/, "$1.$2")
+ .replace(/^(\d{3})\.(\d{3})(\d)/, "$1.$2.$3")
+ .replace(/^(\d{3})\.(\d{3})\.(\d{3})(\d{1,2})$/, "$1.$2.$3-$4");
+ }
+
+ // CNPJ — 14 dígitos
+ return digits
+ .slice(0, 14)
+ .replace(/^(\d{2})(\d)/, "$1.$2")
+ .replace(/^(\d{2})\.(\d{3})(\d)/, "$1.$2.$3")
+ .replace(/^(\d{2})\.(\d{3})\.(\d{3})(\d)/, "$1.$2.$3/$4")
+ .replace(/^(\d{2})\.(\d{3})\.(\d{3})\/(\d{4})(\d{1,2})$/, "$1.$2.$3/$4-$5");
+}
diff --git a/src/shared/actions/CPF/UnmaskCPFCNPJForm.ts b/src/shared/actions/CPF/UnmaskCPFCNPJForm.ts
new file mode 100644
index 0000000..462ca38
--- /dev/null
+++ b/src/shared/actions/CPF/UnmaskCPFCNPJForm.ts
@@ -0,0 +1,3 @@
+export function UnmaskCPFCNPJForm(value: string = ""): string {
+ return value.replace(/\D/g, "").slice(0, 11);
+}