@@ -3,7 +3,7 @@ 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 dayjs from "../../utils/day";
|
import dayjs from "../../utils/day";
|
||||||
import { dateFormats, dateTimeFormats } from "./formats.js";
|
import { fuzzyMatchDate } from "./formats.js";
|
||||||
|
|
||||||
const DateTimePicker = ({ value, onChange, onBlur, id, onlyFuture, onlyToday, isDateOnly = false, ...restProps }) => {
|
const DateTimePicker = ({ value, onChange, onBlur, id, onlyFuture, onlyToday, isDateOnly = false, ...restProps }) => {
|
||||||
const [isManualInput, setIsManualInput] = useState(false);
|
const [isManualInput, setIsManualInput] = useState(false);
|
||||||
@@ -11,79 +11,34 @@ const DateTimePicker = ({ value, onChange, onBlur, id, onlyFuture, onlyToday, is
|
|||||||
|
|
||||||
const handleChange = useCallback(
|
const handleChange = useCallback(
|
||||||
(newDate) => {
|
(newDate) => {
|
||||||
if (newDate === null && onChange) {
|
if (onChange) {
|
||||||
onChange(null);
|
onChange(newDate || null);
|
||||||
} else if (newDate && onChange) {
|
|
||||||
onChange(newDate);
|
|
||||||
}
|
}
|
||||||
setIsManualInput(false);
|
setIsManualInput(false);
|
||||||
},
|
},
|
||||||
[onChange]
|
[onChange]
|
||||||
);
|
);
|
||||||
|
|
||||||
const normalizeDateTimeString = (input) => {
|
|
||||||
const upperV = input.toUpperCase().replaceAll(".", "/").replaceAll("-", "/");
|
|
||||||
|
|
||||||
const [datePart, ...timeParts] = upperV.split(" ");
|
|
||||||
|
|
||||||
if (timeParts.length === 0) {
|
|
||||||
return datePart; // If there's no time part, just return the date part.
|
|
||||||
}
|
|
||||||
|
|
||||||
const timePart = timeParts.join(" "); // In case there are multiple spaces, join them back
|
|
||||||
|
|
||||||
// Normalize the time part by ensuring there's a space before AM/PM if not already present
|
|
||||||
const normalizedTime = timePart.replace(/(\d{1,2})(:\d{2})?\s?(AM|PM)/, "$1$2 $3");
|
|
||||||
|
|
||||||
// Combine the date part with the normalized time part
|
|
||||||
return `${datePart} ${normalizedTime}`.trim();
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleBlur = useCallback(
|
const handleBlur = useCallback(
|
||||||
(e) => {
|
(e) => {
|
||||||
|
// Bail if this is not a manual input
|
||||||
if (!isManualInput) {
|
if (!isManualInput) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Reset manual input flag
|
||||||
setIsManualInput(false);
|
setIsManualInput(false);
|
||||||
|
|
||||||
const v = e.target.value;
|
const v = e?.target?.value;
|
||||||
|
|
||||||
if (!v) return;
|
if (!v) return;
|
||||||
|
|
||||||
const upperV = normalizeDateTimeString(v);
|
let parsedDate = isDateOnly ? fuzzyMatchDate(v)?.startOf("day") : fuzzyMatchDate(v);
|
||||||
let parsedDate;
|
|
||||||
|
|
||||||
for (const format of isDateOnly ? dateFormats : dateTimeFormats) {
|
if (parsedDate && onChange) {
|
||||||
parsedDate = dayjs(upperV, format);
|
onChange(parsedDate);
|
||||||
if (parsedDate.isValid()) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parsedDate && parsedDate.isValid()) {
|
|
||||||
if (isDateOnly) {
|
|
||||||
parsedDate = parsedDate.startOf("day");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value && value.isValid && value.isValid()) {
|
|
||||||
parsedDate = parsedDate.set({
|
|
||||||
hours: value.hours(),
|
|
||||||
minutes: value.minutes(),
|
|
||||||
seconds: value.seconds(),
|
|
||||||
milliseconds: value.milliseconds()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (onlyFuture) {
|
|
||||||
if (dayjs().subtract(1, "day").isBefore(parsedDate)) {
|
|
||||||
onChange(parsedDate);
|
|
||||||
} else {
|
|
||||||
onChange(dayjs().startOf("day"));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
onChange(parsedDate);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[isManualInput, isDateOnly, onlyFuture, onChange, value]
|
[isManualInput, isDateOnly, onChange]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleKeyDown = useCallback(
|
const handleKeyDown = useCallback(
|
||||||
|
|||||||
@@ -1,96 +1,63 @@
|
|||||||
export const dateTimeFormats = [
|
import dayjs from "../../utils/day";
|
||||||
// Four-digit year with time
|
|
||||||
"M/D/YYYY h:mm A", // Example: 1/5/2023 9:00 AM
|
|
||||||
"M/D/YYYY h:mmA", // Example: 1/5/2023 9:00AM
|
|
||||||
"M/D/YYYY h A", // Example: 1/5/2023 9 AM
|
|
||||||
"M/D/YYYY hA", // Example: 1/5/2023 9AM
|
|
||||||
"M/D/YYYY hh:mm A", // Example: 1/5/2023 02:25 PM
|
|
||||||
"M/D/YYYY hh:mm:ss A", // Example: 1/5/2023 02:25:45 PM
|
|
||||||
|
|
||||||
"MM/D/YYYY h:mm A", // Example: 12/5/2023 9:00 AM
|
const dateFormats = [
|
||||||
"MM/D/YYYY h:mmA", // Example: 12/5/2023 9:00AM
|
|
||||||
"MM/D/YYYY h A", // Example: 12/5/2023 9 AM
|
|
||||||
"MM/D/YYYY hA", // Example: 12/5/2023 9AM
|
|
||||||
"MM/D/YYYY hh:mm A", // Example: 12/5/2023 02:25 PM
|
|
||||||
"MM/D/YYYY hh:mm:ss A", // Example: 12/5/2023 02:25:45 PM
|
|
||||||
|
|
||||||
"M/DD/YYYY h:mm A", // Example: 1/25/2023 9:00 AM
|
|
||||||
"M/DD/YYYY h:mmA", // Example: 1/25/2023 9:00AM
|
|
||||||
"M/DD/YYYY h A", // Example: 1/25/2023 9 AM
|
|
||||||
"M/DD/YYYY hA", // Example: 1/25/2023 9AM
|
|
||||||
"M/DD/YYYY hh:mm A", // Example: 1/25/2023 02:25 PM
|
|
||||||
"M/DD/YYYY hh:mm:ss A", // Example: 1/25/2023 02:25:45 PM
|
|
||||||
|
|
||||||
"MM/DD/YYYY h:mm A", // Example: 12/25/2023 9:00 AM
|
|
||||||
"MM/DD/YYYY h:mmA", // Example: 12/25/2023 9:00AM
|
|
||||||
"MM/DD/YYYY h A", // Example: 12/25/2023 9 AM
|
|
||||||
"MM/DD/YYYY hA", // Example: 12/25/2023 9AM
|
|
||||||
"MM/DD/YYYY hh:mm A", // Example: 12/25/2023 02:25 PM
|
|
||||||
"MM/DD/YYYY hh:mm:ss A", // Example: 12/25/2023 02:25:45 PM
|
|
||||||
|
|
||||||
// Two-digit year with time
|
|
||||||
"M/D/YY h:mm A", // Example: 1/5/23 9:00 AM
|
|
||||||
"M/D/YY h:mmA", // Example: 1/5/23 9:00AM
|
|
||||||
"M/D/YY h A", // Example: 1/5/23 9 AM
|
|
||||||
"M/D/YY hA", // Example: 1/5/23 9AM
|
|
||||||
"M/D/YY hh:mm A", // Example: 1/5/23 02:25 PM
|
|
||||||
"M/D/YY hh:mm:ss A", // Example: 1/5/23 02:25:45 PM
|
|
||||||
|
|
||||||
"MM/D/YY h:mm A", // Example: 12/5/23 9:00 AM
|
|
||||||
"MM/D/YY h:mmA", // Example: 12/5/23 9:00AM
|
|
||||||
"MM/D/YY h A", // Example: 12/5/23 9 AM
|
|
||||||
"MM/D/YY hA", // Example: 12/5/23 9AM
|
|
||||||
"MM/D/YY hh:mm A", // Example: 12/5/23 02:25 PM
|
|
||||||
"MM/D/YY hh:mm:ss A", // Example: 12/5/23 02:25:45 PM
|
|
||||||
|
|
||||||
"M/DD/YY h:mm A", // Example: 1/25/23 9:00 AM
|
|
||||||
"M/DD/YY h:mmA", // Example: 1/25/23 9:00AM
|
|
||||||
"M/DD/YY h A", // Example: 1/25/23 9 AM
|
|
||||||
"M/DD/YY hA", // Example: 1/25/23 9AM
|
|
||||||
"M/DD/YY hh:mm A", // Example: 1/25/23 02:25 PM
|
|
||||||
"M/DD/YY hh:mm:ss A", // Example: 1/25/23 02:25:45 PM
|
|
||||||
|
|
||||||
"MM/DD/YY h:mm A", // Example: 12/25/23 9:00 AM
|
|
||||||
"MM/DD/YY h:mmA", // Example: 12/25/23 9:00AM
|
|
||||||
"MM/DD/YY h A", // Example: 12/25/23 9 AM
|
|
||||||
"MM/DD/YY hA", // Example: 12/25/23 9AM
|
|
||||||
"MM/DD/YY hh:mm A", // Example: 12/25/23 02:25 PM
|
|
||||||
"MM/DD/YY hh:mm:ss A", // Example: 12/25/23 02:25:45 PM
|
|
||||||
|
|
||||||
// Four-digit year without time
|
|
||||||
"M/D/YYYY", // Example: 1/5/2023
|
|
||||||
"MM/D/YYYY", // Example: 12/5/2023
|
|
||||||
"M/DD/YYYY", // Example: 1/25/2023
|
|
||||||
"MM/DD/YYYY", // Example: 12/25/2023
|
|
||||||
|
|
||||||
// Two-digit year without time
|
|
||||||
"M/D/YY", // Example: 1/5/23
|
|
||||||
"MM/D/YY", // Example: 12/5/23
|
|
||||||
"M/DD/YY", // Example: 1/25/23
|
|
||||||
"MM/DD/YY" // Example: 12/25/23
|
|
||||||
];
|
|
||||||
|
|
||||||
// CONFIRMED
|
|
||||||
export const dateFormats = [
|
|
||||||
"MMDDYYYY",
|
"MMDDYYYY",
|
||||||
"MMDDYY",
|
"MMDDYY",
|
||||||
// Four-digit year
|
"M/D/YYYY",
|
||||||
"M/D/YYYY", // Example: 1/5/2023
|
"MM/D/YYYY",
|
||||||
"MM/D/YYYY", // Example: 12/5/2023
|
"M/DD/YYYY",
|
||||||
"M/DD/YYYY", // Example: 1/25/2023
|
"MM/DD/YYYY",
|
||||||
"MM/DD/YYYY", // Example: 12/25/2023
|
"M/D/YY",
|
||||||
|
"MM/D/YY",
|
||||||
// Two-digit year
|
"M/DD/YY",
|
||||||
"M/D/YY", // Example: 1/5/23
|
"MM/DD/YY"
|
||||||
"MM/D/YY", // Example: 12/5/23
|
|
||||||
"M/DD/YY", // Example: 1/25/23
|
|
||||||
"MM/DD/YY", // Example: 12/25/23
|
|
||||||
|
|
||||||
// Explicitly handle single-digit month and day
|
|
||||||
"M/D/YY", // Example: 1/5/23
|
|
||||||
"M/D/YYYY", // Example: 1/5/2023
|
|
||||||
"M/DD/YY", // Example: 1/25/23
|
|
||||||
"M/DD/YYYY", // Example: 1/25/2023
|
|
||||||
"MM/D/YY", // Example: 12/5/23
|
|
||||||
"MM/D/YYYY" // Example: 12/5/2023
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const timeFormats = ["h:mm A", "h:mmA", "h A", "hA", "hh:mm A", "hh:mm:ss A"];
|
||||||
|
|
||||||
|
const dateTimeFormats = [
|
||||||
|
...["M/D/YYYY", "MM/D/YYYY", "M/DD/YYYY", "MM/DD/YYYY", "M/D/YY", "MM/D/YY", "M/DD/YY", "MM/DD/YY"].flatMap(
|
||||||
|
(dateFormat) => timeFormats.map((timeFormat) => `${dateFormat} ${timeFormat}`)
|
||||||
|
),
|
||||||
|
|
||||||
|
...["MMDDYYYY", "MMDDYY"].flatMap((dateFormat) => timeFormats.map((timeFormat) => `${dateFormat} ${timeFormat}`)),
|
||||||
|
|
||||||
|
"M/D/YYYY",
|
||||||
|
"MM/D/YYYY",
|
||||||
|
"M/DD/YYYY",
|
||||||
|
"MM/DD/YYYY",
|
||||||
|
"M/D/YY",
|
||||||
|
"MM/D/YY",
|
||||||
|
"M/DD/YY",
|
||||||
|
"MM/DD/YY",
|
||||||
|
"MMDDYYYY",
|
||||||
|
"MMDDYY"
|
||||||
|
];
|
||||||
|
|
||||||
|
const sanitizeInput = (input) =>
|
||||||
|
input
|
||||||
|
.trim()
|
||||||
|
.toUpperCase()
|
||||||
|
.replace(/\s*(am|pm)\s*/i, " $1")
|
||||||
|
.replaceAll(".", "/")
|
||||||
|
.replaceAll("-", "/");
|
||||||
|
|
||||||
|
export const fuzzyMatchDate = (dateString) => {
|
||||||
|
const sanitizedInput = sanitizeInput(dateString);
|
||||||
|
|
||||||
|
for (const format of dateFormats) {
|
||||||
|
const parsedDate = dayjs(sanitizedInput, format, true);
|
||||||
|
if (parsedDate.isValid()) {
|
||||||
|
return parsedDate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const format of dateTimeFormats) {
|
||||||
|
const parsedDateTime = dayjs(sanitizedInput, format, true);
|
||||||
|
if (parsedDateTime.isValid()) {
|
||||||
|
return parsedDateTime; // Return the dayjs object
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null; // If no matching format is found
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,3 +1,11 @@
|
|||||||
|
- name: Kaizen Data Pump
|
||||||
|
webhook: '{{HASURA_API_URL}}/data/kaizen'
|
||||||
|
schedule: 30 6 * * *
|
||||||
|
include_in_metadata: true
|
||||||
|
payload: {}
|
||||||
|
headers:
|
||||||
|
- name: x-imex-auth
|
||||||
|
value_from_env: DATAPUMP_AUTH
|
||||||
- name: Task Reminders
|
- name: Task Reminders
|
||||||
webhook: '{{HASURA_API_URL}}/tasks-remind-handler'
|
webhook: '{{HASURA_API_URL}}/tasks-remind-handler'
|
||||||
schedule: '*/15 * * * *'
|
schedule: '*/15 * * * *'
|
||||||
|
|||||||
@@ -56,8 +56,8 @@ exports.default = async (req, res) => {
|
|||||||
try {
|
try {
|
||||||
const { jobs, bodyshops_by_pk } = await client.request(queries.KAIZEN_QUERY, {
|
const { jobs, bodyshops_by_pk } = await client.request(queries.KAIZEN_QUERY, {
|
||||||
bodyshopid: bodyshop.id,
|
bodyshopid: bodyshop.id,
|
||||||
start: start ? moment(start).startOf("hours") : moment().subtract(2, "hours").startOf("hour"),
|
start: start ? moment(start).startOf("day") : moment().subtract(5, "days").startOf("day"),
|
||||||
...(end && { end: moment(end).endOf("hours") })
|
...(end && { end: moment(end).endOf("day") })
|
||||||
});
|
});
|
||||||
|
|
||||||
const kaizenObject = {
|
const kaizenObject = {
|
||||||
@@ -176,24 +176,19 @@ exports.default = async (req, res) => {
|
|||||||
} finally {
|
} finally {
|
||||||
sftp.end();
|
sftp.end();
|
||||||
}
|
}
|
||||||
// sendServerEmail({
|
sendServerEmail({
|
||||||
// subject: `Kaizen Report ${moment().format("MM-DD-YY")}`,
|
subject: `Kaizen Report ${moment().format("MM-DD-YY")}`,
|
||||||
// text: `Errors: ${allErrors.map((e) => JSON.stringify(e, null, 2))}
|
text: `Errors: ${allErrors.map((e) => JSON.stringify(e, null, 2))}
|
||||||
// Uploaded: ${JSON.stringify(
|
Uploaded: ${JSON.stringify(
|
||||||
// allxmlsToUpload.map((x) => ({ filename: x.filename, count: x.count })),
|
allxmlsToUpload.map((x) => ({ filename: x.filename, count: x.count })),
|
||||||
// null,
|
null,
|
||||||
// 2
|
2
|
||||||
// )}
|
)}
|
||||||
// `,
|
`
|
||||||
// });
|
});
|
||||||
res.sendStatus(200);
|
res.sendStatus(200);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
res.status(200).json(error);
|
res.status(200).json(error);
|
||||||
sendServerEmail({
|
|
||||||
subject: `Kaizen Report ${moment().format("MM-DD-YY @ HH:mm:ss")}`,
|
|
||||||
text: `Errors: JSON.stringify(error)}
|
|
||||||
All Errors: ${allErrors.map((e) => JSON.stringify(e, null, 2))}`
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -965,22 +965,17 @@ function CalculateTaxesTotals(job, otherTotals) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (job.adjustment_bottom_line) {
|
if (job.adjustment_bottom_line && job.adjustment_bottom_line !== 0) {
|
||||||
const subtotal_before_adjustment = subtotal.add(Dinero({ amount: Math.round(job.adjustment_bottom_line * -100) }));
|
for (let tyCounter = 1; tyCounter <= 5; tyCounter++) {
|
||||||
const percent_of_adjustment =
|
if (IsTrueOrYes(pfp["PAN"][`prt_tx_in${tyCounter}`])) {
|
||||||
Math.round(
|
//This amount is taxable for this type.
|
||||||
subtotal_before_adjustment.toUnit() /
|
taxableAmountsByTier[`ty${tyCounter}Tax`] = taxableAmountsByTier[`ty${tyCounter}Tax`].add(
|
||||||
(job.adjustment_bottom_line > 0 ? job.adjustment_bottom_line : job.adjustment_bottom_line * -1)
|
Dinero({
|
||||||
) / 100;
|
amount: Math.round(job.adjustment_bottom_line * 100)
|
||||||
|
})
|
||||||
Object.keys(taxableAmountsByTier).forEach((taxTierKey) => {
|
);
|
||||||
taxable_adjustment = taxableAmountsByTier[taxTierKey].multiply(percent_of_adjustment);
|
|
||||||
if (job.adjustment_bottom_line > 0) {
|
|
||||||
taxableAmountsByTier[taxTierKey] = taxableAmountsByTier[taxTierKey].add(taxable_adjustment);
|
|
||||||
} else {
|
|
||||||
taxableAmountsByTier[taxTierKey] = taxableAmountsByTier[taxTierKey].subtract(taxable_adjustment);
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const remainingTaxableAmounts = taxableAmountsByTier;
|
const remainingTaxableAmounts = taxableAmountsByTier;
|
||||||
|
|||||||
Reference in New Issue
Block a user