|
@@ -186,6 +186,84 @@
|
|
|
'cpr_zip_code'
|
|
'cpr_zip_code'
|
|
|
]);
|
|
]);
|
|
|
|
|
|
|
|
|
|
+ const repeatingGroupDefinitions = [
|
|
|
|
|
+ {
|
|
|
|
|
+ key: 'issuers',
|
|
|
|
|
+ title: 'Dados dos emissores',
|
|
|
|
|
+ description: 'Adicione quantos emissores forem necessários.',
|
|
|
|
|
+ itemLabel: 'Emissor',
|
|
|
|
|
+ addLabel: 'Adicionar emissor',
|
|
|
|
|
+ columns: 2,
|
|
|
|
|
+ fields: [
|
|
|
|
|
+ { key: 'cpr_issuer_name', label: 'Razão Social do Emissor' },
|
|
|
|
|
+ { key: 'cpr_issuers_document_number', label: 'Documento' },
|
|
|
|
|
+ { key: 'cpr_issuers_person_type_acronym', label: 'Tipo de pessoa' },
|
|
|
|
|
+ { key: 'cpr_issuer_legal_nature_code', label: 'Natureza jurídica' },
|
|
|
|
|
+ { key: 'cpr_issuers_state_acronym', label: 'Estado' },
|
|
|
|
|
+ { key: 'cpr_issuers_city_name', label: 'Cidade' }
|
|
|
|
|
+ ]
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ key: 'collaterals',
|
|
|
|
|
+ title: 'Garantias e colaterais',
|
|
|
|
|
+ description: 'Informe todos os colaterais vinculados a esta CPR.',
|
|
|
|
|
+ itemLabel: 'Colateral',
|
|
|
|
|
+ addLabel: 'Adicionar colateral',
|
|
|
|
|
+ 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: [
|
|
|
|
|
+ { label: 'Selecione...', value: '' },
|
|
|
|
|
+ { label: 'Sim', value: 'S' },
|
|
|
|
|
+ { label: 'Não', value: 'N' }
|
|
|
|
|
+ ] },
|
|
|
|
|
+ { key: 'cpr_otc_bondsman_account_code', label: 'Conta OTC do fiador' }
|
|
|
|
|
+ ]
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ key: 'productionPlaces',
|
|
|
|
|
+ title: 'Locais de produção',
|
|
|
|
|
+ description: 'Cadastre cada propriedade vinculada ao lastro.',
|
|
|
|
|
+ itemLabel: 'Propriedade',
|
|
|
|
|
+ addLabel: 'Adicionar 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' }
|
|
|
|
|
+ ]
|
|
|
|
|
+ }
|
|
|
|
|
+ ];
|
|
|
|
|
+
|
|
|
|
|
+ const repeatingFieldToGroup = repeatingGroupDefinitions.reduce((acc, config) => {
|
|
|
|
|
+ config.fields.forEach((field) => {
|
|
|
|
|
+ acc[field.key] = config.key;
|
|
|
|
|
+ });
|
|
|
|
|
+ return acc;
|
|
|
|
|
+ }, {});
|
|
|
|
|
+
|
|
|
|
|
+ function createEmptyRepeatingEntry(config) {
|
|
|
|
|
+ return config.fields.reduce((entry, field) => {
|
|
|
|
|
+ entry[field.key] = '';
|
|
|
|
|
+ return entry;
|
|
|
|
|
+ }, {});
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const createInitialRepeatingGroups = () => {
|
|
|
|
|
+ const groups = {};
|
|
|
|
|
+ repeatingGroupDefinitions.forEach((config) => {
|
|
|
|
|
+ groups[config.key] = [createEmptyRepeatingEntry(config)];
|
|
|
|
|
+ });
|
|
|
|
|
+ return groups;
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
const createInitialForm = () =>
|
|
const createInitialForm = () =>
|
|
|
allFieldKeys.reduce((acc, key) => {
|
|
allFieldKeys.reduce((acc, key) => {
|
|
|
acc[key] = '';
|
|
acc[key] = '';
|
|
@@ -193,6 +271,7 @@
|
|
|
}, {});
|
|
}, {});
|
|
|
|
|
|
|
|
let cprForm = createInitialForm();
|
|
let cprForm = createInitialForm();
|
|
|
|
|
+ let repeatingGroups = createInitialRepeatingGroups();
|
|
|
let submitError = '';
|
|
let submitError = '';
|
|
|
let submitSuccess = '';
|
|
let submitSuccess = '';
|
|
|
let isSubmitting = false;
|
|
let isSubmitting = false;
|
|
@@ -226,8 +305,49 @@
|
|
|
cprForm = { ...cprForm, [key]: value ?? '' };
|
|
cprForm = { ...cprForm, [key]: value ?? '' };
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ function cloneRepeatingEntries(groupKey) {
|
|
|
|
|
+ const entries = repeatingGroups[groupKey] ?? [];
|
|
|
|
|
+ return entries.map((entry) => ({ ...entry }));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ function handleRepeatingFieldChange(groupKey, index, fieldKey, value) {
|
|
|
|
|
+ submitError = '';
|
|
|
|
|
+ submitSuccess = '';
|
|
|
|
|
+ const nextEntries = cloneRepeatingEntries(groupKey);
|
|
|
|
|
+ if (!nextEntries[index]) return;
|
|
|
|
|
+ nextEntries[index] = {
|
|
|
|
|
+ ...nextEntries[index],
|
|
|
|
|
+ [fieldKey]: value ?? ''
|
|
|
|
|
+ };
|
|
|
|
|
+ repeatingGroups = {
|
|
|
|
|
+ ...repeatingGroups,
|
|
|
|
|
+ [groupKey]: nextEntries
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ function handleAddRepeatingEntry(groupKey) {
|
|
|
|
|
+ const config = repeatingGroupDefinitions.find((c) => c.key === groupKey);
|
|
|
|
|
+ if (!config) return;
|
|
|
|
|
+ const nextEntries = cloneRepeatingEntries(groupKey);
|
|
|
|
|
+ nextEntries.push(createEmptyRepeatingEntry(config));
|
|
|
|
|
+ repeatingGroups = {
|
|
|
|
|
+ ...repeatingGroups,
|
|
|
|
|
+ [groupKey]: nextEntries
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ function handleRemoveRepeatingEntry(groupKey, index) {
|
|
|
|
|
+ const nextEntries = cloneRepeatingEntries(groupKey);
|
|
|
|
|
+ if (nextEntries.length <= 1) return;
|
|
|
|
|
+ repeatingGroups = {
|
|
|
|
|
+ ...repeatingGroups,
|
|
|
|
|
+ [groupKey]: nextEntries.filter((_, i) => i !== index)
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
function handleAddTop() {
|
|
function handleAddTop() {
|
|
|
cprForm = createInitialForm();
|
|
cprForm = createInitialForm();
|
|
|
|
|
+ repeatingGroups = createInitialRepeatingGroups();
|
|
|
submitError = '';
|
|
submitError = '';
|
|
|
submitSuccess = '';
|
|
submitSuccess = '';
|
|
|
activeTab = 0;
|
|
activeTab = 0;
|
|
@@ -279,9 +399,25 @@
|
|
|
function getMissingRequiredFields() {
|
|
function getMissingRequiredFields() {
|
|
|
const missing = [];
|
|
const missing = [];
|
|
|
requiredFields.forEach((key) => {
|
|
requiredFields.forEach((key) => {
|
|
|
- const raw = cprForm[key];
|
|
|
|
|
- if (!raw || String(raw).trim() === '') {
|
|
|
|
|
- missing.push(key);
|
|
|
|
|
|
|
+ const groupKey = repeatingFieldToGroup[key];
|
|
|
|
|
+ if (groupKey) {
|
|
|
|
|
+ const config = repeatingGroupDefinitions.find((c) => c.key === groupKey);
|
|
|
|
|
+ const entries = repeatingGroups[groupKey] ?? [];
|
|
|
|
|
+ if (!entries.length) {
|
|
|
|
|
+ missing.push(`${key} (${config?.itemLabel ?? groupKey})`);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ entries.forEach((entry, index) => {
|
|
|
|
|
+ const raw = entry?.[key];
|
|
|
|
|
+ if (!raw || String(raw).trim() === '') {
|
|
|
|
|
+ missing.push(`${key} (${config?.itemLabel ?? groupKey} ${index + 1})`);
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ } else {
|
|
|
|
|
+ const raw = cprForm[key];
|
|
|
|
|
+ if (!raw || String(raw).trim() === '') {
|
|
|
|
|
+ missing.push(key);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
|
return missing;
|
|
return missing;
|
|
@@ -290,6 +426,21 @@
|
|
|
function buildPayload() {
|
|
function buildPayload() {
|
|
|
const payload = {};
|
|
const payload = {};
|
|
|
for (const key of allFieldKeys) {
|
|
for (const key of allFieldKeys) {
|
|
|
|
|
+ const groupKey = repeatingFieldToGroup[key];
|
|
|
|
|
+ if (groupKey) {
|
|
|
|
|
+ const entries = repeatingGroups[groupKey] ?? [];
|
|
|
|
|
+ const values = entries
|
|
|
|
|
+ .map((entry) => entry?.[key])
|
|
|
|
|
+ .map((value) => (typeof value === 'string' ? value.trim() : value))
|
|
|
|
|
+ .filter((value) => value && value !== '');
|
|
|
|
|
+ payload[key] = values.length
|
|
|
|
|
+ ? values.join('; ')
|
|
|
|
|
+ : requiredFields.has(key)
|
|
|
|
|
+ ? ''
|
|
|
|
|
+ : 'NA';
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
const raw = cprForm[key];
|
|
const raw = cprForm[key];
|
|
|
const trimmed = typeof raw === 'string' ? raw.trim() : raw;
|
|
const trimmed = typeof raw === 'string' ? raw.trim() : raw;
|
|
|
if (trimmed === '' || trimmed === undefined || trimmed === null) {
|
|
if (trimmed === '' || trimmed === undefined || trimmed === null) {
|
|
@@ -349,6 +500,7 @@
|
|
|
|
|
|
|
|
submitSuccess = response?.msg ?? 'CPR registrada com sucesso.';
|
|
submitSuccess = response?.msg ?? 'CPR registrada com sucesso.';
|
|
|
cprForm = createInitialForm();
|
|
cprForm = createInitialForm();
|
|
|
|
|
+ repeatingGroups = createInitialRepeatingGroups();
|
|
|
activeTab = 4;
|
|
activeTab = 4;
|
|
|
} catch (err) {
|
|
} catch (err) {
|
|
|
submitError = err?.message ?? 'Falha ao registrar CPR.';
|
|
submitError = err?.message ?? 'Falha ao registrar CPR.';
|
|
@@ -434,7 +586,16 @@
|
|
|
{:else if activeTab === 2}
|
|
{:else if activeTab === 2}
|
|
|
<Tabs {tabs} bind:active={activeTab} showCloseIcon={true} on:close={handleCancel} />
|
|
<Tabs {tabs} bind:active={activeTab} showCloseIcon={true} on:close={handleCancel} />
|
|
|
<div class="mt-4">
|
|
<div class="mt-4">
|
|
|
- <EmissionCpr formData={cprForm} onFieldChange={handleFieldChange} {requiredFields} />
|
|
|
|
|
|
|
+ <EmissionCpr
|
|
|
|
|
+ formData={cprForm}
|
|
|
|
|
+ onFieldChange={handleFieldChange}
|
|
|
|
|
+ {requiredFields}
|
|
|
|
|
+ repeatingConfigs={repeatingGroupDefinitions}
|
|
|
|
|
+ {repeatingGroups}
|
|
|
|
|
+ onRepeatingFieldChange={handleRepeatingFieldChange}
|
|
|
|
|
+ onAddRepeatingEntry={handleAddRepeatingEntry}
|
|
|
|
|
+ onRemoveRepeatingEntry={handleRemoveRepeatingEntry}
|
|
|
|
|
+ />
|
|
|
</div>
|
|
</div>
|
|
|
<!-- Navigation Controls -->
|
|
<!-- Navigation Controls -->
|
|
|
<div class="flex justify-between mt-6">
|
|
<div class="flex justify-between mt-6">
|