Compare commits

..

12 Commits

Author SHA1 Message Date
Allan Carr
831802f5af IO-3235 FeatureAccess on VisualBoard for SmartSchedule Option of Color Cards
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2025-05-20 15:25:29 -07:00
Allan Carr
6005eaee6a Merged in feature/IO-3217-OTSL-Labor-Type (pull request #2319)
IO-3217 OTSL Labor Type
2025-05-19 21:02:01 +00:00
Patrick Fic
c069600cfd Merged in hotfix/2025-05-15 (pull request #2317)
Hotfix/2025 05 15 IO-3217 IO-3066 IO-3210 IO-2328
2025-05-15 22:47:26 +00:00
Patrick Fic
186cbf2c97 Merge branch 'feature/IO-3066-ems-upload' into hotfix/2025-05-15 2025-05-15 15:47:04 -07:00
Patrick Fic
392988ae11 Io-3066 resolve typo. 2025-05-15 15:46:45 -07:00
Allan Carr
2e33b79eb9 Merged in feature/IO-3210-Podium-Datapump (pull request #2315)
IO-3210 Podium Datapump

Approved-by: Patrick Fic
2025-05-15 22:39:39 +00:00
Patrick Fic
fa99ef7b37 Merge branch 'feature/IO-3066-ems-upload' into hotfix/2025-05-15 2025-05-15 15:36:44 -07:00
Patrick Fic
c4aff1b516 Merge branch 'feature/IO-2328-intellipay-querystring-package' into hotfix/2025-05-15 2025-05-15 15:36:31 -07:00
Allan Carr
8b89e2eb9d IO-3210 Podium Datapump
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2025-05-15 15:27:59 -07:00
Patrick Fic
9ab41308e7 IO-3066 add EMS upload functionality. 2025-05-15 12:53:41 -07:00
Allan Carr
f76052ec9b Merge branch 'master-AIO' into feature/IO-3210-Podium-Datapump
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2025-05-15 12:41:09 -07:00
Allan Carr
12c87ed689 IO-3217 OTSL Labor Type
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2025-04-23 18:48:35 -07:00
7 changed files with 76 additions and 19 deletions

View File

@@ -4,11 +4,12 @@ import { Col, Row } from "antd";
import Axios from "axios";
import _ from "lodash";
import queryString from "query-string";
import React, { useCallback, useEffect, useState } from "react";
import { useCallback, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { useLocation, useNavigate } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
import { logImEXEvent } from "../../firebase/firebase.utils";
import {
DELETE_AVAILABLE_JOB,
@@ -33,7 +34,6 @@ import OwnerFindModalContainer from "../owner-find-modal/owner-find-modal.contai
import { GetSupplementDelta } from "./jobs-available-supplement.estlines.util";
import HeaderFields from "./jobs-available-supplement.headerfields";
import JobsAvailableTableComponent from "./jobs-available-table.component";
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
@@ -195,7 +195,7 @@ export function JobsAvailableContainer({ bodyshop, currentUser, insertAuditTrail
await deleteJob({
variables: { id: estData.id }
}).then((r) => {
}).then(() => {
refetch();
setInsertLoading(false);
});
@@ -315,7 +315,7 @@ export function JobsAvailableContainer({ bodyshop, currentUser, insertAuditTrail
deleteJob({
variables: { id: estData.id }
}).then((r) => {
}).then(() => {
refetch();
setInsertLoading(false);
});
@@ -372,7 +372,7 @@ export function JobsAvailableContainer({ bodyshop, currentUser, insertAuditTrail
loadEstData({ variables: { id: record.id } });
modalSearchState[1](record.clm_no);
setJobModalVisible(true);
// eslint-disable-next-line react-hooks/exhaustive-deps
// eslint-disable-next-line
}, []);
useEffect(() => {
@@ -456,7 +456,7 @@ function replaceEmpty(someObj, replaceValue = null) {
return JSON.parse(temp);
}
async function CheckTaxRatesUSA(estData, bodyshop) {
async function CheckTaxRatesUSA(estData) {
if (!estData.parts_tax_rates?.PAM) {
estData.parts_tax_rates.PAM = estData.parts_tax_rates.PAC;
}
@@ -568,7 +568,7 @@ async function CheckTaxRates(estData, bodyshop) {
});
//}
}
function ResolveCCCLineIssues(estData, bodyshop) {
function ResolveCCCLineIssues(estData) {
//Find all misc amounts, populate them to the act price.
//This needs to be done before cleansing unq_seq since some misc prices could move over.
estData.joblines.data.forEach((line) => {
@@ -585,6 +585,9 @@ function ResolveCCCLineIssues(estData, bodyshop) {
// line.notes += ` | ET/UT Update (prev = ${line.mod_lbr_ty})`;
line.mod_lbr_ty = "LAR";
}
if (line.mod_lbr_ty === "OTSL") {
line.mod_lbr_ty = line.mod_lbr_hrs === 0 ? null : "LAB";
}
}
});
});

View File

@@ -1,7 +1,15 @@
import { Card, Col, Form, Radio, Row } from "antd";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../../redux/user/user.selectors";
import { HasFeatureAccess } from "../../feature-wrapper/feature-wrapper.component";
const LayoutSettings = ({ t }) => (
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop
});
const LayoutSettings = ({ t, bodyshop }) => (
<Card title={t("production.settings.layout")} style={{ maxWidth: "100%", overflowX: "auto" }}>
<Row gutter={[16, 16]}>
{[
@@ -30,14 +38,18 @@ const LayoutSettings = ({ t }) => (
{ value: false, label: t("production.labels.wide") }
]
},
{
name: "cardcolor",
label: t("production.labels.cardcolor"),
options: [
{ value: true, label: t("production.labels.on") },
{ value: false, label: t("production.labels.off") }
]
},
...(HasFeatureAccess({ bodyshop, featureName: "smartscheduling" })
? [
{
name: "cardcolor",
label: t("production.labels.cardcolor"),
options: [
{ value: true, label: t("production.labels.on") },
{ value: false, label: t("production.labels.off") }
]
}
]
: []),
{
name: "kiosk",
label: t("production.labels.kiosk_mode"),
@@ -67,4 +79,4 @@ LayoutSettings.propTypes = {
t: PropTypes.func.isRequired
};
export default LayoutSettings;
export default connect(mapStateToProps)(LayoutSettings);

View File

@@ -4,4 +4,5 @@ exports.chatter = require("./chatter").default;
exports.claimscorp = require("./claimscorp").default;
exports.kaizen = require("./kaizen").default;
exports.usageReport = require("./usageReport").default;
exports.podium = require("./podium").default;
exports.podium = require("./podium").default;
exports.emsUpload = require("./emsUpload").default;

22
server/data/emsUpload.js Normal file
View File

@@ -0,0 +1,22 @@
const moment = require("moment-timezone");
const logger = require("../utils/logger");
const s3Client = require("../utils/s3"); // Using the S3 client utilities with LocalStack support
const emsUpload = async (req, res) => {
try {
const { bodyshopid, ciecaid, clm_no, ownr_ln } = req.body;
const presignedUrl = await s3Client.getPresignedUrl({
bucketName: process.env.S3_EMS_UPLOAD_BUCKET,
key: `${bodyshopid}/${ciecaid}-${clm_no}-${ownr_ln}-${moment().format("YYYY-MM-DD--HH-mm-ss")}.zip`
});
res.status(200).json({ presignedUrl });
} catch (error) {
logger.log("ems-upload-presign-error", "ERROR", req?.user?.email, null, {
error: error.message,
stack: error.stack
});
res.status(500).json({ error: error.message, stack: error.stack });
}
};
exports.default = emsUpload;

View File

@@ -185,7 +185,7 @@ async function uploadViaSFTP(csvObj) {
await sftp.connect(ftpSetup);
try {
csvObj.result = await sftp.put(Buffer.from(csvObj.xml), `${csvObj.filename}`);
csvObj.result = await sftp.put(Buffer.from(csvObj.csv), `${csvObj.filename}`);
logger.log("podium-sftp-upload", "DEBUG", "api", csvObj.bodyshopid, {
imexshopid: csvObj.imexshopid,
filename: csvObj.filename,

View File

@@ -138,6 +138,9 @@ router.post("/canvastest", validateFirebaseIdTokenMiddleware, canvastest);
// Alert Check
router.post("/alertcheck", eventAuthorizationMiddleware, alertCheck);
//EMS Upload
router.post("/emsupload", validateFirebaseIdTokenMiddleware, data.emsUpload);
// Redis Cache Routes
router.post("/bodyshop-cache", eventAuthorizationMiddleware, updateBodyshopCache);

View File

@@ -9,6 +9,7 @@ const {
const { defaultProvider } = require("@aws-sdk/credential-provider-node");
const { InstanceRegion } = require("./instanceMgr");
const { isString, isEmpty } = require("lodash");
const { getSignedUrl } = require("@aws-sdk/s3-request-presigner");
const createS3Client = () => {
const S3Options = {
@@ -95,6 +96,17 @@ const createS3Client = () => {
throw error;
}
};
const getPresignedUrl = async ({ bucketName, key }) => {
const command = new PutObjectCommand({
Bucket: bucketName,
Key: key,
StorageClass: "INTELLIGENT_TIERING"
});
const presignedUrl = await getSignedUrl(s3Client, command, { expiresIn: 360 });
return presignedUrl;
}
return {
uploadFileToS3,
downloadFileFromS3,
@@ -102,8 +114,12 @@ const createS3Client = () => {
deleteFileFromS3,
copyFileInS3,
fileExistsInS3,
getPresignedUrl,
...s3Client
};
};
module.exports = createS3Client();