Merge remote-tracking branch 'origin/release/2025-09-12' into feature/IO-3255-simplified-part-management
This commit is contained in:
@@ -67,11 +67,14 @@ export const uploadToS3 = async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Key should be same as we provided to maintain backwards compatibility.
|
//Key should be same as we provided to maintain backwards compatibility.
|
||||||
const { presignedUrl: preSignedUploadUrlToS3, key: s3Key } = signedURLResponse.data.signedUrls[0];
|
const { presignedUrl: preSignedUploadUrlToS3, key: s3Key, contentType } = signedURLResponse.data.signedUrls[0];
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
onUploadProgress: (e) => {
|
onUploadProgress: (e) => {
|
||||||
if (onProgress) onProgress({ percent: (e.loaded / e.total) * 100 });
|
if (onProgress) onProgress({ percent: (e.loaded / e.total) * 100 });
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
...contentType ? { "Content-Type": fileType } : {}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -20,35 +20,27 @@ export function JobTotalsCashDiscount({ bodyshop, amountDinero }) {
|
|||||||
const notification = useNotification();
|
const notification = useNotification();
|
||||||
|
|
||||||
const fetchData = useCallback(async () => {
|
const fetchData = useCallback(async () => {
|
||||||
if (amountDinero && bodyshop) {
|
if (!amountDinero || !bodyshop) return;
|
||||||
setLoading(true);
|
|
||||||
let response;
|
|
||||||
try {
|
|
||||||
response = await axios.post("/intellipay/checkfee", {
|
|
||||||
bodyshop: { id: bodyshop.id, imexshopid: bodyshop.imexshopid, state: bodyshop.state },
|
|
||||||
amount: Dinero(amountDinero).toFormat("0.00")
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response?.data?.error) {
|
setLoading(true);
|
||||||
notification.open({
|
const errorMessage = "Error encountered when contacting IntelliPay service to determine cash discounted price.";
|
||||||
type: "error",
|
|
||||||
message:
|
try {
|
||||||
response.data?.error ||
|
const { id, imexshopid, state } = bodyshop;
|
||||||
"Error encountered when contacting IntelliPay service to determine cash discounted price."
|
const { data } = await axios.post("/intellipay/checkfee", {
|
||||||
});
|
bodyshop: { id, imexshopid, state },
|
||||||
} else {
|
amount: Dinero(amountDinero).toUnit()
|
||||||
setFee(response.data?.fee || 0);
|
});
|
||||||
}
|
|
||||||
} catch (error) {
|
if (data?.error) {
|
||||||
notification.open({
|
notification.open({ type: "error", message: data.error || errorMessage });
|
||||||
type: "error",
|
} else {
|
||||||
message:
|
setFee(data?.fee ?? 0);
|
||||||
error.response?.data?.error ||
|
|
||||||
"Error encountered when contacting IntelliPay service to determine cash discounted price."
|
|
||||||
});
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
}
|
||||||
|
} catch (error) {
|
||||||
|
notification.open({ type: "error", message: error.response?.data?.error || errorMessage });
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
}
|
}
|
||||||
}, [amountDinero, bodyshop, notification]);
|
}, [amountDinero, bodyshop, notification]);
|
||||||
|
|
||||||
|
|||||||
@@ -40,27 +40,26 @@ export function ScheduleCalendarWrapperComponent({
|
|||||||
const currentView = search.view || defaultView || "week";
|
const currentView = search.view || defaultView || "week";
|
||||||
|
|
||||||
const handleEventPropStyles = (event) => {
|
const handleEventPropStyles = (event) => {
|
||||||
const hasColor = Boolean(event?.color?.hex || event?.color);
|
const { color, block, arrived } = event ?? {};
|
||||||
|
const hasColor = Boolean(color?.hex || color);
|
||||||
const useBg = currentView !== "agenda";
|
const useBg = currentView !== "agenda";
|
||||||
|
|
||||||
// Prioritize explicit blocked-day background to ensure red in all themes
|
// Prioritize explicit blocked-day background to ensure red in all themes
|
||||||
let bg;
|
let bg;
|
||||||
if (useBg) {
|
if (useBg) {
|
||||||
if (event?.block) {
|
bg = block
|
||||||
bg = "var(--event-block-bg)";
|
? "var(--event-block-bg)"
|
||||||
} else if (hasColor) {
|
: arrived
|
||||||
bg = event?.color?.hex ?? event?.color;
|
? "var(--event-arrived-bg)"
|
||||||
} else {
|
: (color?.hex ?? color ?? "var(--event-bg-fallback)");
|
||||||
bg = "var(--event-bg-fallback)";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const usedFallback = !hasColor && !event?.block; // only mark as fallback when not blocked
|
const usedFallback = !hasColor && !block && !arrived; // only mark as fallback when not blocked or arrived
|
||||||
|
|
||||||
const classes = [
|
const classes = [
|
||||||
"imex-event",
|
"imex-event",
|
||||||
event.arrived && "imex-event-arrived",
|
arrived && "imex-event-arrived",
|
||||||
event.block && "imex-event-block",
|
block && "imex-event-block",
|
||||||
usedFallback && "imex-event-fallback"
|
usedFallback && "imex-event-fallback"
|
||||||
]
|
]
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
|
|||||||
@@ -23,13 +23,24 @@ export default function ShopInfoContainer() {
|
|||||||
});
|
});
|
||||||
const notification = useNotification();
|
const notification = useNotification();
|
||||||
|
|
||||||
const combinedFeatureConfig = {
|
const combineFeatureConfigs = (...configs) =>
|
||||||
...FEATURE_CONFIGS.general,
|
(configs || [])
|
||||||
...FEATURE_CONFIGS.responsibilitycenters
|
.filter(Boolean)
|
||||||
};
|
.flatMap((cfg) => Object.entries(cfg))
|
||||||
|
.reduce((acc, [featureName, fieldPaths]) => {
|
||||||
|
if (!Array.isArray(fieldPaths)) return acc;
|
||||||
|
acc[featureName] = [...(acc[featureName] ?? []), ...fieldPaths];
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
const combinedFeatureConfig = combineFeatureConfigs(FEATURE_CONFIGS.general, FEATURE_CONFIGS.responsibilitycenters);
|
||||||
|
|
||||||
// Use form data preservation for all shop-info features
|
// Use form data preservation for all shop-info features
|
||||||
const { createSubmissionHandler } = useFormDataPreservation(form, data?.bodyshops[0], combinedFeatureConfig);
|
const { createSubmissionHandler, preserveHiddenFormData } = useFormDataPreservation(
|
||||||
|
form,
|
||||||
|
data?.bodyshops[0],
|
||||||
|
combinedFeatureConfig
|
||||||
|
);
|
||||||
|
|
||||||
const handleFinish = createSubmissionHandler((values) => {
|
const handleFinish = createSubmissionHandler((values) => {
|
||||||
setSaveLoading(true);
|
setSaveLoading(true);
|
||||||
@@ -51,8 +62,11 @@ export default function ShopInfoContainer() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (data) form.resetFields();
|
if (!data) return;
|
||||||
}, [form, data]);
|
form.resetFields();
|
||||||
|
// After reset, re-apply hidden field preservation so values aren't wiped
|
||||||
|
preserveHiddenFormData();
|
||||||
|
}, [data, form, preserveHiddenFormData]);
|
||||||
|
|
||||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||||
if (loading) return <LoadingSpinner />;
|
if (loading) return <LoadingSpinner />;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useCallback, useEffect } from "react";
|
import { useCallback, useEffect, useMemo } from "react";
|
||||||
import { HasFeatureAccess } from "./../feature-wrapper/feature-wrapper.component";
|
import { HasFeatureAccess } from "./../feature-wrapper/feature-wrapper.component";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -8,73 +8,57 @@ import { HasFeatureAccess } from "./../feature-wrapper/feature-wrapper.component
|
|||||||
* @param {Object} featureConfig - Configuration object defining which features and their associated fields to preserve
|
* @param {Object} featureConfig - Configuration object defining which features and their associated fields to preserve
|
||||||
*/
|
*/
|
||||||
export const useFormDataPreservation = (form, bodyshop, featureConfig) => {
|
export const useFormDataPreservation = (form, bodyshop, featureConfig) => {
|
||||||
const getNestedValue = (obj, path) => {
|
// Safe nested getters/setters using path arrays
|
||||||
return path.reduce((current, key) => current?.[key], obj);
|
const getNestedValue = (obj, path) => path?.reduce((acc, key) => acc?.[key], obj);
|
||||||
};
|
|
||||||
|
|
||||||
const setNestedValue = (obj, path, value) => {
|
const setNestedValue = (obj, path, value) => {
|
||||||
const lastKey = path[path.length - 1];
|
const lastKey = path[path.length - 1];
|
||||||
const parentPath = path.slice(0, -1);
|
const parent = path.slice(0, -1).reduce((curr, key) => {
|
||||||
|
if (!curr[key] || typeof curr[key] !== "object") curr[key] = {};
|
||||||
const parent = parentPath.reduce((current, key) => {
|
return curr[key];
|
||||||
if (!current[key]) current[key] = {};
|
|
||||||
return current[key];
|
|
||||||
}, obj);
|
}, obj);
|
||||||
|
|
||||||
parent[lastKey] = value;
|
parent[lastKey] = value;
|
||||||
};
|
};
|
||||||
|
|
||||||
const preserveHiddenFormData = useCallback(() => {
|
// Paths for features that are NOT accessible
|
||||||
const preservationData = {};
|
const disabledPaths = useMemo(() => {
|
||||||
let hasDataToPreserve = false;
|
const result = [];
|
||||||
|
if (!featureConfig) return result;
|
||||||
Object.entries(featureConfig).forEach(([featureName, fieldPaths]) => {
|
Object.entries(featureConfig).forEach(([featureName, fieldPaths]) => {
|
||||||
const hasAccess = HasFeatureAccess({ featureName, bodyshop });
|
const hasAccess = HasFeatureAccess({ featureName, bodyshop });
|
||||||
|
if (hasAccess || !Array.isArray(fieldPaths)) return;
|
||||||
|
fieldPaths.forEach((p) => Array.isArray(p) && p.length && result.push(p));
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}, [featureConfig, bodyshop]);
|
||||||
|
|
||||||
if (!hasAccess) {
|
const preserveHiddenFormData = useCallback(() => {
|
||||||
fieldPaths.forEach((fieldPath) => {
|
const currentValues = form.getFieldsValue();
|
||||||
const currentValues = form.getFieldsValue();
|
const preservationData = {};
|
||||||
let value = getNestedValue(currentValues, fieldPath);
|
let hasAny = false;
|
||||||
|
|
||||||
if (value === undefined || value === null) {
|
disabledPaths.forEach((path) => {
|
||||||
value = getNestedValue(bodyshop, fieldPath);
|
let value = getNestedValue(currentValues, path);
|
||||||
}
|
if (value == null) value = getNestedValue(bodyshop, path);
|
||||||
|
if (value != null) {
|
||||||
if (value !== undefined && value !== null) {
|
setNestedValue(preservationData, path, value);
|
||||||
setNestedValue(preservationData, fieldPath, value);
|
hasAny = true;
|
||||||
hasDataToPreserve = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (hasDataToPreserve) {
|
if (hasAny) form.setFieldsValue(preservationData);
|
||||||
form.setFieldsValue(preservationData);
|
}, [form, bodyshop, disabledPaths]);
|
||||||
}
|
|
||||||
}, [form, featureConfig, bodyshop]);
|
|
||||||
|
|
||||||
const getCompleteFormValues = () => {
|
const getCompleteFormValues = () => {
|
||||||
const currentFormValues = form.getFieldsValue();
|
const currentValues = form.getFieldsValue();
|
||||||
const completeValues = { ...currentFormValues };
|
const complete = { ...currentValues };
|
||||||
|
|
||||||
Object.entries(featureConfig).forEach(([featureName, fieldPaths]) => {
|
disabledPaths.forEach((path) => {
|
||||||
const hasAccess = HasFeatureAccess({ featureName, bodyshop });
|
let value = getNestedValue(currentValues, path);
|
||||||
|
if (value == null) value = getNestedValue(bodyshop, path);
|
||||||
if (!hasAccess) {
|
if (value != null) setNestedValue(complete, path, value);
|
||||||
fieldPaths.forEach((fieldPath) => {
|
|
||||||
let value = getNestedValue(currentFormValues, fieldPath);
|
|
||||||
if (value === undefined || value === null) {
|
|
||||||
value = getNestedValue(bodyshop, fieldPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value !== undefined && value !== null) {
|
|
||||||
setNestedValue(completeValues, fieldPath, value);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return completeValues;
|
return complete;
|
||||||
};
|
};
|
||||||
|
|
||||||
const createSubmissionHandler = (originalHandler) => {
|
const createSubmissionHandler = (originalHandler) => {
|
||||||
@@ -103,8 +87,8 @@ export const FEATURE_CONFIGS = {
|
|||||||
["md_responsibility_centers", "profits"],
|
["md_responsibility_centers", "profits"],
|
||||||
["md_responsibility_centers", "defaults"],
|
["md_responsibility_centers", "defaults"],
|
||||||
["md_responsibility_centers", "dms_defaults"],
|
["md_responsibility_centers", "dms_defaults"],
|
||||||
["md_responsibility_centers", "taxes", "itemexemptcode"],
|
["md_responsibility_centers", "taxes"],
|
||||||
["md_responsibility_centers", "taxes", "invoiceexemptcode"],
|
["md_responsibility_centers", "cieca_pfl"],
|
||||||
["md_responsibility_centers", "ar"],
|
["md_responsibility_centers", "ar"],
|
||||||
["md_responsibility_centers", "refund"],
|
["md_responsibility_centers", "refund"],
|
||||||
["md_responsibility_centers", "sales_tax_codes"],
|
["md_responsibility_centers", "sales_tax_codes"],
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ export function VendorsFormComponent({ bodyshop, form, formLoading, handleDelete
|
|||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="tags"
|
name="tags"
|
||||||
label={t("vendor.fields.tags")}
|
label={t("vendors.fields.tags")}
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
//message: t("general.validation.required"),
|
//message: t("general.validation.required"),
|
||||||
|
|||||||
@@ -959,6 +959,7 @@
|
|||||||
- enforce_referral
|
- enforce_referral
|
||||||
- entegral_configuration
|
- entegral_configuration
|
||||||
- entegral_id
|
- entegral_id
|
||||||
|
- external_shop_id
|
||||||
- features
|
- features
|
||||||
- federal_tax_id
|
- federal_tax_id
|
||||||
- id
|
- id
|
||||||
@@ -1012,6 +1013,8 @@
|
|||||||
- prodtargethrs
|
- prodtargethrs
|
||||||
- production_config
|
- production_config
|
||||||
- region_config
|
- region_config
|
||||||
|
- rr_configuration
|
||||||
|
- rr_dealerid
|
||||||
- schedule_end_time
|
- schedule_end_time
|
||||||
- schedule_start_time
|
- schedule_start_time
|
||||||
- scoreboard_target
|
- scoreboard_target
|
||||||
@@ -1035,7 +1038,6 @@
|
|||||||
- use_fippa
|
- use_fippa
|
||||||
- use_paint_scale_data
|
- use_paint_scale_data
|
||||||
- uselocalmediaserver
|
- uselocalmediaserver
|
||||||
- external_shop_id
|
|
||||||
- website
|
- website
|
||||||
- workingdays
|
- workingdays
|
||||||
- zip_post
|
- zip_post
|
||||||
@@ -1068,6 +1070,7 @@
|
|||||||
- enforce_conversion_category
|
- enforce_conversion_category
|
||||||
- enforce_conversion_csr
|
- enforce_conversion_csr
|
||||||
- enforce_referral
|
- enforce_referral
|
||||||
|
- external_shop_id
|
||||||
- federal_tax_id
|
- federal_tax_id
|
||||||
- id
|
- id
|
||||||
- inhousevendorid
|
- inhousevendorid
|
||||||
@@ -1113,6 +1116,7 @@
|
|||||||
- phone
|
- phone
|
||||||
- prodtargethrs
|
- prodtargethrs
|
||||||
- production_config
|
- production_config
|
||||||
|
- rr_configuration
|
||||||
- schedule_end_time
|
- schedule_end_time
|
||||||
- schedule_start_time
|
- schedule_start_time
|
||||||
- scoreboard_target
|
- scoreboard_target
|
||||||
@@ -1131,7 +1135,6 @@
|
|||||||
- use_fippa
|
- use_fippa
|
||||||
- use_paint_scale_data
|
- use_paint_scale_data
|
||||||
- uselocalmediaserver
|
- uselocalmediaserver
|
||||||
- external_shop_id
|
|
||||||
- website
|
- website
|
||||||
- workingdays
|
- workingdays
|
||||||
- zip_post
|
- zip_post
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
-- Could not auto-generate a down migration.
|
||||||
|
-- Please write an appropriate down migration for the SQL below:
|
||||||
|
-- alter table "public"."bodyshops" add column "rr_configuration" jsonb
|
||||||
|
-- null default jsonb_build_object();
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
alter table "public"."bodyshops" add column "rr_configuration" jsonb
|
||||||
|
null default jsonb_build_object();
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
-- Could not auto-generate a down migration.
|
||||||
|
-- Please write an appropriate down migration for the SQL below:
|
||||||
|
-- alter table "public"."bodyshops" add column "rr_dealierid" text
|
||||||
|
-- null;
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
alter table "public"."bodyshops" add column "rr_dealierid" text
|
||||||
|
null;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
alter table "public"."bodyshops" rename column "rr_dealerid" to "rr_dealierid";
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
alter table "public"."bodyshops" rename column "rr_dealierid" to "rr_dealerid";
|
||||||
@@ -252,35 +252,27 @@ const generatePaymentUrl = async (req, res) => {
|
|||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
const checkFee = async (req, res) => {
|
const checkFee = async (req, res) => {
|
||||||
const logResponseMeta = {
|
const { bodyshop = {}, amount } = req.body || {};
|
||||||
bodyshop: {
|
const { id, imexshopid, shopname, state } = bodyshop;
|
||||||
id: req.body?.bodyshop?.id,
|
const logResponseMeta = { bodyshop: { id, imexshopid, name: shopname, state }, amount };
|
||||||
imexshopid: req.body?.bodyshop?.imexshopid,
|
|
||||||
name: req.body?.bodyshop?.shopname,
|
|
||||||
state: req.body?.bodyshop?.state
|
|
||||||
},
|
|
||||||
amount: req.body?.amount
|
|
||||||
};
|
|
||||||
|
|
||||||
logger.log("intellipay-checkfee-request-received", "DEBUG", req.user?.email, null, logResponseMeta);
|
logger.log("intellipay-checkfee-request-received", "DEBUG", req.user?.email, null, logResponseMeta);
|
||||||
|
|
||||||
if (!isNumber(req.body?.amount) || req.body?.amount <= 0) {
|
if (!isNumber(amount) || amount <= 0) {
|
||||||
logger.log("intellipay-checkfee-skip", "DEBUG", req.user?.email, null, {
|
logger.log("intellipay-checkfee-skip", "DEBUG", req.user?.email, null, {
|
||||||
message: "Amount is zero or undefined, skipping fee check.",
|
message: "Amount is zero or undefined, skipping fee check.",
|
||||||
...logResponseMeta
|
...logResponseMeta
|
||||||
});
|
});
|
||||||
|
|
||||||
return res.json({ fee: 0 });
|
return res.json({ fee: 0 });
|
||||||
}
|
}
|
||||||
|
|
||||||
const shopCredentials = await getShopCredentials(req.body.bodyshop);
|
const shopCredentials = await getShopCredentials(bodyshop);
|
||||||
|
|
||||||
if (shopCredentials?.error) {
|
if (shopCredentials?.error) {
|
||||||
logger.log("intellipay-checkfee-credentials-error", "ERROR", req.user?.email, null, {
|
logger.log("intellipay-checkfee-credentials-error", "ERROR", req.user?.email, null, {
|
||||||
message: shopCredentials.error?.message,
|
message: shopCredentials.error?.message,
|
||||||
...logResponseMeta
|
...logResponseMeta
|
||||||
});
|
});
|
||||||
|
|
||||||
return res.status(400).json({ error: shopCredentials.error?.message, ...logResponseMeta });
|
return res.status(400).json({ error: shopCredentials.error?.message, ...logResponseMeta });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,13 +284,10 @@ const checkFee = async (req, res) => {
|
|||||||
{
|
{
|
||||||
method: "fee",
|
method: "fee",
|
||||||
...shopCredentials,
|
...shopCredentials,
|
||||||
amount: req.body.amount,
|
amount: String(amount), // Type cast to string as required by API
|
||||||
paymenttype: `CC`,
|
paymenttype: "CC",
|
||||||
cardnum: "4111111111111111", // Required for compatibility with API
|
cardnum: "4111111111111111", // Required for compatibility with API
|
||||||
state:
|
state: state?.toUpperCase() || "ZZ"
|
||||||
req.body.bodyshop?.state && req.body.bodyshop.state.length === 2
|
|
||||||
? req.body.bodyshop.state.toUpperCase()
|
|
||||||
: "ZZ"
|
|
||||||
},
|
},
|
||||||
{ sort: false } // Ensure query string order is preserved
|
{ sort: false } // Ensure query string order is preserved
|
||||||
),
|
),
|
||||||
@@ -310,46 +299,24 @@ const checkFee = async (req, res) => {
|
|||||||
...logResponseMeta
|
...logResponseMeta
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await axios(options);
|
const { data } = await axios(options);
|
||||||
|
|
||||||
if (response.data?.error) {
|
if (data?.error || data < 0) {
|
||||||
logger.log("intellipay-checkfee-api-error", "ERROR", req.user?.email, null, {
|
const errorType = data?.error ? "intellipay-checkfee-api-error" : "intellipay-checkfee-negative-fee";
|
||||||
message: response.data?.error,
|
const errorMessage = data?.error
|
||||||
...logResponseMeta
|
? data?.error
|
||||||
});
|
: "Fee amount negative. Check API credentials & account configuration.";
|
||||||
|
logger.log(errorType, "ERROR", req.user?.email, null, { message: errorMessage, data, ...logResponseMeta });
|
||||||
return res.status(400).json({
|
return res.status(400).json({ error: errorMessage, type: errorType, data, ...logResponseMeta });
|
||||||
error: response.data?.error,
|
|
||||||
type: "intellipay-checkfee-api-error",
|
|
||||||
...logResponseMeta
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response.data < 0) {
|
logger.log("intellipay-checkfee-success", "DEBUG", req.user?.email, null, { fee: data, ...logResponseMeta });
|
||||||
logger.log("intellipay-checkfee-negative-fee", "ERROR", req.user?.email, null, {
|
return res.json({ fee: data, ...logResponseMeta });
|
||||||
message: "Fee amount returned is negative.",
|
|
||||||
...logResponseMeta
|
|
||||||
});
|
|
||||||
|
|
||||||
return res.json({
|
|
||||||
error: "Fee amount negative. Check API credentials & account configuration.",
|
|
||||||
...logResponseMeta,
|
|
||||||
type: "intellipay-checkfee-negative-fee"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.log("intellipay-checkfee-success", "DEBUG", req.user?.email, null, {
|
|
||||||
fee: response.data,
|
|
||||||
...logResponseMeta
|
|
||||||
});
|
|
||||||
|
|
||||||
return res.json({ fee: response.data, ...logResponseMeta });
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.log("intellipay-checkfee-error", "ERROR", req.user?.email, null, {
|
logger.log("intellipay-checkfee-error", "ERROR", req.user?.email, null, {
|
||||||
message: error?.message,
|
message: error?.message,
|
||||||
...logResponseMeta
|
...logResponseMeta
|
||||||
});
|
});
|
||||||
|
|
||||||
return res.status(500).json({ error: error?.message, logResponseMeta });
|
return res.status(500).json({ error: error?.message, logResponseMeta });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -58,8 +58,20 @@ const generateSignedUploadUrls = async (req, res) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const command = new PutObjectCommand(commandParams);
|
const command = new PutObjectCommand(commandParams);
|
||||||
const presignedUrl = await getSignedUrl(client, command, { expiresIn: 360 });
|
|
||||||
signedUrls.push({ filename, presignedUrl, key });
|
// For PDFs, we need to add conditions to the presigned URL to enforce content type
|
||||||
|
const presignedUrlOptions = { expiresIn: 360 };
|
||||||
|
if (isPdf) {
|
||||||
|
presignedUrlOptions.signableHeaders = new Set(['content-type']);
|
||||||
|
}
|
||||||
|
|
||||||
|
const presignedUrl = await getSignedUrl(client, command, presignedUrlOptions);
|
||||||
|
signedUrls.push({
|
||||||
|
filename,
|
||||||
|
presignedUrl,
|
||||||
|
key,
|
||||||
|
...(isPdf && { contentType: "application/pdf" })
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.log("imgproxy-upload-success", "DEBUG", req.user?.email, jobid, { signedUrls });
|
logger.log("imgproxy-upload-success", "DEBUG", req.user?.email, jobid, { signedUrls });
|
||||||
|
|||||||
Reference in New Issue
Block a user