Compare commits
69 Commits
feature/IO
...
feature/IO
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5cbf00b0c8 | ||
|
|
78771ae750 | ||
|
|
8eee371a90 | ||
|
|
5fce548666 | ||
|
|
80322caad0 | ||
|
|
83a1b7690d | ||
|
|
73ab02225e | ||
|
|
c9e28b1ed2 | ||
|
|
c25c66d00f | ||
|
|
d319ab49d4 | ||
|
|
a069989ea7 | ||
|
|
8e3aa186cb | ||
|
|
01c55d6277 | ||
|
|
3438907d8d | ||
|
|
ae020b651e | ||
|
|
d22988df15 | ||
|
|
8136a56ad2 | ||
|
|
830f6c0eea | ||
|
|
4c1849289a | ||
|
|
c45a4780e3 | ||
|
|
d4adc4c1aa | ||
|
|
d9e71423f5 | ||
|
|
6cac0f9594 | ||
|
|
2ab4615642 | ||
|
|
dd5961d419 | ||
|
|
8190958ba3 | ||
|
|
77e009f316 | ||
|
|
2b2738a8d1 | ||
|
|
3d10c9da7f | ||
|
|
e82c77d119 | ||
|
|
855a78be05 | ||
|
|
a29e840797 | ||
|
|
1b30c1ab58 | ||
|
|
80f235f12e | ||
|
|
9b67148522 | ||
|
|
6b501e4619 | ||
|
|
42f1d6fa13 | ||
|
|
3f247a9227 | ||
|
|
63b914731b | ||
|
|
23f8f69bbe | ||
|
|
fc3ea2bdf8 | ||
|
|
96e970faf7 | ||
|
|
c133195607 | ||
|
|
d75ea2b1a6 | ||
|
|
ec0fd840e4 | ||
|
|
971a81fc27 | ||
|
|
19050d31f7 | ||
|
|
e605433379 | ||
|
|
b9ebb70b7a | ||
|
|
79ed6f2388 | ||
|
|
785449a986 | ||
|
|
0b7d469e0e | ||
|
|
a57156756e | ||
|
|
c4c30d98d4 | ||
|
|
d4e8803b13 | ||
|
|
1f2786ddec | ||
|
|
e90cda07e4 | ||
|
|
9793daa04c | ||
|
|
117ced8fe7 | ||
|
|
e7909205d1 | ||
|
|
18028a70ab | ||
|
|
eeb8d8d26f | ||
|
|
23659fc412 | ||
|
|
ba65057782 | ||
|
|
60a859cac8 | ||
|
|
d085a9c7c9 | ||
|
|
ec518a0593 | ||
|
|
26836f662a | ||
|
|
6e88faa9d8 |
@@ -1 +1,2 @@
|
|||||||
client_max_body_size 50M;
|
client_max_body_size 50M;
|
||||||
|
client_body_buffer_size 5M;
|
||||||
|
|||||||
1
_reference/localEmailViewer/.gitignore
vendored
Normal file
1
_reference/localEmailViewer/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
node_modules
|
||||||
7
_reference/localEmailViewer/README.md
Normal file
7
_reference/localEmailViewer/README.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
This will connect to your dockers local stack session and render the email in HTML.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
node index.js
|
||||||
|
```
|
||||||
|
|
||||||
|
http://localhost:3334
|
||||||
116
_reference/localEmailViewer/index.js
Normal file
116
_reference/localEmailViewer/index.js
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
// index.js
|
||||||
|
|
||||||
|
import express from 'express';
|
||||||
|
import fetch from 'node-fetch';
|
||||||
|
import {simpleParser} from 'mailparser';
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
const PORT = 3334;
|
||||||
|
|
||||||
|
app.get('/', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const response = await fetch('http://localhost:4566/_aws/ses');
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Network response was not ok');
|
||||||
|
}
|
||||||
|
const data = await response.json();
|
||||||
|
const messagesHtml = await parseMessages(data.messages);
|
||||||
|
res.send(renderHtml(messagesHtml));
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching messages:', error);
|
||||||
|
res.status(500).send('Error fetching messages');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
async function parseMessages(messages) {
|
||||||
|
const parsedMessages = await Promise.all(
|
||||||
|
messages.map(async (message, index) => {
|
||||||
|
try {
|
||||||
|
const parsed = await simpleParser(message.RawData);
|
||||||
|
return `
|
||||||
|
<div class="shadow-md rounded-lg p-4 mb-6" style="background-color: lightgray">
|
||||||
|
<div class="shadow-md rounded-lg p-4 mb-6" style="background-color: white">
|
||||||
|
<div class="mb-2">
|
||||||
|
<span class="font-bold text-lg">Message ${index + 1}</span>
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<span class="font-semibold">From:</span> ${message.Source}
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<span class="font-semibold">Region:</span> ${message.Region}
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<span class="font-semibold">Timestamp:</span> ${message.Timestamp}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="prose">
|
||||||
|
${parsed.html || parsed.textAsHtml || 'No HTML content available'}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error parsing email:', error);
|
||||||
|
return `
|
||||||
|
<div class="bg-white shadow-md rounded-lg p-4 mb-6">
|
||||||
|
<div class="mb-2">
|
||||||
|
<span class="font-bold text-lg">Message ${index + 1}</span>
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<span class="font-semibold">From:</span> ${message.Source}
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<span class="font-semibold">Region:</span> ${message.Region}
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<span class="font-semibold">Timestamp:</span> ${message.Timestamp}
|
||||||
|
</div>
|
||||||
|
<div class="text-red-500">
|
||||||
|
Error parsing email content
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return parsedMessages.join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderHtml(messagesHtml) {
|
||||||
|
return `
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Email Messages Viewer</title>
|
||||||
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background-color: #f3f4f6;
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 50px auto;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
.prose {
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container bg-white shadow-lg rounded-lg p-6">
|
||||||
|
<h1 class="text-2xl font-bold text-center mb-6">Email Messages Viewer</h1>
|
||||||
|
<div id="messages-container">
|
||||||
|
${messagesHtml}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
app.listen(PORT, () => {
|
||||||
|
console.log(`Server is running on http://localhost:${PORT}`);
|
||||||
|
});
|
||||||
1214
_reference/localEmailViewer/package-lock.json
generated
Normal file
1214
_reference/localEmailViewer/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
18
_reference/localEmailViewer/package.json
Normal file
18
_reference/localEmailViewer/package.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"name": "localemailviewer",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "index.js",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"description": "",
|
||||||
|
"dependencies": {
|
||||||
|
"express": "^4.21.1",
|
||||||
|
"mailparser": "^3.7.1",
|
||||||
|
"node-fetch": "^3.3.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,8 +2,6 @@ import { ApolloProvider } from "@apollo/client";
|
|||||||
import { SplitFactoryProvider, SplitSdk } from "@splitsoftware/splitio-react";
|
import { SplitFactoryProvider, SplitSdk } from "@splitsoftware/splitio-react";
|
||||||
import { ConfigProvider } from "antd";
|
import { ConfigProvider } from "antd";
|
||||||
import enLocale from "antd/es/locale/en_US";
|
import enLocale from "antd/es/locale/en_US";
|
||||||
import dayjs from "../utils/day";
|
|
||||||
import "dayjs/locale/en";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import GlobalLoadingBar from "../components/global-loading-bar/global-loading-bar.component";
|
import GlobalLoadingBar from "../components/global-loading-bar/global-loading-bar.component";
|
||||||
@@ -19,8 +17,6 @@ if (import.meta.env.DEV) {
|
|||||||
Userpilot.initialize("NX-69145f08");
|
Userpilot.initialize("NX-69145f08");
|
||||||
}
|
}
|
||||||
|
|
||||||
dayjs.locale("en");
|
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
core: {
|
core: {
|
||||||
authorizationKey: import.meta.env.VITE_APP_SPLIT_API,
|
authorizationKey: import.meta.env.VITE_APP_SPLIT_API,
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ export function ChatPopupComponent({ chatVisible, selectedConversation, toggleCh
|
|||||||
if (fcmToken) {
|
if (fcmToken) {
|
||||||
setpollInterval(0);
|
setpollInterval(0);
|
||||||
} else {
|
} else {
|
||||||
setpollInterval(60000);
|
setpollInterval(90000);
|
||||||
}
|
}
|
||||||
}, [fcmToken]);
|
}, [fcmToken]);
|
||||||
|
|
||||||
|
|||||||
@@ -40,13 +40,11 @@ export function DmsLogEvents({ socket, logs, bodyshop }) {
|
|||||||
|
|
||||||
function LogLevelHierarchy(level) {
|
function LogLevelHierarchy(level) {
|
||||||
switch (level) {
|
switch (level) {
|
||||||
case "TRACE":
|
|
||||||
return "pink";
|
|
||||||
case "DEBUG":
|
case "DEBUG":
|
||||||
return "orange";
|
return "orange";
|
||||||
case "INFO":
|
case "INFO":
|
||||||
return "blue";
|
return "blue";
|
||||||
case "WARNING":
|
case "WARN":
|
||||||
return "yellow";
|
return "yellow";
|
||||||
case "ERROR":
|
case "ERROR":
|
||||||
return "red";
|
return "red";
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { INSERT_EULA_ACCEPTANCE } from "../../graphql/user.queries";
|
|||||||
import { useMutation } from "@apollo/client";
|
import { useMutation } from "@apollo/client";
|
||||||
import { acceptEula } from "../../redux/user/user.actions";
|
import { acceptEula } from "../../redux/user/user.actions";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import day from "../../utils/day";
|
import dayjs from "../../utils/day";
|
||||||
|
|
||||||
import "./eula.styles.scss";
|
import "./eula.styles.scss";
|
||||||
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component.jsx";
|
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component.jsx";
|
||||||
@@ -208,7 +208,7 @@ const EulaFormComponent = ({ form, handleChange, onFinish, t }) => (
|
|||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
validator: (_, value) => {
|
validator: (_, value) => {
|
||||||
if (day(value).isSame(day(), "day")) {
|
if (dayjs(value).isSame(dayjs(), "day")) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
return Promise.reject(new Error(t("eula.messages.date_accepted")));
|
return Promise.reject(new Error(t("eula.messages.date_accepted")));
|
||||||
|
|||||||
@@ -2,21 +2,38 @@ import { DatePicker } from "antd";
|
|||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import React, { useCallback, useState } from "react";
|
import React, { useCallback, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import { createStructuredSelector } from "reselect";
|
||||||
|
import { selectBodyshop } from "../../redux/user/user.selectors.js";
|
||||||
import dayjs from "../../utils/day";
|
import dayjs from "../../utils/day";
|
||||||
import { fuzzyMatchDate } from "./formats.js";
|
import { fuzzyMatchDate } from "./formats.js";
|
||||||
|
|
||||||
const DateTimePicker = ({ value, onChange, onBlur, id, onlyFuture, onlyToday, isDateOnly = false, ...restProps }) => {
|
const mapStateToProps = createStructuredSelector({
|
||||||
|
bodyshop: selectBodyshop
|
||||||
|
});
|
||||||
|
|
||||||
|
const DateTimePicker = ({
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
onBlur,
|
||||||
|
id,
|
||||||
|
onlyFuture,
|
||||||
|
onlyToday,
|
||||||
|
isDateOnly = false,
|
||||||
|
bodyshop,
|
||||||
|
...restProps
|
||||||
|
}) => {
|
||||||
const [isManualInput, setIsManualInput] = useState(false);
|
const [isManualInput, setIsManualInput] = useState(false);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const handleChange = useCallback(
|
const handleChange = useCallback(
|
||||||
(newDate) => {
|
(newDate) => {
|
||||||
if (onChange) {
|
if (onChange) {
|
||||||
onChange(newDate || null);
|
onChange(bodyshop?.timezone && newDate ? dayjs(newDate).tz(bodyshop.timezone, true) : newDate);
|
||||||
}
|
}
|
||||||
setIsManualInput(false);
|
setIsManualInput(false);
|
||||||
},
|
},
|
||||||
[onChange]
|
[onChange, bodyshop?.timezone]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleBlur = useCallback(
|
const handleBlur = useCallback(
|
||||||
@@ -102,4 +119,4 @@ DateTimePicker.propTypes = {
|
|||||||
isDateOnly: PropTypes.bool
|
isDateOnly: PropTypes.bool
|
||||||
};
|
};
|
||||||
|
|
||||||
export default React.memo(DateTimePicker);
|
export default connect(mapStateToProps, null)(DateTimePicker);
|
||||||
|
|||||||
@@ -116,18 +116,15 @@ function Header({
|
|||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const deleteBetaCookie = () => {
|
// const deleteBetaCookie = () => {
|
||||||
const cookieExists = document.cookie.split("; ").some((row) => row.startsWith(`betaSwitchImex=`));
|
// const cookieExists = document.cookie.split("; ").some((row) => row.startsWith(`betaSwitchImex=`));
|
||||||
if (cookieExists) {
|
// if (cookieExists) {
|
||||||
const domain = window.location.hostname.split(".").slice(-2).join(".");
|
// const domain = window.location.hostname.split(".").slice(-2).join(".");
|
||||||
document.cookie = `betaSwitchImex=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=.${domain}`;
|
// document.cookie = `betaSwitchImex=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=.${domain}`;
|
||||||
console.log(`betaSwitchImex cookie deleted`);
|
// }
|
||||||
} else {
|
// };
|
||||||
console.log(`betaSwitchImex cookie does not exist`);
|
//
|
||||||
}
|
// deleteBetaCookie();
|
||||||
};
|
|
||||||
|
|
||||||
deleteBetaCookie();
|
|
||||||
|
|
||||||
const accountingChildren = [];
|
const accountingChildren = [];
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import ScheduleEventColor from "./schedule-event.color.component";
|
|||||||
import ScheduleEventNote from "./schedule-event.note.component";
|
import ScheduleEventNote from "./schedule-event.note.component";
|
||||||
import { useMutation } from "@apollo/client";
|
import { useMutation } from "@apollo/client";
|
||||||
import { UPDATE_APPOINTMENT } from "../../graphql/appointments.queries";
|
import { UPDATE_APPOINTMENT } from "../../graphql/appointments.queries";
|
||||||
|
import ProductionListColumnComment from "../production-list-columns/production-list-columns.comment.component";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop
|
bodyshop: selectBodyshop
|
||||||
@@ -127,6 +128,9 @@ export function ScheduleEventComponent({
|
|||||||
{(event.job && event.job.alt_transport) || ""}
|
{(event.job && event.job.alt_transport) || ""}
|
||||||
<ScheduleAtChange job={event && event.job} />
|
<ScheduleAtChange job={event && event.job} />
|
||||||
</DataLabel>
|
</DataLabel>
|
||||||
|
<DataLabel label={t("jobs.fields.comment")} valueStyle={{ overflow: "hidden", textOverflow: "ellipsis" }}>
|
||||||
|
<ProductionListColumnComment record={event && event.job} />
|
||||||
|
</DataLabel>
|
||||||
<ScheduleEventNote event={event} />
|
<ScheduleEventNote event={event} />
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
@@ -316,6 +320,7 @@ export function ScheduleEventComponent({
|
|||||||
})`}
|
})`}
|
||||||
|
|
||||||
{event.job && event.job.alt_transport && <div style={{ margin: ".1rem" }}>{event.job.alt_transport}</div>}
|
{event.job && event.job.alt_transport && <div style={{ margin: ".1rem" }}>{event.job.alt_transport}</div>}
|
||||||
|
{event?.job?.comment && `C: ${event.job.comment}`}
|
||||||
</Space>
|
</Space>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { useCallback, useEffect, useState } from "react";
|
import React, { useCallback, useEffect, useState } from "react";
|
||||||
import day from "../../utils/day";
|
import dayjs from "../../utils/day";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { Badge, Card, Space, Table, Tag } from "antd";
|
import { Badge, Card, Space, Table, Tag } from "antd";
|
||||||
import { gql, useQuery } from "@apollo/client";
|
import { gql, useQuery } from "@apollo/client";
|
||||||
@@ -72,7 +72,7 @@ export function JobLifecycleComponent({ job, statuses, ...rest }) {
|
|||||||
dataIndex: "start",
|
dataIndex: "start",
|
||||||
key: "start",
|
key: "start",
|
||||||
render: (text) => DateTimeFormatterFunction(text),
|
render: (text) => DateTimeFormatterFunction(text),
|
||||||
sorter: (a, b) => day(a.start).unix() - day(b.start).unix()
|
sorter: (a, b) => dayjs(a.start).unix() - dayjs(b.start).unix()
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("job_lifecycle.columns.relative_start"),
|
title: t("job_lifecycle.columns.relative_start"),
|
||||||
@@ -90,7 +90,7 @@ export function JobLifecycleComponent({ job, statuses, ...rest }) {
|
|||||||
}
|
}
|
||||||
return isEmpty(a.end) ? 1 : -1;
|
return isEmpty(a.end) ? 1 : -1;
|
||||||
}
|
}
|
||||||
return day(a.end).unix() - day(b.end).unix();
|
return dayjs(a.end).unix() - dayjs(b.end).unix();
|
||||||
},
|
},
|
||||||
render: (text) => (isEmpty(text) ? t("job_lifecycle.content.not_available") : DateTimeFormatterFunction(text))
|
render: (text) => (isEmpty(text) ? t("job_lifecycle.content.not_available") : DateTimeFormatterFunction(text))
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import React, { useState } from "react";
|
|||||||
|
|
||||||
import { useMutation } from "@apollo/client";
|
import { useMutation } from "@apollo/client";
|
||||||
import { Button, Form, notification, Popover, Select, Space } from "antd";
|
import { Button, Form, notification, Popover, Select, Space } from "antd";
|
||||||
import day from "../../utils/day";
|
import dayjs from "../../utils/day";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
@@ -48,7 +48,7 @@ export function JobLineDispatchButton({
|
|||||||
const result = await dispatchLines({
|
const result = await dispatchLines({
|
||||||
variables: {
|
variables: {
|
||||||
partsDispatch: {
|
partsDispatch: {
|
||||||
dispatched_at: day(),
|
dispatched_at: dayjs(),
|
||||||
employeeid: values.employeeid,
|
employeeid: values.employeeid,
|
||||||
jobid: job.id,
|
jobid: job.id,
|
||||||
dispatched_by: currentUser.email,
|
dispatched_by: currentUser.email,
|
||||||
@@ -138,7 +138,11 @@ export function JobLineDispatchButton({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover open={visible} content={popMenu}>
|
<Popover open={visible} content={popMenu}>
|
||||||
<Button disabled={selectedLines.length === 0 || jobRO || disabled} loading={loading} onClick={() => setVisible(true)}>
|
<Button
|
||||||
|
disabled={selectedLines.length === 0 || jobRO || disabled}
|
||||||
|
loading={loading}
|
||||||
|
onClick={() => setVisible(true)}
|
||||||
|
>
|
||||||
{t("joblines.actions.dispatchparts", { count: selectedLines.length })}
|
{t("joblines.actions.dispatchparts", { count: selectedLines.length })}
|
||||||
</Button>
|
</Button>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useMutation } from "@apollo/client";
|
import { useMutation } from "@apollo/client";
|
||||||
import { Button, Card, Col, notification, Row, Table } from "antd";
|
import { Button, Card, Col, notification, Row, Table } from "antd";
|
||||||
import day from "../../utils/day";
|
import dayjs from "../../utils/day";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { UPDATE_PARTS_DISPATCH_LINE } from "../../graphql/parts-dispatch.queries";
|
import { UPDATE_PARTS_DISPATCH_LINE } from "../../graphql/parts-dispatch.queries";
|
||||||
@@ -11,7 +11,7 @@ export default function PartsDispatchExpander({ dispatch, job }) {
|
|||||||
const [updateDispatchLine] = useMutation(UPDATE_PARTS_DISPATCH_LINE);
|
const [updateDispatchLine] = useMutation(UPDATE_PARTS_DISPATCH_LINE);
|
||||||
|
|
||||||
const handleAccept = async ({ partsDispatchLineId }) => {
|
const handleAccept = async ({ partsDispatchLineId }) => {
|
||||||
const accepted_at = day();
|
const accepted_at = dayjs();
|
||||||
const result = await updateDispatchLine({
|
const result = await updateDispatchLine({
|
||||||
variables: { id: partsDispatchLineId, line: { accepted_at } },
|
variables: { id: partsDispatchLineId, line: { accepted_at } },
|
||||||
optimisticResponse: {
|
optimisticResponse: {
|
||||||
|
|||||||
@@ -120,14 +120,6 @@ var formats = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const localizer = (dayjsLib) => {
|
const localizer = (dayjsLib) => {
|
||||||
// load dayjs plugins
|
|
||||||
dayjsLib.extend(isBetween);
|
|
||||||
dayjsLib.extend(isSameOrAfter);
|
|
||||||
dayjsLib.extend(isSameOrBefore);
|
|
||||||
dayjsLib.extend(localeData);
|
|
||||||
dayjsLib.extend(localizedFormat);
|
|
||||||
dayjsLib.extend(minMax);
|
|
||||||
dayjsLib.extend(utc);
|
|
||||||
var locale = function locale(dj, c) {
|
var locale = function locale(dj, c) {
|
||||||
return c ? dj.locale(c) : dj;
|
return c ? dj.locale(c) : dj;
|
||||||
};
|
};
|
||||||
@@ -136,7 +128,8 @@ const localizer = (dayjsLib) => {
|
|||||||
// then use the timezone aware version
|
// then use the timezone aware version
|
||||||
|
|
||||||
//TODO This was the issue entirely...
|
//TODO This was the issue entirely...
|
||||||
// var dayjs = dayjsLib.tz ? dayjsLib.tz : dayjsLib;
|
// var dayjs = dayjsLib.tz ? dayjsLib.tz : dayjsLib;
|
||||||
|
|
||||||
var dayjs = dayjsLib;
|
var dayjs = dayjsLib;
|
||||||
|
|
||||||
function getTimezoneOffset(date) {
|
function getTimezoneOffset(date) {
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ const mapStateToProps = createStructuredSelector({
|
|||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
problemJobs: selectProblemJobs
|
problemJobs: selectProblemJobs
|
||||||
});
|
});
|
||||||
|
|
||||||
const localizer = local(dayjs);
|
const localizer = local(dayjs);
|
||||||
|
|
||||||
export function ScheduleCalendarWrapperComponent({
|
export function ScheduleCalendarWrapperComponent({
|
||||||
|
|||||||
@@ -4,12 +4,12 @@ import ScoreboardChart from "../scoreboard-chart/scoreboard-chart.component";
|
|||||||
import ScoreboardLastDays from "../scoreboard-last-days/scoreboard-last-days.component";
|
import ScoreboardLastDays from "../scoreboard-last-days/scoreboard-last-days.component";
|
||||||
import ScoreboardTargetsTable from "../scoreboard-targets-table/scoreboard-targets-table.component";
|
import ScoreboardTargetsTable from "../scoreboard-targets-table/scoreboard-targets-table.component";
|
||||||
|
|
||||||
|
import { useApolloClient, useQuery } from "@apollo/client";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
|
import { GET_BLOCKED_DAYS, QUERY_SCOREBOARD } from "../../graphql/scoreboard.queries";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import dayjs from "../../utils/day";
|
import dayjs from "../../utils/day";
|
||||||
import { useApolloClient, useQuery } from "@apollo/client";
|
|
||||||
import { GET_BLOCKED_DAYS, QUERY_SCOREBOARD } from "../../graphql/scoreboard.queries";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
//currentUser: selectCurrentUser
|
//currentUser: selectCurrentUser
|
||||||
@@ -26,7 +26,7 @@ export function ScoreboardDisplayComponent({ bodyshop }) {
|
|||||||
start: dayjs().startOf("month"),
|
start: dayjs().startOf("month"),
|
||||||
end: dayjs().endOf("month")
|
end: dayjs().endOf("month")
|
||||||
},
|
},
|
||||||
pollInterval: 60000
|
pollInterval: 60000*5
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data } = scoreboardSubscription;
|
const { data } = scoreboardSubscription;
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import { useQuery } from "@apollo/client";
|
import { useQuery } from "@apollo/client";
|
||||||
import { Col, Row } from "antd";
|
import { Col, Row } from "antd";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import dayjs from "../../utils/day";
|
|
||||||
import React, { useMemo } from "react";
|
import React, { useMemo } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { QUERY_TIME_TICKETS_IN_RANGE_SB } from "../../graphql/timetickets.queries";
|
import { QUERY_TIME_TICKETS_IN_RANGE_SB } from "../../graphql/timetickets.queries";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
|
import dayjs from "../../utils/day";
|
||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from "../alert/alert.component";
|
||||||
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
||||||
import * as Utils from "../scoreboard-targets-table/scoreboard-targets-table.util";
|
import * as Utils from "../scoreboard-targets-table/scoreboard-targets-table.util";
|
||||||
@@ -86,7 +86,7 @@ export function ScoreboardTimeTicketsStats({ bodyshop }) {
|
|||||||
},
|
},
|
||||||
fetchPolicy: "network-only",
|
fetchPolicy: "network-only",
|
||||||
nextFetchPolicy: "network-only",
|
nextFetchPolicy: "network-only",
|
||||||
pollInterval: 60000,
|
pollInterval: 60000*5,
|
||||||
skip: !fixedPeriods
|
skip: !fixedPeriods
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { useQuery } from "@apollo/client";
|
import { useQuery } from "@apollo/client";
|
||||||
import { Col, Row } from "antd";
|
import { Col, Row } from "antd";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import dayjs from "../../utils/day";
|
|
||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
import React, { useMemo } from "react";
|
import React, { useMemo } from "react";
|
||||||
import { useLocation } from "react-router-dom";
|
import { useLocation } from "react-router-dom";
|
||||||
import { QUERY_TIME_TICKETS_IN_RANGE_SB } from "../../graphql/timetickets.queries";
|
import { QUERY_TIME_TICKETS_IN_RANGE_SB } from "../../graphql/timetickets.queries";
|
||||||
|
import dayjs from "../../utils/day";
|
||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from "../alert/alert.component";
|
||||||
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
||||||
import * as Utils from "../scoreboard-targets-table/scoreboard-targets-table.util";
|
import * as Utils from "../scoreboard-targets-table/scoreboard-targets-table.util";
|
||||||
@@ -68,7 +68,7 @@ export default function ScoreboardTimeTickets() {
|
|||||||
},
|
},
|
||||||
fetchPolicy: "network-only",
|
fetchPolicy: "network-only",
|
||||||
nextFetchPolicy: "network-only",
|
nextFetchPolicy: "network-only",
|
||||||
pollInterval: 60000,
|
pollInterval: 60000*5,
|
||||||
skip: !fixedPeriods
|
skip: !fixedPeriods
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,3 @@
|
|||||||
import { Button, Card, Space, Switch, Table } from "antd";
|
|
||||||
import queryString from "query-string";
|
|
||||||
import React, { useCallback, useEffect } from "react";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import { Link, useLocation, useNavigate } from "react-router-dom";
|
|
||||||
import { pageLimit } from "../../utils/config";
|
|
||||||
import dayjs from "../../utils/day";
|
|
||||||
import {
|
import {
|
||||||
CheckCircleFilled,
|
CheckCircleFilled,
|
||||||
CheckCircleOutlined,
|
CheckCircleOutlined,
|
||||||
@@ -15,9 +8,16 @@ import {
|
|||||||
PlusCircleFilled,
|
PlusCircleFilled,
|
||||||
SyncOutlined
|
SyncOutlined
|
||||||
} from "@ant-design/icons";
|
} from "@ant-design/icons";
|
||||||
import { DateFormatter, DateTimeFormatter } from "../../utils/DateFormatter.jsx";
|
import { Button, Card, Space, Switch, Table } from "antd";
|
||||||
|
import queryString from "query-string";
|
||||||
|
import React, { useCallback, useEffect } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
|
import { Link, useLocation, useNavigate } from "react-router-dom";
|
||||||
import { setModalContext } from "../../redux/modals/modals.actions";
|
import { setModalContext } from "../../redux/modals/modals.actions";
|
||||||
|
import { pageLimit } from "../../utils/config";
|
||||||
|
import { DateFormatter, DateTimeFormatter } from "../../utils/DateFormatter.jsx";
|
||||||
|
import dayjs from "../../utils/day";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Task List Component
|
* Task List Component
|
||||||
@@ -140,6 +140,17 @@ function TaskListComponent({
|
|||||||
render: (text, record) => <DateTimeFormatter>{record.created_at}</DateTimeFormatter>
|
render: (text, record) => <DateTimeFormatter>{record.created_at}</DateTimeFormatter>
|
||||||
});
|
});
|
||||||
|
|
||||||
|
columns.push({
|
||||||
|
title: t("tasks.fields.created_by"),
|
||||||
|
dataIndex: "created_by",
|
||||||
|
key: "created_by",
|
||||||
|
width: "8%",
|
||||||
|
defaultSortOrder: "descend",
|
||||||
|
sorter: true,
|
||||||
|
sortOrder: sortcolumn === "created_by" && sortorder,
|
||||||
|
render: (text, record) => record.created_by
|
||||||
|
});
|
||||||
|
|
||||||
if (!onlyMine) {
|
if (!onlyMine) {
|
||||||
columns.push({
|
columns.push({
|
||||||
title: t("tasks.fields.assigned_to"),
|
title: t("tasks.fields.assigned_to"),
|
||||||
@@ -155,65 +166,70 @@ function TaskListComponent({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showRo) {
|
columns.push({
|
||||||
columns.push({
|
title: t("tasks.fields.related_items"),
|
||||||
title: t("tasks.fields.job.ro_number"),
|
key: "related_items",
|
||||||
dataIndex: ["job", "ro_number"],
|
width: "12%",
|
||||||
key: "job.ro_number",
|
render: (text, record) => {
|
||||||
width: "8%",
|
const items = [];
|
||||||
render: (text, record) =>
|
|
||||||
record.job ? (
|
// Job
|
||||||
<Link to={`/manage/jobs/${record.job.id}?tab=tasks`}>{record.job.ro_number || t("general.labels.na")}</Link>
|
if (showRo && record.job) {
|
||||||
) : (
|
items.push(
|
||||||
t("general.labels.na")
|
<Link key="job" to={`/manage/jobs/${record.job.id}?tab=tasks`}>
|
||||||
)
|
{t("tasks.fields.job.ro_number")}: {record.job.ro_number}
|
||||||
});
|
</Link>
|
||||||
}
|
);
|
||||||
|
}
|
||||||
|
if (showRo && !record.job) {
|
||||||
|
items.push(`${t("tasks.fields.job.ro_number")}: ${t("general.labels.na")}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Jobline
|
||||||
|
if (record.jobline?.line_desc) {
|
||||||
|
items.push(
|
||||||
|
<span key="jobline">
|
||||||
|
{t("tasks.fields.jobline")}: {record.jobline.line_desc}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parts Order
|
||||||
|
if (record.parts_order) {
|
||||||
|
const { order_number, vendor } = record.parts_order;
|
||||||
|
const partsOrderText =
|
||||||
|
order_number && vendor?.name ? `${order_number} - ${vendor.name}` : t("general.labels.na");
|
||||||
|
items.push(
|
||||||
|
<Link
|
||||||
|
key="parts_order"
|
||||||
|
to={`/manage/jobs/${record.job.id}?partsorderid=${record.parts_order.id}&tab=partssublet`}
|
||||||
|
>
|
||||||
|
{t("tasks.fields.parts_order")}: {partsOrderText}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bill
|
||||||
|
if (record.bill) {
|
||||||
|
const { invoice_number, vendor } = record.bill;
|
||||||
|
const billText = invoice_number && vendor?.name ? `${invoice_number} - ${vendor.name}` : t("general.labels.na");
|
||||||
|
items.push(
|
||||||
|
<Link key="bill" to={`/manage/jobs/${record.job.id}?billid=${record.bill.id}&tab=partssublet`}>
|
||||||
|
{t("tasks.fields.bill")}: {billText}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return items.length > 0 ? <Space direction="vertical">{items}</Space> : null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
columns.push(
|
columns.push(
|
||||||
{
|
|
||||||
title: t("tasks.fields.jobline"),
|
|
||||||
dataIndex: ["jobline", "id"],
|
|
||||||
key: "jobline.id",
|
|
||||||
width: "8%",
|
|
||||||
render: (text, record) => record?.jobline?.line_desc || ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t("tasks.fields.parts_order"),
|
|
||||||
dataIndex: ["parts_order", "id"],
|
|
||||||
key: "part_order.id",
|
|
||||||
width: "8%",
|
|
||||||
render: (text, record) =>
|
|
||||||
record.parts_order ? (
|
|
||||||
<Link to={`/manage/jobs/${record.job.id}?partsorderid=${record.parts_order.id}&tab=partssublet`}>
|
|
||||||
{record.parts_order.order_number && record.parts_order.vendor && record.parts_order.vendor.name
|
|
||||||
? `${record.parts_order.order_number} - ${record.parts_order.vendor.name}`
|
|
||||||
: t("general.labels.na")}
|
|
||||||
</Link>
|
|
||||||
) : (
|
|
||||||
""
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t("tasks.fields.bill"),
|
|
||||||
dataIndex: ["bill", "id"],
|
|
||||||
key: "bill.id",
|
|
||||||
width: "10%",
|
|
||||||
render: (text, record) =>
|
|
||||||
record.bill ? (
|
|
||||||
<Link to={`/manage/jobs/${record.job.id}?billid=${record.bill.id}&tab=partssublet`}>
|
|
||||||
{record.bill.invoice_number && record.bill.vendor && record.bill.vendor.name
|
|
||||||
? `${record.bill.invoice_number} - ${record.bill.vendor.name}`
|
|
||||||
: t("general.labels.na")}
|
|
||||||
</Link>
|
|
||||||
) : (
|
|
||||||
""
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: t("tasks.fields.title"),
|
title: t("tasks.fields.title"),
|
||||||
dataIndex: "title",
|
dataIndex: "title",
|
||||||
key: "title",
|
key: "title",
|
||||||
|
minWidth: "20%",
|
||||||
sorter: true,
|
sorter: true,
|
||||||
sortOrder: sortcolumn === "title" && sortorder
|
sortOrder: sortcolumn === "title" && sortorder
|
||||||
},
|
},
|
||||||
@@ -247,7 +263,7 @@ function TaskListComponent({
|
|||||||
{
|
{
|
||||||
title: t("tasks.fields.actions"),
|
title: t("tasks.fields.actions"),
|
||||||
key: "toggleCompleted",
|
key: "toggleCompleted",
|
||||||
width: "5%",
|
width: "8%",
|
||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
<Space direction="horizontal">
|
<Space direction="horizontal">
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ export function TimeTicketList({
|
|||||||
extra
|
extra
|
||||||
}) {
|
}) {
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
sortedInfo: {},
|
sortedInfo: { columnKey: 'date', order: 'descend' },
|
||||||
filteredInfo: { text: "" }
|
filteredInfo: { text: "" }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useMutation, useQuery } from "@apollo/client";
|
|
||||||
import { Button, Form, Modal, notification, Space } from "antd";
|
|
||||||
import { PageHeader } from "@ant-design/pro-layout";
|
import { PageHeader } from "@ant-design/pro-layout";
|
||||||
import dayjs from "../../utils/day";
|
import { useMutation, useQuery } from "@apollo/client";
|
||||||
|
import { useSplitTreatments } from "@splitsoftware/splitio-react";
|
||||||
|
import { Button, Form, Modal, notification, Space } from "antd";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
@@ -11,9 +11,9 @@ import { INSERT_NEW_TIME_TICKET, UPDATE_TIME_TICKET } from "../../graphql/timeti
|
|||||||
import { toggleModalVisible } from "../../redux/modals/modals.actions";
|
import { toggleModalVisible } from "../../redux/modals/modals.actions";
|
||||||
import { selectTimeTicket } from "../../redux/modals/modals.selectors";
|
import { selectTimeTicket } from "../../redux/modals/modals.selectors";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import TimeTicketModalComponent from "./time-ticket-modal.component";
|
import dayjs from "../../utils/day";
|
||||||
import TimeTicketsCommitToggleComponent from "../time-tickets-commit-toggle/time-tickets-commit-toggle.component";
|
import TimeTicketsCommitToggleComponent from "../time-tickets-commit-toggle/time-tickets-commit-toggle.component";
|
||||||
import { useSplitTreatments } from "@splitsoftware/splitio-react";
|
import TimeTicketModalComponent from "./time-ticket-modal.component";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
timeTicketModal: selectTimeTicket,
|
timeTicketModal: selectTimeTicket,
|
||||||
@@ -87,7 +87,7 @@ export function TimeTicketModalContainer({ timeTicketModal, toggleModalVisible,
|
|||||||
if (enterAgain) {
|
if (enterAgain) {
|
||||||
//Capture the existing information and repopulate it.
|
//Capture the existing information and repopulate it.
|
||||||
|
|
||||||
const prev = form.getFieldsValue(["date", "employeeid"]);
|
const prev = form.getFieldsValue(["date", "employeeid", "flat_rate"]);
|
||||||
|
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useMutation } from "@apollo/client";
|
import { useMutation } from "@apollo/client";
|
||||||
import { Button, notification } from "antd";
|
import { Button, notification } from "antd";
|
||||||
import day from "../../utils/day";
|
import dayjs from "../../utils/day";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
@@ -29,7 +29,7 @@ export function TimeTicketsCommit({ bodyshop, currentUser, timeticket, disabled,
|
|||||||
? { commited_by: null, committed_at: null }
|
? { commited_by: null, committed_at: null }
|
||||||
: {
|
: {
|
||||||
commited_by: currentUser.email,
|
commited_by: currentUser.email,
|
||||||
committed_at: day()
|
committed_at: dayjs()
|
||||||
};
|
};
|
||||||
|
|
||||||
const result = await updateTimeTicket({
|
const result = await updateTimeTicket({
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useMutation } from "@apollo/client";
|
import { useMutation } from "@apollo/client";
|
||||||
import { Button, notification } from "antd";
|
import { Button, notification } from "antd";
|
||||||
import day from "../../utils/day";
|
import dayjs from "../../utils/day";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
@@ -34,7 +34,7 @@ export function TimeTicketsCommit({
|
|||||||
timeticketIds: timetickets.map((ticket) => ticket.id),
|
timeticketIds: timetickets.map((ticket) => ticket.id),
|
||||||
timeticket: {
|
timeticket: {
|
||||||
commited_by: currentUser.email,
|
commited_by: currentUser.email,
|
||||||
committed_at: day()
|
committed_at: dayjs()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
update(cache) {
|
update(cache) {
|
||||||
@@ -47,7 +47,7 @@ export function TimeTicketsCommit({
|
|||||||
return {
|
return {
|
||||||
...ticket,
|
...ticket,
|
||||||
commited_by: currentUser.email,
|
commited_by: currentUser.email,
|
||||||
committed_at: day()
|
committed_at: dayjs()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return ticket;
|
return ticket;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useApolloClient } from "@apollo/client";
|
import { useApolloClient } from "@apollo/client";
|
||||||
import { Button, notification } from "antd";
|
import { Button, notification } from "antd";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import day from "../../utils/day";
|
import dayjs from "../../utils/day";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
@@ -49,7 +49,7 @@ export function TtApproveButton({
|
|||||||
})),
|
})),
|
||||||
approvalIds: selectedTickets,
|
approvalIds: selectedTickets,
|
||||||
approvalUpdate: {
|
approvalUpdate: {
|
||||||
approved_at: day(),
|
approved_at: dayjs(),
|
||||||
approved_by: currentUser.email
|
approved_by: currentUser.email
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ export const QUERY_ALL_ACTIVE_APPOINTMENTS = gql`
|
|||||||
v_model_desc
|
v_model_desc
|
||||||
est_ct_fn
|
est_ct_fn
|
||||||
est_ct_ln
|
est_ct_ln
|
||||||
|
comment
|
||||||
labhrs: joblines_aggregate(where: { mod_lbr_ty: { _neq: "LAR" }, removed: { _eq: false } }) {
|
labhrs: joblines_aggregate(where: { mod_lbr_ty: { _neq: "LAR" }, removed: { _eq: false } }) {
|
||||||
aggregate {
|
aggregate {
|
||||||
sum {
|
sum {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { gql } from "@apollo/client";
|
|||||||
|
|
||||||
export const QUERY_TICKETS_BY_JOBID = gql`
|
export const QUERY_TICKETS_BY_JOBID = gql`
|
||||||
query QUERY_TICKETS_BY_JOBID($jobid: uuid!) {
|
query QUERY_TICKETS_BY_JOBID($jobid: uuid!) {
|
||||||
timetickets(where: { jobid: { _eq: $jobid } }, order_by: { date: desc_nulls_first }) {
|
timetickets(where: { jobid: { _eq: $jobid } }) {
|
||||||
actualhrs
|
actualhrs
|
||||||
cost_center
|
cost_center
|
||||||
ciecacode
|
ciecacode
|
||||||
@@ -26,7 +26,7 @@ export const QUERY_TICKETS_BY_JOBID = gql`
|
|||||||
|
|
||||||
export const QUERY_TIME_TICKETS_IN_RANGE = gql`
|
export const QUERY_TIME_TICKETS_IN_RANGE = gql`
|
||||||
query QUERY_TIME_TICKETS_IN_RANGE($start: date!, $end: date!) {
|
query QUERY_TIME_TICKETS_IN_RANGE($start: date!, $end: date!) {
|
||||||
timetickets(where: { date: { _gte: $start, _lte: $end } }, order_by: { date: desc_nulls_first }) {
|
timetickets(where: { date: { _gte: $start, _lte: $end } }) {
|
||||||
actualhrs
|
actualhrs
|
||||||
ciecacode
|
ciecacode
|
||||||
clockoff
|
clockoff
|
||||||
@@ -69,7 +69,6 @@ export const QUERY_TIME_TICKETS_TECHNICIAN_IN_RANGE = gql`
|
|||||||
) {
|
) {
|
||||||
timetickets(
|
timetickets(
|
||||||
where: { date: { _gte: $start, _lte: $end }, employeeid: { _eq: $employeeid } }
|
where: { date: { _gte: $start, _lte: $end }, employeeid: { _eq: $employeeid } }
|
||||||
order_by: { date: desc_nulls_first }
|
|
||||||
) {
|
) {
|
||||||
actualhrs
|
actualhrs
|
||||||
ciecacode
|
ciecacode
|
||||||
@@ -101,7 +100,6 @@ export const QUERY_TIME_TICKETS_TECHNICIAN_IN_RANGE = gql`
|
|||||||
}
|
}
|
||||||
fixedperiod: timetickets(
|
fixedperiod: timetickets(
|
||||||
where: { date: { _gte: $fixedStart, _lte: $fixedEnd }, employeeid: { _eq: $employeeid } }
|
where: { date: { _gte: $fixedStart, _lte: $fixedEnd }, employeeid: { _eq: $employeeid } }
|
||||||
order_by: { date: desc_nulls_first }
|
|
||||||
) {
|
) {
|
||||||
actualhrs
|
actualhrs
|
||||||
ciecacode
|
ciecacode
|
||||||
@@ -145,7 +143,6 @@ export const QUERY_TIME_TICKETS_IN_RANGE_SB = gql`
|
|||||||
) {
|
) {
|
||||||
timetickets(
|
timetickets(
|
||||||
where: { date: { _gte: $start, _lte: $end }, cost_center: { _neq: "timetickets.labels.shift" } }
|
where: { date: { _gte: $start, _lte: $end }, cost_center: { _neq: "timetickets.labels.shift" } }
|
||||||
order_by: { date: desc_nulls_first }
|
|
||||||
) {
|
) {
|
||||||
actualhrs
|
actualhrs
|
||||||
ciecacode
|
ciecacode
|
||||||
@@ -180,7 +177,6 @@ export const QUERY_TIME_TICKETS_IN_RANGE_SB = gql`
|
|||||||
}
|
}
|
||||||
fixedperiod: timetickets(
|
fixedperiod: timetickets(
|
||||||
where: { date: { _gte: $fixedStart, _lte: $fixedEnd }, cost_center: { _neq: "timetickets.labels.shift" } }
|
where: { date: { _gte: $fixedStart, _lte: $fixedEnd }, cost_center: { _neq: "timetickets.labels.shift" } }
|
||||||
order_by: { date: desc_nulls_first }
|
|
||||||
) {
|
) {
|
||||||
actualhrs
|
actualhrs
|
||||||
ciecacode
|
ciecacode
|
||||||
@@ -335,7 +331,6 @@ export const UPDATE_TIME_TICKETS = gql`
|
|||||||
export const QUERY_ACTIVE_TIME_TICKETS = gql`
|
export const QUERY_ACTIVE_TIME_TICKETS = gql`
|
||||||
query QUERY_ACTIVE_TIME_TICKETS($employeeId: uuid) {
|
query QUERY_ACTIVE_TIME_TICKETS($employeeId: uuid) {
|
||||||
timetickets(
|
timetickets(
|
||||||
order_by: { date: desc_nulls_first }
|
|
||||||
where: {
|
where: {
|
||||||
_and: {
|
_and: {
|
||||||
clockoff: { _is_null: true }
|
clockoff: { _is_null: true }
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
|
|||||||
...logs,
|
...logs,
|
||||||
{
|
{
|
||||||
timestamp: new Date(),
|
timestamp: new Date(),
|
||||||
level: "WARNING",
|
level: "WARN",
|
||||||
message: "Reconnected to CDK Export Service"
|
message: "Reconnected to CDK Export Service"
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
@@ -123,10 +123,9 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
|
|||||||
socket.emit("set-log-level", value);
|
socket.emit("set-log-level", value);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Select.Option key="TRACE">TRACE</Select.Option>
|
|
||||||
<Select.Option key="DEBUG">DEBUG</Select.Option>
|
<Select.Option key="DEBUG">DEBUG</Select.Option>
|
||||||
<Select.Option key="INFO">INFO</Select.Option>
|
<Select.Option key="INFO">INFO</Select.Option>
|
||||||
<Select.Option key="WARNING">WARNING</Select.Option>
|
<Select.Option key="WARN">WARN</Select.Option>
|
||||||
<Select.Option key="ERROR">ERROR</Select.Option>
|
<Select.Option key="ERROR">ERROR</Select.Option>
|
||||||
</Select>
|
</Select>
|
||||||
<Button onClick={() => setLogs([])}>Clear Logs</Button>
|
<Button onClick={() => setLogs([])}>Clear Logs</Button>
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, inse
|
|||||||
...logs,
|
...logs,
|
||||||
{
|
{
|
||||||
timestamp: new Date(),
|
timestamp: new Date(),
|
||||||
level: "WARNING",
|
level: "warn",
|
||||||
message: "Reconnected to CDK Export Service"
|
message: "Reconnected to CDK Export Service"
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
@@ -173,10 +173,9 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, inse
|
|||||||
socket.emit("set-log-level", value);
|
socket.emit("set-log-level", value);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Select.Option key="TRACE">TRACE</Select.Option>
|
|
||||||
<Select.Option key="DEBUG">DEBUG</Select.Option>
|
<Select.Option key="DEBUG">DEBUG</Select.Option>
|
||||||
<Select.Option key="INFO">INFO</Select.Option>
|
<Select.Option key="INFO">INFO</Select.Option>
|
||||||
<Select.Option key="WARNING">WARNING</Select.Option>
|
<Select.Option key="WARN">WARN</Select.Option>
|
||||||
<Select.Option key="ERROR">ERROR</Select.Option>
|
<Select.Option key="ERROR">ERROR</Select.Option>
|
||||||
</Select>
|
</Select>
|
||||||
<Button onClick={() => setLogs([])}>Clear Logs</Button>
|
<Button onClick={() => setLogs([])}>Clear Logs</Button>
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import {
|
|||||||
} from "../../firebase/firebase.utils";
|
} from "../../firebase/firebase.utils";
|
||||||
import { QUERY_EULA } from "../../graphql/bodyshop.queries";
|
import { QUERY_EULA } from "../../graphql/bodyshop.queries";
|
||||||
import client from "../../utils/GraphQLClient";
|
import client from "../../utils/GraphQLClient";
|
||||||
import day from "../../utils/day";
|
import dayjs from "../../utils/day";
|
||||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||||
import {
|
import {
|
||||||
checkInstanceId,
|
checkInstanceId,
|
||||||
@@ -96,7 +96,7 @@ export function* isUserAuthenticated() {
|
|||||||
const eulaQuery = yield client.query({
|
const eulaQuery = yield client.query({
|
||||||
query: QUERY_EULA,
|
query: QUERY_EULA,
|
||||||
variables: {
|
variables: {
|
||||||
now: day()
|
now: dayjs()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -314,8 +314,7 @@ export function* SetAuthLevelFromShopDetails({ payload }) {
|
|||||||
try {
|
try {
|
||||||
const userEmail = yield select((state) => state.user.currentUser.email);
|
const userEmail = yield select((state) => state.user.currentUser.email);
|
||||||
try {
|
try {
|
||||||
console.log("Setting shop timezone.");
|
dayjs.tz.setDefault(payload.timezone);
|
||||||
day.tz.setDefault(payload.timezone);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3187,6 +3187,7 @@
|
|||||||
"billid": "Bill",
|
"billid": "Bill",
|
||||||
"completed": "Completed",
|
"completed": "Completed",
|
||||||
"created_at": "Created At",
|
"created_at": "Created At",
|
||||||
|
"created_by": "Created By",
|
||||||
"description": "Description",
|
"description": "Description",
|
||||||
"due_date": "Due Date",
|
"due_date": "Due Date",
|
||||||
"job": {
|
"job": {
|
||||||
@@ -3203,6 +3204,7 @@
|
|||||||
"medium": "Medium"
|
"medium": "Medium"
|
||||||
},
|
},
|
||||||
"priority": "Priority",
|
"priority": "Priority",
|
||||||
|
"related_items": "Related Items",
|
||||||
"remind_at": "Remind At",
|
"remind_at": "Remind At",
|
||||||
"title": "Title"
|
"title": "Title"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3187,6 +3187,7 @@
|
|||||||
"billid": "",
|
"billid": "",
|
||||||
"completed": "",
|
"completed": "",
|
||||||
"created_at": "",
|
"created_at": "",
|
||||||
|
"created_by": "",
|
||||||
"description": "",
|
"description": "",
|
||||||
"due_date": "",
|
"due_date": "",
|
||||||
"job": {
|
"job": {
|
||||||
@@ -3203,6 +3204,7 @@
|
|||||||
"medium": ""
|
"medium": ""
|
||||||
},
|
},
|
||||||
"priority": "",
|
"priority": "",
|
||||||
|
"related_items": "",
|
||||||
"remind_at": "",
|
"remind_at": "",
|
||||||
"title": ""
|
"title": ""
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3187,6 +3187,7 @@
|
|||||||
"billid": "",
|
"billid": "",
|
||||||
"completed": "",
|
"completed": "",
|
||||||
"created_at": "",
|
"created_at": "",
|
||||||
|
"created_by": "",
|
||||||
"description": "",
|
"description": "",
|
||||||
"due_date": "",
|
"due_date": "",
|
||||||
"job": {
|
"job": {
|
||||||
@@ -3203,6 +3204,7 @@
|
|||||||
"medium": ""
|
"medium": ""
|
||||||
},
|
},
|
||||||
"priority": "",
|
"priority": "",
|
||||||
|
"related_items": "",
|
||||||
"remind_at": "",
|
"remind_at": "",
|
||||||
"title": ""
|
"title": ""
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
|
import "dayjs/locale/en";
|
||||||
import dayjsBusinessDays from "dayjs-business-days2";
|
import dayjsBusinessDays from "dayjs-business-days2";
|
||||||
import isSameOrAfter from "dayjs/plugin/isSameOrAfter";
|
import isSameOrAfter from "dayjs/plugin/isSameOrAfter";
|
||||||
import updateLocale from "dayjs/plugin/updateLocale";
|
import updateLocale from "dayjs/plugin/updateLocale";
|
||||||
@@ -64,4 +65,6 @@ dayjs.extend(minMax);
|
|||||||
dayjs.extend(isBetween);
|
dayjs.extend(isBetween);
|
||||||
dayjs.extend(dayjsBusinessDays);
|
dayjs.extend(dayjsBusinessDays);
|
||||||
|
|
||||||
|
dayjs.locale("en");
|
||||||
|
|
||||||
export default dayjs;
|
export default dayjs;
|
||||||
|
|||||||
@@ -69,7 +69,6 @@
|
|||||||
delete_permissions:
|
delete_permissions:
|
||||||
- role: user
|
- role: user
|
||||||
permission:
|
permission:
|
||||||
backend_only: false
|
|
||||||
filter:
|
filter:
|
||||||
jobline:
|
jobline:
|
||||||
job:
|
job:
|
||||||
@@ -180,7 +179,6 @@
|
|||||||
delete_permissions:
|
delete_permissions:
|
||||||
- role: user
|
- role: user
|
||||||
permission:
|
permission:
|
||||||
backend_only: false
|
|
||||||
filter:
|
filter:
|
||||||
bodyshop:
|
bodyshop:
|
||||||
associations:
|
associations:
|
||||||
@@ -387,7 +385,6 @@
|
|||||||
delete_permissions:
|
delete_permissions:
|
||||||
- role: user
|
- role: user
|
||||||
permission:
|
permission:
|
||||||
backend_only: false
|
|
||||||
filter:
|
filter:
|
||||||
bodyshop:
|
bodyshop:
|
||||||
associations:
|
associations:
|
||||||
@@ -504,7 +501,6 @@
|
|||||||
delete_permissions:
|
delete_permissions:
|
||||||
- role: user
|
- role: user
|
||||||
permission:
|
permission:
|
||||||
backend_only: false
|
|
||||||
filter:
|
filter:
|
||||||
bill:
|
bill:
|
||||||
job:
|
job:
|
||||||
@@ -671,7 +667,6 @@
|
|||||||
delete_permissions:
|
delete_permissions:
|
||||||
- role: user
|
- role: user
|
||||||
permission:
|
permission:
|
||||||
backend_only: false
|
|
||||||
filter:
|
filter:
|
||||||
_and:
|
_and:
|
||||||
- job:
|
- job:
|
||||||
@@ -1285,7 +1280,6 @@
|
|||||||
delete_permissions:
|
delete_permissions:
|
||||||
- role: user
|
- role: user
|
||||||
permission:
|
permission:
|
||||||
backend_only: false
|
|
||||||
filter:
|
filter:
|
||||||
courtesycar:
|
courtesycar:
|
||||||
bodyshop:
|
bodyshop:
|
||||||
@@ -1526,7 +1520,6 @@
|
|||||||
delete_permissions:
|
delete_permissions:
|
||||||
- role: user
|
- role: user
|
||||||
permission:
|
permission:
|
||||||
backend_only: false
|
|
||||||
filter:
|
filter:
|
||||||
bodyshop:
|
bodyshop:
|
||||||
associations:
|
associations:
|
||||||
@@ -1786,7 +1779,6 @@
|
|||||||
delete_permissions:
|
delete_permissions:
|
||||||
- role: user
|
- role: user
|
||||||
permission:
|
permission:
|
||||||
backend_only: false
|
|
||||||
filter:
|
filter:
|
||||||
bodyshop:
|
bodyshop:
|
||||||
associations:
|
associations:
|
||||||
@@ -1920,7 +1912,6 @@
|
|||||||
delete_permissions:
|
delete_permissions:
|
||||||
- role: user
|
- role: user
|
||||||
permission:
|
permission:
|
||||||
backend_only: false
|
|
||||||
filter:
|
filter:
|
||||||
_or:
|
_or:
|
||||||
- job:
|
- job:
|
||||||
@@ -2105,7 +2096,6 @@
|
|||||||
delete_permissions:
|
delete_permissions:
|
||||||
- role: user
|
- role: user
|
||||||
permission:
|
permission:
|
||||||
backend_only: false
|
|
||||||
filter:
|
filter:
|
||||||
employee_team:
|
employee_team:
|
||||||
bodyshop:
|
bodyshop:
|
||||||
@@ -2268,7 +2258,6 @@
|
|||||||
delete_permissions:
|
delete_permissions:
|
||||||
- role: user
|
- role: user
|
||||||
permission:
|
permission:
|
||||||
backend_only: false
|
|
||||||
filter:
|
filter:
|
||||||
employee:
|
employee:
|
||||||
bodyshop:
|
bodyshop:
|
||||||
@@ -2449,7 +2438,6 @@
|
|||||||
delete_permissions:
|
delete_permissions:
|
||||||
- role: user
|
- role: user
|
||||||
permission:
|
permission:
|
||||||
backend_only: false
|
|
||||||
filter:
|
filter:
|
||||||
bodyshop:
|
bodyshop:
|
||||||
associations:
|
associations:
|
||||||
@@ -2696,7 +2684,6 @@
|
|||||||
delete_permissions:
|
delete_permissions:
|
||||||
- role: user
|
- role: user
|
||||||
permission:
|
permission:
|
||||||
backend_only: false
|
|
||||||
filter:
|
filter:
|
||||||
bodyshop:
|
bodyshop:
|
||||||
associations:
|
associations:
|
||||||
@@ -2808,7 +2795,6 @@
|
|||||||
delete_permissions:
|
delete_permissions:
|
||||||
- role: user
|
- role: user
|
||||||
permission:
|
permission:
|
||||||
backend_only: false
|
|
||||||
filter:
|
filter:
|
||||||
conversation:
|
conversation:
|
||||||
bodyshop:
|
bodyshop:
|
||||||
@@ -3123,7 +3109,6 @@
|
|||||||
delete_permissions:
|
delete_permissions:
|
||||||
- role: user
|
- role: user
|
||||||
permission:
|
permission:
|
||||||
backend_only: false
|
|
||||||
filter:
|
filter:
|
||||||
job:
|
job:
|
||||||
bodyshop:
|
bodyshop:
|
||||||
@@ -4232,7 +4217,6 @@
|
|||||||
delete_permissions:
|
delete_permissions:
|
||||||
- role: user
|
- role: user
|
||||||
permission:
|
permission:
|
||||||
backend_only: false
|
|
||||||
filter:
|
filter:
|
||||||
bodyshop:
|
bodyshop:
|
||||||
associations:
|
associations:
|
||||||
@@ -4248,41 +4232,41 @@
|
|||||||
enable_manual: false
|
enable_manual: false
|
||||||
update:
|
update:
|
||||||
columns:
|
columns:
|
||||||
- clm_no
|
|
||||||
- v_make_desc
|
|
||||||
- date_next_contact
|
|
||||||
- status
|
|
||||||
- employee_csr
|
|
||||||
- employee_prep
|
- employee_prep
|
||||||
- clm_total
|
- clm_total
|
||||||
- suspended
|
- suspended
|
||||||
- employee_body
|
- employee_body
|
||||||
- ro_number
|
- ro_number
|
||||||
- actual_in
|
|
||||||
- ownr_co_nm
|
- ownr_co_nm
|
||||||
- v_model_yr
|
|
||||||
- comment
|
|
||||||
- job_totals
|
|
||||||
- v_vin
|
- v_vin
|
||||||
- ownr_fn
|
|
||||||
- scheduled_completion
|
- scheduled_completion
|
||||||
- special_coverage_policy
|
- special_coverage_policy
|
||||||
- v_color
|
|
||||||
- ca_gst_registrant
|
|
||||||
- scheduled_delivery
|
- scheduled_delivery
|
||||||
- actual_delivery
|
- actual_delivery
|
||||||
- actual_completion
|
- actual_completion
|
||||||
- kanbanparent
|
- kanbanparent
|
||||||
- est_ct_fn
|
- est_ct_fn
|
||||||
|
- alt_transport
|
||||||
|
- v_model_desc
|
||||||
|
- clm_no
|
||||||
|
- v_make_desc
|
||||||
|
- date_next_contact
|
||||||
|
- status
|
||||||
|
- employee_csr
|
||||||
|
- actual_in
|
||||||
|
- v_model_yr
|
||||||
|
- comment
|
||||||
|
- job_totals
|
||||||
|
- ownr_fn
|
||||||
|
- v_color
|
||||||
|
- ca_gst_registrant
|
||||||
- employee_refinish
|
- employee_refinish
|
||||||
- ownr_ph1
|
- ownr_ph1
|
||||||
- date_last_contacted
|
- date_last_contacted
|
||||||
- alt_transport
|
|
||||||
- inproduction
|
- inproduction
|
||||||
- est_ct_ln
|
- est_ct_ln
|
||||||
- production_vars
|
- production_vars
|
||||||
- category
|
- category
|
||||||
- v_model_desc
|
|
||||||
- date_invoiced
|
- date_invoiced
|
||||||
- est_co_nm
|
- est_co_nm
|
||||||
- ownr_ln
|
- ownr_ln
|
||||||
@@ -4295,6 +4279,12 @@
|
|||||||
- name: event-secret
|
- name: event-secret
|
||||||
value_from_env: EVENT_SECRET
|
value_from_env: EVENT_SECRET
|
||||||
request_transform:
|
request_transform:
|
||||||
|
body:
|
||||||
|
action: transform
|
||||||
|
template: |-
|
||||||
|
{
|
||||||
|
"data": {{$body?.event?.data?.new}}
|
||||||
|
}
|
||||||
method: POST
|
method: POST
|
||||||
query_params: {}
|
query_params: {}
|
||||||
template_engine: Kriti
|
template_engine: Kriti
|
||||||
@@ -4496,7 +4486,6 @@
|
|||||||
delete_permissions:
|
delete_permissions:
|
||||||
- role: user
|
- role: user
|
||||||
permission:
|
permission:
|
||||||
backend_only: false
|
|
||||||
filter:
|
filter:
|
||||||
conversation:
|
conversation:
|
||||||
bodyshop:
|
bodyshop:
|
||||||
@@ -4670,7 +4659,6 @@
|
|||||||
delete_permissions:
|
delete_permissions:
|
||||||
- role: user
|
- role: user
|
||||||
permission:
|
permission:
|
||||||
backend_only: false
|
|
||||||
filter:
|
filter:
|
||||||
job:
|
job:
|
||||||
bodyshop:
|
bodyshop:
|
||||||
@@ -4805,7 +4793,6 @@
|
|||||||
delete_permissions:
|
delete_permissions:
|
||||||
- role: user
|
- role: user
|
||||||
permission:
|
permission:
|
||||||
backend_only: false
|
|
||||||
filter:
|
filter:
|
||||||
bodyshop:
|
bodyshop:
|
||||||
associations:
|
associations:
|
||||||
@@ -5110,7 +5097,6 @@
|
|||||||
delete_permissions:
|
delete_permissions:
|
||||||
- role: user
|
- role: user
|
||||||
permission:
|
permission:
|
||||||
backend_only: false
|
|
||||||
filter:
|
filter:
|
||||||
parts_order:
|
parts_order:
|
||||||
job:
|
job:
|
||||||
@@ -5243,7 +5229,6 @@
|
|||||||
delete_permissions:
|
delete_permissions:
|
||||||
- role: user
|
- role: user
|
||||||
permission:
|
permission:
|
||||||
backend_only: false
|
|
||||||
filter:
|
filter:
|
||||||
job:
|
job:
|
||||||
bodyshop:
|
bodyshop:
|
||||||
@@ -5419,7 +5404,6 @@
|
|||||||
delete_permissions:
|
delete_permissions:
|
||||||
- role: user
|
- role: user
|
||||||
permission:
|
permission:
|
||||||
backend_only: false
|
|
||||||
filter:
|
filter:
|
||||||
job:
|
job:
|
||||||
bodyshop:
|
bodyshop:
|
||||||
@@ -5559,7 +5543,6 @@
|
|||||||
delete_permissions:
|
delete_permissions:
|
||||||
- role: user
|
- role: user
|
||||||
permission:
|
permission:
|
||||||
backend_only: false
|
|
||||||
filter:
|
filter:
|
||||||
bodyshop:
|
bodyshop:
|
||||||
associations:
|
associations:
|
||||||
@@ -5670,7 +5653,6 @@
|
|||||||
delete_permissions:
|
delete_permissions:
|
||||||
- role: user
|
- role: user
|
||||||
permission:
|
permission:
|
||||||
backend_only: false
|
|
||||||
filter:
|
filter:
|
||||||
_or:
|
_or:
|
||||||
- parentjob_rel:
|
- parentjob_rel:
|
||||||
@@ -5760,7 +5742,6 @@
|
|||||||
delete_permissions:
|
delete_permissions:
|
||||||
- role: user
|
- role: user
|
||||||
permission:
|
permission:
|
||||||
backend_only: false
|
|
||||||
filter:
|
filter:
|
||||||
job:
|
job:
|
||||||
bodyshop:
|
bodyshop:
|
||||||
@@ -6045,7 +6026,6 @@
|
|||||||
delete_permissions:
|
delete_permissions:
|
||||||
- role: user
|
- role: user
|
||||||
permission:
|
permission:
|
||||||
backend_only: false
|
|
||||||
filter:
|
filter:
|
||||||
bodyshop:
|
bodyshop:
|
||||||
associations:
|
associations:
|
||||||
@@ -6541,7 +6521,6 @@
|
|||||||
delete_permissions:
|
delete_permissions:
|
||||||
- role: user
|
- role: user
|
||||||
permission:
|
permission:
|
||||||
backend_only: false
|
|
||||||
filter:
|
filter:
|
||||||
bodyshop:
|
bodyshop:
|
||||||
associations:
|
associations:
|
||||||
@@ -6698,7 +6677,6 @@
|
|||||||
delete_permissions:
|
delete_permissions:
|
||||||
- role: user
|
- role: user
|
||||||
permission:
|
permission:
|
||||||
backend_only: false
|
|
||||||
filter:
|
filter:
|
||||||
bodyshop:
|
bodyshop:
|
||||||
associations:
|
associations:
|
||||||
|
|||||||
28
server.js
28
server.js
@@ -153,18 +153,13 @@ const connectToRedisCluster = async () => {
|
|||||||
} else {
|
} else {
|
||||||
// Use the Dockerized Redis cluster in development
|
// Use the Dockerized Redis cluster in development
|
||||||
if (isEmpty(process.env?.REDIS_URL) || !isString(process.env?.REDIS_URL)) {
|
if (isEmpty(process.env?.REDIS_URL) || !isString(process.env?.REDIS_URL)) {
|
||||||
logger.log(`[${process.env.NODE_ENV}] No or Malformed REDIS_URL present.`, "ERROR", "redis", "api");
|
logger.log(`No or Malformed REDIS_URL present.`, "ERROR", "redis", "api");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
redisServers = JSON.parse(process.env.REDIS_URL);
|
redisServers = JSON.parse(process.env.REDIS_URL);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.log(
|
logger.log(`Failed to parse REDIS_URL: ${error.message}. Exiting...`, "ERROR", "redis", "api");
|
||||||
`[${process.env.NODE_ENV}] Failed to parse REDIS_URL: ${error.message}. Exiting...`,
|
|
||||||
"ERROR",
|
|
||||||
"redis",
|
|
||||||
"api"
|
|
||||||
);
|
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -172,12 +167,7 @@ const connectToRedisCluster = async () => {
|
|||||||
const clusterRetryStrategy = (times) => {
|
const clusterRetryStrategy = (times) => {
|
||||||
const delay =
|
const delay =
|
||||||
Math.min(CLUSTER_RETRY_BASE_DELAY + times * 50, CLUSTER_RETRY_MAX_DELAY) + Math.random() * CLUSTER_RETRY_JITTER;
|
Math.min(CLUSTER_RETRY_BASE_DELAY + times * 50, CLUSTER_RETRY_MAX_DELAY) + Math.random() * CLUSTER_RETRY_JITTER;
|
||||||
logger.log(
|
logger.log(`Redis cluster not yet ready. Retrying in ${delay.toFixed(2)}ms`, "WARN", "redis", "api");
|
||||||
`[${process.env.NODE_ENV}] Redis cluster not yet ready. Retrying in ${delay.toFixed(2)}ms`,
|
|
||||||
"WARN",
|
|
||||||
"redis",
|
|
||||||
"api"
|
|
||||||
);
|
|
||||||
return delay;
|
return delay;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -194,12 +184,12 @@ const connectToRedisCluster = async () => {
|
|||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
redisCluster.on("ready", () => {
|
redisCluster.on("ready", () => {
|
||||||
logger.log(`[${process.env.NODE_ENV}] Redis cluster connection established.`, "INFO", "redis", "api");
|
logger.log(`Redis cluster connection established.`, "INFO", "redis", "api");
|
||||||
resolve(redisCluster);
|
resolve(redisCluster);
|
||||||
});
|
});
|
||||||
|
|
||||||
redisCluster.on("error", (err) => {
|
redisCluster.on("error", (err) => {
|
||||||
logger.log(`[${process.env.NODE_ENV}] Redis cluster connection failed: ${err.message}`, "ERROR", "redis", "api");
|
logger.log(`Redis cluster connection failed: ${err.message}`, "ERROR", "redis", "api");
|
||||||
reject(err);
|
reject(err);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -215,7 +205,7 @@ const applySocketIO = async ({ server, app }) => {
|
|||||||
|
|
||||||
// Handle errors
|
// Handle errors
|
||||||
redisCluster.on("error", (err) => {
|
redisCluster.on("error", (err) => {
|
||||||
logger.log(`[${process.env.NODE_ENV}] Redis ERROR`, "ERROR", "redis", "api");
|
logger.log(`Redis ERROR`, "ERROR", "redis", "api");
|
||||||
});
|
});
|
||||||
|
|
||||||
const pubClient = redisCluster;
|
const pubClient = redisCluster;
|
||||||
@@ -249,7 +239,7 @@ const applySocketIO = async ({ server, app }) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (isString(process.env.REDIS_ADMIN_PASS) && !isEmpty(process.env.REDIS_ADMIN_PASS)) {
|
if (isString(process.env.REDIS_ADMIN_PASS) && !isEmpty(process.env.REDIS_ADMIN_PASS)) {
|
||||||
logger.log(`[${process.env.NODE_ENV}] Initializing Redis Admin UI....`, "INFO", "redis", "api");
|
logger.log(`Initializing Redis Admin UI....`, "INFO", "redis", "api");
|
||||||
instrument(ioRedis, {
|
instrument(ioRedis, {
|
||||||
auth: {
|
auth: {
|
||||||
type: "basic",
|
type: "basic",
|
||||||
@@ -312,9 +302,9 @@ const main = async () => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await server.listen(port);
|
await server.listen(port);
|
||||||
logger.log(`[${process.env.NODE_ENV}] Server started on port ${port}`, "INFO", "api");
|
logger.log(`Server started on port ${port}`, "INFO", "api");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.log(`[${process.env.NODE_ENV}] Server failed to start on port ${port}`, "ERROR", "api", error);
|
logger.log(`Server failed to start on port ${port}`, "ERROR", "api", error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ axios.interceptors.request.use((x) => {
|
|||||||
} | ${JSON.stringify(x.data)} | ${JSON.stringify(headers)}`;
|
} | ${JSON.stringify(x.data)} | ${JSON.stringify(headers)}`;
|
||||||
//console.log(printable);
|
//console.log(printable);
|
||||||
|
|
||||||
CdkBase.createJsonEvent(socket, "TRACE", `Raw Request: ${printable}`, x.data);
|
CdkBase.createJsonEvent(socket, "SILLY", `Raw Request: ${printable}`, x.data);
|
||||||
|
|
||||||
return x;
|
return x;
|
||||||
});
|
});
|
||||||
@@ -36,7 +36,7 @@ axios.interceptors.response.use((x) => {
|
|||||||
|
|
||||||
const printable = `${new Date()} | Response: ${x.status} | ${JSON.stringify(x.data)}`;
|
const printable = `${new Date()} | Response: ${x.status} | ${JSON.stringify(x.data)}`;
|
||||||
//console.log(printable);
|
//console.log(printable);
|
||||||
CdkBase.createJsonEvent(socket, "TRACE", `Raw Response: ${printable}`, x.data);
|
CdkBase.createJsonEvent(socket, "SILLY", `Raw Response: ${printable}`, x.data);
|
||||||
|
|
||||||
return x;
|
return x;
|
||||||
});
|
});
|
||||||
@@ -181,7 +181,7 @@ async function QueryBillData(socket, billids) {
|
|||||||
const result = await client
|
const result = await client
|
||||||
.setHeaders({ Authorization: `Bearer ${socket.handshake.auth.token}` })
|
.setHeaders({ Authorization: `Bearer ${socket.handshake.auth.token}` })
|
||||||
.request(queries.GET_PBS_AP_ALLOCATIONS, { billids: billids });
|
.request(queries.GET_PBS_AP_ALLOCATIONS, { billids: billids });
|
||||||
CdkBase.createLogEvent(socket, "TRACE", `Bill data query result ${JSON.stringify(result, null, 2)}`);
|
CdkBase.createLogEvent(socket, "SILLY", `Bill data query result ${JSON.stringify(result, null, 2)}`);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ axios.interceptors.request.use((x) => {
|
|||||||
} | ${JSON.stringify(x.data)} | ${JSON.stringify(headers)}`;
|
} | ${JSON.stringify(x.data)} | ${JSON.stringify(headers)}`;
|
||||||
//console.log(printable);
|
//console.log(printable);
|
||||||
|
|
||||||
CdkBase.createJsonEvent(socket, "TRACE", `Raw Request: ${printable}`, x.data);
|
CdkBase.createJsonEvent(socket, "SILLY", `Raw Request: ${printable}`, x.data);
|
||||||
|
|
||||||
return x;
|
return x;
|
||||||
});
|
});
|
||||||
@@ -38,7 +38,7 @@ axios.interceptors.response.use((x) => {
|
|||||||
|
|
||||||
const printable = `${new Date()} | Response: ${x.status} | ${JSON.stringify(x.data)}`;
|
const printable = `${new Date()} | Response: ${x.status} | ${JSON.stringify(x.data)}`;
|
||||||
//console.log(printable);
|
//console.log(printable);
|
||||||
CdkBase.createJsonEvent(socket, "TRACE", `Raw Response: ${printable}`, x.data);
|
CdkBase.createJsonEvent(socket, "SILLY", `Raw Response: ${printable}`, x.data);
|
||||||
|
|
||||||
return x;
|
return x;
|
||||||
});
|
});
|
||||||
@@ -118,7 +118,7 @@ async function CheckForErrors(socket, response) {
|
|||||||
CdkBase.createLogEvent(socket, "DEBUG", `Successful response from DMS. ${response.Message || ""}`);
|
CdkBase.createLogEvent(socket, "DEBUG", `Successful response from DMS. ${response.Message || ""}`);
|
||||||
} else {
|
} else {
|
||||||
CdkBase.createLogEvent(socket, "ERROR", `Error received from DMS: ${response.Message}`);
|
CdkBase.createLogEvent(socket, "ERROR", `Error received from DMS: ${response.Message}`);
|
||||||
CdkBase.createLogEvent(socket, "TRACE", `Error received from DMS: ${JSON.stringify(response)}`);
|
CdkBase.createLogEvent(socket, "SILLY", `Error received from DMS: ${JSON.stringify(response)}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,7 +130,7 @@ async function QueryJobData(socket, jobid) {
|
|||||||
const result = await client
|
const result = await client
|
||||||
.setHeaders({ Authorization: `Bearer ${socket.handshake.auth.token}` })
|
.setHeaders({ Authorization: `Bearer ${socket.handshake.auth.token}` })
|
||||||
.request(queries.QUERY_JOBS_FOR_PBS_EXPORT, { id: jobid });
|
.request(queries.QUERY_JOBS_FOR_PBS_EXPORT, { id: jobid });
|
||||||
CdkBase.createLogEvent(socket, "TRACE", `Job data query result ${JSON.stringify(result, null, 2)}`);
|
CdkBase.createLogEvent(socket, "SILLY", `Job data query result ${JSON.stringify(result, null, 2)}`);
|
||||||
return result.jobs_by_pk;
|
return result.jobs_by_pk;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -611,7 +611,7 @@ async function InsertFailedExportLog(socket, error) {
|
|||||||
bodyshopid: socket.JobData.bodyshop.id,
|
bodyshopid: socket.JobData.bodyshop.id,
|
||||||
jobid: socket.JobData.id,
|
jobid: socket.JobData.id,
|
||||||
successful: false,
|
successful: false,
|
||||||
message: [error],
|
message: JSON.stringify(error),
|
||||||
useremail: socket.user.email
|
useremail: socket.user.email
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ exports.default = function ({ bodyshop, jobs_by_pk, qbo = false, items, taxCodes
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (!account) {
|
if (!account) {
|
||||||
logger.log("qbxml-receivables-no-account", "warn", null, jobline.id, null);
|
logger.log("qbxml-receivables-no-account", "warn", null, jobline.id);
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`A matching account does not exist for the part allocation. Center: ${jobline.profitcenter_part}`
|
`A matching account does not exist for the part allocation. Center: ${jobline.profitcenter_part}`
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ exports.default = async (req, res) => {
|
|||||||
const BearerToken = req.BearerToken;
|
const BearerToken = req.BearerToken;
|
||||||
const client = req.userGraphQLClient;
|
const client = req.userGraphQLClient;
|
||||||
|
|
||||||
logger.log("qbo-payable-create", "DEBUG", req.user.email, billsToQuery);
|
logger.log("qbo-payable-create", "DEBUG", req.user.email, null, { billsToQuery });
|
||||||
|
|
||||||
const result = await client
|
const result = await client
|
||||||
.setHeaders({ Authorization: BearerToken })
|
.setHeaders({ Authorization: BearerToken })
|
||||||
@@ -91,6 +91,12 @@ exports.default = async (req, res) => {
|
|||||||
|
|
||||||
ret.push({ billid: bill.id, success: true });
|
ret.push({ billid: bill.id, success: true });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
logger.log("qbo-paybles-create-error", "ERROR", req.user.email, null, {
|
||||||
|
error:
|
||||||
|
(error && error.authResponse && error.authResponse.body) ||
|
||||||
|
error.response?.data?.Fault?.Error.map((e) => e.Detail).join(", ") ||
|
||||||
|
(error && error.message)
|
||||||
|
});
|
||||||
ret.push({
|
ret.push({
|
||||||
billid: bill.id,
|
billid: bill.id,
|
||||||
success: false,
|
success: false,
|
||||||
@@ -122,7 +128,7 @@ exports.default = async (req, res) => {
|
|||||||
res.status(200).json(ret);
|
res.status(200).json(ret);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
//console.log(error);
|
//console.log(error);
|
||||||
logger.log("qbo-payable-create-error", "ERROR", req.user.email, {
|
logger.log("qbo-payable-create-error", "ERROR", req.user.email, null, {
|
||||||
error: error.message,
|
error: error.message,
|
||||||
stack: error.stack
|
stack: error.stack
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ exports.default = async (req, res) => {
|
|||||||
const BearerToken = req.BearerToken;
|
const BearerToken = req.BearerToken;
|
||||||
const client = req.userGraphQLClient;
|
const client = req.userGraphQLClient;
|
||||||
|
|
||||||
logger.log("qbo-payment-create", "DEBUG", req.user.email, paymentsToQuery);
|
logger.log("qbo-payment-create", "DEBUG", req.user.email, null, { paymentsToQuery });
|
||||||
|
|
||||||
const result = await client.setHeaders({ Authorization: BearerToken }).request(queries.QUERY_PAYMENTS_FOR_EXPORT, {
|
const result = await client.setHeaders({ Authorization: BearerToken }).request(queries.QUERY_PAYMENTS_FOR_EXPORT, {
|
||||||
payments: paymentsToQuery
|
payments: paymentsToQuery
|
||||||
@@ -152,7 +152,7 @@ exports.default = async (req, res) => {
|
|||||||
|
|
||||||
ret.push({ paymentid: payment.id, success: true });
|
ret.push({ paymentid: payment.id, success: true });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.log("qbo-payment-create-error", "ERROR", req.user.email, {
|
logger.log("qbo-payment-create-error", "ERROR", req.user.email, null, {
|
||||||
error: (error && error.authResponse && error.authResponse.body) || (error && error.message)
|
error: (error && error.authResponse && error.authResponse.body) || (error && error.message)
|
||||||
});
|
});
|
||||||
//Add the export log error.
|
//Add the export log error.
|
||||||
@@ -183,7 +183,7 @@ exports.default = async (req, res) => {
|
|||||||
res.status(200).json(ret);
|
res.status(200).json(ret);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
//console.log(error);
|
//console.log(error);
|
||||||
logger.log("qbo-payment-create-error", "ERROR", req.user.email, {
|
logger.log("qbo-payment-create-error", "ERROR", req.user.email, null, {
|
||||||
error: error.message,
|
error: error.message,
|
||||||
stack: error.stack
|
stack: error.stack
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -42,9 +42,10 @@ exports.default = async (req, res) => {
|
|||||||
//For each invoice.
|
//For each invoice.
|
||||||
res.status(200).json(QbXmlToExecute);
|
res.status(200).json(QbXmlToExecute);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.log("qbxml-payable-error", "ERROR", req.user.email, req.body.billsToQuery, {
|
logger.log("qbxml-payable-error", "ERROR", req?.user?.email, null, {
|
||||||
error: error.message,
|
billsToQuery: req?.body?.billsToQuery,
|
||||||
stack: error.stack
|
error: error?.message,
|
||||||
|
stack: error?.stack
|
||||||
});
|
});
|
||||||
res.status(400).send(JSON.stringify(error));
|
res.status(400).send(JSON.stringify(error));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,9 @@ exports.default = async (req, res) => {
|
|||||||
const client = req.userGraphQLClient;
|
const client = req.userGraphQLClient;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
logger.log("qbxml-payments-create", "DEBUG", req.user.email, req.body.paymentsToQuery, null);
|
logger.log("qbxml-payments-create", "DEBUG", req?.user?.email, null, {
|
||||||
|
paymentsToQuery: req.body?.paymentsToQuery
|
||||||
|
});
|
||||||
|
|
||||||
const result = await client.setHeaders({ Authorization: BearerToken }).request(queries.QUERY_PAYMENTS_FOR_EXPORT, {
|
const result = await client.setHeaders({ Authorization: BearerToken }).request(queries.QUERY_PAYMENTS_FOR_EXPORT, {
|
||||||
payments: paymentsToQuery
|
payments: paymentsToQuery
|
||||||
@@ -62,7 +64,8 @@ exports.default = async (req, res) => {
|
|||||||
|
|
||||||
res.status(200).json(QbXmlToExecute);
|
res.status(200).json(QbXmlToExecute);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.log("qbxml-payments-error", "error", req.user.email, req.body.paymentsToQuery, {
|
logger.log("qbxml-payments-error", "error", req?.user?.email, null, {
|
||||||
|
paymentsToQuery: req.body?.paymentsToQuery,
|
||||||
error: error.message,
|
error: error.message,
|
||||||
stack: error.stack
|
stack: error.stack
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -23,7 +23,9 @@ exports.default = async (req, res) => {
|
|||||||
const client = req.userGraphQLClient;
|
const client = req.userGraphQLClient;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
logger.log("qbxml-receivables-create", "DEBUG", req.user.email, req.body.jobIds, null);
|
logger.log("qbxml-receivables-create", "DEBUG", req?.user?.email, null, {
|
||||||
|
jobIds: req?.body?.jobIds
|
||||||
|
});
|
||||||
|
|
||||||
const result = await client
|
const result = await client
|
||||||
.setHeaders({ Authorization: BearerToken })
|
.setHeaders({ Authorization: BearerToken })
|
||||||
@@ -74,7 +76,8 @@ exports.default = async (req, res) => {
|
|||||||
|
|
||||||
res.status(200).json(QbXmlToExecute);
|
res.status(200).json(QbXmlToExecute);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.log("qbxml-receivables-error", "error", req.user.email, req.body.jobIds, {
|
logger.log("qbxml-receivables-error", "error", req?.user?.email, null, {
|
||||||
|
jobIds: req.body?.jobIds,
|
||||||
error: error.message,
|
error: error.message,
|
||||||
stack: error.stack
|
stack: error.stack
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ async function QueryJobData(connectionData, token, jobid) {
|
|||||||
CdkBase.createLogEvent(connectionData, "DEBUG", `Querying job data for id ${jobid}`);
|
CdkBase.createLogEvent(connectionData, "DEBUG", `Querying job data for id ${jobid}`);
|
||||||
const client = new GraphQLClient(process.env.GRAPHQL_ENDPOINT, {});
|
const client = new GraphQLClient(process.env.GRAPHQL_ENDPOINT, {});
|
||||||
const result = await client.setHeaders({ Authorization: token }).request(queries.GET_CDK_ALLOCATIONS, { id: jobid });
|
const result = await client.setHeaders({ Authorization: token }).request(queries.GET_CDK_ALLOCATIONS, { id: jobid });
|
||||||
CdkBase.createLogEvent(connectionData, "TRACE", `Job data query result ${JSON.stringify(result, null, 2)}`);
|
CdkBase.createLogEvent(connectionData, "SILLY", `Job data query result ${JSON.stringify(result, null, 2)}`);
|
||||||
return result.jobs_by_pk;
|
return result.jobs_by_pk;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,13 +373,19 @@ function calculateAllocations(connectionData, job) {
|
|||||||
});
|
});
|
||||||
//profile level adjustments for labor and materials
|
//profile level adjustments for labor and materials
|
||||||
Object.keys(job.job_totals.rates).forEach((key) => {
|
Object.keys(job.job_totals.rates).forEach((key) => {
|
||||||
if (job.job_totals.rates[key] && job.job_totals.rates[key].adjustment && Dinero(job.job_totals.rates[key].adjustment).isZero() === false) {
|
if (
|
||||||
|
job.job_totals.rates[key] &&
|
||||||
|
job.job_totals.rates[key].adjustment &&
|
||||||
|
Dinero(job.job_totals.rates[key].adjustment).isZero() === false
|
||||||
|
) {
|
||||||
const accountName = selectedDmsAllocationConfig.profits[key.toUpperCase()];
|
const accountName = selectedDmsAllocationConfig.profits[key.toUpperCase()];
|
||||||
const otherAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === accountName);
|
const otherAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === accountName);
|
||||||
if (otherAccount) {
|
if (otherAccount) {
|
||||||
if (!profitCenterHash[accountName]) profitCenterHash[accountName] = Dinero();
|
if (!profitCenterHash[accountName]) profitCenterHash[accountName] = Dinero();
|
||||||
|
|
||||||
profitCenterHash[accountName] = profitCenterHash[accountName].add(Dinero(job.job_totals.rates[key].adjustments));
|
profitCenterHash[accountName] = profitCenterHash[accountName].add(
|
||||||
|
Dinero(job.job_totals.rates[key].adjustments)
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
CdkBase.createLogEvent(
|
CdkBase.createLogEvent(
|
||||||
connectionData,
|
connectionData,
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ exports.default = async function ReloadCdkMakes(req, res) {
|
|||||||
const deleteResult = await client
|
const deleteResult = await client
|
||||||
.setHeaders({ Authorization: BearerToken })
|
.setHeaders({ Authorization: BearerToken })
|
||||||
.request(queries.DELETE_ALL_DMS_VEHICLES, {});
|
.request(queries.DELETE_ALL_DMS_VEHICLES, {});
|
||||||
console.log("🚀 ~ file: cdk-get-makes.js ~ line 53 ~ deleteResult", deleteResult);
|
|
||||||
|
|
||||||
|
// logger.logger.debug("🚀 ~ file: cdk-get-makes.js ~ line 53 ~ deleteResult", { deleteResult });
|
||||||
//Insert the new ones.
|
//Insert the new ones.
|
||||||
|
|
||||||
const insertResult = await client.setHeaders({ Authorization: BearerToken }).request(queries.INSERT_DMS_VEHICLES, {
|
const insertResult = await client.setHeaders({ Authorization: BearerToken }).request(queries.INSERT_DMS_VEHICLES, {
|
||||||
@@ -59,6 +59,7 @@ exports.default = async function ReloadCdkMakes(req, res) {
|
|||||||
cdk_dealerid,
|
cdk_dealerid,
|
||||||
count: newList.length
|
count: newList.length
|
||||||
});
|
});
|
||||||
|
|
||||||
res.sendStatus(200);
|
res.sendStatus(200);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.log("cdk-replace-makes-models-error", "ERROR", req.user.email, null, {
|
logger.log("cdk-replace-makes-models-error", "ERROR", req.user.email, null, {
|
||||||
|
|||||||
@@ -151,7 +151,7 @@ async function QueryJobData(socket, jobid) {
|
|||||||
const result = await client
|
const result = await client
|
||||||
.setHeaders({ Authorization: `Bearer ${socket.handshake.auth.token}` })
|
.setHeaders({ Authorization: `Bearer ${socket.handshake.auth.token}` })
|
||||||
.request(queries.QUERY_JOBS_FOR_CDK_EXPORT, { id: jobid });
|
.request(queries.QUERY_JOBS_FOR_CDK_EXPORT, { id: jobid });
|
||||||
CdkBase.createLogEvent(socket, "TRACE", `Job data query result ${JSON.stringify(result, null, 2)}`);
|
CdkBase.createLogEvent(socket, "SILLY", `Job data query result ${JSON.stringify(result, null, 2)}`);
|
||||||
return result.jobs_by_pk;
|
return result.jobs_by_pk;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,7 +171,7 @@ async function CalculateDmsVid(socket, JobData) {
|
|||||||
|
|
||||||
CdkBase.createLogEvent(
|
CdkBase.createLogEvent(
|
||||||
socket,
|
socket,
|
||||||
"TRACE",
|
"SILLY",
|
||||||
`soapClientVehicleInsertUpdate.getVehIdsAsync Result ${JSON.stringify(result, null, 2)}`
|
`soapClientVehicleInsertUpdate.getVehIdsAsync Result ${JSON.stringify(result, null, 2)}`
|
||||||
);
|
);
|
||||||
CheckCdkResponseForError(socket, soapResponseVehicleInsertUpdate);
|
CheckCdkResponseForError(socket, soapResponseVehicleInsertUpdate);
|
||||||
@@ -214,7 +214,7 @@ async function QueryDmsVehicleById(socket, JobData, DMSVid) {
|
|||||||
|
|
||||||
CdkBase.createLogEvent(
|
CdkBase.createLogEvent(
|
||||||
socket,
|
socket,
|
||||||
"TRACE",
|
"SILLY",
|
||||||
`soapClientVehicleInsertUpdate.readAsync Result ${JSON.stringify(result, null, 2)}`
|
`soapClientVehicleInsertUpdate.readAsync Result ${JSON.stringify(result, null, 2)}`
|
||||||
);
|
);
|
||||||
CdkBase.createXmlEvent(socket, rawResponse, `soapClientVehicleInsertUpdate.readAsync response.`);
|
CdkBase.createXmlEvent(socket, rawResponse, `soapClientVehicleInsertUpdate.readAsync response.`);
|
||||||
@@ -246,7 +246,7 @@ async function QueryDmsCustomerById(socket, JobData, CustomerId) {
|
|||||||
CdkBase.createXmlEvent(socket, rawResponse, `soapClientCustomerInsertUpdate.readAsync response.`);
|
CdkBase.createXmlEvent(socket, rawResponse, `soapClientCustomerInsertUpdate.readAsync response.`);
|
||||||
CdkBase.createLogEvent(
|
CdkBase.createLogEvent(
|
||||||
socket,
|
socket,
|
||||||
"TRACE",
|
"SILLY",
|
||||||
`soapClientCustomerInsertUpdate.readAsync Result ${JSON.stringify(result, null, 2)}`
|
`soapClientCustomerInsertUpdate.readAsync Result ${JSON.stringify(result, null, 2)}`
|
||||||
);
|
);
|
||||||
CheckCdkResponseForError(socket, soapResponseCustomerInsertUpdate);
|
CheckCdkResponseForError(socket, soapResponseCustomerInsertUpdate);
|
||||||
@@ -295,7 +295,7 @@ async function QueryDmsCustomerByName(socket, JobData) {
|
|||||||
|
|
||||||
CdkBase.createLogEvent(
|
CdkBase.createLogEvent(
|
||||||
socket,
|
socket,
|
||||||
"TRACE",
|
"SILLY",
|
||||||
`soapClientCustomerSearch.executeSearchBulkAsync Result ${JSON.stringify(result, null, 2)}`
|
`soapClientCustomerSearch.executeSearchBulkAsync Result ${JSON.stringify(result, null, 2)}`
|
||||||
);
|
);
|
||||||
CheckCdkResponseForError(socket, soapResponseCustomerSearch);
|
CheckCdkResponseForError(socket, soapResponseCustomerSearch);
|
||||||
@@ -337,7 +337,7 @@ async function GenerateDmsCustomerNumber(socket) {
|
|||||||
|
|
||||||
CdkBase.createLogEvent(
|
CdkBase.createLogEvent(
|
||||||
socket,
|
socket,
|
||||||
"TRACE",
|
"SILLY",
|
||||||
`soapClientCustomerInsertUpdate.getCustomerNumberAsync Result ${JSON.stringify(result, null, 2)}`
|
`soapClientCustomerInsertUpdate.getCustomerNumberAsync Result ${JSON.stringify(result, null, 2)}`
|
||||||
);
|
);
|
||||||
CheckCdkResponseForError(socket, soapResponseCustomerInsertUpdate);
|
CheckCdkResponseForError(socket, soapResponseCustomerInsertUpdate);
|
||||||
@@ -425,7 +425,7 @@ async function InsertDmsCustomer(socket, newCustomerNumber) {
|
|||||||
CdkBase.createXmlEvent(socket, rawResponse, `soapClientCustomerInsertUpdate.insertAsync response.`);
|
CdkBase.createXmlEvent(socket, rawResponse, `soapClientCustomerInsertUpdate.insertAsync response.`);
|
||||||
CdkBase.createLogEvent(
|
CdkBase.createLogEvent(
|
||||||
socket,
|
socket,
|
||||||
"TRACE",
|
"SILLY",
|
||||||
`soapClientCustomerInsertUpdate.insertAsync Result ${JSON.stringify(result, null, 2)}`
|
`soapClientCustomerInsertUpdate.insertAsync Result ${JSON.stringify(result, null, 2)}`
|
||||||
);
|
);
|
||||||
CheckCdkResponseForError(socket, soapResponseCustomerInsertUpdate);
|
CheckCdkResponseForError(socket, soapResponseCustomerInsertUpdate);
|
||||||
@@ -505,7 +505,7 @@ async function InsertDmsVehicle(socket) {
|
|||||||
|
|
||||||
CdkBase.createLogEvent(
|
CdkBase.createLogEvent(
|
||||||
socket,
|
socket,
|
||||||
"TRACE",
|
"SILLY",
|
||||||
`soapClientVehicleInsertUpdate.insertAsync Result ${JSON.stringify(result, null, 2)}`
|
`soapClientVehicleInsertUpdate.insertAsync Result ${JSON.stringify(result, null, 2)}`
|
||||||
);
|
);
|
||||||
CdkBase.createXmlEvent(socket, rawResponse, `soapClientVehicleInsertUpdate.insertAsync response.`);
|
CdkBase.createXmlEvent(socket, rawResponse, `soapClientVehicleInsertUpdate.insertAsync response.`);
|
||||||
@@ -611,7 +611,7 @@ async function UpdateDmsVehicle(socket) {
|
|||||||
|
|
||||||
CdkBase.createLogEvent(
|
CdkBase.createLogEvent(
|
||||||
socket,
|
socket,
|
||||||
"TRACE",
|
"DEBUG",
|
||||||
`soapClientVehicleInsertUpdate.updateAsync Result ${JSON.stringify(result, null, 2)}`
|
`soapClientVehicleInsertUpdate.updateAsync Result ${JSON.stringify(result, null, 2)}`
|
||||||
);
|
);
|
||||||
CdkBase.createXmlEvent(socket, rawResponse, `soapClientVehicleInsertUpdate.updateAsync response.`);
|
CdkBase.createXmlEvent(socket, rawResponse, `soapClientVehicleInsertUpdate.updateAsync response.`);
|
||||||
@@ -650,7 +650,7 @@ async function InsertServiceVehicleHistory(socket) {
|
|||||||
|
|
||||||
CdkBase.createLogEvent(
|
CdkBase.createLogEvent(
|
||||||
socket,
|
socket,
|
||||||
"TRACE",
|
"SILLY",
|
||||||
`soapClientServiceHistoryInsert.serviceHistoryHeaderInsert Result ${JSON.stringify(result, null, 2)}`
|
`soapClientServiceHistoryInsert.serviceHistoryHeaderInsert Result ${JSON.stringify(result, null, 2)}`
|
||||||
);
|
);
|
||||||
CdkBase.createXmlEvent(socket, rawResponse, `soapClientServiceHistoryInsert.serviceHistoryHeaderInsert response.`);
|
CdkBase.createXmlEvent(socket, rawResponse, `soapClientServiceHistoryInsert.serviceHistoryHeaderInsert response.`);
|
||||||
@@ -690,7 +690,7 @@ async function InsertDmsStartWip(socket) {
|
|||||||
|
|
||||||
CdkBase.createLogEvent(
|
CdkBase.createLogEvent(
|
||||||
socket,
|
socket,
|
||||||
"TRACE",
|
"SILLY",
|
||||||
`soapClientAccountingGLInsertUpdate.doStartWIPAsync Result ${JSON.stringify(result, null, 2)}`
|
`soapClientAccountingGLInsertUpdate.doStartWIPAsync Result ${JSON.stringify(result, null, 2)}`
|
||||||
);
|
);
|
||||||
CdkBase.createXmlEvent(socket, rawResponse, `soapClientAccountingGLInsertUpdate.doStartWIPAsync response.`);
|
CdkBase.createXmlEvent(socket, rawResponse, `soapClientAccountingGLInsertUpdate.doStartWIPAsync response.`);
|
||||||
@@ -721,7 +721,7 @@ async function InsertDmsBatchWip(socket) {
|
|||||||
|
|
||||||
CdkBase.createLogEvent(
|
CdkBase.createLogEvent(
|
||||||
socket,
|
socket,
|
||||||
"TRACE",
|
"SILLY",
|
||||||
`soapClientAccountingGLInsertUpdate.doTransBatchWIPAsync Result ${JSON.stringify(result, null, 2)}`
|
`soapClientAccountingGLInsertUpdate.doTransBatchWIPAsync Result ${JSON.stringify(result, null, 2)}`
|
||||||
);
|
);
|
||||||
CdkBase.createXmlEvent(socket, rawResponse, `soapClientAccountingGLInsertUpdate.doTransBatchWIPAsync response.`);
|
CdkBase.createXmlEvent(socket, rawResponse, `soapClientAccountingGLInsertUpdate.doTransBatchWIPAsync response.`);
|
||||||
@@ -885,7 +885,7 @@ async function PostDmsBatchWip(socket) {
|
|||||||
|
|
||||||
CdkBase.createLogEvent(
|
CdkBase.createLogEvent(
|
||||||
socket,
|
socket,
|
||||||
"TRACE",
|
"SILLY",
|
||||||
`soapClientAccountingGLInsertUpdate.doPostBatchWIPAsync Result ${JSON.stringify(result, null, 2)}`
|
`soapClientAccountingGLInsertUpdate.doPostBatchWIPAsync Result ${JSON.stringify(result, null, 2)}`
|
||||||
);
|
);
|
||||||
CdkBase.createXmlEvent(socket, rawResponse, `soapClientAccountingGLInsertUpdate.doPostBatchWIPAsync response.`);
|
CdkBase.createXmlEvent(socket, rawResponse, `soapClientAccountingGLInsertUpdate.doPostBatchWIPAsync response.`);
|
||||||
@@ -914,7 +914,7 @@ async function QueryDmsErrWip(socket) {
|
|||||||
|
|
||||||
CdkBase.createLogEvent(
|
CdkBase.createLogEvent(
|
||||||
socket,
|
socket,
|
||||||
"TRACE",
|
"DEBUG",
|
||||||
`soapClientAccountingGLInsertUpdate.doErrWIPAsync Result ${JSON.stringify(result, null, 2)}`
|
`soapClientAccountingGLInsertUpdate.doErrWIPAsync Result ${JSON.stringify(result, null, 2)}`
|
||||||
);
|
);
|
||||||
CdkBase.createXmlEvent(socket, rawResponse, `soapClientAccountingGLInsertUpdate.doErrWIPAsync response.`);
|
CdkBase.createXmlEvent(socket, rawResponse, `soapClientAccountingGLInsertUpdate.doErrWIPAsync response.`);
|
||||||
@@ -945,7 +945,7 @@ async function DeleteDmsWip(socket) {
|
|||||||
|
|
||||||
CdkBase.createLogEvent(
|
CdkBase.createLogEvent(
|
||||||
socket,
|
socket,
|
||||||
"TRACE",
|
"SILLY",
|
||||||
`soapClientAccountingGLInsertUpdate.doPostBatchWIPAsync Result ${JSON.stringify(result, null, 2)}`
|
`soapClientAccountingGLInsertUpdate.doPostBatchWIPAsync Result ${JSON.stringify(result, null, 2)}`
|
||||||
);
|
);
|
||||||
CdkBase.createXmlEvent(socket, rawResponse, `soapClientAccountingGLInsertUpdate.doPostBatchWIPAsync response.`);
|
CdkBase.createXmlEvent(socket, rawResponse, `soapClientAccountingGLInsertUpdate.doPostBatchWIPAsync response.`);
|
||||||
@@ -995,7 +995,7 @@ async function InsertFailedExportLog(socket, error) {
|
|||||||
bodyshopid: socket.JobData.bodyshop.id,
|
bodyshopid: socket.JobData.bodyshop.id,
|
||||||
jobid: socket.JobData.id,
|
jobid: socket.JobData.id,
|
||||||
successful: false,
|
successful: false,
|
||||||
message: [error],
|
message: JSON.stringify(error),
|
||||||
useremail: socket.user.email
|
useremail: socket.user.email
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ function CheckCdkResponseForError(socket, soapResponse) {
|
|||||||
//The response was null, this might be ok, it might not.
|
//The response was null, this might be ok, it might not.
|
||||||
CdkBase.createLogEvent(
|
CdkBase.createLogEvent(
|
||||||
socket,
|
socket,
|
||||||
"WARNING",
|
"warn",
|
||||||
`Warning detected in CDK Response - it appears to be null. Stack: ${new Error().stack}`
|
`Warning detected in CDK Response - it appears to be null. Stack: ${new Error().stack}`
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ let Client = require("ssh2-sftp-client");
|
|||||||
|
|
||||||
const client = require("../graphql-client/graphql-client").client;
|
const client = require("../graphql-client/graphql-client").client;
|
||||||
const { sendServerEmail } = require("../email/sendemail");
|
const { sendServerEmail } = require("../email/sendemail");
|
||||||
|
|
||||||
const AHDineroFormat = "0.00";
|
const AHDineroFormat = "0.00";
|
||||||
const AhDateFormat = "MMDDYYYY";
|
const AhDateFormat = "MMDDYYYY";
|
||||||
|
|
||||||
@@ -26,170 +27,177 @@ const ftpSetup = {
|
|||||||
password: process.env.AUTOHOUSE_PASSWORD,
|
password: process.env.AUTOHOUSE_PASSWORD,
|
||||||
debug: (message, ...data) => logger.log(message, "DEBUG", "api", null, data),
|
debug: (message, ...data) => logger.log(message, "DEBUG", "api", null, data),
|
||||||
algorithms: {
|
algorithms: {
|
||||||
serverHostKey: ["ssh-rsa", "ssh-dss"]
|
serverHostKey: ["ssh-rsa", "ssh-dss", "rsa-sha2-256", "rsa-sha2-512", "ecdsa-sha2-nistp256", "ecdsa-sha2-nistp384"]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const allxmlsToUpload = [];
|
||||||
|
const allErrors = [];
|
||||||
|
|
||||||
exports.default = async (req, res) => {
|
exports.default = async (req, res) => {
|
||||||
// Only process if in production environment.
|
// Only process if in production environment.
|
||||||
if (process.env.NODE_ENV !== "production") {
|
if (process.env.NODE_ENV !== "production") {
|
||||||
res.sendStatus(403);
|
res.sendStatus(403);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Only process if the appropriate token is provided.
|
||||||
//Query for the List of Bodyshop Clients.
|
|
||||||
logger.log("autohouse-start", "DEBUG", "api", null, null);
|
|
||||||
const { bodyshops } = await client.request(queries.GET_AUTOHOUSE_SHOPS);
|
|
||||||
|
|
||||||
const specificShopIds = req.body.bodyshopIds; // ['uuid]
|
|
||||||
const { start, end, skipUpload } = req.body; //YYYY-MM-DD
|
|
||||||
if (req.headers["x-imex-auth"] !== process.env.AUTOHOUSE_AUTH_TOKEN) {
|
if (req.headers["x-imex-auth"] !== process.env.AUTOHOUSE_AUTH_TOKEN) {
|
||||||
res.sendStatus(401);
|
res.sendStatus(401);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const allxmlsToUpload = [];
|
|
||||||
const allErrors = [];
|
// Send immediate response and continue processing.
|
||||||
|
res.status(200).send();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (const bodyshop of specificShopIds ? bodyshops.filter((b) => specificShopIds.includes(b.id)) : bodyshops) {
|
logger.log("autohouse-start", "DEBUG", "api", null, null);
|
||||||
|
const { bodyshops } = await client.request(queries.GET_AUTOHOUSE_SHOPS); //Query for the List of Bodyshop Clients.
|
||||||
|
const specificShopIds = req.body.bodyshopIds; // ['uuid];
|
||||||
|
const { start, end, skipUpload } = req.body; //YYYY-MM-DD
|
||||||
|
|
||||||
|
const batchSize = 10;
|
||||||
|
|
||||||
|
const shopsToProcess =
|
||||||
|
specificShopIds?.length > 0 ? bodyshops.filter((shop) => specificShopIds.includes(shop.id)) : bodyshops;
|
||||||
|
logger.log("autohouse-shopsToProcess-generated", "DEBUG", "api", null, null);
|
||||||
|
|
||||||
|
if (shopsToProcess.length === 0) {
|
||||||
|
logger.log("autohouse-shopsToProcess-empty", "DEBUG", "api", null, null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const batchPromises = [];
|
||||||
|
for (let i = 0; i < shopsToProcess.length; i += batchSize) {
|
||||||
|
const batch = shopsToProcess.slice(i, i + batchSize);
|
||||||
|
const batchPromise = (async () => {
|
||||||
|
await processBatch(batch, start, end);
|
||||||
|
|
||||||
|
if (skipUpload) {
|
||||||
|
for (const xmlObj of allxmlsToUpload) {
|
||||||
|
fs.writeFileSync(`./logs/${xmlObj.filename}`, xmlObj.xml);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await uploadViaSFTP(allxmlsToUpload);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
batchPromises.push(batchPromise);
|
||||||
|
}
|
||||||
|
await Promise.all(batchPromises);
|
||||||
|
await sendServerEmail({
|
||||||
|
subject: `Autohouse Report ${moment().format("MM-DD-YY")}`,
|
||||||
|
text: `Errors:\n${JSON.stringify(allErrors, null, 2)}\n\nUploaded:\n${JSON.stringify(
|
||||||
|
allxmlsToUpload.map((x) => ({ filename: x.filename, count: x.count, result: x.result })),
|
||||||
|
null,
|
||||||
|
2
|
||||||
|
)}`
|
||||||
|
});
|
||||||
|
|
||||||
|
logger.log("autohouse-end", "DEBUG", "api", null, null);
|
||||||
|
} catch (error) {
|
||||||
|
logger.log("autohouse-error", "ERROR", "api", null, { error: error.message, stack: error.stack });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
async function processBatch(batch, start, end) {
|
||||||
|
for (const bodyshop of batch) {
|
||||||
|
const erroredJobs = [];
|
||||||
|
try {
|
||||||
logger.log("autohouse-start-shop-extract", "DEBUG", "api", bodyshop.id, {
|
logger.log("autohouse-start-shop-extract", "DEBUG", "api", bodyshop.id, {
|
||||||
shopname: bodyshop.shopname
|
shopname: bodyshop.shopname
|
||||||
});
|
});
|
||||||
const erroredJobs = [];
|
|
||||||
try {
|
|
||||||
const { jobs, bodyshops_by_pk } = await client.request(queries.AUTOHOUSE_QUERY, {
|
|
||||||
bodyshopid: bodyshop.id,
|
|
||||||
start: start ? moment(start).startOf("day") : moment().subtract(5, "days").startOf("day"),
|
|
||||||
...(end && { end: moment(end).endOf("day") })
|
|
||||||
});
|
|
||||||
|
|
||||||
const autoHouseObject = {
|
const { jobs, bodyshops_by_pk } = await client.request(queries.AUTOHOUSE_QUERY, {
|
||||||
AutoHouseExport: {
|
bodyshopid: bodyshop.id,
|
||||||
RepairOrder: jobs.map((j) =>
|
start: start ? moment(start).startOf("day") : moment().subtract(5, "days").startOf("day"),
|
||||||
CreateRepairOrderTag({ ...j, bodyshop: bodyshops_by_pk }, function ({ job, error }) {
|
...(end && { end: moment(end).endOf("day") })
|
||||||
erroredJobs.push({ job: job, error: error.toString() });
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (erroredJobs.length > 0) {
|
|
||||||
logger.log("autohouse-failed-jobs", "ERROR", "api", bodyshop.id, {
|
|
||||||
count: erroredJobs.length,
|
|
||||||
jobs: JSON.stringify(erroredJobs.map((j) => j.job.ro_number))
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var ret = builder
|
|
||||||
.create(
|
|
||||||
{
|
|
||||||
// version: "1.0",
|
|
||||||
// encoding: "UTF-8",
|
|
||||||
//keepNullNodes: true,
|
|
||||||
},
|
|
||||||
autoHouseObject
|
|
||||||
)
|
|
||||||
.end({ allowEmptyTags: true });
|
|
||||||
|
|
||||||
allxmlsToUpload.push({
|
|
||||||
count: autoHouseObject.AutoHouseExport.RepairOrder.length,
|
|
||||||
xml: ret,
|
|
||||||
filename: `IM_${bodyshop.autohouseid}_${moment().format("DDMMYYYY_HHMMss")}.xml`
|
|
||||||
});
|
|
||||||
|
|
||||||
logger.log("autohouse-end-shop-extract", "DEBUG", "api", bodyshop.id, {
|
|
||||||
shopname: bodyshop.shopname
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
//Error at the shop level.
|
|
||||||
logger.log("autohouse-error-shop", "ERROR", "api", bodyshop.id, {
|
|
||||||
...error
|
|
||||||
});
|
|
||||||
|
|
||||||
allErrors.push({
|
|
||||||
bodyshopid: bodyshop.id,
|
|
||||||
imexshopid: bodyshop.imexshopid,
|
|
||||||
autuhouseid: bodyshop.autuhouseid,
|
|
||||||
fatal: true,
|
|
||||||
errors: [error.toString()]
|
|
||||||
});
|
|
||||||
} finally {
|
|
||||||
allErrors.push({
|
|
||||||
bodyshopid: bodyshop.id,
|
|
||||||
imexshopid: bodyshop.imexshopid,
|
|
||||||
autohouseid: bodyshop.autohouseid,
|
|
||||||
errors: erroredJobs.map((ej) => ({
|
|
||||||
ro_number: ej.job?.ro_number,
|
|
||||||
jobid: ej.job?.id,
|
|
||||||
error: ej.error
|
|
||||||
}))
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (skipUpload) {
|
|
||||||
for (const xmlObj of allxmlsToUpload) {
|
|
||||||
fs.writeFileSync(`./logs/${xmlObj.filename}`, xmlObj.xml);
|
|
||||||
}
|
|
||||||
|
|
||||||
res.json(allxmlsToUpload);
|
|
||||||
sendServerEmail({
|
|
||||||
subject: `Autohouse Report ${moment().format("MM-DD-YY")}`,
|
|
||||||
text: `Errors: ${allErrors.map((e) => JSON.stringify(e, null, 2))}
|
|
||||||
Uploaded: ${JSON.stringify(
|
|
||||||
allxmlsToUpload.map((x) => ({ filename: x.filename, count: x.count })),
|
|
||||||
null,
|
|
||||||
2
|
|
||||||
)}
|
|
||||||
`
|
|
||||||
});
|
});
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let sftp = new Client();
|
const autoHouseObject = {
|
||||||
sftp.on("error", (errors) =>
|
AutoHouseExport: {
|
||||||
logger.log("autohouse-sftp-error", "ERROR", "api", null, {
|
RepairOrder: jobs.map((j) =>
|
||||||
...errors
|
CreateRepairOrderTag({ ...j, bodyshop: bodyshops_by_pk }, function ({ job, error }) {
|
||||||
})
|
erroredJobs.push({ job: job, error: error.toString() });
|
||||||
);
|
})
|
||||||
try {
|
)
|
||||||
//Connect to the FTP and upload all.
|
}
|
||||||
|
};
|
||||||
|
|
||||||
await sftp.connect(ftpSetup);
|
if (erroredJobs.length > 0) {
|
||||||
|
logger.log("autohouse-failed-jobs", "ERROR", "api", bodyshop.id, {
|
||||||
for (const xmlObj of allxmlsToUpload) {
|
count: erroredJobs.length,
|
||||||
logger.log("autohouse-sftp-upload", "DEBUG", "api", null, {
|
jobs: JSON.stringify(erroredJobs.map((j) => j.job.ro_number))
|
||||||
filename: xmlObj.filename
|
|
||||||
});
|
|
||||||
|
|
||||||
const uploadResult = await sftp.put(Buffer.from(xmlObj.xml), `/${xmlObj.filename}`);
|
|
||||||
logger.log("autohouse-sftp-upload-result", "DEBUG", "api", null, {
|
|
||||||
uploadResult
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//***TODO Change filing naming when creating the cron job. IM_ShopInternalName_DDMMYYYY_HHMMSS.xml
|
const ret = builder.create({}, autoHouseObject).end({ allowEmptyTags: true });
|
||||||
|
|
||||||
|
allxmlsToUpload.push({
|
||||||
|
count: autoHouseObject.AutoHouseExport.RepairOrder.length,
|
||||||
|
xml: ret,
|
||||||
|
filename: `IM_${bodyshop.autohouseid}_${moment().format("DDMMYYYY_HHMMss")}.xml`
|
||||||
|
});
|
||||||
|
|
||||||
|
logger.log("autohouse-end-shop-extract", "DEBUG", "api", bodyshop.id, {
|
||||||
|
shopname: bodyshop.shopname
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.log("autohouse-sftp-error", "ERROR", "api", null, {
|
//Error at the shop level.
|
||||||
...error
|
logger.log("autohouse-error-shop", "ERROR", "api", bodyshop.id, { error: error.message, stack: error.stack });
|
||||||
|
|
||||||
|
allErrors.push({
|
||||||
|
bodyshopid: bodyshop.id,
|
||||||
|
imexshopid: bodyshop.imexshopid,
|
||||||
|
autuhouseid: bodyshop.autuhouseid,
|
||||||
|
fatal: true,
|
||||||
|
errors: [error.toString()]
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
sftp.end();
|
allErrors.push({
|
||||||
|
bodyshopid: bodyshop.id,
|
||||||
|
imexshopid: bodyshop.imexshopid,
|
||||||
|
autuhouseid: bodyshop.autuhouseid,
|
||||||
|
errors: erroredJobs.map((ej) => ({
|
||||||
|
ro_number: ej.job?.ro_number,
|
||||||
|
jobid: ej.job?.id,
|
||||||
|
error: ej.error
|
||||||
|
}))
|
||||||
|
});
|
||||||
}
|
}
|
||||||
sendServerEmail({
|
|
||||||
subject: `Autohouse Report ${moment().format("MM-DD-YY")}`,
|
|
||||||
text: `Errors: ${allErrors.map((e) => JSON.stringify(e, null, 2))}
|
|
||||||
Uploaded: ${JSON.stringify(
|
|
||||||
allxmlsToUpload.map((x) => ({ filename: x.filename, count: x.count })),
|
|
||||||
null,
|
|
||||||
2
|
|
||||||
)}
|
|
||||||
`
|
|
||||||
});
|
|
||||||
res.sendStatus(200);
|
|
||||||
} catch (error) {
|
|
||||||
res.status(200).json(error);
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
async function uploadViaSFTP(allxmlsToUpload) {
|
||||||
|
const sftp = new Client();
|
||||||
|
sftp.on("error", (errors) =>
|
||||||
|
logger.log("autohouse-sftp-connection-error", "ERROR", "api", null, { error: errors.message, stack: errors.stack })
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
//Connect to the FTP and upload all.
|
||||||
|
await sftp.connect(ftpSetup);
|
||||||
|
|
||||||
|
for (const xmlObj of allxmlsToUpload) {
|
||||||
|
try {
|
||||||
|
logger.log("autohouse-sftp-upload", "DEBUG", "api", null, { filename: xmlObj.filename });
|
||||||
|
xmlObj.result = await sftp.put(Buffer.from(xmlObj.xml), `${xmlObj.filename}`);
|
||||||
|
logger.log("autohouse-sftp-upload-result", "DEBUG", "api", null, {
|
||||||
|
filename: xmlObj.filename,
|
||||||
|
result: xmlObj.result
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
logger.log("autohouse-sftp-upload-error", "ERROR", "api", null, {
|
||||||
|
filename: xmlObj.filename,
|
||||||
|
error: error.message,
|
||||||
|
stack: error.stack
|
||||||
|
});
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
logger.log("autohouse-sftp-error", "ERROR", "api", null, { error: error.message, stack: error.stack });
|
||||||
|
throw error;
|
||||||
|
} finally {
|
||||||
|
sftp.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const CreateRepairOrderTag = (job, errorCallback) => {
|
const CreateRepairOrderTag = (job, errorCallback) => {
|
||||||
//Level 2
|
//Level 2
|
||||||
@@ -287,8 +295,8 @@ const CreateRepairOrderTag = (job, errorCallback) => {
|
|||||||
InsuranceCo: job.ins_co_nm || "",
|
InsuranceCo: job.ins_co_nm || "",
|
||||||
CompanyName: job.ins_co_nm || "",
|
CompanyName: job.ins_co_nm || "",
|
||||||
Address: job.ins_addr1 || "",
|
Address: job.ins_addr1 || "",
|
||||||
City: job.ins_addr1 || "",
|
City: job.ins_city || "",
|
||||||
State: job.ins_city || "",
|
State: job.ins_st || "",
|
||||||
Zip: job.ins_zip || "",
|
Zip: job.ins_zip || "",
|
||||||
Phone: job.ins_ph1 || "",
|
Phone: job.ins_ph1 || "",
|
||||||
Fax: job.ins_fax || "",
|
Fax: job.ins_fax || "",
|
||||||
|
|||||||
@@ -160,7 +160,8 @@ async function getPrivateKey() {
|
|||||||
try {
|
try {
|
||||||
const { SecretString, SecretBinary } = await client.send(command);
|
const { SecretString, SecretBinary } = await client.send(command);
|
||||||
if (SecretString || SecretBinary) logger.log("chatter-retrieved-private-key", "DEBUG", "api", null, null);
|
if (SecretString || SecretBinary) logger.log("chatter-retrieved-private-key", "DEBUG", "api", null, null);
|
||||||
return SecretString || Buffer.from(SecretBinary, "base64").toString("ascii");
|
const chatterPrivateKey = SecretString ? JSON.parse(SecretString) : JSON.parse(Buffer.from(SecretBinary, "base64").toString("ascii"));
|
||||||
|
return chatterPrivateKey.private_key;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.log("chatter-get-private-key", "ERROR", "api", null, error);
|
logger.log("chatter-get-private-key", "ERROR", "api", null, error);
|
||||||
throw err;
|
throw err;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ const { defaultProvider } = require("@aws-sdk/credential-provider-node");
|
|||||||
const { default: InstanceManager } = require("../utils/instanceMgr");
|
const { default: InstanceManager } = require("../utils/instanceMgr");
|
||||||
const aws = require("@aws-sdk/client-ses");
|
const aws = require("@aws-sdk/client-ses");
|
||||||
const nodemailer = require("nodemailer");
|
const nodemailer = require("nodemailer");
|
||||||
|
const logger = require("../utils/logger");
|
||||||
|
|
||||||
const isLocal = isString(process.env?.LOCALSTACK_HOSTNAME) && !isEmpty(process.env?.LOCALSTACK_HOSTNAME);
|
const isLocal = isString(process.env?.LOCALSTACK_HOSTNAME) && !isEmpty(process.env?.LOCALSTACK_HOSTNAME);
|
||||||
|
|
||||||
@@ -19,7 +20,7 @@ const sesConfig = {
|
|||||||
|
|
||||||
if (isLocal) {
|
if (isLocal) {
|
||||||
sesConfig.endpoint = `http://${process.env.LOCALSTACK_HOSTNAME}:4566`;
|
sesConfig.endpoint = `http://${process.env.LOCALSTACK_HOSTNAME}:4566`;
|
||||||
console.log(`SES Mailer set to LocalStack end point: ${sesConfig.endpoint}`);
|
logger.logger.debug(`SES Mailer set to LocalStack end point: ${sesConfig.endpoint}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const ses = new aws.SES(sesConfig);
|
const ses = new aws.SES(sesConfig);
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ const getImage = async (imageUrl) => {
|
|||||||
// Log the email in the database
|
// Log the email in the database
|
||||||
const logEmail = async (req, email) => {
|
const logEmail = async (req, email) => {
|
||||||
try {
|
try {
|
||||||
const insertresult = await client.request(queries.INSERT_EMAIL_AUDIT, {
|
await client.request(queries.INSERT_EMAIL_AUDIT, {
|
||||||
email: {
|
email: {
|
||||||
to: email.to,
|
to: email.to,
|
||||||
cc: email.cc,
|
cc: email.cc,
|
||||||
@@ -34,13 +34,13 @@ const logEmail = async (req, email) => {
|
|||||||
status: "Sent"
|
status: "Sent"
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
console.log(insertresult);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.log("email-log-error", "error", req.user.email, null, {
|
logger.log("email-log-error", "error", req?.user?.email, null, {
|
||||||
from: `${req.body.from.name} <${req.body.from.address}>`,
|
from: `${req.body.from.name} <${req.body.from.address}>`,
|
||||||
to: req.body.to,
|
to: req?.body?.to,
|
||||||
cc: req.body.cc,
|
cc: req?.body?.cc,
|
||||||
subject: req.body.subject
|
subject: req?.body?.subject,
|
||||||
|
email
|
||||||
// info,
|
// info,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -70,12 +70,11 @@ const sendServerEmail = async ({ subject, text }) => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
(err, info) => {
|
(err, info) => {
|
||||||
console.log(err || info);
|
logger.log("server-email-failure", err ? "error" : "debug", null, null, { message: err || info });
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
logger.log("server-email-failure", "error", null, null, { error });
|
||||||
logger.log("server-email-failure", "error", null, null, error);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -88,8 +87,7 @@ const sendProManagerWelcomeEmail = async ({ to, subject, html }) => {
|
|||||||
html
|
html
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
logger.log("server-email-failure", "error", null, null, { error });
|
||||||
logger.log("server-email-failure", "error", null, null, error);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -108,12 +106,12 @@ const sendTaskEmail = async ({ to, subject, type = "text", html, text, attachmen
|
|||||||
attachments: attachments || null
|
attachments: attachments || null
|
||||||
},
|
},
|
||||||
(err, info) => {
|
(err, info) => {
|
||||||
console.log(err || info);
|
// (message, type, user, record, meta
|
||||||
|
logger.log("server-email", err ? "error" : "debug", null, null, { message: err || info });
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
logger.log("server-email-failure", "error", null, null, { error });
|
||||||
logger.log("server-email-failure", "error", null, null, error);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -184,9 +182,8 @@ const sendEmail = async (req, res) => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
(err, info) => {
|
(err, info) => {
|
||||||
console.log(err || info);
|
|
||||||
if (info) {
|
if (info) {
|
||||||
logger.log("send-email-success", "DEBUG", req.user.email, null, {
|
logger.log("send-email-success", "DEBUG", req?.user?.email, null, {
|
||||||
from: `${req.body.from.name} <${req.body.from.address}>`,
|
from: `${req.body.from.name} <${req.body.from.address}>`,
|
||||||
replyTo: req.body.ReplyTo.Email,
|
replyTo: req.body.ReplyTo.Email,
|
||||||
to: req.body.to,
|
to: req.body.to,
|
||||||
@@ -205,7 +202,7 @@ const sendEmail = async (req, res) => {
|
|||||||
success: true //response: info
|
success: true //response: info
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
logger.log("send-email-failure", "ERROR", req.user.email, null, {
|
logger.log("send-email-failure", "ERROR", req?.user?.email, null, {
|
||||||
from: `${req.body.from.name} <${req.body.from.address}>`,
|
from: `${req.body.from.name} <${req.body.from.address}>`,
|
||||||
replyTo: req.body.ReplyTo.Email,
|
replyTo: req.body.ReplyTo.Email,
|
||||||
to: req.body.to,
|
to: req.body.to,
|
||||||
@@ -290,7 +287,9 @@ ${body.bounce?.bouncedRecipients.map(
|
|||||||
`
|
`
|
||||||
},
|
},
|
||||||
(err, info) => {
|
(err, info) => {
|
||||||
console.log("***", err || info);
|
logger.log("sns-error", err ? "error" : "debug", "api", null, {
|
||||||
|
message: err ? JSON.stringify(error) : info
|
||||||
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,10 +18,10 @@ const tasksEmailQueue = taskEmailQueue();
|
|||||||
const tasksEmailQueueCleanup = async () => {
|
const tasksEmailQueueCleanup = async () => {
|
||||||
try {
|
try {
|
||||||
// Example async operation
|
// Example async operation
|
||||||
console.log("Performing Tasks Email Reminder process cleanup...");
|
// console.log("Performing Tasks Email Reminder process cleanup...");
|
||||||
await new Promise((resolve) => tasksEmailQueue.destroy(() => resolve()));
|
await new Promise((resolve) => tasksEmailQueue.destroy(() => resolve()));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Tasks Email Reminder process cleanup failed:", err);
|
// console.error("Tasks Email Reminder process cleanup failed:", err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -77,6 +77,7 @@ const formatPriority = (priority) => {
|
|||||||
* @param priority
|
* @param priority
|
||||||
* @param description
|
* @param description
|
||||||
* @param dueDate
|
* @param dueDate
|
||||||
|
* @param createdBy
|
||||||
* @param bodyshop
|
* @param bodyshop
|
||||||
* @param job
|
* @param job
|
||||||
* @param taskId
|
* @param taskId
|
||||||
@@ -96,11 +97,11 @@ const getEndpoints = (bodyshop) =>
|
|||||||
: "https://romeonline.io"
|
: "https://romeonline.io"
|
||||||
});
|
});
|
||||||
|
|
||||||
const generateTemplateArgs = (title, priority, description, dueDate, bodyshop, job, taskId, dateLine) => {
|
const generateTemplateArgs = (title, priority, description, dueDate, bodyshop, job, taskId, dateLine, createdBy) => {
|
||||||
const endPoints = getEndpoints(bodyshop);
|
const endPoints = getEndpoints(bodyshop);
|
||||||
return {
|
return {
|
||||||
header: title,
|
header: title,
|
||||||
subHeader: `Body Shop: ${bodyshop.shopname} | Priority: ${formatPriority(priority)} ${formatDate(dueDate)}`,
|
subHeader: `Body Shop: ${bodyshop.shopname} | Priority: ${formatPriority(priority)} ${formatDate(dueDate)} | Created By: ${createdBy || "N/A"}`,
|
||||||
body: `Reference: ${job.ro_number || "N/A"} | ${job.ownr_co_nm ? job.ownr_co_nm : `${job.ownr_fn || ""} ${job.ownr_ln || ""}`.trim()} | ${`${job.v_model_yr || ""} ${job.v_make_desc || ""} ${job.v_model_desc || ""}`.trim()}<br>${description ? description.concat("<br>") : ""}<a href="${endPoints}/manage/tasks/alltasks?taskid=${taskId}">View this task.</a>`,
|
body: `Reference: ${job.ro_number || "N/A"} | ${job.ownr_co_nm ? job.ownr_co_nm : `${job.ownr_fn || ""} ${job.ownr_ln || ""}`.trim()} | ${`${job.v_model_yr || ""} ${job.v_make_desc || ""} ${job.v_model_desc || ""}`.trim()}<br>${description ? description.concat("<br>") : ""}<a href="${endPoints}/manage/tasks/alltasks?taskid=${taskId}">View this task.</a>`,
|
||||||
dateLine
|
dateLine
|
||||||
};
|
};
|
||||||
@@ -181,7 +182,8 @@ const taskAssignedEmail = async (req, res) => {
|
|||||||
tasks_by_pk.bodyshop,
|
tasks_by_pk.bodyshop,
|
||||||
tasks_by_pk.job,
|
tasks_by_pk.job,
|
||||||
newTask.id,
|
newTask.id,
|
||||||
dateLine
|
dateLine,
|
||||||
|
newTask.created_by
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
null,
|
null,
|
||||||
@@ -268,7 +270,8 @@ const tasksRemindEmail = async (req, res) => {
|
|||||||
onlyTask.bodyshop,
|
onlyTask.bodyshop,
|
||||||
onlyTask.job,
|
onlyTask.job,
|
||||||
onlyTask.id,
|
onlyTask.id,
|
||||||
dateLine
|
dateLine,
|
||||||
|
onlyTask.created_by
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,8 +10,9 @@ const logger = require("../utils/logger");
|
|||||||
const taskEmailQueue = () =>
|
const taskEmailQueue = () =>
|
||||||
new Queue(
|
new Queue(
|
||||||
(taskIds, cb) => {
|
(taskIds, cb) => {
|
||||||
console.log("Processing reminds for taskIds: ", taskIds.join(", "));
|
logger.log("Processing reminds for taskIds: ", "silly", null, null, {
|
||||||
|
taskIds: taskIds?.join(", ")
|
||||||
|
});
|
||||||
// Set the remind_at_sent to the current time.
|
// Set the remind_at_sent to the current time.
|
||||||
const now = moment().toISOString();
|
const now = moment().toISOString();
|
||||||
|
|
||||||
|
|||||||
@@ -269,10 +269,14 @@ const sendNotification = async (req, res) => {
|
|||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
// Response is a message ID string.
|
// Response is a message ID string.
|
||||||
console.log("Successfully sent message:", response);
|
logger.log("Successfully sent message:", "debug", req?.user?.email, null, {
|
||||||
|
response
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.log("Error sending message:", error);
|
logger.log("Successfully sent message:", "error", req?.user?.email, null, {
|
||||||
|
error
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
res.sendStatus(200);
|
res.sendStatus(200);
|
||||||
|
|||||||
@@ -2506,6 +2506,7 @@ exports.QUERY_TASK_BY_ID = `
|
|||||||
query QUERY_TASK_BY_ID($id: uuid!) {
|
query QUERY_TASK_BY_ID($id: uuid!) {
|
||||||
tasks_by_pk(id: $id) {
|
tasks_by_pk(id: $id) {
|
||||||
id
|
id
|
||||||
|
created_by
|
||||||
assigned_to_employee{
|
assigned_to_employee{
|
||||||
id
|
id
|
||||||
user_email
|
user_email
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ exports.default = async (req, res) => {
|
|||||||
|
|
||||||
res.sendStatus(200);
|
res.sendStatus(200);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.log("ioevent-error", "trace", user, null, {
|
logger.log("ioevent-error", "silly", user, null, {
|
||||||
operationname: operationName,
|
operationname: operationName,
|
||||||
time,
|
time,
|
||||||
dbevent,
|
dbevent,
|
||||||
|
|||||||
@@ -19,7 +19,8 @@ async function JobCosting(req, res) {
|
|||||||
const BearerToken = req.BearerToken;
|
const BearerToken = req.BearerToken;
|
||||||
const client = req.userGraphQLClient;
|
const client = req.userGraphQLClient;
|
||||||
|
|
||||||
logger.log("job-costing-start", "DEBUG", req.user.email, jobid, null);
|
//Uncomment for further testing
|
||||||
|
// logger.log("job-costing-start", "DEBUG", req.user.email, jobid, null);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const resp = await client.setHeaders({ Authorization: BearerToken }).request(queries.QUERY_JOB_COSTING_DETAILS, {
|
const resp = await client.setHeaders({ Authorization: BearerToken }).request(queries.QUERY_JOB_COSTING_DETAILS, {
|
||||||
@@ -46,7 +47,10 @@ async function JobCostingMulti(req, res) {
|
|||||||
const BearerToken = req.BearerToken;
|
const BearerToken = req.BearerToken;
|
||||||
const client = req.userGraphQLClient;
|
const client = req.userGraphQLClient;
|
||||||
|
|
||||||
logger.log("job-costing-multi-start", "DEBUG", req.user.email, jobids, null);
|
//Uncomment for further testing
|
||||||
|
// logger.log("job-costing-multi-start", "DEBUG", req?.user?.email, null, {
|
||||||
|
// jobids
|
||||||
|
// });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const resp = await client
|
const resp = await client
|
||||||
@@ -244,7 +248,8 @@ async function JobCostingMulti(req, res) {
|
|||||||
data: ret
|
data: ret
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.log("job-costing-multi-error", "ERROR", req.user.email, [jobids], {
|
logger.log("job-costing-multi-error", "ERROR", req?.user?.email, null, {
|
||||||
|
jobids,
|
||||||
message: error.message,
|
message: error.message,
|
||||||
stack: error.stack
|
stack: error.stack
|
||||||
});
|
});
|
||||||
@@ -282,7 +287,13 @@ function GenerateCostingData(job) {
|
|||||||
if (val.mod_lbr_ty) {
|
if (val.mod_lbr_ty) {
|
||||||
const laborProfitCenter = val.profitcenter_labor || defaultProfits[val.mod_lbr_ty] || "Unknown";
|
const laborProfitCenter = val.profitcenter_labor || defaultProfits[val.mod_lbr_ty] || "Unknown";
|
||||||
|
|
||||||
if (laborProfitCenter === "Unknown") console.log("Unknown type", val.line_desc, val.mod_lbr_ty);
|
//Uncomment for further testing
|
||||||
|
// if (laborProfitCenter === "Unknown") {
|
||||||
|
// logger.log("job-costing unknown type", "debug", null, null, {
|
||||||
|
// line_desc: val.line_desc,
|
||||||
|
// mod_lbr_ty: val.mod_lbr_ty
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
const rateName = `rate_${(val.mod_lbr_ty || "").toLowerCase()}`;
|
const rateName = `rate_${(val.mod_lbr_ty || "").toLowerCase()}`;
|
||||||
|
|
||||||
@@ -349,10 +360,22 @@ function GenerateCostingData(job) {
|
|||||||
if (val.part_type && val.part_type !== "PAE" && val.part_type !== "PAS" && val.part_type !== "PASL") {
|
if (val.part_type && val.part_type !== "PAE" && val.part_type !== "PAS" && val.part_type !== "PASL") {
|
||||||
const partsProfitCenter = val.profitcenter_part || defaultProfits[val.part_type] || "Unknown";
|
const partsProfitCenter = val.profitcenter_part || defaultProfits[val.part_type] || "Unknown";
|
||||||
|
|
||||||
if (partsProfitCenter === "Unknown") console.log("Unknown type", val.line_desc, val.part_type);
|
//Uncomment for further testing
|
||||||
|
// if (partsProfitCenter === "Unknown" || !partsProfitCenter) {
|
||||||
|
// logger.log(
|
||||||
|
// partsProfitCenter === "Unknown"
|
||||||
|
// ? "job-costing unknown type"
|
||||||
|
// : "Unknown cost/profit center mapping for parts.",
|
||||||
|
// "debug",
|
||||||
|
// null,
|
||||||
|
// null,
|
||||||
|
// {
|
||||||
|
// line_desc: val.line_desc,
|
||||||
|
// part_type: val.part_type
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
if (!partsProfitCenter)
|
|
||||||
console.log("Unknown cost/profit center mapping for parts.", val.line_desc, val.part_type);
|
|
||||||
let partsAmount = Dinero({
|
let partsAmount = Dinero({
|
||||||
amount: val.act_price_before_ppc
|
amount: val.act_price_before_ppc
|
||||||
? Math.round(val.act_price_before_ppc * 100)
|
? Math.round(val.act_price_before_ppc * 100)
|
||||||
@@ -409,10 +432,22 @@ function GenerateCostingData(job) {
|
|||||||
if (val.part_type && val.part_type !== "PAE" && (val.part_type === "PAS" || val.part_type === "PASL")) {
|
if (val.part_type && val.part_type !== "PAE" && (val.part_type === "PAS" || val.part_type === "PASL")) {
|
||||||
const partsProfitCenter = val.profitcenter_part || defaultProfits[val.part_type] || "Unknown";
|
const partsProfitCenter = val.profitcenter_part || defaultProfits[val.part_type] || "Unknown";
|
||||||
|
|
||||||
if (partsProfitCenter === "Unknown") console.log("Unknown type", val.line_desc, val.part_type);
|
//Uncomment for further testing
|
||||||
|
// if (partsProfitCenter === "Unknown" || !partsProfitCenter) {
|
||||||
|
// logger.log(
|
||||||
|
// partsProfitCenter === "Unknown"
|
||||||
|
// ? "job-costing unknown type"
|
||||||
|
// : "job-costing Unknown cost/profit center mapping for sublet",
|
||||||
|
// "debug",
|
||||||
|
// null,
|
||||||
|
// null,
|
||||||
|
// {
|
||||||
|
// line_desc: val.line_desc,
|
||||||
|
// part_type: val.part_type
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
if (!partsProfitCenter)
|
|
||||||
console.log("Unknown cost/profit center mapping for sublet.", val.line_desc, val.part_type);
|
|
||||||
const partsAmount = Dinero({
|
const partsAmount = Dinero({
|
||||||
amount: Math.round((val.act_price || 0) * 100)
|
amount: Math.round((val.act_price || 0) * 100)
|
||||||
})
|
})
|
||||||
@@ -443,9 +478,14 @@ function GenerateCostingData(job) {
|
|||||||
//If so, use it, otherwise try to use the same from the auto-allocate logic in IO app jobs-close-auto-allocate.
|
//If so, use it, otherwise try to use the same from the auto-allocate logic in IO app jobs-close-auto-allocate.
|
||||||
const partsProfitCenter = val.profitcenter_part || getAdditionalCostCenter(val, defaultProfits) || "Unknown";
|
const partsProfitCenter = val.profitcenter_part || getAdditionalCostCenter(val, defaultProfits) || "Unknown";
|
||||||
|
|
||||||
if (partsProfitCenter === "Unknown") {
|
//Uncomment for further testing
|
||||||
console.log("Unknown type", val.line_desc, val.part_type);
|
// if (partsProfitCenter === "Unknown") {
|
||||||
}
|
// logger.log("job-costing unknown type", "debug", null, null, {
|
||||||
|
// line_desc: val.line_desc,
|
||||||
|
// part_type: val.part_type
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
const partsAmount = Dinero({
|
const partsAmount = Dinero({
|
||||||
amount: Math.round((val.act_price || 0) * 100)
|
amount: Math.round((val.act_price || 0) * 100)
|
||||||
})
|
})
|
||||||
@@ -476,7 +516,7 @@ function GenerateCostingData(job) {
|
|||||||
if (!hasMapaLine) {
|
if (!hasMapaLine) {
|
||||||
if (!jobLineTotalsByProfitCenter.additional[defaultProfits["MAPA"]])
|
if (!jobLineTotalsByProfitCenter.additional[defaultProfits["MAPA"]])
|
||||||
jobLineTotalsByProfitCenter.additional[defaultProfits["MAPA"]] = Dinero();
|
jobLineTotalsByProfitCenter.additional[defaultProfits["MAPA"]] = Dinero();
|
||||||
|
|
||||||
jobLineTotalsByProfitCenter.additional[defaultProfits["MAPA"]] = jobLineTotalsByProfitCenter.additional[
|
jobLineTotalsByProfitCenter.additional[defaultProfits["MAPA"]] = jobLineTotalsByProfitCenter.additional[
|
||||||
defaultProfits["MAPA"]
|
defaultProfits["MAPA"]
|
||||||
].add(
|
].add(
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ exports.totalsSsu = async function (req, res) {
|
|||||||
const BearerToken = req.BearerToken;
|
const BearerToken = req.BearerToken;
|
||||||
const client = req.userGraphQLClient;
|
const client = req.userGraphQLClient;
|
||||||
|
|
||||||
logger.log("job-totals-ssu-USA", "DEBUG", req.user.email, id, null);
|
logger.log("job-totals-ssu-USA", "DEBUG", req?.user?.email, id);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const job = await client.setHeaders({ Authorization: BearerToken }).request(queries.GET_JOB_BY_PK, {
|
const job = await client.setHeaders({ Authorization: BearerToken }).request(queries.GET_JOB_BY_PK, {
|
||||||
@@ -47,7 +47,7 @@ exports.totalsSsu = async function (req, res) {
|
|||||||
|
|
||||||
res.status(200).send();
|
res.status(200).send();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.log("job-totals-ssu-USA-error", "ERROR", req.user.email, id, {
|
logger.log("job-totals-ssu-USA-error", "ERROR", req?.user?.email, id, {
|
||||||
jobid: id,
|
jobid: id,
|
||||||
error
|
error
|
||||||
});
|
});
|
||||||
@@ -84,12 +84,10 @@ async function Totals(req, res) {
|
|||||||
const logger = req.logger;
|
const logger = req.logger;
|
||||||
const client = req.userGraphQLClient;
|
const client = req.userGraphQLClient;
|
||||||
|
|
||||||
logger.log("job-totals-USA", "DEBUG", req.user.email, job.id, {
|
logger.log("job-totals-ssu-USA", "DEBUG", req.user.email, job.id, {
|
||||||
jobid: job.id
|
jobid: job.id
|
||||||
});
|
});
|
||||||
|
|
||||||
logger.log("job-totals-ssu-USA", "DEBUG", req.user.email, id, null);
|
|
||||||
|
|
||||||
await AutoAddAtsIfRequired({ job, client });
|
await AutoAddAtsIfRequired({ job, client });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -961,7 +959,9 @@ function CalculateTaxesTotals(job, otherTotals) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Key with issue", key);
|
logger.log("job-totals-USA Key with issue", "error", null, null, {
|
||||||
|
key
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1026,7 +1026,9 @@ function CalculateTaxesTotals(job, otherTotals) {
|
|||||||
totalTaxByTier[taxTierKey] = totalTaxByTier[taxTierKey].add(taxAmountToAdd);
|
totalTaxByTier[taxTierKey] = totalTaxByTier[taxTierKey].add(taxAmountToAdd);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("PFP Calculation error", error);
|
logger.log("job-totals-USA - PFP Calculation Error", "error", null, null, {
|
||||||
|
error
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,16 @@ const { isObject } = require("lodash");
|
|||||||
|
|
||||||
const jobUpdated = async (req, res) => {
|
const jobUpdated = async (req, res) => {
|
||||||
const { ioRedis, logger, ioHelpers } = req;
|
const { ioRedis, logger, ioHelpers } = req;
|
||||||
|
// Old Way
|
||||||
|
if (req?.body?.event?.data?.new || isObject(req?.body?.event?.data?.new)) {
|
||||||
|
const updatedJob = req.body.event.data.new;
|
||||||
|
const bodyshopID = updatedJob.shopid;
|
||||||
|
ioRedis.to(ioHelpers.getBodyshopRoom(bodyshopID)).emit("production-job-updated", updatedJob);
|
||||||
|
return res.json({ message: "Job updated and event emitted" });
|
||||||
|
}
|
||||||
|
|
||||||
if (!req?.body?.event?.data?.new || !isObject(req?.body?.event?.data?.new)) {
|
// New way
|
||||||
|
if (!req?.body?.data || !isObject(req.body.data)) {
|
||||||
logger.log("job-update-error", "ERROR", req.user?.email, null, {
|
logger.log("job-update-error", "ERROR", req.user?.email, null, {
|
||||||
message: `Malformed Job Update request sent from Hasura`,
|
message: `Malformed Job Update request sent from Hasura`,
|
||||||
body: req?.body
|
body: req?.body
|
||||||
@@ -15,12 +23,14 @@ const jobUpdated = async (req, res) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.log("job-update", "INFO", req.user?.email, null, {
|
// Uncomment for further testing
|
||||||
message: `Job updated event received from Hasura`,
|
// You can also test this using SocketIOAdmin
|
||||||
jobid: req?.body?.event?.data?.new?.id
|
// logger.log("job-update", "DEBUG", req.user?.email, null, {
|
||||||
});
|
// message: `Job updated event received from Hasura`,
|
||||||
|
// jobid: req?.body?.event?.data?.new?.id
|
||||||
|
// });
|
||||||
|
|
||||||
const updatedJob = req.body.event.data.new;
|
const updatedJob = req.body.data;
|
||||||
const bodyshopID = updatedJob.shopid;
|
const bodyshopID = updatedJob.shopid;
|
||||||
|
|
||||||
// Emit the job-updated event only to the room corresponding to the bodyshop
|
// Emit the job-updated event only to the room corresponding to the bodyshop
|
||||||
|
|||||||
@@ -16,7 +16,11 @@ const validateFirebaseIdTokenMiddleware = async (req, res, next) => {
|
|||||||
(!req.headers.authorization || !req.headers.authorization.startsWith("Bearer ")) &&
|
(!req.headers.authorization || !req.headers.authorization.startsWith("Bearer ")) &&
|
||||||
!(req.cookies && req.cookies.__session)
|
!(req.cookies && req.cookies.__session)
|
||||||
) {
|
) {
|
||||||
console.error("Unauthorized attempt. No authorization provided.");
|
logger.log("api-authorization-call", "warn", req?.user?.email, null, {
|
||||||
|
type: "unauthorized",
|
||||||
|
path: req.path,
|
||||||
|
body: req.body
|
||||||
|
});
|
||||||
return res.status(403).send("Unauthorized");
|
return res.status(403).send("Unauthorized");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,10 +36,10 @@ const validateFirebaseIdTokenMiddleware = async (req, res, next) => {
|
|||||||
idToken = req.cookies.__session;
|
idToken = req.cookies.__session;
|
||||||
} else {
|
} else {
|
||||||
// No cookie
|
// No cookie
|
||||||
console.error("Unauthorized attempt. No cookie provided.");
|
logger.log("api-unauthorized-call", "warn", null, null, {
|
||||||
logger.log("api-unauthorized-call", "WARN", null, null, {
|
type: "unauthorized",
|
||||||
req,
|
path: req.path,
|
||||||
type: "no-cookie"
|
body: req.body
|
||||||
});
|
});
|
||||||
|
|
||||||
return res.status(403).send("Unauthorized");
|
return res.status(403).send("Unauthorized");
|
||||||
@@ -47,11 +51,11 @@ const validateFirebaseIdTokenMiddleware = async (req, res, next) => {
|
|||||||
req.user = decodedIdToken;
|
req.user = decodedIdToken;
|
||||||
next();
|
next();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.log("api-unauthorized-call", "WARN", null, null, {
|
logger.log("api-unauthorized-call", "warn", null, null, {
|
||||||
path: req.path,
|
path: req.path,
|
||||||
body: req.body,
|
body: req.body,
|
||||||
|
|
||||||
type: "unauthroized",
|
type: "unauthorized",
|
||||||
...error
|
...error
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -9,11 +9,9 @@ require("dotenv").config({
|
|||||||
});
|
});
|
||||||
|
|
||||||
exports.mixdataUpload = async (req, res) => {
|
exports.mixdataUpload = async (req, res) => {
|
||||||
const { bodyshopid } = req.body;
|
|
||||||
|
|
||||||
const client = req.userGraphQLClient;
|
const client = req.userGraphQLClient;
|
||||||
|
|
||||||
logger.log("job-mixdata-upload", "DEBUG", req.user.email, null, null);
|
logger.log("job-mixdata-upload", "DEBUG", req?.user?.email, null, null);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (const element of req.files) {
|
for (const element of req.files) {
|
||||||
@@ -23,7 +21,7 @@ exports.mixdataUpload = async (req, res) => {
|
|||||||
explicitArray: false
|
explicitArray: false
|
||||||
});
|
});
|
||||||
|
|
||||||
logger.log("job-mixdata-parse", "DEBUG", req.user.email, inboundRequest);
|
logger.log("job-mixdata-parse", "DEBUG", req?.user?.email, null, { inboundRequest });
|
||||||
|
|
||||||
const ScaleType = DetermineScaleType(inboundRequest);
|
const ScaleType = DetermineScaleType(inboundRequest);
|
||||||
const RoNumbersFromInboundRequest = GetListOfRos(inboundRequest, ScaleType);
|
const RoNumbersFromInboundRequest = GetListOfRos(inboundRequest, ScaleType);
|
||||||
@@ -61,7 +59,7 @@ exports.mixdataUpload = async (req, res) => {
|
|||||||
res.status(500).json(error);
|
res.status(500).json(error);
|
||||||
logger.log("job-mixdata-upload-error", "ERROR", null, null, {
|
logger.log("job-mixdata-upload-error", "ERROR", null, null, {
|
||||||
error: error.message,
|
error: error.message,
|
||||||
...error
|
stack: error.stack
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -70,7 +68,7 @@ function DetermineScaleType(inboundRequest) {
|
|||||||
const ret = { type: "", verson: 0 };
|
const ret = { type: "", verson: 0 };
|
||||||
|
|
||||||
//PPG Mix Data
|
//PPG Mix Data
|
||||||
if (inboundRequest.PPG && inboundRequest.PPG.Header.Protocol.Name === "PPG") {
|
if (inboundRequest?.PPG?.Header?.Protocol?.Name === "PPG") {
|
||||||
return {
|
return {
|
||||||
type: inboundRequest.PPG.Header.Protocol.Name,
|
type: inboundRequest.PPG.Header.Protocol.Name,
|
||||||
company: "PPG",
|
company: "PPG",
|
||||||
@@ -80,13 +78,13 @@ function DetermineScaleType(inboundRequest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function GetListOfRos(inboundRequest, ScaleType) {
|
function GetListOfRos(inboundRequest, ScaleType) {
|
||||||
if (ScaleType.company === "PPG" && ScaleType.version === "1.3.0") {
|
if (ScaleType?.company === "PPG" && ScaleType?.version === "1.3.0") {
|
||||||
return inboundRequest.PPG.MixDataInterface.ROData.RepairOrders.RO.map((r) => r.RONumber);
|
return inboundRequest.PPG.MixDataInterface.ROData.RepairOrders.RO.map((r) => r.RONumber);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function GenerateMixDataArray(inboundRequest, ScaleType, jobHash) {
|
function GenerateMixDataArray(inboundRequest, ScaleType, jobHash) {
|
||||||
if (ScaleType.company === "PPG" && ScaleType.version === "1.3.0") {
|
if (ScaleType?.company === "PPG" && ScaleType?.version === "1.3.0") {
|
||||||
return inboundRequest.PPG.MixDataInterface.ROData.RepairOrders.RO.map((r) => {
|
return inboundRequest.PPG.MixDataInterface.ROData.RepairOrders.RO.map((r) => {
|
||||||
return {
|
return {
|
||||||
jobid: jobHash[r.RONumber]?.jobid,
|
jobid: jobHash[r.RONumber]?.jobid,
|
||||||
|
|||||||
@@ -45,12 +45,12 @@ exports.payall = async function (req, res) {
|
|||||||
const path = diffParser(diff);
|
const path = diffParser(diff);
|
||||||
|
|
||||||
if (diff.op === "add") {
|
if (diff.op === "add") {
|
||||||
console.log(Object.keys(diff.val));
|
// console.log(Object.keys(diff.val));
|
||||||
if (typeof diff.val === "object" && Object.keys(diff.val).length > 1) {
|
if (typeof diff.val === "object" && Object.keys(diff.val).length > 1) {
|
||||||
//Multiple values to add.
|
//Multiple values to add.
|
||||||
Object.keys(diff.val).forEach((key) => {
|
Object.keys(diff.val).forEach((key) => {
|
||||||
console.log("Hours", diff.val[key][Object.keys(diff.val[key])[0]]);
|
// console.log("Hours", diff.val[key][Object.keys(diff.val[key])[0]]);
|
||||||
console.log("Rate", Object.keys(diff.val[key])[0]);
|
// console.log("Rate", Object.keys(diff.val[key])[0]);
|
||||||
ticketsToInsert.push({
|
ticketsToInsert.push({
|
||||||
task_name: "Pay All",
|
task_name: "Pay All",
|
||||||
jobid: job.id,
|
jobid: job.id,
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ exports.job = async (req, res) => {
|
|||||||
if (bucketId) {
|
if (bucketId) {
|
||||||
load.productionTotal[bucketId].count = load.productionTotal[bucketId].count + 1;
|
load.productionTotal[bucketId].count = load.productionTotal[bucketId].count + 1;
|
||||||
} else {
|
} else {
|
||||||
console.log("Uh oh, this job doesn't fit in a bucket!", item);
|
// console.log("Uh oh, this job doesn't fit in a bucket!", item);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -254,7 +254,7 @@ const CalculateLoad = (currentLoad, buckets, jobsIn, jobsOut) => {
|
|||||||
if (bucketId) {
|
if (bucketId) {
|
||||||
newLoad[bucketId].count = newLoad[bucketId].count + 1;
|
newLoad[bucketId].count = newLoad[bucketId].count + 1;
|
||||||
} else {
|
} else {
|
||||||
console.log("[Util Arr Job]Uh oh, this job doesn't fit in a bucket!", job);
|
// console.log("[Util Arr Job]Uh oh, this job doesn't fit in a bucket!", job);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -263,10 +263,10 @@ const CalculateLoad = (currentLoad, buckets, jobsIn, jobsOut) => {
|
|||||||
if (bucketId) {
|
if (bucketId) {
|
||||||
newLoad[bucketId].count = newLoad[bucketId].count - 1;
|
newLoad[bucketId].count = newLoad[bucketId].count - 1;
|
||||||
if (newLoad[bucketId].count < 0) {
|
if (newLoad[bucketId].count < 0) {
|
||||||
console.log("***ERROR: NEGATIVE LOAD Bucket =>", bucketId, job);
|
// console.log("***ERROR: NEGATIVE LOAD Bucket =>", bucketId, job);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.log("[Util Out Job]Uh oh, this job doesn't fit in a bucket!", job);
|
// console.log("[Util Out Job]Uh oh, this job doesn't fit in a bucket!", job);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ const processor = async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("error", error);
|
// console.log("error", error);
|
||||||
res.status(400).send(error);
|
res.status(400).send(error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,10 +6,11 @@ const client = require("../graphql-client/graphql-client").client;
|
|||||||
const emailer = require("../email/sendemail");
|
const emailer = require("../email/sendemail");
|
||||||
const moment = require("moment-timezone");
|
const moment = require("moment-timezone");
|
||||||
const converter = require("json-2-csv");
|
const converter = require("json-2-csv");
|
||||||
|
const logger = require("../utils/logger");
|
||||||
|
|
||||||
exports.taskHandler = async (req, res) => {
|
exports.taskHandler = async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { bodyshopid, query, variables, text, to, subject, timezone } = req.body;
|
const { query, variables, text, to, subject, timezone } = req.body;
|
||||||
|
|
||||||
//Check the variables to see if they are an object.
|
//Check the variables to see if they are an object.
|
||||||
Object.keys(variables).forEach((key) => {
|
Object.keys(variables).forEach((key) => {
|
||||||
@@ -32,8 +33,10 @@ exports.taskHandler = async (req, res) => {
|
|||||||
text,
|
text,
|
||||||
attachments: [{ filename: "query.csv", content: csv }]
|
attachments: [{ filename: "query.csv", content: csv }]
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((error) => {
|
||||||
console.error("Errors sending CSV Email.");
|
logger.log("Tasks - Error sending CSV EMAIL", "error", req?.user?.email, null, {
|
||||||
|
error
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return res.status(200).send(csv);
|
return res.status(200).send(csv);
|
||||||
|
|||||||
@@ -8,6 +8,19 @@ const InstanceManager = require("../utils/instanceMgr").default;
|
|||||||
const winston = require("winston");
|
const winston = require("winston");
|
||||||
const WinstonCloudWatch = require("winston-cloudwatch");
|
const WinstonCloudWatch = require("winston-cloudwatch");
|
||||||
const { isString, isEmpty } = require("lodash");
|
const { isString, isEmpty } = require("lodash");
|
||||||
|
const { networkInterfaces, hostname } = require("node:os");
|
||||||
|
|
||||||
|
const LOG_LEVELS = {
|
||||||
|
error: { level: 0, name: "error" },
|
||||||
|
warn: { level: 1, name: "warn" },
|
||||||
|
info: { level: 2, name: "info" },
|
||||||
|
http: { level: 3, name: "http" },
|
||||||
|
verbose: { level: 4, name: "verbose" },
|
||||||
|
debug: { level: 5, name: "debug" },
|
||||||
|
silly: { level: 6, name: "silly" }
|
||||||
|
};
|
||||||
|
|
||||||
|
const normalizeLevel = (level) => (level ? level.toLowerCase() : LOG_LEVELS.debug.name);
|
||||||
|
|
||||||
const createLogger = () => {
|
const createLogger = () => {
|
||||||
try {
|
try {
|
||||||
@@ -27,9 +40,6 @@ const createLogger = () => {
|
|||||||
|
|
||||||
if (isLocal) {
|
if (isLocal) {
|
||||||
winstonCloudwatchTransportDefaults.awsOptions.endpoint = `http://${process.env.LOCALSTACK_HOSTNAME}:4566`;
|
winstonCloudwatchTransportDefaults.awsOptions.endpoint = `http://${process.env.LOCALSTACK_HOSTNAME}:4566`;
|
||||||
console.log(
|
|
||||||
`Winston Transports set to LocalStack end point: ${winstonCloudwatchTransportDefaults.awsOptions.endpoint}`
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const levelFilter = (levels) => {
|
const levelFilter = (levels) => {
|
||||||
@@ -42,6 +52,22 @@ const createLogger = () => {
|
|||||||
})();
|
})();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getHostNameOrIP = () => {
|
||||||
|
// Try to get the hostname first
|
||||||
|
const hostName = hostname();
|
||||||
|
if (hostName) return hostName;
|
||||||
|
|
||||||
|
const interfaces = networkInterfaces();
|
||||||
|
for (const name of Object.keys(interfaces)) {
|
||||||
|
for (const iface of interfaces[name]) {
|
||||||
|
if (iface.family === "IPv4" && !iface.internal) {
|
||||||
|
return iface.address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "127.0.0.1";
|
||||||
|
};
|
||||||
const createProductionTransport = (level, logStreamName, filters) => {
|
const createProductionTransport = (level, logStreamName, filters) => {
|
||||||
return new WinstonCloudWatch({
|
return new WinstonCloudWatch({
|
||||||
level,
|
level,
|
||||||
@@ -51,17 +77,26 @@ const createLogger = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const internalHostname = process.env.HOSTNAME || getHostNameOrIP();
|
||||||
|
|
||||||
const getDevelopmentTransports = () => [
|
const getDevelopmentTransports = () => [
|
||||||
new winston.transports.Console({
|
new winston.transports.Console({
|
||||||
level: "silly",
|
level: "silly",
|
||||||
format: winston.format.combine(
|
format: winston.format.combine(
|
||||||
winston.format.colorize(),
|
winston.format.colorize(),
|
||||||
winston.format.timestamp(),
|
winston.format.timestamp(),
|
||||||
winston.format.printf(({ level, message, timestamp, user, record, object }) => {
|
winston.format.printf(({ level, message, timestamp, user, record, meta }) => {
|
||||||
return `${timestamp} [${level}]: ${message} ${
|
const hostnameColor = `\x1b[34m${internalHostname}\x1b[0m`; // Blue
|
||||||
user ? `| user: ${JSON.stringify(user)}` : ""
|
const timestampColor = `\x1b[36m${timestamp}\x1b[0m`; // Cyan
|
||||||
} ${record ? `| record: ${JSON.stringify(record)}` : ""} ${
|
const labelColor = "\x1b[33m"; // Yellow
|
||||||
object ? `| object: ${JSON.stringify(object, null, 2)}` : ""
|
const separatorColor = "\x1b[35m|\x1b[0m"; // Magenta for separators
|
||||||
|
|
||||||
|
return `${timestampColor} [${hostnameColor}] [${level}]: ${message} ${
|
||||||
|
user ? `${separatorColor} ${labelColor}user:\x1b[0m ${JSON.stringify(user)}` : ""
|
||||||
|
} ${record ? `${separatorColor} ${labelColor}record:\x1b[0m ${JSON.stringify(record)}` : ""}${
|
||||||
|
meta
|
||||||
|
? `\n${separatorColor} ${labelColor}meta:\x1b[0m ${JSON.stringify(meta, null, 2)} ${separatorColor}`
|
||||||
|
: ""
|
||||||
}`;
|
}`;
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
@@ -83,12 +118,19 @@ const createLogger = () => {
|
|||||||
: [...getDevelopmentTransports(), ...getProductionTransports()]
|
: [...getDevelopmentTransports(), ...getProductionTransports()]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (isLocal) {
|
||||||
|
winstonLogger.debug(
|
||||||
|
`CloudWatch set to LocalStack end point: ${winstonCloudwatchTransportDefaults.awsOptions.endpoint}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const log = (message, type, user, record, meta) => {
|
const log = (message, type, user, record, meta) => {
|
||||||
winstonLogger.log({
|
winstonLogger.log({
|
||||||
level: type.toLowerCase(),
|
level: normalizeLevel(type),
|
||||||
message,
|
message,
|
||||||
user,
|
user,
|
||||||
record,
|
record,
|
||||||
|
hostname: internalHostname,
|
||||||
meta
|
meta
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -101,7 +143,8 @@ const createLogger = () => {
|
|||||||
console.error("Error setting up enhanced Logger, defaulting to console.: " + e?.message || "");
|
console.error("Error setting up enhanced Logger, defaulting to console.: " + e?.message || "");
|
||||||
return {
|
return {
|
||||||
log: console.log,
|
log: console.log,
|
||||||
logger: console.log
|
logger: console.log,
|
||||||
|
LOG_LEVELS
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ const redisSocketEvents = ({
|
|||||||
}) => {
|
}) => {
|
||||||
// Logging helper functions
|
// Logging helper functions
|
||||||
const createLogEvent = (socket, level, message) => {
|
const createLogEvent = (socket, level, message) => {
|
||||||
//console.log(`[IOREDIS LOG EVENT] - ${socket?.user?.email} - ${socket.id} - ${message}`);
|
|
||||||
logger.log("ioredis-log-event", level, socket?.user?.email, null, { wsmessage: message });
|
logger.log("ioredis-log-event", level, socket?.user?.email, null, { wsmessage: message });
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -33,7 +32,6 @@ const redisSocketEvents = ({
|
|||||||
next(new Error("Authentication error - no authorization token."));
|
next(new Error("Authentication error - no authorization token."));
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
//console.log("Uncaught connection error:::", error);
|
|
||||||
logger.log("websocket-connection-error", "error", null, null, {
|
logger.log("websocket-connection-error", "error", null, null, {
|
||||||
...error
|
...error
|
||||||
});
|
});
|
||||||
@@ -43,7 +41,8 @@ const redisSocketEvents = ({
|
|||||||
|
|
||||||
// Register Socket Events
|
// Register Socket Events
|
||||||
const registerSocketEvents = (socket) => {
|
const registerSocketEvents = (socket) => {
|
||||||
createLogEvent(socket, "DEBUG", `Registering RedisIO Socket Events.`);
|
// Uncomment for further testing
|
||||||
|
// createLogEvent(socket, "debug", `Registering RedisIO Socket Events.`);
|
||||||
|
|
||||||
// Token Update Events
|
// Token Update Events
|
||||||
const registerUpdateEvents = (socket) => {
|
const registerUpdateEvents = (socket) => {
|
||||||
@@ -56,18 +55,19 @@ const redisSocketEvents = ({
|
|||||||
// If We ever want to persist user Data across workers
|
// If We ever want to persist user Data across workers
|
||||||
// await setSessionData(socket.id, "user", user);
|
// await setSessionData(socket.id, "user", user);
|
||||||
|
|
||||||
createLogEvent(socket, "INFO", "Token updated successfully");
|
// Uncomment for further testing
|
||||||
|
// createLogEvent(socket, "debug", "Token updated successfully");
|
||||||
|
|
||||||
socket.emit("token-updated", { success: true });
|
socket.emit("token-updated", { success: true });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.code === "auth/id-token-expired") {
|
if (error.code === "auth/id-token-expired") {
|
||||||
createLogEvent(socket, "WARNING", "Stale token received, waiting for new token");
|
createLogEvent(socket, "warn", "Stale token received, waiting for new token");
|
||||||
socket.emit("token-updated", {
|
socket.emit("token-updated", {
|
||||||
success: false,
|
success: false,
|
||||||
error: "Stale token."
|
error: "Stale token."
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
createLogEvent(socket, "ERROR", `Token update failed: ${error.message}`);
|
createLogEvent(socket, "error", `Token update failed: ${error.message}`);
|
||||||
socket.emit("token-updated", { success: false, error: error.message });
|
socket.emit("token-updated", { success: false, error: error.message });
|
||||||
// For any other errors, optionally disconnect the socket
|
// For any other errors, optionally disconnect the socket
|
||||||
socket.disconnect();
|
socket.disconnect();
|
||||||
@@ -82,9 +82,9 @@ const redisSocketEvents = ({
|
|||||||
try {
|
try {
|
||||||
const room = getBodyshopRoom(bodyshopUUID);
|
const room = getBodyshopRoom(bodyshopUUID);
|
||||||
socket.join(room);
|
socket.join(room);
|
||||||
createLogEvent(socket, "DEBUG", `Client joined bodyshop room: ${room}`);
|
// createLogEvent(socket, "debug", `Client joined bodyshop room: ${room}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
createLogEvent(socket, "ERROR", `Error joining room: ${error}`);
|
createLogEvent(socket, "error", `Error joining room: ${error}`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -92,9 +92,9 @@ const redisSocketEvents = ({
|
|||||||
try {
|
try {
|
||||||
const room = getBodyshopRoom(bodyshopUUID);
|
const room = getBodyshopRoom(bodyshopUUID);
|
||||||
socket.leave(room);
|
socket.leave(room);
|
||||||
createLogEvent(socket, "DEBUG", `Client left bodyshop room: ${room}`);
|
createLogEvent(socket, "debug", `Client left bodyshop room: ${room}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
createLogEvent(socket, "ERROR", `Error joining room: ${error}`);
|
createLogEvent(socket, "error", `Error joining room: ${error}`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -102,9 +102,10 @@ const redisSocketEvents = ({
|
|||||||
try {
|
try {
|
||||||
const room = getBodyshopRoom(bodyshopUUID);
|
const room = getBodyshopRoom(bodyshopUUID);
|
||||||
io.to(room).emit("bodyshop-message", message);
|
io.to(room).emit("bodyshop-message", message);
|
||||||
createLogEvent(socket, "DEBUG", `Broadcast message to bodyshop ${room}`);
|
// We do not need this as these can be debugged live
|
||||||
|
// createLogEvent(socket, "debug", `Broadcast message to bodyshop ${room}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
createLogEvent(socket, "ERROR", `Error getting room: ${error}`);
|
createLogEvent(socket, "error", `Error getting room: ${error}`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -115,7 +116,9 @@ const redisSocketEvents = ({
|
|||||||
// Disconnect Events
|
// Disconnect Events
|
||||||
const registerDisconnectEvents = (socket) => {
|
const registerDisconnectEvents = (socket) => {
|
||||||
const disconnect = () => {
|
const disconnect = () => {
|
||||||
createLogEvent(socket, "DEBUG", `User disconnected.`);
|
// Uncomment for further testing
|
||||||
|
// createLogEvent(socket, "debug", `User disconnected.`);
|
||||||
|
|
||||||
const rooms = Array.from(socket.rooms).filter((room) => room !== socket.id);
|
const rooms = Array.from(socket.rooms).filter((room) => room !== socket.id);
|
||||||
for (const room of rooms) {
|
for (const room of rooms) {
|
||||||
socket.leave(room);
|
socket.leave(room);
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ io.use(function (socket, next) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
io.on("connection", (socket) => {
|
io.on("connection", (socket) => {
|
||||||
socket.log_level = "TRACE";
|
socket.log_level = "DEBUG";
|
||||||
createLogEvent(socket, "DEBUG", `Connected and Authenticated.`);
|
createLogEvent(socket, "DEBUG", `Connected and Authenticated.`);
|
||||||
|
|
||||||
socket.on("set-log-level", (level) => {
|
socket.on("set-log-level", (level) => {
|
||||||
@@ -75,7 +75,7 @@ io.on("connection", (socket) => {
|
|||||||
socket.on("cdk-calculate-allocations", async (jobid, callback) => {
|
socket.on("cdk-calculate-allocations", async (jobid, callback) => {
|
||||||
const allocations = await CdkCalculateAllocations(socket, jobid);
|
const allocations = await CdkCalculateAllocations(socket, jobid);
|
||||||
createLogEvent(socket, "DEBUG", `Allocations calculated.`);
|
createLogEvent(socket, "DEBUG", `Allocations calculated.`);
|
||||||
createLogEvent(socket, "TRACE", `Allocations calculated. ${JSON.stringify(allocations, null, 2)}`);
|
createLogEvent(socket, "SILLY", `Allocations calculated. ${JSON.stringify(allocations, null, 2)}`);
|
||||||
|
|
||||||
callback(allocations);
|
callback(allocations);
|
||||||
});
|
});
|
||||||
@@ -85,7 +85,7 @@ io.on("connection", (socket) => {
|
|||||||
socket.on("pbs-calculate-allocations", async (jobid, callback) => {
|
socket.on("pbs-calculate-allocations", async (jobid, callback) => {
|
||||||
const allocations = await CdkCalculateAllocations(socket, jobid);
|
const allocations = await CdkCalculateAllocations(socket, jobid);
|
||||||
createLogEvent(socket, "DEBUG", `Allocations calculated.`);
|
createLogEvent(socket, "DEBUG", `Allocations calculated.`);
|
||||||
createLogEvent(socket, "TRACE", `Allocations calculated. ${JSON.stringify(allocations, null, 2)}`);
|
createLogEvent(socket, "SILLY", `Allocations calculated. ${JSON.stringify(allocations, null, 2)}`);
|
||||||
|
|
||||||
callback(allocations);
|
callback(allocations);
|
||||||
});
|
});
|
||||||
@@ -103,7 +103,7 @@ io.on("connection", (socket) => {
|
|||||||
socket.on("pbs-calculate-allocations-ap", async (billids, callback) => {
|
socket.on("pbs-calculate-allocations-ap", async (billids, callback) => {
|
||||||
const allocations = await PbsCalculateAllocationsAp(socket, billids);
|
const allocations = await PbsCalculateAllocationsAp(socket, billids);
|
||||||
createLogEvent(socket, "DEBUG", `AP Allocations calculated.`);
|
createLogEvent(socket, "DEBUG", `AP Allocations calculated.`);
|
||||||
createLogEvent(socket, "TRACE", `Allocations calculated. ${JSON.stringify(allocations, null, 2)}`);
|
createLogEvent(socket, "DEBUG", `Allocations calculated. ${JSON.stringify(allocations, null, 2)}`);
|
||||||
socket.apAllocations = allocations;
|
socket.apAllocations = allocations;
|
||||||
callback(allocations);
|
callback(allocations);
|
||||||
});
|
});
|
||||||
@@ -122,7 +122,7 @@ io.on("connection", (socket) => {
|
|||||||
|
|
||||||
function createLogEvent(socket, level, message) {
|
function createLogEvent(socket, level, message) {
|
||||||
if (LogLevelHierarchy(socket.log_level) >= LogLevelHierarchy(level)) {
|
if (LogLevelHierarchy(socket.log_level) >= LogLevelHierarchy(level)) {
|
||||||
// console.log(`[WS LOG EVENT] ${level} - ${new Date()} - ${socket.user.email} - ${socket.id} - ${message}`);
|
// console.log(`[WS LOG EVENT] ${level} - ${new Date()} - ${socket.user.email} - ${socket.id} - ${message}`);
|
||||||
socket.emit("log-event", {
|
socket.emit("log-event", {
|
||||||
timestamp: new Date(),
|
timestamp: new Date(),
|
||||||
level,
|
level,
|
||||||
@@ -173,17 +173,17 @@ function createJsonEvent(socket, level, message, json) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function createXmlEvent(socket, xml, message, isError = false) {
|
function createXmlEvent(socket, xml, message, isError = false) {
|
||||||
if (LogLevelHierarchy(socket.log_level) >= LogLevelHierarchy("TRACE")) {
|
if (LogLevelHierarchy(socket.log_level) >= LogLevelHierarchy("SILLY")) {
|
||||||
socket.emit("log-event", {
|
socket.emit("log-event", {
|
||||||
timestamp: new Date(),
|
timestamp: new Date(),
|
||||||
level: isError ? "ERROR" : "TRACE",
|
level: isError ? "ERROR" : "SILLY",
|
||||||
message: `${message}: ${xml}`
|
message: `${message}: ${xml}`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.log(
|
logger.log(
|
||||||
isError ? "ws-log-event-xml-error" : "ws-log-event-xml",
|
isError ? "ws-log-event-xml-error" : "ws-log-event-xml",
|
||||||
isError ? "ERROR" : "TRACE",
|
isError ? "ERROR" : "SILLY",
|
||||||
socket.user.email,
|
socket.user.email,
|
||||||
socket.recordid,
|
socket.recordid,
|
||||||
{
|
{
|
||||||
@@ -195,7 +195,7 @@ function createXmlEvent(socket, xml, message, isError = false) {
|
|||||||
if (socket.logEvents && isArray(socket.logEvents)) {
|
if (socket.logEvents && isArray(socket.logEvents)) {
|
||||||
socket.logEvents.push({
|
socket.logEvents.push({
|
||||||
timestamp: new Date(),
|
timestamp: new Date(),
|
||||||
level: isError ? "ERROR" : "TRACE",
|
level: isError ? "ERROR" : "SILLY",
|
||||||
message,
|
message,
|
||||||
xml
|
xml
|
||||||
});
|
});
|
||||||
@@ -206,13 +206,13 @@ function LogLevelHierarchy(level) {
|
|||||||
switch (level) {
|
switch (level) {
|
||||||
case "XML":
|
case "XML":
|
||||||
return 5;
|
return 5;
|
||||||
case "TRACE":
|
case "SILLY":
|
||||||
return 5;
|
return 5;
|
||||||
case "DEBUG":
|
case "DEBUG":
|
||||||
return 4;
|
return 4;
|
||||||
case "INFO":
|
case "INFO":
|
||||||
return 3;
|
return 3;
|
||||||
case "WARNING":
|
case "WARN":
|
||||||
return 2;
|
return 2;
|
||||||
case "ERROR":
|
case "ERROR":
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
Reference in New Issue
Block a user