updates
This commit is contained in:
parent
fca6321dcf
commit
0b6601fabc
|
|
@ -139,25 +139,14 @@ const getAttachmentName = (attachment: any) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const getAttachmentUrl = (attachment: any) => {
|
const getAttachmentUrl = (attachment: any) => {
|
||||||
// If attachment is just a string (filename), assume it's in the client-emails bucket
|
// If attachment has a path and bucket, construct the download URL
|
||||||
if (typeof attachment === 'string') {
|
if (attachment.path && attachment.bucket) {
|
||||||
return `/api/files/proxy-download?fileName=${encodeURIComponent(attachment)}&bucket=client-emails`;
|
return `/api/files/proxy-download?path=${encodeURIComponent(attachment.path)}&bucket=${attachment.bucket}`;
|
||||||
}
|
}
|
||||||
|
// If it's just a URL, return it
|
||||||
// If it has a path property, use that
|
if (attachment.url) return attachment.url;
|
||||||
if (attachment?.path) {
|
// Otherwise return a placeholder
|
||||||
const bucket = attachment.bucket || 'client-emails';
|
return '#';
|
||||||
return `/api/files/proxy-download?fileName=${encodeURIComponent(attachment.path)}&bucket=${bucket}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If it has a url property, use that directly
|
|
||||||
if (attachment?.url) {
|
|
||||||
return attachment.url;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default fallback
|
|
||||||
const name = attachment?.name || attachment?.filename || 'attachment';
|
|
||||||
return `/api/files/proxy-download?fileName=${encodeURIComponent(name)}&bucket=client-emails`;
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -196,7 +196,7 @@
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="12">
|
<v-col cols="12">
|
||||||
<v-btn
|
<v-btn
|
||||||
@click="handleMobileSave"
|
@click="() => debouncedSaveInterest ? debouncedSaveInterest() : saveInterest()"
|
||||||
variant="flat"
|
variant="flat"
|
||||||
color="success"
|
color="success"
|
||||||
block
|
block
|
||||||
|
|
@ -407,8 +407,46 @@
|
||||||
prepend-inner-icon="mdi-tag"
|
prepend-inner-icon="mdi-tag"
|
||||||
></v-select>
|
></v-select>
|
||||||
</v-col>
|
</v-col>
|
||||||
<!-- Berth Recommendations field hidden per user request -->
|
<v-col cols="12" md="6">
|
||||||
<v-col cols="12" md="12">
|
<v-autocomplete
|
||||||
|
v-model="selectedBerthRecommendations"
|
||||||
|
:items="groupedBerths"
|
||||||
|
:item-title="(item) => item.isDivider ? '' : item['Mooring Number']"
|
||||||
|
:item-value="(item) => item.isDivider ? null : item.Id"
|
||||||
|
label="Berth Recommendations"
|
||||||
|
variant="outlined"
|
||||||
|
density="comfortable"
|
||||||
|
multiple
|
||||||
|
chips
|
||||||
|
closable-chips
|
||||||
|
:loading="loadingBerths"
|
||||||
|
prepend-inner-icon="mdi-star"
|
||||||
|
@update:model-value="updateBerthRecommendations"
|
||||||
|
>
|
||||||
|
<template v-slot:item="{ props, item }">
|
||||||
|
<v-divider v-if="item.raw.isDivider" class="mt-2 mb-2">
|
||||||
|
<template v-slot:default>
|
||||||
|
<div class="text-caption text-medium-emphasis px-2">
|
||||||
|
{{ item.raw.letter }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</v-divider>
|
||||||
|
<v-list-item
|
||||||
|
v-else
|
||||||
|
v-bind="props"
|
||||||
|
:title="item.raw['Mooring Number']"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template v-slot:chip="{ props, item }">
|
||||||
|
<v-chip
|
||||||
|
v-bind="props"
|
||||||
|
:text="item.raw['Mooring Number']"
|
||||||
|
size="small"
|
||||||
|
></v-chip>
|
||||||
|
</template>
|
||||||
|
</v-autocomplete>
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="12" md="6">
|
||||||
<v-autocomplete
|
<v-autocomplete
|
||||||
v-model="selectedBerths"
|
v-model="selectedBerths"
|
||||||
:items="groupedBerths"
|
:items="groupedBerths"
|
||||||
|
|
@ -1056,18 +1094,9 @@ const updateBerths = async (newBerths: number[]) => {
|
||||||
|
|
||||||
// Update original values
|
// Update original values
|
||||||
originalBerths.value = [...newBerths];
|
originalBerths.value = [...newBerths];
|
||||||
|
|
||||||
// Show success message
|
|
||||||
if (toAdd.length > 0 || toRemove.length > 0) {
|
|
||||||
toast.success("Berths updated successfully");
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to update berths:", error);
|
console.error("Failed to update berths:", error);
|
||||||
// Show more specific error message on mobile
|
toast.error("Failed to update berths. Please try again.");
|
||||||
const errorMessage = mobile.value
|
|
||||||
? "Could not update berths. Please check your connection and try again."
|
|
||||||
: "Failed to update berths. Please try again.";
|
|
||||||
toast.error(errorMessage);
|
|
||||||
// Revert to original values on error
|
// Revert to original values on error
|
||||||
selectedBerths.value = [...originalBerths.value];
|
selectedBerths.value = [...originalBerths.value];
|
||||||
}
|
}
|
||||||
|
|
@ -1273,20 +1302,6 @@ const onInterestUpdated = async () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle mobile save - call the save function directly without debounce
|
|
||||||
const handleMobileSave = () => {
|
|
||||||
console.log('Mobile save button clicked');
|
|
||||||
// Cancel any pending debounced saves
|
|
||||||
if (debouncedSaveInterest) {
|
|
||||||
debouncedSaveInterest.cancel();
|
|
||||||
}
|
|
||||||
if (autoSave) {
|
|
||||||
autoSave.cancel();
|
|
||||||
}
|
|
||||||
// Call save directly
|
|
||||||
saveInterest();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Load berths when component mounts
|
// Load berths when component mounts
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
loadAvailableBerths();
|
loadAvailableBerths();
|
||||||
|
|
|
||||||
|
|
@ -125,7 +125,7 @@
|
||||||
:headers="headers"
|
:headers="headers"
|
||||||
:items="filteredInterests"
|
:items="filteredInterests"
|
||||||
:search="search"
|
:search="search"
|
||||||
:sort-by="[{ key: 'Id', order: 'desc' }]"
|
:sort-by="[{ key: 'Created At', order: 'desc' }, { key: 'Full Name', order: 'asc' }]"
|
||||||
must-sort
|
must-sort
|
||||||
hover
|
hover
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ interface EmailMessage {
|
||||||
timestamp: string;
|
timestamp: string;
|
||||||
direction: 'sent' | 'received';
|
direction: 'sent' | 'received';
|
||||||
threadId?: string;
|
threadId?: string;
|
||||||
attachments?: any[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default defineEventHandler(async (event) => {
|
export default defineEventHandler(async (event) => {
|
||||||
|
|
@ -305,15 +304,6 @@ async function fetchImapEmails(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract attachments
|
|
||||||
const attachments = parsed.attachments ? parsed.attachments.map((att: any) => ({
|
|
||||||
filename: att.filename || 'attachment',
|
|
||||||
name: att.filename || 'attachment',
|
|
||||||
size: att.size || 0,
|
|
||||||
type: att.contentType || 'application/octet-stream',
|
|
||||||
cid: att.cid || undefined
|
|
||||||
})) : [];
|
|
||||||
|
|
||||||
const email: EmailMessage = {
|
const email: EmailMessage = {
|
||||||
id: parsed.messageId || `${Date.now()}-${seqno}`,
|
id: parsed.messageId || `${Date.now()}-${seqno}`,
|
||||||
from: fromEmail,
|
from: fromEmail,
|
||||||
|
|
@ -322,8 +312,7 @@ async function fetchImapEmails(
|
||||||
body: parsed.text || '',
|
body: parsed.text || '',
|
||||||
html: parsed.html || undefined,
|
html: parsed.html || undefined,
|
||||||
timestamp: parsed.date?.toISOString() || new Date().toISOString(),
|
timestamp: parsed.date?.toISOString() || new Date().toISOString(),
|
||||||
direction: fromEmail.toLowerCase().includes(userEmail.toLowerCase()) ? 'sent' : 'received',
|
direction: fromEmail.toLowerCase().includes(userEmail.toLowerCase()) ? 'sent' : 'received'
|
||||||
attachments: attachments
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (parsed.headers.has('in-reply-to')) {
|
if (parsed.headers.has('in-reply-to')) {
|
||||||
|
|
|
||||||
|
|
@ -29,9 +29,6 @@ export default defineEventHandler(async (event) => {
|
||||||
throw createError({ statusCode: 401, statusMessage: "unauthenticated" });
|
throw createError({ statusCode: 401, statusMessage: "unauthenticated" });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set longer timeout for this endpoint to prevent 502 errors
|
|
||||||
event.node.res.setTimeout(60000); // 60 seconds
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const body = await readBody(event);
|
const body = await readBody(event);
|
||||||
const { interestId } = body;
|
const { interestId } = body;
|
||||||
|
|
@ -46,83 +43,19 @@ export default defineEventHandler(async (event) => {
|
||||||
throw createError({ statusCode: 404, statusMessage: "Interest not found" });
|
throw createError({ statusCode: 404, statusMessage: "Interest not found" });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Documenso API configuration (declare early for use in regeneration)
|
|
||||||
const documensoApiKey = process.env.NUXT_DOCUMENSO_API_KEY;
|
|
||||||
const documensoBaseUrl = process.env.NUXT_DOCUMENSO_BASE_URL;
|
|
||||||
|
|
||||||
// Check if EOI already exists (has signature links)
|
// Check if EOI already exists (has signature links)
|
||||||
const hasExistingEOI = !!(interest['Signature Link Client'] && interest['Signature Link CC'] && interest['Signature Link Developer']);
|
if (interest['Signature Link Client'] && interest['Signature Link CC'] && interest['Signature Link Developer']) {
|
||||||
|
console.log('EOI already exists, returning existing links');
|
||||||
if (hasExistingEOI) {
|
return {
|
||||||
console.log('EOI already exists, checking if regeneration is needed');
|
success: true,
|
||||||
|
documentId: 'existing',
|
||||||
// For regeneration, we need to delete the old document first
|
clientSigningUrl: interest['Signature Link Client'],
|
||||||
const regenerateRequested = body.regenerate === true;
|
signingLinks: {
|
||||||
|
'Client': interest['Signature Link Client'],
|
||||||
if (!regenerateRequested) {
|
'CC': interest['Signature Link CC'],
|
||||||
console.log('Returning existing EOI links');
|
'Developer': interest['Signature Link Developer']
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
documentId: 'existing',
|
|
||||||
clientSigningUrl: interest['Signature Link Client'],
|
|
||||||
signingLinks: {
|
|
||||||
'Client': interest['Signature Link Client'],
|
|
||||||
'CC': interest['Signature Link CC'],
|
|
||||||
'Developer': interest['Signature Link Developer']
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
console.log('Regeneration requested, deleting old document first');
|
|
||||||
|
|
||||||
// Try to delete the old document from Documenso
|
|
||||||
try {
|
|
||||||
const externalId = `loi-${interestId}`;
|
|
||||||
|
|
||||||
// Import the delete utility functions
|
|
||||||
const { getDocumesoDocumentByExternalId, checkDocumentSignatureStatus } = await import('~/server/utils/documeso');
|
|
||||||
|
|
||||||
const document = await getDocumesoDocumentByExternalId(externalId);
|
|
||||||
if (document) {
|
|
||||||
// Check if all parties have signed
|
|
||||||
const signatureStatus = await checkDocumentSignatureStatus(document.id);
|
|
||||||
|
|
||||||
if (signatureStatus.allSigned) {
|
|
||||||
throw createError({
|
|
||||||
statusCode: 403,
|
|
||||||
statusMessage: 'Cannot regenerate: All parties have already signed this document',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Deleting old document from Documenso:', document.id);
|
|
||||||
|
|
||||||
const deleteResponse = await fetch(`${documensoBaseUrl}/api/v1/documents/${document.id}`, {
|
|
||||||
method: 'DELETE',
|
|
||||||
headers: {
|
|
||||||
'Authorization': `Bearer ${documensoApiKey}`,
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!deleteResponse.ok) {
|
|
||||||
console.warn('Failed to delete old document from Documenso, continuing with new generation');
|
|
||||||
} else {
|
|
||||||
console.log('Successfully deleted old document from Documenso');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error: any) {
|
|
||||||
console.warn('Error during old document cleanup:', error.message);
|
|
||||||
// Continue with new document generation even if cleanup fails
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
// Reset signature links so new ones will be generated
|
|
||||||
await updateInterest(interestId, {
|
|
||||||
'Signature Link Client': undefined,
|
|
||||||
'Signature Link CC': undefined,
|
|
||||||
'Signature Link Developer': undefined
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('Old document cleanup completed, proceeding with new generation');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate required fields
|
// Validate required fields
|
||||||
|
|
@ -172,6 +105,8 @@ export default defineEventHandler(async (event) => {
|
||||||
const berthNumbers = berths.map(b => b['Mooring Number']).join(', ');
|
const berthNumbers = berths.map(b => b['Mooring Number']).join(', ');
|
||||||
|
|
||||||
// Documenso API configuration
|
// Documenso API configuration
|
||||||
|
const documensoApiKey = process.env.NUXT_DOCUMENSO_API_KEY;
|
||||||
|
const documensoBaseUrl = process.env.NUXT_DOCUMENSO_BASE_URL;
|
||||||
const templateId = '9';
|
const templateId = '9';
|
||||||
|
|
||||||
if (!documensoApiKey || !documensoBaseUrl) {
|
if (!documensoApiKey || !documensoBaseUrl) {
|
||||||
|
|
|
||||||
|
|
@ -181,8 +181,7 @@ export default defineEventHandler(async (event) => {
|
||||||
html: htmlBody,
|
html: htmlBody,
|
||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
direction: 'sent',
|
direction: 'sent',
|
||||||
interestId: interestId,
|
interestId: interestId
|
||||||
attachments: attachments // Include attachment info
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const objectName = `interest-${interestId}/${Date.now()}-sent.json`;
|
const objectName = `interest-${interestId}/${Date.now()}-sent.json`;
|
||||||
|
|
|
||||||
|
|
@ -1,148 +0,0 @@
|
||||||
import { getInterestById, updateInterest } from '~/server/utils/nocodb';
|
|
||||||
import { getDocumesoDocumentByExternalId, checkDocumentSignatureStatus } from '~/server/utils/documeso';
|
|
||||||
|
|
||||||
export default defineEventHandler(async (event) => {
|
|
||||||
const xTagHeader = getRequestHeader(event, "x-tag");
|
|
||||||
|
|
||||||
console.log('[EOI Delete Generated] Request received with x-tag:', xTagHeader);
|
|
||||||
|
|
||||||
if (!xTagHeader || (xTagHeader !== "094ut234" && xTagHeader !== "pjnvü1230")) {
|
|
||||||
console.error('[EOI Delete Generated] Authentication failed - invalid x-tag');
|
|
||||||
throw createError({ statusCode: 401, statusMessage: "unauthenticated" });
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const body = await readBody(event);
|
|
||||||
const { interestId } = body;
|
|
||||||
|
|
||||||
console.log('[EOI Delete Generated] Interest ID:', interestId);
|
|
||||||
|
|
||||||
if (!interestId) {
|
|
||||||
console.error('[EOI Delete Generated] No interest ID provided');
|
|
||||||
throw createError({
|
|
||||||
statusCode: 400,
|
|
||||||
statusMessage: 'Interest ID is required',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get current interest data
|
|
||||||
const interest = await getInterestById(interestId);
|
|
||||||
if (!interest) {
|
|
||||||
throw createError({
|
|
||||||
statusCode: 404,
|
|
||||||
statusMessage: 'Interest not found',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if there are signature links (indicating a generated document)
|
|
||||||
const hasSignatureLinks = !!(interest['Signature Link Client'] ||
|
|
||||||
interest['Signature Link CC'] ||
|
|
||||||
interest['Signature Link Developer']);
|
|
||||||
|
|
||||||
if (!hasSignatureLinks) {
|
|
||||||
throw createError({
|
|
||||||
statusCode: 400,
|
|
||||||
statusMessage: 'No generated EOI document found for this interest',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check signature status to prevent deletion of fully signed documents
|
|
||||||
const externalId = `loi-${interestId}`;
|
|
||||||
let documentId: number | null = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const document = await getDocumesoDocumentByExternalId(externalId);
|
|
||||||
if (document) {
|
|
||||||
documentId = document.id;
|
|
||||||
|
|
||||||
// Check if all parties have signed
|
|
||||||
const signatureStatus = await checkDocumentSignatureStatus(documentId);
|
|
||||||
|
|
||||||
if (signatureStatus.allSigned) {
|
|
||||||
throw createError({
|
|
||||||
statusCode: 403,
|
|
||||||
statusMessage: 'Cannot delete: All parties have already signed this document',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('[EOI Delete Generated] Document found in Documenso:', documentId);
|
|
||||||
console.log('[EOI Delete Generated] Signature status:', {
|
|
||||||
allSigned: signatureStatus.allSigned,
|
|
||||||
clientSigned: signatureStatus.clientSigned,
|
|
||||||
signedCount: signatureStatus.signedRecipients.length,
|
|
||||||
unsignedCount: signatureStatus.unsignedRecipients.length
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error: any) {
|
|
||||||
console.warn('[EOI Delete Generated] Could not find or check Documenso document:', error.message);
|
|
||||||
// Continue with deletion even if Documenso document not found
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete document from Documenso if it exists
|
|
||||||
if (documentId) {
|
|
||||||
try {
|
|
||||||
const documensoApiKey = process.env.NUXT_DOCUMENSO_API_KEY;
|
|
||||||
const documensoBaseUrl = process.env.NUXT_DOCUMENSO_BASE_URL;
|
|
||||||
|
|
||||||
if (!documensoApiKey || !documensoBaseUrl) {
|
|
||||||
console.error('[EOI Delete Generated] Documenso configuration missing');
|
|
||||||
throw createError({
|
|
||||||
statusCode: 500,
|
|
||||||
statusMessage: 'Documenso configuration missing',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('[EOI Delete Generated] Deleting document from Documenso:', documentId);
|
|
||||||
|
|
||||||
const deleteResponse = await fetch(`${documensoBaseUrl}/api/v1/documents/${documentId}`, {
|
|
||||||
method: 'DELETE',
|
|
||||||
headers: {
|
|
||||||
'Authorization': `Bearer ${documensoApiKey}`,
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!deleteResponse.ok) {
|
|
||||||
const errorText = await deleteResponse.text();
|
|
||||||
console.error('[EOI Delete Generated] Failed to delete from Documenso:', errorText);
|
|
||||||
throw new Error(`Failed to delete document from Documenso: ${deleteResponse.statusText}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('[EOI Delete Generated] Successfully deleted document from Documenso');
|
|
||||||
} catch (error: any) {
|
|
||||||
console.error('[EOI Delete Generated] Error deleting from Documenso:', error);
|
|
||||||
// Don't throw here - continue with database cleanup even if Documenso deletion fails
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset interest fields
|
|
||||||
const updateData = {
|
|
||||||
'EOI Status': 'Awaiting Further Details' as const,
|
|
||||||
'Sales Process Level': 'Specific Qualified Interest' as const,
|
|
||||||
'EOI Time Sent': undefined,
|
|
||||||
'Signature Link Client': undefined,
|
|
||||||
'Signature Link CC': undefined,
|
|
||||||
'Signature Link Developer': undefined,
|
|
||||||
'Documeso ID': undefined,
|
|
||||||
'reminder_enabled': false
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log('[EOI Delete Generated] Resetting interest fields');
|
|
||||||
|
|
||||||
// Update the interest
|
|
||||||
await updateInterest(interestId, updateData);
|
|
||||||
|
|
||||||
console.log('[EOI Delete Generated] Delete completed successfully');
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
message: 'Generated EOI document deleted successfully',
|
|
||||||
};
|
|
||||||
} catch (error: any) {
|
|
||||||
console.error('[EOI Delete Generated] Failed to delete generated EOI document:', error);
|
|
||||||
console.error('[EOI Delete Generated] Error stack:', error.stack);
|
|
||||||
throw createError({
|
|
||||||
statusCode: error.statusCode || 500,
|
|
||||||
statusMessage: error.statusMessage || error.message || 'Failed to delete generated EOI document',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
@ -196,7 +196,6 @@ export const createInterest = async (data: Partial<Interest>) => {
|
||||||
"Date Added",
|
"Date Added",
|
||||||
"Width",
|
"Width",
|
||||||
"Depth",
|
"Depth",
|
||||||
"Created At",
|
|
||||||
"Source",
|
"Source",
|
||||||
"Contact Method Preferred",
|
"Contact Method Preferred",
|
||||||
"Lead Category",
|
"Lead Category",
|
||||||
|
|
@ -214,11 +213,6 @@ export const createInterest = async (data: Partial<Interest>) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set Created At to current timestamp if not provided
|
|
||||||
if (!cleanData["Created At"]) {
|
|
||||||
cleanData["Created At"] = new Date().toISOString();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove any computed or relation fields that shouldn't be sent
|
// Remove any computed or relation fields that shouldn't be sent
|
||||||
delete cleanData.Id;
|
delete cleanData.Id;
|
||||||
delete cleanData.Berths;
|
delete cleanData.Berths;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue