Ver código fonte

add the new fields on cpr

gdias 4 semanas atrás
pai
commit
97c9249df1

+ 146 - 74
src/lib/components/commodities/cpr/ContractCpr.svelte

@@ -1,84 +1,156 @@
 <script>
-    let outside = false;
-    let creditOperationContractCode = "";
-    let operationNature = "";
-    let transactionDate = "";
-    let netCreditValue = "";
-    let totalCreditValue = "";
-  </script>
-  
-  <div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg shadow-sm">
-  <form class="space-y-4 p-4">
-    <!-- Código Contrato da Operação de Crédito -->
-    <div>
-      <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Código Contrato da Operação de Crédito *</label>
-      <input
-        bind:value={creditOperationContractCode}
-        class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 placeholder-gray-400 dark:placeholder-gray-400 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
-        placeholder="Digite o código do contrato"
-      />
-    </div>
+  export let formData = {};
+  export let onFieldChange = () => {};
+  export let requiredFields = new Set();
 
-    <!-- Natureza de Operação -->
-    <div>
-      <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Natureza de Operação *</label>
-      <select
-        bind:value={operationNature}
-        class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
-      >
-        <option value="">Selecione a natureza da operação</option>
-        <option value="financiamento">Financiamento</option>
-        <option value="emprestimo">Empréstimo</option>
-        <option value="antecipacao">Antecipação</option>
-        <option value="desconto">Desconto</option>
-      </select>
-    </div>
+  const sections = [
+    {
+      title: 'Identificação do Contrato',
+      columns: 2,
+      fields: [
+        { key: 'cpr_contract_code', label: 'Código do Contrato' },
+        { key: 'cpr_contract_number', label: 'Número do Contrato' },
+        { key: 'cpr_number', label: 'Número da CPR' },
+        { key: 'cpr_self_number', label: 'Número Próprio' },
+        { key: 'cpr_ipoc_code', label: 'Código IPOC' },
+        { key: 'cpr_calculation_type_code', label: 'Tipo de Cálculo' },
+        { key: 'cpr_initial_exchange_value', label: 'Valor Inicial de Câmbio' },
+        { key: 'cpr_fixing_type_code', label: 'Tipo de Fixing' },
+        { key: 'cpr_data_source_type_code', label: 'Fonte de Dados' },
+        { key: 'cpr_adjustment_frequency_type_code', label: 'Frequência de Ajuste' },
+        { key: 'cpr_adjustment_pro_rata_type_code', label: 'Ajuste Pro Rata' },
+        { key: 'cpr_adjustment_type_code', label: 'Tipo de Ajuste' }
+      ]
+    },
+    {
+      title: 'Datas importantes',
+      columns: 3,
+      fields: [
+        { key: 'cpr_issue_date', label: 'Data de Emissão', type: 'date' },
+        { key: 'cpr_maturity_date', label: 'Data de Vencimento', type: 'date' },
+        { key: 'cpr_reference_date', label: 'Data de Referência', type: 'date' },
+        { key: 'cpr_profitability_start_date', label: 'Início da Rentabilidade', type: 'date' },
+        { key: 'cpr_payment_start_date', label: 'Início Pagamentos', type: 'date' },
+        { key: 'cpr_amortization_start_date', label: 'Início Amortização', type: 'date' },
+        { key: 'cpr_interest_payment_date', label: 'Pagamento de Juros', type: 'date' }
+      ]
+    },
+    {
+      title: 'Valores',
+      columns: 3,
+      fields: [
+        { key: 'cpr_issue_quantity', label: 'Quantidade emitida' },
+        { key: 'cpr_issue_value', label: 'Valor da emissão' },
+        { key: 'cpr_issue_financial_value', label: 'Valor financeiro' },
+        { key: 'cpr_unit_value', label: 'Valor unitário' },
+        { key: 'cpr_unit_price_value', label: 'Preço unitário' },
+        { key: 'cpr_interest_unit_price_value', label: 'Preço unitário juros' },
+        { key: 'cpr_residual_value', label: 'Valor residual' },
+        { key: 'cpr_amortization_percentage', label: '% de amortização' },
+        { key: 'cpr_event_quantity', label: 'Quantidade do evento' }
+      ]
+    },
+    {
+      title: 'Credor',
+      columns: 2,
+      fields: [
+        { key: 'cpr_creditor_name', label: 'Nome do credor' },
+        { key: 'cpr_creditor_document_number', label: 'Documento do credor' }
+      ]
+    },
+    {
+      title: 'Pagamento e indexadores',
+      columns: 2,
+      fields: [
+        { key: 'cpr_payment_method_code', label: 'Método de pagamento' },
+        { key: 'cpr_index_code', label: 'Código do índice' },
+        { key: 'cpr_index_short_name', label: 'Nome curto do índice' },
+        { key: 'cpr_vcp_indicator_type_code', label: 'Indicador VCP' },
+        { key: 'cpr_indexador_percentage_value', label: '% do indexador' },
+        { key: 'cpr_interest_rate_spread_percentage', label: 'Spread (%)' },
+        { key: 'cpr_interest_rate_criteria_type_code', label: 'Critério de juros' },
+        { key: 'cpr_interest_payment_value', label: 'Valor de pagamento de juros' },
+        { key: 'cpr_interest_payment_frequency_code', label: 'Frequência de juros' },
+        { key: 'cpr_interest_months_quantity', label: 'Meses de juros' },
+        { key: 'cpr_interestPaymentFlow_time_unit_type_code', label: 'Unidade tempo fluxo juros' },
+        { key: 'cpr_interestPaymentFlow_deadline_type_code', label: 'Prazo fluxo juros' },
+        { key: 'cpr_amortization_type_code', label: 'Tipo de amortização' },
+        { key: 'cpr_amortization_months_quantity', label: 'Meses de amortização' },
+        { key: 'cpr_amortizationPaymentFlow_time_unit_type_code', label: 'Unidade tempo fluxo amort.' },
+        { key: 'cpr_amortizationPaymentFlow_deadline_type_code', label: 'Prazo fluxo amort.' }
+      ]
+    }
+  ];
 
-    <!-- Data da Transação -->
-    <div>
-      <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Data da Transação *</label>
-      <input
-        type="date"
-        bind:value={transactionDate}
-        class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 placeholder-gray-400 dark:placeholder-gray-400 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
-      />
-    </div>
+  const notesField = { key: 'cpr_additional_text', label: 'Observações adicionais', type: 'textarea' };
 
-    <!-- Valores em grid de 2 colunas -->
-    <div class="grid grid-cols-2 gap-4">
-      <!-- Valor Líquido do Crédito -->
-      <div>
-        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Valor Líquido do Crédito (R$) *</label>
-        <input
-          type="number"
-          step="0.01"
-          min="0"
-          bind:value={netCreditValue}
-          class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 placeholder-gray-400 dark:placeholder-gray-400 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
-          placeholder="0,00"
-        />
-      </div>
+  function getValue(key) {
+    return formData?.[key] ?? '';
+  }
+
+  function handleInput(key, formatter) {
+    return (event) => {
+      const raw = event.currentTarget.value;
+      const value = formatter ? formatter(raw) : raw;
+      onFieldChange(key, value);
+    };
+  }
+</script>
 
-      <!-- Valor Total do Crédito -->
-      <div>
-        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Valor Total do Crédito (R$) *</label>
-        <input
-          type="number"
-          step="0.01"
-          min="0"
-          bind:value={totalCreditValue}
-          class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 placeholder-gray-400 dark:placeholder-gray-400 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
-          placeholder="0,00"
-        />
+<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg shadow-sm">
+  <form class="space-y-6 p-4">
+    {#each sections as section}
+      <div class="space-y-3">
+        <div>
+          <h3 class="text-base font-semibold text-gray-900 dark:text-gray-100">{section.title}</h3>
+          <p class="text-sm text-gray-500 dark:text-gray-400">Preencha os campos relacionados.</p>
+        </div>
+        <div class={`grid gap-4 ${section.columns === 3 ? 'md:grid-cols-3' : 'md:grid-cols-2'} grid-cols-1`}>
+          {#each section.fields as field}
+            <div class="space-y-1">
+              <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">
+                {field.label}
+                {#if requiredFields?.has(field.key)}
+                  <span class="text-red-500">*</span>
+                {/if}
+              </label>
+              {#if field.type === 'date'}
+                <input
+                  type="date"
+                  class="w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-100 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
+                  value={getValue(field.key)}
+                  on:input={handleInput(field.key)}
+                  required={requiredFields?.has(field.key)}
+                />
+              {:else}
+                <input
+                  type="text"
+                  class="w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-100 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
+                  value={getValue(field.key)}
+                  on:input={handleInput(field.key)}
+                  required={requiredFields?.has(field.key)}
+                />
+              {/if}
+            </div>
+          {/each}
+        </div>
       </div>
-    </div>
+    {/each}
 
-    <div class="flex gap-4">
-      <label class="flex items-center gap-2 text-gray-700 dark:text-gray-300">
-        <input type="checkbox" bind:checked={outside} class="accent-blue-600" />
-        CPR Externo
+    <div class="space-y-1">
+      <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">
+        {notesField.label}
+        {#if requiredFields?.has(notesField.key)}
+          <span class="text-red-500">*</span>
+        {/if}
       </label>
+      <textarea
+        rows="3"
+        class="w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-100 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
+        value={getValue(notesField.key)}
+        on:input={handleInput(notesField.key)}
+        required={requiredFields?.has(notesField.key)}
+      ></textarea>
     </div>
-  
   </form>
-  </div>
+</div>

+ 161 - 64
src/lib/components/commodities/cpr/EmissionCpr.svelte

@@ -1,71 +1,168 @@
 <script>
-    let outside = false;
-    let creditOperationContractCode = "";
-    let operationNature = "";
-    let transactionDate = "";
-    let netCreditValue = "";
-    let totalCreditValue = "";
-    let issuerCompanyName = "";
-    let issueLocation = "";
-    let deliveryDate = "";
-    let type = "";
-  </script>
-  
-  <div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg shadow-sm">
-  <form class="space-y-4 p-4">
+  export let formData = {};
+  export let onFieldChange = () => {};
+  export let requiredFields = new Set();
 
-    <!-- Razão Social do Emissor -->
-    <div>
-      <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Razão Social do Emissor *</label>
-      <input
-        bind:value={issuerCompanyName}
-        class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 placeholder-gray-400 dark:placeholder-gray-400 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
-        placeholder="Digite a razão social do emissor"
-      />
-    </div>
+  const indicatorOptions = [
+    { label: 'Selecione...', value: '' },
+    { label: 'Sim', value: 'S' },
+    { label: 'Não', value: 'N' }
+  ];
 
-    <!-- Local de Emissão e Data da Entrega em grid -->
-    <div class="grid grid-cols-2 gap-4">
-      <!-- Local de Emissão -->
-      <div>
-        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Local de Emissão *</label>
-        <input
-          bind:value={issueLocation}
-          class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 placeholder-gray-400 dark:placeholder-gray-400 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
-          placeholder="Digite o local de emissão"
-        />
-      </div>
+  const sections = [
+    {
+      title: 'Emissão e Entrega',
+      description: 'Local de entrega e prazos do documento.',
+      columns: 2,
+      fields: [
+        { key: 'cpr_issuer_name', label: 'Razão Social do Emissor' },
+        { key: 'cpr_place_name', label: 'Local de Entrega' },
+        { key: 'cpr_document_deadline_days_number', label: 'Prazo para documentos (dias)' },
+        { key: 'cpr_deliveryPlace_state_acronym', label: 'Estado da entrega' },
+        { key: 'cpr_deliveryPlace_city_name', label: 'Cidade da entrega' },
+        { key: 'cpr_deliveryPlace_ibge_code', label: 'IBGE da entrega' }
+      ]
+    },
+    {
+      title: 'Dados do emissor',
+      description: 'Informações cadastrais do emissor.',
+      columns: 2,
+      fields: [
+        { key: 'cpr_issuer_legal_nature_code', label: 'Natureza jurídica' },
+        { key: 'cpr_issuers_person_type_acronym', label: 'Tipo de pessoa' },
+        { key: 'cpr_issuers_document_number', label: 'Documento' },
+        { key: 'cpr_issuers_state_acronym', label: 'Estado' },
+        { key: 'cpr_issuers_city_name', label: 'Cidade' },
+        { key: 'cpr_issuers_ibge_code', label: 'IBGE' }
+      ]
+    },
+    {
+      title: 'Garantias e colaterais',
+      description: 'Detalhes das garantias vinculadas à CPR.',
+      columns: 2,
+      fields: [
+        { key: 'cpr_collateral_type_code', label: 'Código do colateral' },
+        { key: 'cpr_collateral_type_name', label: 'Descrição do colateral' },
+        { key: 'cpr_constitution_process_indicator', label: 'Processo constituído', type: 'select', options: indicatorOptions },
+        { key: 'cpr_otc_bondsman_account_code', label: 'Conta OTC do fiador' },
+        { key: 'cpr_collaterals_document_number', label: 'Documento da garantia' }
+      ]
+    },
+    {
+      title: 'Produto e lastro',
+      description: 'Características do produto e da produção.',
+      columns: 3,
+      fields: [
+        { key: 'cpr_product_name', label: 'Produto' },
+        { key: 'cpr_product_class_name', label: 'Classe' },
+        { key: 'cpr_product_harvest', label: 'Safra' },
+        { key: 'cpr_product_quantity', label: 'Quantidade' },
+        { key: 'cpr_measure_unit_name', label: 'Unidade de medida' },
+        { key: 'cpr_packaging_way_name', label: 'Empacotamento' },
+        { key: 'cpr_product_status_code', label: 'Status do produto' },
+        { key: 'cpr_production_type_code', label: 'Tipo de produção' }
+      ],
+      textarea: { key: 'cpr_product_description', label: 'Descrição do produto' }
+    },
+    {
+      title: 'Local de produção',
+      description: 'Informações da fazenda/propriedade.',
+      columns: 3,
+      fields: [
+        { key: 'cpr_production_place_name', label: 'Nome da propriedade' },
+        { key: 'cpr_property_registration_number', label: 'Registro da propriedade' },
+        { key: 'cpr_notary_name', label: 'Cartório' },
+        { key: 'cpr_total_production_area_in_hectares_number', label: 'Área de produção (ha)' },
+        { key: 'cpr_total_area_in_hectares_number', label: 'Área total (ha)' },
+        { key: 'cpr_car_code', label: 'Código CAR' },
+        { key: 'cpr_latitude_code', label: 'Latitude' },
+        { key: 'cpr_longitude_code', label: 'Longitude' },
+        { key: 'cpr_zip_code', label: 'CEP' }
+      ]
+    },
+    {
+      title: 'Green CPR',
+      description: 'Campos específicos para CPRs verdes.',
+      columns: 2,
+      fields: [
+        { key: 'cpr_green_cpr_indicator', label: 'Indicador Green CPR' },
+        { key: 'cpr_green_cpr_certificate_name', label: 'Certificadora' },
+        { key: 'cpr_green_cpr_certificate_cnpj_number', label: 'CNPJ da certificadora' },
+        { key: 'cpr_green_cpr_declaration_indicator', label: 'Declaração apresentada' }
+      ],
+      textarea: { key: 'cpr_green_cpr_georeferencing_description', label: 'Descrição do georreferenciamento' }
+    }
+  ];
 
-      <!-- Data da Entrega -->
-      <div>
-        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Data da Entrega *</label>
-        <input
-          type="date"
-          bind:value={deliveryDate}
-          class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 placeholder-gray-400 dark:placeholder-gray-400 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
-        />
-      </div>
-    </div>
+  function getValue(key) {
+    return formData?.[key] ?? '';
+  }
 
-    <!-- Tipo -->
-    <div>
-      <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Tipo *</label>
-      <select
-        bind:value={type}
-        class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
-      >
-        <option value="">Selecione...</option>
-        <option value="fisico">Físico</option>
-        <option value="financeiro">Financeiro</option>
-      </select>
-    </div>
+  function handleInput(key) {
+    return (event) => {
+      onFieldChange(key, event.currentTarget.value);
+    };
+  }
+</script>
 
-    <div class="flex gap-4">
-      <label class="flex items-center gap-2 text-gray-700 dark:text-gray-300">
-        <input type="checkbox" bind:checked={outside} class="accent-blue-600" />
-        CPR Externo
-      </label>
-    </div>
-  
+<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg shadow-sm">
+  <form class="space-y-6 p-4">
+    {#each sections as section}
+      <div class="space-y-3">
+        <div>
+          <h3 class="text-base font-semibold text-gray-900 dark:text-gray-100">{section.title}</h3>
+          <p class="text-sm text-gray-500 dark:text-gray-400">{section.description}</p>
+        </div>
+        <div class={`grid gap-4 ${section.columns === 3 ? 'md:grid-cols-3' : 'md:grid-cols-2'} grid-cols-1`}>
+          {#each section.fields as field}
+            <div class="space-y-1">
+              <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">
+                {field.label}
+                {#if requiredFields?.has(field.key)}
+                  <span class="text-red-500">*</span>
+                {/if}
+              </label>
+              {#if field.type === 'select'}
+                <select
+                  class="w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-100 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
+                  value={getValue(field.key)}
+                  on:change={handleInput(field.key)}
+                  required={requiredFields?.has(field.key)}
+                >
+                  {#each field.options as option}
+                    <option value={option.value}>{option.label}</option>
+                  {/each}
+                </select>
+              {:else}
+                <input
+                  type="text"
+                  class="w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-100 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
+                  value={getValue(field.key)}
+                  on:input={handleInput(field.key)}
+                  required={requiredFields?.has(field.key)}
+                />
+              {/if}
+            </div>
+          {/each}
+        </div>
+        {#if section.textarea}
+          <div class="space-y-1">
+            <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">
+              {section.textarea.label}
+              {#if requiredFields?.has(section.textarea.key)}
+                <span class="text-red-500">*</span>
+              {/if}
+            </label>
+            <textarea
+              rows="3"
+              class="w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-100 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
+              value={getValue(section.textarea.key)}
+              on:input={handleInput(section.textarea.key)}
+              required={requiredFields?.has(section.textarea.key)}
+            ></textarea>
+          </div>
+        {/if}
+      </div>
+    {/each}
   </form>
-  </div>
+</div>

+ 149 - 49
src/lib/components/commodities/cpr/RegisterCpr.svelte

@@ -1,53 +1,153 @@
 <script>
-    let additive = "";
-    let contractCode = "";
-    let issuer = "";
-    let outside = false;
-  </script>
-  
-  <div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg shadow-sm">
-  <form class="space-y-4 p-4">
-    <div class="grid grid-cols-2 gap-4">
-      <div>
-        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Aditivo *</label>
-        <input
-          bind:value={additive}
-          class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 placeholder-gray-400 dark:placeholder-gray-400 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
-          placeholder="Digite o nome"
-        />
-      </div>
-    </div>
-  
-    <div>
-      <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Código Contrato *</label>
-      <select
-        bind:value={contractCode}
-        class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
-      >
-        <option value="">Código Contrato</option>
-        <option value="1">Categoria 1</option>
-        <option value="2">Categoria 2</option>
-      </select>
-    </div>
+  export let formData = {};
+  export let onFieldChange = () => {};
+  export let requiredFields = new Set();
+
+  const indicatorOptions = [
+    { label: 'Selecione...', value: '' },
+    { label: 'Sim', value: 'S' },
+    { label: 'Não', value: 'N' }
+  ];
+
+  const sections = [
+    {
+      title: 'Informações Gerais',
+      description: 'Dados básicos da CPR e status cadastral.',
+      columns: 2,
+      fields: [
+        { key: 'cpr_type_code', label: 'Tipo da CPR' },
+        { key: 'cpr_internal_control_number', label: 'Controle Interno' },
+        { key: 'cpr_isin_code', label: 'Código ISIN' },
+        { key: 'cpr_reference_date', label: 'Data de Referência', type: 'date' },
+        { key: 'cpr_electronic_emission_indicator', label: 'Emissão Eletrônica', type: 'select', options: indicatorOptions },
+        { key: 'cpr_automatic_expiration_indicator', label: 'Expiração Automática', type: 'select', options: indicatorOptions }
+      ]
+    },
+    {
+      title: 'Contas OTC e Liquidação',
+      description: 'Vinculação das contas na câmara de registro e liquidação.',
+      columns: 2,
+      fields: [
+        { key: 'cpr_otc_register_account_code', label: 'Conta OTC de Registro' },
+        { key: 'cpr_otc_payment_agent_account_code', label: 'Conta OTC Agente de Pagamento' },
+        { key: 'cpr_otc_custodian_account_code', label: 'Conta OTC Custódia' },
+        { key: 'cpr_otc_favored_account_code', label: 'Conta OTC Favorecido' },
+        { key: 'cpr_settlement_modality_type_code', label: 'Modalidade de Liquidação' },
+        { key: 'cpr_otc_settlement_bank_account_code', label: 'Conta Bancária de Liquidação' }
+      ]
+    },
+    {
+      title: 'Depósito e Garantias',
+      description: 'Detalhes complementares sobre garantias e depósitos.',
+      columns: 3,
+      fields: [
+        { key: 'cpr_ballast_type_code', label: 'Tipo de lastro' },
+        { key: 'cpr_lot_number', label: 'Número do lote' },
+        { key: 'cpr_ballast_quantity', label: 'Quantidade do lastro' },
+        { key: 'cpr_currency_code', label: 'Código da moeda' },
+        { key: 'cpr_transaction_identification', label: 'Identificação da operação' },
+        { key: 'cpr_guarantee_limit_type_code', label: 'Tipo limite garantia' },
+        { key: 'cpr_mother_code', label: 'Código mãe' },
+        { key: 'cpr_deposit_quantity', label: 'Quantidade depositada' },
+        { key: 'cpr_deposit_unit_price_value', label: 'Valor unitário depósito' },
+        { key: 'cpr_deposit_person_type_acronym', label: 'Tipo pessoa depósito' },
+        { key: 'cpr_deposit_document_number', label: 'Documento do depositante' }
+      ]
+    },
+    {
+      title: 'Eventos e operação',
+      description: 'Campos relacionados aos eventos e códigos regulatórios.',
+      columns: 2,
+      fields: [
+        { key: 'cpr_event_type_code', label: 'Tipo do evento' },
+        { key: 'cpr_event_original_date', label: 'Data original do evento', type: 'date' },
+        { key: 'cpr_operation_modality_type_code', label: 'Modalidade da operação' },
+        { key: 'cpr_bacen_reference_code', label: 'Código Bacen' },
+        { key: 'cpr_children_codes', label: 'Códigos filhos (separados por vírgula)', type: 'textarea' }
+      ]
+    },
+    {
+      title: 'SCR e finalidades',
+      description: 'Dados necessários para reporte ao SCR.',
+      columns: 2,
+      fields: [
+        { key: 'cpr_scr_type_code', label: 'Tipo SCR' },
+        { key: 'cpr_finality_code', label: 'Finalidade' },
+        { key: 'cpr_scr_customer_detail', label: 'Detalhe do cliente' },
+        { key: 'cpr_scr_person_type_acronym', label: 'Tipo de pessoa SCR' },
+        { key: 'cpr_scr_document_number', label: 'Documento do SCR' },
+        { key: 'cpr_contract_code', label: 'Código do contrato principal' }
+      ]
+    }
+  ];
+
+  function getValue(key) {
+    return formData?.[key] ?? '';
+  }
+
+  function handleInput(key) {
+    return (event) => {
+      onFieldChange(key, event.currentTarget.value);
+    };
+  }
+</script>
 
-    <div>
-        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Emissor *</label>
-        <select
-          bind:value={issuer}
-          class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
-        >
-          <option value="">Emissor</option>
-          <option value="1">Categoria 1</option>
-          <option value="2">Categoria 2</option>
-        </select>
+<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg shadow-sm">
+  <form class="space-y-6 p-4">
+    {#each sections as section}
+      <div class="space-y-3">
+        <div>
+          <h3 class="text-base font-semibold text-gray-900 dark:text-gray-100">{section.title}</h3>
+          <p class="text-sm text-gray-500 dark:text-gray-400">{section.description}</p>
+        </div>
+        <div class={`grid gap-4 ${section.columns === 3 ? 'md:grid-cols-3' : 'md:grid-cols-2'} grid-cols-1`}>
+          {#each section.fields as field}
+            <div class="space-y-1">
+              <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">
+                {field.label}
+                {#if requiredFields?.has(field.key)}
+                  <span class="text-red-500">*</span>
+                {/if}
+              </label>
+              {#if field.type === 'date'}
+                <input
+                  type="date"
+                  class="w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-100 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
+                  value={getValue(field.key)}
+                  on:input={handleInput(field.key)}
+                  required={requiredFields?.has(field.key)}
+                />
+              {:else if field.type === 'textarea'}
+                <textarea
+                  rows="3"
+                  class="w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-100 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
+                  on:input={handleInput(field.key)}
+                  required={requiredFields?.has(field.key)}
+                >{getValue(field.key)}</textarea>
+              {:else if field.type === 'select'}
+                <select
+                  class="w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-100 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
+                  value={getValue(field.key)}
+                  on:change={handleInput(field.key)}
+                  required={requiredFields?.has(field.key)}
+                >
+                  {#each field.options as option}
+                    <option value={option.value}>{option.label}</option>
+                  {/each}
+                </select>
+              {:else}
+                <input
+                  type="text"
+                  class="w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-100 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
+                  value={getValue(field.key)}
+                  on:input={handleInput(field.key)}
+                  required={requiredFields?.has(field.key)}
+                />
+              {/if}
+            </div>
+          {/each}
+        </div>
       </div>
-  
-    <div class="flex gap-4">
-      <label class="flex items-center gap-2 text-gray-700 dark:text-gray-300">
-        <input type="checkbox" bind:checked={outside} class="accent-blue-600" />
-        CPR Externo
-      </label>
-    </div>
-  
+    {/each}
   </form>
-  </div>
+</div>

+ 300 - 11
src/routes/cpr/+page.svelte

@@ -7,6 +7,195 @@
   import EmissionCpr from '$lib/components/commodities/cpr/EmissionCpr.svelte';
   import CprEditModal from '$lib/components/commodities/cpr/CprEditModal.svelte';
   import ConfirmModal from '$lib/components/ui/PopUpDelete.svelte';
+  import { authToken } from '$lib/utils/stores';
+
+  const apiUrl = import.meta.env.VITE_API_URL;
+
+  const fieldKeys = [
+    'cpr_contract_code',
+    'cpr_contract_number',
+    'cpr_number',
+    'cpr_self_number',
+    'cpr_ipoc_code',
+    'cpr_calculation_type_code',
+    'cpr_initial_exchange_value',
+    'cpr_fixing_type_code',
+    'cpr_data_source_type_code',
+    'cpr_adjustment_frequency_type_code',
+    'cpr_adjustment_pro_rata_type_code',
+    'cpr_adjustment_type_code',
+    'cpr_issue_date',
+    'cpr_maturity_date',
+    'cpr_reference_date',
+    'cpr_profitability_start_date',
+    'cpr_payment_start_date',
+    'cpr_amortization_start_date',
+    'cpr_interest_payment_date',
+    'cpr_issue_quantity',
+    'cpr_issue_value',
+    'cpr_issue_financial_value',
+    'cpr_unit_value',
+    'cpr_unit_price_value',
+    'cpr_interest_unit_price_value',
+    'cpr_residual_value',
+    'cpr_amortization_percentage',
+    'cpr_event_quantity',
+    'cpr_creditor_name',
+    'cpr_creditor_document_number',
+    'cpr_payment_method_code',
+    'cpr_index_code',
+    'cpr_index_short_name',
+    'cpr_vcp_indicator_type_code',
+    'cpr_indexador_percentage_value',
+    'cpr_interest_rate_spread_percentage',
+    'cpr_interest_rate_criteria_type_code',
+    'cpr_interest_payment_value',
+    'cpr_interest_payment_frequency_code',
+    'cpr_interest_months_quantity',
+    'cpr_interestPaymentFlow_time_unit_type_code',
+    'cpr_interestPaymentFlow_deadline_type_code',
+    'cpr_amortization_type_code',
+    'cpr_amortization_months_quantity',
+    'cpr_amortizationPaymentFlow_time_unit_type_code',
+    'cpr_amortizationPaymentFlow_deadline_type_code',
+    'cpr_additional_text',
+    'cpr_type_code',
+    'cpr_internal_control_number',
+    'cpr_isin_code',
+    'cpr_electronic_emission_indicator',
+    'cpr_automatic_expiration_indicator',
+    'cpr_otc_register_account_code',
+    'cpr_otc_payment_agent_account_code',
+    'cpr_otc_custodian_account_code',
+    'cpr_otc_favored_account_code',
+    'cpr_settlement_modality_type_code',
+    'cpr_otc_settlement_bank_account_code',
+    'cpr_ballast_type_code',
+    'cpr_lot_number',
+    'cpr_ballast_quantity',
+    'cpr_currency_code',
+    'cpr_transaction_identification',
+    'cpr_guarantee_limit_type_code',
+    'cpr_mother_code',
+    'cpr_deposit_quantity',
+    'cpr_deposit_unit_price_value',
+    'cpr_deposit_person_type_acronym',
+    'cpr_deposit_document_number',
+    'cpr_event_type_code',
+    'cpr_event_original_date',
+    'cpr_operation_modality_type_code',
+    'cpr_bacen_reference_code',
+    'cpr_children_codes',
+    'cpr_scr_type_code',
+    'cpr_finality_code',
+    'cpr_scr_customer_detail',
+    'cpr_scr_person_type_acronym',
+    'cpr_scr_document_number',
+    'cpr_issuer_name',
+    'cpr_place_name',
+    'cpr_document_deadline_days_number',
+    'cpr_deliveryPlace_state_acronym',
+    'cpr_deliveryPlace_city_name',
+    'cpr_deliveryPlace_ibge_code',
+    'cpr_issuer_legal_nature_code',
+    'cpr_issuers_person_type_acronym',
+    'cpr_issuers_document_number',
+    'cpr_issuers_state_acronym',
+    'cpr_issuers_city_name',
+    'cpr_issuers_ibge_code',
+    'cpr_collateral_type_code',
+    'cpr_collateral_type_name',
+    'cpr_constitution_process_indicator',
+    'cpr_otc_bondsman_account_code',
+    'cpr_collaterals_document_number',
+    'cpr_product_name',
+    'cpr_product_class_name',
+    'cpr_product_harvest',
+    'cpr_product_quantity',
+    'cpr_measure_unit_name',
+    'cpr_packaging_way_name',
+    'cpr_product_status_code',
+    'cpr_production_type_code',
+    'cpr_product_description',
+    'cpr_production_place_name',
+    'cpr_property_registration_number',
+    'cpr_notary_name',
+    'cpr_total_production_area_in_hectares_number',
+    'cpr_total_area_in_hectares_number',
+    'cpr_car_code',
+    'cpr_latitude_code',
+    'cpr_longitude_code',
+    'cpr_zip_code',
+    'cpr_green_cpr_indicator',
+    'cpr_green_cpr_certificate_name',
+    'cpr_green_cpr_certificate_cnpj_number',
+    'cpr_green_cpr_declaration_indicator',
+    'cpr_green_cpr_georeferencing_description'
+  ];
+
+  const allFieldKeys = Array.from(new Set(fieldKeys));
+
+  const requiredFields = new Set([
+    'cpr_type_code',
+    'cpr_otc_register_account_code',
+    'cpr_otc_custodian_account_code',
+    'cpr_electronic_emission_indicator',
+    'cpr_issue_date',
+    'cpr_maturity_date',
+    'cpr_issue_quantity',
+    'cpr_issue_value',
+    'cpr_issue_financial_value',
+    'cpr_profitability_start_date',
+    'cpr_automatic_expiration_indicator',
+    'cpr_collateral_type_code',
+    'cpr_collateral_type_name',
+    'cpr_constitution_process_indicator',
+    'cpr_otc_bondsman_account_code',
+    'cpr_product_name',
+    'cpr_product_class_name',
+    'cpr_product_harvest',
+    'cpr_product_description',
+    'cpr_product_quantity',
+    'cpr_measure_unit_name',
+    'cpr_packaging_way_name',
+    'cpr_product_status_code',
+    'cpr_production_type_code',
+    'cpr_document_deadline_days_number',
+    'cpr_place_name',
+    'cpr_deliveryPlace_state_acronym',
+    'cpr_deliveryPlace_city_name',
+    'cpr_issuer_name',
+    'cpr_issuers_document_number',
+    'cpr_issuers_person_type_acronym',
+    'cpr_issuer_legal_nature_code',
+    'cpr_issuers_state_acronym',
+    'cpr_issuers_city_name',
+    'cpr_scr_type_code',
+    'cpr_finality_code',
+    'cpr_contract_code',
+    'cpr_creditor_name',
+    'cpr_creditor_document_number',
+    'cpr_production_place_name',
+    'cpr_property_registration_number',
+    'cpr_notary_name',
+    'cpr_total_production_area_in_hectares_number',
+    'cpr_total_area_in_hectares_number',
+    'cpr_car_code',
+    'cpr_latitude_code',
+    'cpr_longitude_code',
+    'cpr_zip_code'
+  ]);
+
+  const createInitialForm = () =>
+    allFieldKeys.reduce((acc, key) => {
+      acc[key] = '';
+      return acc;
+    }, {});
+
+  let cprForm = createInitialForm();
+  let submitError = '';
+  let submitSuccess = '';
+  let isSubmitting = false;
 
   // EditModal
   let showCprEdit = false;
@@ -31,7 +220,16 @@
     { nome: "CPR B", status: "Indisponível" }
   ];
 
+  function handleFieldChange(key, value) {
+    submitError = '';
+    submitSuccess = '';
+    cprForm = { ...cprForm, [key]: value ?? '' };
+  }
+
   function handleAddTop() {
+    cprForm = createInitialForm();
+    submitError = '';
+    submitSuccess = '';
     activeTab = 0;
   }
 
@@ -44,7 +242,7 @@
   function handleEditRow(e) {
     const { row } = e.detail;
     selectedRow = row;
-    editValue = { ...row }; 
+    editValue = { ...row };
     showCprEdit = true;
   }
 
@@ -62,13 +260,9 @@
     editValue = {};
   }
 
-  function handleFinalize() {
-    alert('CPR finalizado com sucesso!');
-    activeTab = 4;
-  }
-
   function handleCancel() {
     activeTab = 4;
+    submitError = '';
   }
 
   function confirmDelete() {
@@ -81,6 +275,87 @@
     showDeleteConfirm = false;
     rowToDelete = null;
   }
+
+  function getMissingRequiredFields() {
+    const missing = [];
+    requiredFields.forEach((key) => {
+      const raw = cprForm[key];
+      if (!raw || String(raw).trim() === '') {
+        missing.push(key);
+      }
+    });
+    return missing;
+  }
+
+  function buildPayload() {
+    const payload = {};
+    for (const key of allFieldKeys) {
+      const raw = cprForm[key];
+      const trimmed = typeof raw === 'string' ? raw.trim() : raw;
+      if (trimmed === '' || trimmed === undefined || trimmed === null) {
+        payload[key] = requiredFields.has(key) ? '' : 'NA';
+      } else {
+        payload[key] = raw;
+      }
+    }
+    return payload;
+  }
+
+  async function handleFinalize(event) {
+    event?.preventDefault();
+    submitError = '';
+    submitSuccess = '';
+
+    const missing = getMissingRequiredFields();
+    if (missing.length) {
+      submitError = `Preencha os campos obrigatórios: ${missing.join(', ')}`;
+      return;
+    }
+
+    const token = $authToken;
+    if (!token) {
+      submitError = 'Sessão expirada. Faça login novamente.';
+      return;
+    }
+
+    const payload = buildPayload();
+    isSubmitting = true;
+
+    try {
+      const res = await fetch(`${apiUrl}/b3/cpr/register`, {
+        method: 'POST',
+        headers: {
+          'content-type': 'application/json',
+          Authorization: `Bearer ${token}`
+        },
+        body: JSON.stringify(payload)
+      });
+
+      const raw = await res.text();
+      let response = null;
+      if (raw) {
+        try {
+          response = JSON.parse(raw);
+        } catch (err) {
+          console.error('Resposta inválida ao registrar CPR:', err, raw);
+          throw new Error('Resposta inválida do servidor ao registrar CPR.');
+        }
+      }
+
+      const serverStatus = response?.status?.toLowerCase?.() ?? '';
+      if (!res.ok || (response?.status && serverStatus !== 'ok')) {
+        throw new Error(response?.msg ?? 'Falha ao registrar CPR.');
+      }
+
+      submitSuccess = response?.msg ?? 'CPR registrada com sucesso.';
+      cprForm = createInitialForm();
+      activeTab = 4;
+    } catch (err) {
+      submitError = err?.message ?? 'Falha ao registrar CPR.';
+    } finally {
+      isSubmitting = false;
+    }
+  }
 </script>
 
 <div>
@@ -88,6 +363,13 @@
   <div class="p-4">
     <div class="max-w-6xl mx-auto mt-4">
     
+      {#if submitError}
+        <div class="mb-4 rounded border border-red-300 bg-red-50 text-red-700 px-3 py-2 text-sm">{submitError}</div>
+      {/if}
+      {#if submitSuccess}
+        <div class="mb-4 rounded border border-green-300 bg-green-50 text-green-700 px-3 py-2 text-sm">{submitSuccess}</div>
+      {/if}
+
       {#if activeTab === 4}
         <Tables
           title="CPRs"
@@ -108,17 +390,19 @@
       {:else if activeTab === 0}
       <Tabs {tabs} bind:active={activeTab} showCloseIcon={true} on:close={handleCancel} />
       <div class="mt-4">
-        <ContractCpr />
+        <ContractCpr formData={cprForm} onFieldChange={handleFieldChange} {requiredFields} />
       </div>
       <!-- Navigation Controls -->
       <div class="flex justify-between mt-6">
         <button 
+          type="button"
           class="px-4 py-2 bg-gray-300 text-gray-700 rounded-lg cursor-not-allowed" 
           disabled
         >
           Anterior
         </button>
         <button 
+          type="button"
           class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700"
           on:click={() => activeTab = 1}
         >
@@ -128,17 +412,19 @@
       {:else if activeTab === 1}
       <Tabs {tabs} bind:active={activeTab} showCloseIcon={true} on:close={handleCancel} />
       <div class="mt-4">
-        <RegisterCpr />
+        <RegisterCpr formData={cprForm} onFieldChange={handleFieldChange} {requiredFields} />
       </div>
       <!-- Navigation Controls -->
       <div class="flex justify-between mt-6">
         <button 
+          type="button"
           class="px-4 py-2 bg-gray-500 text-white rounded-lg hover:bg-gray-600"
           on:click={() => activeTab = 0}
         >
           Anterior
         </button>
         <button 
+          type="button"
           class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700"
           on:click={() => activeTab = 2}
         >
@@ -148,21 +434,24 @@
       {:else if activeTab === 2}
       <Tabs {tabs} bind:active={activeTab} showCloseIcon={true} on:close={handleCancel} />
       <div class="mt-4">
-        <EmissionCpr />
+        <EmissionCpr formData={cprForm} onFieldChange={handleFieldChange} {requiredFields} />
       </div>
       <!-- Navigation Controls -->
       <div class="flex justify-between mt-6">
         <button 
+          type="button"
           class="px-4 py-2 bg-gray-500 text-white rounded-lg hover:bg-gray-600"
           on:click={() => activeTab = 1}
         >
           Anterior
         </button>
         <button 
+          type="button"
           class="px-6 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 font-semibold"
-          on:click={handleFinalize}
+          on:click|preventDefault={handleFinalize}
+          disabled={isSubmitting}
         >
-          Finalizar CPR
+          {isSubmitting ? 'Enviando...' : 'Finalizar CPR'}
         </button>
       </div>