feature/IO-2433-esignature - Code review fixes
This commit is contained in:
@@ -8,6 +8,7 @@ import { createStructuredSelector } from "reselect";
|
||||
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
||||
import { setModalContext } from "../../redux/modals/modals.actions";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { hasDocumensoApiKey } from "../../utils/esignature.js";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop
|
||||
@@ -28,6 +29,10 @@ export function EsignatureCustomDocument({ bodyshop, jobId, setEsignatureContext
|
||||
const notification = useNotification();
|
||||
const { t } = useTranslation();
|
||||
|
||||
if (!hasDocumensoApiKey(bodyshop)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const uploadCustomDocument = async ({ file, onError, onSuccess }) => {
|
||||
const formData = new FormData();
|
||||
formData.append("document", file);
|
||||
|
||||
@@ -9,6 +9,7 @@ import { selectEsignature } from "../../redux/modals/modals.selectors";
|
||||
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors";
|
||||
import { useState } from "react";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
import { hasDocumensoApiKey } from "../../utils/esignature.js";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
esignatureModal: selectEsignature,
|
||||
@@ -25,6 +26,11 @@ export function EsignatureModalContainer({ esignatureModal, toggleModalVisible,
|
||||
const { open, context } = esignatureModal;
|
||||
const { token, envelopeId, documentId, jobid } = context;
|
||||
const [distributing, setDistributing] = useState(false);
|
||||
|
||||
if (!hasDocumensoApiKey(bodyshop)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
open={open}
|
||||
|
||||
@@ -14,6 +14,7 @@ import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
||||
import UpsellComponent, { upsellEnum } from "../upsell/upsell.component";
|
||||
import axios from "axios";
|
||||
import { useNotification } from "../../contexts/Notifications/notificationContext";
|
||||
import { hasDocumensoApiKey } from "../../utils/esignature.js";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop
|
||||
@@ -26,6 +27,7 @@ export default connect(mapStateToProps, mapDispatchToProps)(JobAuditTrail);
|
||||
export function JobAuditTrail({ bodyshop, jobId }) {
|
||||
const { t } = useTranslation();
|
||||
const notification = useNotification();
|
||||
const esignatureEnabled = hasDocumensoApiKey(bodyshop);
|
||||
const { loading, data, refetch } = useQuery(QUERY_AUDIT_TRAIL, {
|
||||
variables: { jobid: jobId },
|
||||
skip: !jobId,
|
||||
@@ -326,18 +328,20 @@ export function JobAuditTrail({ bodyshop, jobId }) {
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
<Card title={t("jobs.labels.esignatures")}>
|
||||
<ResponsiveTable
|
||||
loading={loading}
|
||||
columns={esigColumns}
|
||||
mobileColumnKeys={["title", "status"]}
|
||||
rowKey="id"
|
||||
scroll={{ x: true }}
|
||||
dataSource={data ? data.esignature_documents : []}
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
{esignatureEnabled && (
|
||||
<Col span={24}>
|
||||
<Card title={t("jobs.labels.esignatures")}>
|
||||
<ResponsiveTable
|
||||
loading={loading}
|
||||
columns={esigColumns}
|
||||
mobileColumnKeys={["title", "status"]}
|
||||
rowKey="id"
|
||||
scroll={{ x: true }}
|
||||
dataSource={data ? data.esignature_documents : []}
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
)}
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { notificationScenarios } from "../../utils/jobNotificationScenarios.js";
|
||||
import { Checkbox, Form } from "antd";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import PropTypes from "prop-types";
|
||||
@@ -9,18 +8,18 @@ import PropTypes from "prop-types";
|
||||
* @param form
|
||||
* @param disabled
|
||||
* @param onHeaderChange
|
||||
* @param scenarioKeys
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const ColumnHeaderCheckbox = ({ channel, form, disabled = false, onHeaderChange }) => {
|
||||
const ColumnHeaderCheckbox = ({ channel, form, disabled = false, onHeaderChange, scenarioKeys }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
// Subscribe to all form values so that this component re-renders on changes.
|
||||
const formValues = Form.useWatch([], form) || {};
|
||||
|
||||
// Determine if all scenarios for this channel are checked.
|
||||
const allChecked =
|
||||
notificationScenarios.length > 0 && notificationScenarios.every((scenario) => formValues[scenario]?.[channel]);
|
||||
const allChecked = scenarioKeys.length > 0 && scenarioKeys.every((scenario) => formValues[scenario]?.[channel]);
|
||||
|
||||
const onChange = (e) => {
|
||||
const checked = e.target.checked;
|
||||
@@ -28,7 +27,7 @@ const ColumnHeaderCheckbox = ({ channel, form, disabled = false, onHeaderChange
|
||||
const currentValues = form.getFieldsValue();
|
||||
// Update each scenario for this channel.
|
||||
const newValues = { ...currentValues };
|
||||
notificationScenarios.forEach((scenario) => {
|
||||
scenarioKeys.forEach((scenario) => {
|
||||
newValues[scenario] = { ...newValues[scenario], [channel]: checked };
|
||||
});
|
||||
// Update form values.
|
||||
@@ -50,7 +49,8 @@ ColumnHeaderCheckbox.propTypes = {
|
||||
channel: PropTypes.oneOf(["app", "email", "fcm"]).isRequired,
|
||||
form: PropTypes.object.isRequired,
|
||||
disabled: PropTypes.bool,
|
||||
onHeaderChange: PropTypes.func
|
||||
onHeaderChange: PropTypes.func,
|
||||
scenarioKeys: PropTypes.arrayOf(PropTypes.string).isRequired
|
||||
};
|
||||
|
||||
export default ColumnHeaderCheckbox;
|
||||
|
||||
@@ -12,12 +12,13 @@ import {
|
||||
UPDATE_NOTIFICATION_SETTINGS,
|
||||
UPDATE_NOTIFICATIONS_AUTOADD
|
||||
} from "../../graphql/user.queries.js";
|
||||
import { notificationScenarios, notificationScenarioDefaults } from "../../utils/jobNotificationScenarios.js";
|
||||
import { getNotificationScenarios, notificationScenarioDefaults } from "../../utils/jobNotificationScenarios.js";
|
||||
import LoadingSpinner from "../loading-spinner/loading-spinner.component.jsx";
|
||||
import PropTypes from "prop-types";
|
||||
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
||||
import ColumnHeaderCheckbox from "../notification-settings/column-header-checkbox.component.jsx";
|
||||
import { useIsEmployee } from "../../utils/useIsEmployee.js";
|
||||
import { hasDocumensoApiKey } from "../../utils/esignature.js";
|
||||
|
||||
/**
|
||||
* Notifications Settings Form
|
||||
@@ -35,6 +36,7 @@ const NotificationSettingsForm = ({ currentUser, bodyshop }) => {
|
||||
const [initialAutoAdd, setInitialAutoAdd] = useState(false);
|
||||
const notification = useNotification();
|
||||
const isEmployee = useIsEmployee(bodyshop, currentUser);
|
||||
const notificationScenarios = getNotificationScenarios({ includeEsign: hasDocumensoApiKey(bodyshop) });
|
||||
|
||||
// Fetch notification settings and notifications_autoadd
|
||||
const { loading, error, data } = useQuery(QUERY_NOTIFICATION_SETTINGS, {
|
||||
@@ -66,7 +68,7 @@ const NotificationSettingsForm = ({ currentUser, bodyshop }) => {
|
||||
setInitialAutoAdd(autoAdd);
|
||||
setIsDirty(false); // Reset dirty state when new data loads
|
||||
}
|
||||
}, [data, form]);
|
||||
}, [data, form, notificationScenarios]);
|
||||
|
||||
// Handle toggle of notifications_autoadd
|
||||
const handleAutoAddToggle = async (checked) => {
|
||||
@@ -137,7 +139,14 @@ const NotificationSettingsForm = ({ currentUser, bodyshop }) => {
|
||||
width: "80%"
|
||||
},
|
||||
{
|
||||
title: <ColumnHeaderCheckbox channel="app" form={form} onHeaderChange={() => setIsDirty(true)} />,
|
||||
title: (
|
||||
<ColumnHeaderCheckbox
|
||||
channel="app"
|
||||
form={form}
|
||||
onHeaderChange={() => setIsDirty(true)}
|
||||
scenarioKeys={notificationScenarios}
|
||||
/>
|
||||
),
|
||||
dataIndex: "app",
|
||||
key: "app",
|
||||
align: "center",
|
||||
@@ -148,7 +157,14 @@ const NotificationSettingsForm = ({ currentUser, bodyshop }) => {
|
||||
)
|
||||
},
|
||||
{
|
||||
title: <ColumnHeaderCheckbox channel="email" form={form} onHeaderChange={() => setIsDirty(true)} />,
|
||||
title: (
|
||||
<ColumnHeaderCheckbox
|
||||
channel="email"
|
||||
form={form}
|
||||
onHeaderChange={() => setIsDirty(true)}
|
||||
scenarioKeys={notificationScenarios}
|
||||
/>
|
||||
),
|
||||
dataIndex: "email",
|
||||
key: "email",
|
||||
align: "center",
|
||||
@@ -163,7 +179,14 @@ const NotificationSettingsForm = ({ currentUser, bodyshop }) => {
|
||||
// Currently disabled for prod
|
||||
if (!import.meta.env.PROD) {
|
||||
columns.push({
|
||||
title: <ColumnHeaderCheckbox channel="fcm" form={form} onHeaderChange={() => setIsDirty(true)} />,
|
||||
title: (
|
||||
<ColumnHeaderCheckbox
|
||||
channel="fcm"
|
||||
form={form}
|
||||
onHeaderChange={() => setIsDirty(true)}
|
||||
scenarioKeys={notificationScenarios}
|
||||
/>
|
||||
),
|
||||
dataIndex: "fcm",
|
||||
key: "fcm",
|
||||
align: "center",
|
||||
|
||||
@@ -12,6 +12,7 @@ import { HasFeatureAccess } from "./../feature-wrapper/feature-wrapper.component
|
||||
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
||||
import axios from "axios";
|
||||
import { setModalContext } from "../../redux/modals/modals.actions.js";
|
||||
import { hasDocumensoApiKey } from "../../utils/esignature.js";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
printCenterModal: selectPrintCenter,
|
||||
@@ -41,6 +42,7 @@ export function PrintCenterItemComponent({
|
||||
const [loading, setLoading] = useState(false);
|
||||
const { context } = printCenterModal;
|
||||
const notification = useNotification();
|
||||
const esignatureEnabled = hasDocumensoApiKey(bodyshop);
|
||||
|
||||
const renderToNewWindow = async () => {
|
||||
setLoading(true);
|
||||
@@ -96,7 +98,7 @@ export function PrintCenterItemComponent({
|
||||
<li>
|
||||
<Space wrap>
|
||||
{item.title}
|
||||
<SignatureFilled onClick={esignatureGenerate} />
|
||||
{esignatureEnabled && <SignatureFilled onClick={esignatureGenerate} />}
|
||||
<PrinterOutlined onClick={renderToNewWindow} />
|
||||
{!technician ? (
|
||||
<MailOutlined
|
||||
|
||||
@@ -15,6 +15,7 @@ import PrintCenterJobsLabels from "../print-center-jobs-labels/print-center-jobs
|
||||
import PrintCenterSpeedPrint from "../print-center-speed-print/print-center-speed-print.component";
|
||||
import { bodyshopHasDmsKey, DMS_MAP, getDmsMode } from "../../utils/dmsUtils";
|
||||
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
||||
import { hasDocumensoApiKey } from "../../utils/esignature.js";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
printCenterModal: selectPrintCenter,
|
||||
@@ -39,6 +40,7 @@ export function PrintCenterJobsComponent({ printCenterModal, bodyshop, technicia
|
||||
const hasDMSKey = bodyshopHasDmsKey(bodyshop);
|
||||
const dmsMode = getDmsMode(bodyshop, "off");
|
||||
const isReynoldsMode = dmsMode === DMS_MAP.reynolds;
|
||||
const esignatureEnabled = hasDocumensoApiKey(bodyshop);
|
||||
|
||||
const Templates = !hasDMSKey
|
||||
? Object.keys(tempList)
|
||||
@@ -98,7 +100,7 @@ export function PrintCenterJobsComponent({ printCenterModal, bodyshop, technicia
|
||||
extra={
|
||||
<Space wrap>
|
||||
<PrintCenterJobsLabels jobId={jobId} />
|
||||
<EsignatureCustomDocument jobId={jobId} />
|
||||
{esignatureEnabled && <EsignatureCustomDocument jobId={jobId} />}
|
||||
<Jobd3RdPartyModal jobId={jobId} job={job} />
|
||||
<Input.Search onChange={(e) => setSearch(e.target.value)} value={search} enterButton />
|
||||
</Space>
|
||||
|
||||
@@ -53,6 +53,7 @@ export const QUERY_BODYSHOP = gql`
|
||||
phone
|
||||
federal_tax_id
|
||||
id
|
||||
documenso_api_key
|
||||
insurance_vendor_id
|
||||
logo_img_path
|
||||
md_ro_statuses
|
||||
|
||||
@@ -57,6 +57,7 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||
import { DateTimeFormat } from "../../utils/DateFormatter";
|
||||
import dayjs from "../../utils/day";
|
||||
import { hasDocumensoApiKey } from "../../utils/esignature.js";
|
||||
import UndefinedToNull from "../../utils/undefinedtonull";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
@@ -105,6 +106,7 @@ export function JobsDetailPage({
|
||||
});
|
||||
const notification = useNotification();
|
||||
const { scenarioNotificationsOn } = useSocket();
|
||||
const esignatureEnabled = hasDocumensoApiKey(bodyshop);
|
||||
|
||||
useEffect(() => {
|
||||
//form.setFieldsValue(transormJobToForm(job));
|
||||
@@ -286,7 +288,7 @@ export function JobsDetailPage({
|
||||
>
|
||||
{t("general.labels.refresh")}
|
||||
</Button>
|
||||
<EsignatureCustomDocument jobId={job.id} />
|
||||
{esignatureEnabled && <EsignatureCustomDocument jobId={job.id} />}
|
||||
<JobsChangeStatus job={job} />
|
||||
<JobSyncButton job={job} />
|
||||
<Button
|
||||
|
||||
@@ -31,6 +31,7 @@ import useAlertsNotifications from "../../hooks/useAlertsNotifications.jsx";
|
||||
import { selectDarkMode } from "../../redux/application/application.selectors.js";
|
||||
import { lazyDev } from "../../utils/lazyWithPreload.jsx";
|
||||
import EsignatureModalContainer from "../../components/esignature-modal/esignature-modal.container.jsx";
|
||||
import { hasDocumensoApiKey } from "../../utils/esignature.js";
|
||||
|
||||
const PrintCenterModalContainer = lazyDev(
|
||||
() => import("../../components/print-center-modal/print-center-modal.container")
|
||||
@@ -128,6 +129,7 @@ const mapStateToProps = createStructuredSelector({
|
||||
|
||||
export function Manage({ conflict, bodyshop, partsManagementOnly, isDarkMode, currentUser }) {
|
||||
const { t } = useTranslation();
|
||||
const esignatureEnabled = hasDocumensoApiKey(bodyshop);
|
||||
const [chatVisible] = useState(false);
|
||||
const didMount = useRef(false);
|
||||
|
||||
@@ -183,7 +185,7 @@ export function Manage({ conflict, bodyshop, partsManagementOnly, isDarkMode, cu
|
||||
<TaskUpsertModalContainer />
|
||||
<BreadCrumbs />
|
||||
<BillEnterModalContainer />
|
||||
<EsignatureModalContainer />
|
||||
{esignatureEnabled && <EsignatureModalContainer />}
|
||||
<JobCostingModal />
|
||||
<ReportCenterModal />
|
||||
<EmailOverlayContainer />
|
||||
|
||||
7
client/src/utils/esignature.js
Normal file
7
client/src/utils/esignature.js
Normal file
@@ -0,0 +1,7 @@
|
||||
export const hasDocumensoApiKey = (bodyshop) => {
|
||||
if (typeof bodyshop?.documenso_api_key === "string") {
|
||||
return bodyshop.documenso_api_key.trim().length > 0;
|
||||
}
|
||||
|
||||
return Boolean(bodyshop?.documenso_api_key);
|
||||
};
|
||||
@@ -2,7 +2,7 @@
|
||||
* @description This file contains the scenarios for job notifications.
|
||||
* @type {string[]}
|
||||
*/
|
||||
const notificationScenarios = [
|
||||
const baseNotificationScenarios = [
|
||||
"job-assigned-to-me",
|
||||
"bill-posted",
|
||||
"critical-parts-status-changed",
|
||||
@@ -16,13 +16,21 @@ const notificationScenarios = [
|
||||
"job-added-to-production",
|
||||
"job-status-change",
|
||||
"payment-collected-completed",
|
||||
"alternate-transport-changed",
|
||||
"alternate-transport-changed"
|
||||
// "supplement-imported", // Disabled for now
|
||||
];
|
||||
|
||||
const esignNotificationScenarios = [
|
||||
"esign-document-opened",
|
||||
"esign-document-completed",
|
||||
"esign-document-upload-failed"
|
||||
// "supplement-imported", // Disabled for now
|
||||
];
|
||||
|
||||
const notificationScenarios = [...baseNotificationScenarios, ...esignNotificationScenarios];
|
||||
|
||||
const getNotificationScenarios = ({ includeEsign = true } = {}) =>
|
||||
includeEsign ? notificationScenarios : baseNotificationScenarios;
|
||||
|
||||
/**
|
||||
* Default channel preferences for e-sign document notifications. By default, all e-sign related notifications will be
|
||||
* sent via the app, but not via email or FCM. These defaults can be overridden by user preferences.
|
||||
@@ -34,4 +42,4 @@ const notificationScenarioDefaults = {
|
||||
"esign-document-upload-failed": { app: true, email: false, fcm: false }
|
||||
};
|
||||
|
||||
export { notificationScenarios, notificationScenarioDefaults };
|
||||
export { esignNotificationScenarios, getNotificationScenarios, notificationScenarios, notificationScenarioDefaults };
|
||||
|
||||
@@ -36,6 +36,41 @@ function getDefaultEsignData({ esigData, bodyshop, fileName }) {
|
||||
};
|
||||
}
|
||||
|
||||
function createClientError(message, statusCode = 400) {
|
||||
const error = new Error(message);
|
||||
error.statusCode = statusCode;
|
||||
return error;
|
||||
}
|
||||
|
||||
function isValidEmail(email) {
|
||||
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
|
||||
}
|
||||
|
||||
function getJobOwnerName(jobData, email) {
|
||||
const ownerName = [jobData?.ownr_fn, jobData?.ownr_ln].filter(Boolean).join(" ").trim();
|
||||
return ownerName || jobData?.ownr_co_nm || email;
|
||||
}
|
||||
|
||||
function getJobOwnerRecipients(jobData) {
|
||||
const ownerEmail = jobData?.ownr_ea?.trim();
|
||||
|
||||
if (!ownerEmail) {
|
||||
throw createClientError("Job owner email is required before sending an e-signature request.");
|
||||
}
|
||||
|
||||
if (!isValidEmail(ownerEmail)) {
|
||||
throw createClientError(`Job owner email "${ownerEmail}" is not valid.`);
|
||||
}
|
||||
|
||||
return [
|
||||
{
|
||||
email: ownerEmail,
|
||||
name: getJobOwnerName(jobData, ownerEmail),
|
||||
role: "SIGNER"
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
async function getDocumensoClient({ bodyshopid, req }) {
|
||||
const client = req.userGraphQLClient;
|
||||
const { bodyshops_by_pk: { documenso_api_key } } = await client.request(QUERY_DOCUMENSO_KEY, { bodyshopid });
|
||||
@@ -52,11 +87,7 @@ async function createEsignDocumentFromPdf({ req, bodyshop, pdfBuffer, esigData,
|
||||
const client = req.userGraphQLClient;
|
||||
|
||||
const { jobs_by_pk: jobData } = await client.request(QUERY_JOB_FOR_SIGNATURE, { jobid });
|
||||
const recipients = [{
|
||||
email: "patrick@imexsystems.ca",
|
||||
name: `${jobData.ownr_fn} ${jobData.ownr_ln}`,
|
||||
role: "SIGNER",
|
||||
}];
|
||||
const recipients = getJobOwnerRecipients(jobData);
|
||||
|
||||
const documenso = await getDocumensoClient({ bodyshopid: bodyshop.id, req })
|
||||
|
||||
@@ -267,7 +298,7 @@ async function newEsignDocument(req, res) {
|
||||
message: error.message, stack: error.stack,
|
||||
body: _.omit(req.body, ["bodyshop"]) // bodyshop can be large, so we omit it from the logs
|
||||
});
|
||||
res.status(500).json({ error: "An error occurred while creating the e-sign document.", message: error.message });
|
||||
res.status(error.statusCode || 500).json({ error: "An error occurred while creating the e-sign document.", message: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,7 +333,7 @@ async function newCustomEsignDocument(req, res) {
|
||||
message: error.message, stack: error.stack,
|
||||
body: _.omit(req.body, ["bodyshop"]) // bodyshop can be large, so we omit it from the logs
|
||||
});
|
||||
res.status(500).json({ error: "An error occurred while creating the custom e-sign document.", message: error.message });
|
||||
res.status(error.statusCode || 500).json({ error: "An error occurred while creating the custom e-sign document.", message: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -219,8 +219,13 @@ async function handleDocumentCompleted(payload) {
|
||||
}
|
||||
};
|
||||
const formData = new FormData();
|
||||
const fileName = document.filename?.toLowerCase().endsWith(".pdf")
|
||||
? document.filename
|
||||
: `${document.filename || `esignature-document-${payload.id}`}.pdf`;
|
||||
const pdfBlob = new Blob([buffer], { type: "application/pdf" });
|
||||
|
||||
formData.append("jobid", jobid);
|
||||
formData.append("file", buffer); //TODO: Validate this is the correct type.
|
||||
formData.append("file", pdfBlob, fileName);
|
||||
|
||||
try {
|
||||
const imexMediaServerResponse = await axios.post(
|
||||
@@ -232,12 +237,9 @@ async function handleDocumentCompleted(payload) {
|
||||
if (imexMediaServerResponse.status === 200) {
|
||||
//Succesful upload - we don't really need to do anything here.
|
||||
} else {
|
||||
logger.log(`esig-webhook-lms-upload-error`, "ERROR", "redis", "api", {
|
||||
message: imexMediaServerResponse.statusText,
|
||||
jobid,
|
||||
documentId: payload.id
|
||||
});
|
||||
notifyUploadFailure();
|
||||
throw new Error(
|
||||
`Local media server upload failed with status ${imexMediaServerResponse.status}: ${imexMediaServerResponse.statusText}`
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.log(`esig-webhook-lms-upload-error`, "ERROR", "redis", "api", {
|
||||
@@ -247,6 +249,7 @@ async function handleDocumentCompleted(payload) {
|
||||
documentId: payload.id
|
||||
});
|
||||
notifyUploadFailure();
|
||||
throw error;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
@@ -274,13 +277,9 @@ async function handleDocumentCompleted(payload) {
|
||||
}
|
||||
});
|
||||
} else {
|
||||
logger.log(`esig-webhook-s3-upload-error`, "ERROR", "redis", "api", {
|
||||
message: uploadResult.message,
|
||||
stack: uploadResult.stack,
|
||||
jobid: jobid,
|
||||
documentId: payload.id
|
||||
});
|
||||
notifyUploadFailure();
|
||||
const uploadError = new Error(uploadResult.message || "S3 upload failed");
|
||||
uploadError.stack = uploadResult.stack || uploadError.stack;
|
||||
throw uploadError;
|
||||
}
|
||||
} catch (error) {
|
||||
logger.log(`esig-webhook-s3-upload-error`, "ERROR", "redis", "api", {
|
||||
@@ -290,6 +289,7 @@ async function handleDocumentCompleted(payload) {
|
||||
documentId: payload.id
|
||||
});
|
||||
notifyUploadFailure();
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -328,6 +328,7 @@ async function handleDocumentCompleted(payload) {
|
||||
stack: error.stack,
|
||||
payload
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user