feat(resellers): campos de representante legal (preparação p/ contrato)
Usuário: o cadastro de revenda precisa ficar completo porque essa mesma base vai alimentar a criação de contrato com a revenda dentro do ERP. resellers ganha rep_full_name/rep_cpf/rep_role/rep_email/ rep_mobile_phone/rep_authorization_ack, mesmo shape de client_registrations.pj_rep_* — um contrato precisa de um signatário nomeado e autorizado, não só a lista geral de sócios. Divergência deliberada: ao contrário de pj_rep_cpf (bloqueado do PATCH genérico em client_registrations, esperando um fluxo de submissão pública que o EDEN ainda não construiu — hoje uma lacuna conhecida, nunca preenchido de fato), rep_cpf aqui fica livremente editável — revenda não tem esse fluxo de submissão pública pra travar atrás. Nova tela: card "Representante legal" entre "Dados da revenda" e "Sócios". Suíte: 107/107 (106→107). pnpm turbo run typecheck build: 28/28. Testado ao vivo em navegador real. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -39,6 +39,12 @@ export interface Reseller {
|
||||
contact_technical_name: string | null;
|
||||
contact_technical_email: string | null;
|
||||
contact_technical_phone: string | null;
|
||||
rep_full_name: string | null;
|
||||
rep_cpf: string | null;
|
||||
rep_role: string | null;
|
||||
rep_email: string | null;
|
||||
rep_mobile_phone: string | null;
|
||||
rep_authorization_ack: boolean;
|
||||
}
|
||||
|
||||
/** Request body — camelCase, matches `CreateResellerDto` exactly. */
|
||||
@@ -74,6 +80,13 @@ export interface CreateResellerInput {
|
||||
contactTechnicalName?: string;
|
||||
contactTechnicalEmail?: string;
|
||||
contactTechnicalPhone?: string;
|
||||
|
||||
repFullName?: string;
|
||||
repCpf?: string;
|
||||
repRole?: string;
|
||||
repEmail?: string;
|
||||
repMobilePhone?: string;
|
||||
repAuthorizationAck?: boolean;
|
||||
}
|
||||
|
||||
/** Matches `UpdateResellerDto`: everything optional. */
|
||||
|
||||
@@ -23,7 +23,15 @@ import { ResellerPartnersSection } from "./ResellerPartnersSection.js";
|
||||
*
|
||||
* Section order when editing (per product direction, same order as
|
||||
* `ClientRegistrationDetailPage`): Dados da revenda (incl. CNPJ lookup) ->
|
||||
* Sócios -> Endereço -> Contatos -> Status.
|
||||
* Representante legal -> Sócios -> Endereço -> Contatos -> Status.
|
||||
*
|
||||
* "Representante legal" (`rep_*`) mirrors `client_registrations.pj_rep_*`
|
||||
* — added because reseller registration data will feed reseller contract
|
||||
* creation later; a contract needs a named, authorized signer, not just
|
||||
* the general Sócios list. Unlike `pj_rep_cpf` there, `repCpf` here is a
|
||||
* plain editable field — see the migration
|
||||
* `1789700100000_resellers-legal-representative.cjs` for why the same
|
||||
* structural lock doesn't apply to resellers.
|
||||
*/
|
||||
interface FormState {
|
||||
name: string;
|
||||
@@ -39,6 +47,13 @@ interface FormState {
|
||||
cnpjSituation: string;
|
||||
mainActivity: string;
|
||||
|
||||
repFullName: string;
|
||||
repCpf: string;
|
||||
repRole: string;
|
||||
repEmail: string;
|
||||
repMobilePhone: string;
|
||||
repAuthorizationAck: boolean;
|
||||
|
||||
addressZip: string;
|
||||
addressStreet: string;
|
||||
addressNumber: string;
|
||||
@@ -73,6 +88,13 @@ const EMPTY_FORM: FormState = {
|
||||
cnpjSituation: "",
|
||||
mainActivity: "",
|
||||
|
||||
repFullName: "",
|
||||
repCpf: "",
|
||||
repRole: "",
|
||||
repEmail: "",
|
||||
repMobilePhone: "",
|
||||
repAuthorizationAck: false,
|
||||
|
||||
addressZip: "",
|
||||
addressStreet: "",
|
||||
addressNumber: "",
|
||||
@@ -112,6 +134,13 @@ function toFormState(reseller: Reseller): FormState {
|
||||
cnpjSituation: reseller.cnpj_situation ?? "",
|
||||
mainActivity: reseller.main_activity ?? "",
|
||||
|
||||
repFullName: reseller.rep_full_name ?? "",
|
||||
repCpf: reseller.rep_cpf ?? "",
|
||||
repRole: reseller.rep_role ?? "",
|
||||
repEmail: reseller.rep_email ?? "",
|
||||
repMobilePhone: reseller.rep_mobile_phone ?? "",
|
||||
repAuthorizationAck: reseller.rep_authorization_ack,
|
||||
|
||||
addressZip: reseller.address_zip ?? "",
|
||||
addressStreet: reseller.address_street ?? "",
|
||||
addressNumber: reseller.address_number ?? "",
|
||||
@@ -206,6 +235,13 @@ export function ResellerFormPage() {
|
||||
cnpjSituation: toOptional(form.cnpjSituation),
|
||||
mainActivity: toOptional(form.mainActivity),
|
||||
|
||||
repFullName: toOptional(form.repFullName),
|
||||
repCpf: toOptional(form.repCpf),
|
||||
repRole: toOptional(form.repRole),
|
||||
repEmail: toOptional(form.repEmail),
|
||||
repMobilePhone: toOptional(form.repMobilePhone),
|
||||
repAuthorizationAck: form.repAuthorizationAck,
|
||||
|
||||
addressZip: toOptional(form.addressZip),
|
||||
addressStreet: toOptional(form.addressStreet),
|
||||
addressNumber: toOptional(form.addressNumber),
|
||||
@@ -418,6 +454,43 @@ export function ResellerFormPage() {
|
||||
) : null}
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{isEditing ? (
|
||||
<Card title="Representante legal">
|
||||
<p className="mb-3 text-xs text-default">
|
||||
Quem assina pela revenda — usado depois na confecção de contrato com a revenda.
|
||||
</p>
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
||||
<Input
|
||||
label="Nome completo"
|
||||
value={form.repFullName}
|
||||
onChange={(e) => updateField("repFullName", e.target.value)}
|
||||
/>
|
||||
<Input label="CPF" value={form.repCpf} onChange={(e) => updateField("repCpf", e.target.value)} />
|
||||
<Input label="Cargo" value={form.repRole} onChange={(e) => updateField("repRole", e.target.value)} />
|
||||
<Input
|
||||
label="E-mail"
|
||||
type="email"
|
||||
value={form.repEmail}
|
||||
onChange={(e) => updateField("repEmail", e.target.value)}
|
||||
/>
|
||||
<Input
|
||||
label="Celular"
|
||||
value={form.repMobilePhone}
|
||||
onChange={(e) => updateField("repMobilePhone", e.target.value)}
|
||||
/>
|
||||
<label className="flex items-center gap-2 py-2.5 text-sm text-title">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="shrink-0 rounded-sm border-border-color text-primary focus:ring-primary"
|
||||
checked={form.repAuthorizationAck}
|
||||
onChange={(e) => updateField("repAuthorizationAck", e.target.checked)}
|
||||
/>
|
||||
Representante confirmou autorização
|
||||
</label>
|
||||
</div>
|
||||
</Card>
|
||||
) : null}
|
||||
</form>
|
||||
|
||||
{isEditing && id ? (
|
||||
|
||||
Reference in New Issue
Block a user