Compare commits
32 Commits
feature/IO
...
feature/IO
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eeed004fe2 | ||
|
|
449330441a | ||
|
|
fcab5e6ef2 | ||
|
|
0212b837ea | ||
|
|
e7438a099e | ||
|
|
c69c86d193 | ||
|
|
af09796df8 | ||
|
|
0aba040338 | ||
|
|
c3bfe87674 | ||
|
|
9aa1279144 | ||
|
|
4e6c45b195 | ||
|
|
4fdb939bd2 | ||
|
|
062a1dcc72 | ||
|
|
7b420b1855 | ||
|
|
40f61bbc8f | ||
|
|
f5d821c394 | ||
|
|
3958ec9189 | ||
|
|
1e4f52e541 | ||
|
|
5cc5cb444e | ||
|
|
4acf0c59ca | ||
|
|
2858a5e871 | ||
|
|
24496d3ee1 | ||
|
|
0a5df69b12 | ||
|
|
80efea02c6 | ||
|
|
9f5c282b41 | ||
|
|
b2602c3385 | ||
|
|
0e584af424 | ||
|
|
cdc3de2a33 | ||
|
|
44cb7577e2 | ||
|
|
46d2b08477 | ||
|
|
0193ff9e65 | ||
|
|
fd9a51209f |
1
client/package-lock.json
generated
1
client/package-lock.json
generated
@@ -7,6 +7,7 @@
|
||||
"": {
|
||||
"name": "bodyshop",
|
||||
"version": "0.2.1",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@ant-design/pro-layout": "^7.19.12",
|
||||
"@apollo/client": "^3.11.4",
|
||||
|
||||
@@ -84,6 +84,7 @@
|
||||
"web-vitals": "^3.5.2"
|
||||
},
|
||||
"scripts": {
|
||||
"postinstall": "echo 'when updating react-big-calendar, remember to check to localizer in the calendar wrapper'",
|
||||
"analyze": "source-map-explorer 'build/static/js/*.js'",
|
||||
"start": "vite",
|
||||
"build": "dotenvx run --env-file=.env.development.imex -- vite build",
|
||||
|
||||
@@ -98,7 +98,7 @@ export function BillDetailEditcontainer({ setPartsOrderContext, insertAuditTrail
|
||||
});
|
||||
|
||||
billlines.forEach((billline) => {
|
||||
const { deductedfromlbr, inventories, jobline, ...il } = billline;
|
||||
const { deductedfromlbr, inventories, jobline, original_actual_price, create_ppc, ...il } = billline;
|
||||
delete il.__typename;
|
||||
|
||||
if (il.id) {
|
||||
|
||||
@@ -141,10 +141,14 @@ export function JobTotalsTableTotals({ bodyshop, job }) {
|
||||
key: t("jobs.fields.ded_amt"),
|
||||
total: job.job_totals.totals.custPayable.deductible
|
||||
},
|
||||
// {
|
||||
// key: t("jobs.fields.federal_tax_payable"),
|
||||
// total: job.job_totals.totals.custPayable.federal_tax,
|
||||
// },
|
||||
...(InstanceRenderManager({
|
||||
imex: [{
|
||||
key: t("jobs.fields.federal_tax_payable"),
|
||||
total: job.job_totals.totals.custPayable.federal_tax
|
||||
}],
|
||||
rome: [],
|
||||
promanager: "USE_ROME"
|
||||
})),
|
||||
{
|
||||
key: t("jobs.fields.other_amount_payable"),
|
||||
total: job.job_totals.totals.custPayable.other_customer_amount
|
||||
|
||||
@@ -27,6 +27,10 @@ export default function PartsOrderModalPriceChange({ form, field }) {
|
||||
key: "25",
|
||||
label: t("parts_orders.labels.discount", { percent: "25%" })
|
||||
},
|
||||
{
|
||||
key: "40",
|
||||
label: t("parts_orders.labels.discount", { percent: "40%" })
|
||||
},
|
||||
{
|
||||
key: "custom",
|
||||
label: (
|
||||
|
||||
@@ -34,28 +34,34 @@ export function ReportCenterModalComponent({ reportCenterModal, bodyshop }) {
|
||||
const [form] = Form.useForm();
|
||||
const [search, setSearch] = useState("");
|
||||
const {
|
||||
treatments: { Enhanced_Payroll }
|
||||
treatments: { Enhanced_Payroll, ADPPayroll }
|
||||
} = useSplitTreatments({
|
||||
attributes: {},
|
||||
names: ["Enhanced_Payroll"],
|
||||
names: ["Enhanced_Payroll", "ADPPayroll"],
|
||||
splitKey: bodyshop.imexshopid
|
||||
});
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
const { t } = useTranslation();
|
||||
const Templates = TemplateList("report_center");
|
||||
const ReportsList =
|
||||
Enhanced_Payroll.treatment === "on"
|
||||
? Object.keys(Templates)
|
||||
.map((key) => {
|
||||
return Templates[key];
|
||||
})
|
||||
.filter((temp) => temp.enhanced_payroll === undefined || temp.enhanced_payroll === true)
|
||||
: Object.keys(Templates)
|
||||
.map((key) => {
|
||||
return Templates[key];
|
||||
})
|
||||
.filter((temp) => temp.enhanced_payroll === undefined || temp.enhanced_payroll === false);
|
||||
const ReportsList = Object.keys(Templates)
|
||||
.map((key) => Templates[key])
|
||||
.filter((temp) => {
|
||||
const enhancedPayrollOn = Enhanced_Payroll.treatment === "on";
|
||||
const adpPayrollOn = ADPPayroll.treatment === "on";
|
||||
|
||||
if (enhancedPayrollOn && adpPayrollOn) {
|
||||
return temp.enhanced_payroll !== false || temp.adp_payroll !== false;
|
||||
}
|
||||
if (enhancedPayrollOn) {
|
||||
return temp.enhanced_payroll !== false && temp.adp_payroll !== true;
|
||||
}
|
||||
if (adpPayrollOn) {
|
||||
return temp.adp_payroll !== false && temp.enhanced_payroll !== true;
|
||||
}
|
||||
|
||||
return temp.enhanced_payroll !== true && temp.adp_payroll !== true;
|
||||
});
|
||||
|
||||
const { open } = reportCenterModal;
|
||||
|
||||
@@ -104,7 +110,7 @@ export function ReportCenterModalComponent({ reportCenterModal, bodyshop }) {
|
||||
to: values.to,
|
||||
subject: Templates[values.key]?.subject
|
||||
},
|
||||
values.sendbyexcel === "excel" ? "x" : values.sendby === "email" ? "e" : "p",
|
||||
values.sendbytext === "text" ? values.sendbytext : values.sendbyexcel === "excel" ? "x" : values.sendby === "email" ? "e" : "p",
|
||||
id
|
||||
);
|
||||
setLoading(false);
|
||||
@@ -291,7 +297,15 @@ export function ReportCenterModalComponent({ reportCenterModal, bodyshop }) {
|
||||
</Radio.Group>
|
||||
</Form.Item>
|
||||
);
|
||||
if (reporttype !== "excel")
|
||||
if (reporttype === "text")
|
||||
return (
|
||||
<Form.Item label={t("general.labels.sendby")} name="sendbytext" initialValue="text">
|
||||
<Radio.Group>
|
||||
<Radio value="text">{t("general.labels.text")}</Radio>
|
||||
</Radio.Group>
|
||||
</Form.Item>
|
||||
);
|
||||
if (reporttype !== "excel" || reporttype !== "text")
|
||||
return (
|
||||
<Form.Item label={t("general.labels.sendby")} name="sendby" initialValue="print">
|
||||
<Radio.Group>
|
||||
|
||||
505
client/src/components/schedule-calendar-wrapper/localizer.js
Normal file
505
client/src/components/schedule-calendar-wrapper/localizer.js
Normal file
@@ -0,0 +1,505 @@
|
||||
import isBetween from "dayjs/plugin/isBetween";
|
||||
import isSameOrAfter from "dayjs/plugin/isSameOrAfter";
|
||||
import isSameOrBefore from "dayjs/plugin/isSameOrBefore";
|
||||
import localeData from "dayjs/plugin/localeData";
|
||||
import localizedFormat from "dayjs/plugin/localizedFormat";
|
||||
import minMax from "dayjs/plugin/minMax";
|
||||
import utc from "dayjs/plugin/utc";
|
||||
import { DateLocalizer } from "react-big-calendar";
|
||||
|
||||
function arrayWithHoles(arr) {
|
||||
if (Array.isArray(arr)) return arr;
|
||||
}
|
||||
|
||||
function iterableToArrayLimit(arr, i) {
|
||||
if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return;
|
||||
var _arr = [];
|
||||
var _n = true;
|
||||
var _d = false;
|
||||
var _e = undefined;
|
||||
try {
|
||||
for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
|
||||
_arr.push(_s.value);
|
||||
if (i && _arr.length === i) break;
|
||||
}
|
||||
} catch (err) {
|
||||
_d = true;
|
||||
_e = err;
|
||||
} finally {
|
||||
try {
|
||||
if (!_n && _i["return"] != null) _i["return"]();
|
||||
} finally {
|
||||
if (_d) throw _e;
|
||||
}
|
||||
}
|
||||
return _arr;
|
||||
}
|
||||
|
||||
function unsupportedIterableToArray(o, minLen) {
|
||||
if (!o) return;
|
||||
if (typeof o === "string") return arrayLikeToArray(o, minLen);
|
||||
var n = Object.prototype.toString.call(o).slice(8, -1);
|
||||
if (n === "Object" && o.constructor) n = o.constructor.name;
|
||||
if (n === "Map" || n === "Set") return Array.from(o);
|
||||
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return arrayLikeToArray(o, minLen);
|
||||
}
|
||||
|
||||
function arrayLikeToArray(arr, len) {
|
||||
if (len == null || len > arr.length) len = arr.length;
|
||||
for (var i = 0, arr2 = new Array(len); i < len; i++) {
|
||||
arr2[i] = arr[i];
|
||||
}
|
||||
return arr2;
|
||||
}
|
||||
|
||||
function nonIterableRest() {
|
||||
throw new TypeError(
|
||||
"Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."
|
||||
);
|
||||
}
|
||||
|
||||
function _slicedToArray(arr, i) {
|
||||
return arrayWithHoles(arr) || iterableToArrayLimit(arr, i) || unsupportedIterableToArray(arr, i) || nonIterableRest();
|
||||
}
|
||||
|
||||
function fixUnit(unit) {
|
||||
var datePart = unit ? unit.toLowerCase() : unit;
|
||||
if (datePart === "FullYear") {
|
||||
datePart = "year";
|
||||
} else if (!datePart) {
|
||||
datePart = undefined;
|
||||
}
|
||||
return datePart;
|
||||
}
|
||||
|
||||
var timeRangeFormat = function timeRangeFormat(_ref3, culture, local) {
|
||||
var start = _ref3.start,
|
||||
end = _ref3.end;
|
||||
return local.format(start, "LT", culture) + " – " + local.format(end, "LT", culture);
|
||||
};
|
||||
var timeRangeStartFormat = function timeRangeStartFormat(_ref4, culture, local) {
|
||||
var start = _ref4.start;
|
||||
return local.format(start, "LT", culture) + " – ";
|
||||
};
|
||||
var timeRangeEndFormat = function timeRangeEndFormat(_ref5, culture, local) {
|
||||
var end = _ref5.end;
|
||||
return " – " + local.format(end, "LT", culture);
|
||||
};
|
||||
var weekRangeFormat = function weekRangeFormat(_ref, culture, local) {
|
||||
var start = _ref.start,
|
||||
end = _ref.end;
|
||||
return (
|
||||
local.format(start, "MMMM DD", culture) +
|
||||
" – " +
|
||||
// updated to use this localizer 'eq()' method
|
||||
local.format(end, local.eq(start, end, "month") ? "DD" : "MMMM DD", culture)
|
||||
);
|
||||
};
|
||||
var dateRangeFormat = function dateRangeFormat(_ref2, culture, local) {
|
||||
var start = _ref2.start,
|
||||
end = _ref2.end;
|
||||
return local.format(start, "L", culture) + " – " + local.format(end, "L", culture);
|
||||
};
|
||||
|
||||
var formats = {
|
||||
dateFormat: "DD",
|
||||
dayFormat: "DD ddd",
|
||||
weekdayFormat: "ddd",
|
||||
selectRangeFormat: timeRangeFormat,
|
||||
eventTimeRangeFormat: timeRangeFormat,
|
||||
eventTimeRangeStartFormat: timeRangeStartFormat,
|
||||
eventTimeRangeEndFormat: timeRangeEndFormat,
|
||||
timeGutterFormat: "LT",
|
||||
monthHeaderFormat: "MMMM YYYY",
|
||||
dayHeaderFormat: "dddd MMM DD",
|
||||
dayRangeHeaderFormat: weekRangeFormat,
|
||||
agendaHeaderFormat: dateRangeFormat,
|
||||
agendaDateFormat: "ddd MMM DD",
|
||||
agendaTimeFormat: "LT",
|
||||
agendaTimeRangeFormat: timeRangeFormat
|
||||
};
|
||||
|
||||
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) {
|
||||
return c ? dj.locale(c) : dj;
|
||||
};
|
||||
|
||||
// if the timezone plugin is loaded,
|
||||
// then use the timezone aware version
|
||||
|
||||
//TODO This was the issue entirely...
|
||||
// var dayjs = dayjsLib.tz ? dayjsLib.tz : dayjsLib;
|
||||
var dayjs = dayjsLib;
|
||||
|
||||
function getTimezoneOffset(date) {
|
||||
// ensures this gets cast to timezone
|
||||
return dayjs(date).toDate().getTimezoneOffset();
|
||||
}
|
||||
|
||||
function getDstOffset(start, end) {
|
||||
var _st$tz$$x$$timezone;
|
||||
// convert to dayjs, in case
|
||||
var st = dayjs(start);
|
||||
var ed = dayjs(end);
|
||||
// if not using the dayjs timezone plugin
|
||||
if (!dayjs.tz) {
|
||||
return st.toDate().getTimezoneOffset() - ed.toDate().getTimezoneOffset();
|
||||
}
|
||||
/**
|
||||
* If a default timezone has been applied, then
|
||||
* use this to get the proper timezone offset, otherwise default
|
||||
* the timezone to the browser local
|
||||
*/
|
||||
var tzName =
|
||||
(_st$tz$$x$$timezone = st.tz().$x.$timezone) !== null && _st$tz$$x$$timezone !== void 0
|
||||
? _st$tz$$x$$timezone
|
||||
: dayjsLib.tz.guess();
|
||||
// invert offsets to be inline with moment.js
|
||||
var startOffset = -dayjs.tz(+st, tzName).utcOffset();
|
||||
var endOffset = -dayjs.tz(+ed, tzName).utcOffset();
|
||||
return startOffset - endOffset;
|
||||
}
|
||||
|
||||
function getDayStartDstOffset(start) {
|
||||
var dayStart = dayjs(start).startOf("day");
|
||||
return getDstOffset(dayStart, start);
|
||||
}
|
||||
|
||||
/*** BEGIN localized date arithmetic methods with dayjs ***/
|
||||
function defineComparators(a, b, unit) {
|
||||
var datePart = fixUnit(unit);
|
||||
var dtA = datePart ? dayjs(a).startOf(datePart) : dayjs(a);
|
||||
var dtB = datePart ? dayjs(b).startOf(datePart) : dayjs(b);
|
||||
return [dtA, dtB, datePart];
|
||||
}
|
||||
|
||||
function startOf() {
|
||||
var date = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
|
||||
var unit = arguments.length > 1 ? arguments[1] : undefined;
|
||||
var datePart = fixUnit(unit);
|
||||
if (datePart) {
|
||||
return dayjs(date).startOf(datePart).toDate();
|
||||
}
|
||||
return dayjs(date).toDate();
|
||||
}
|
||||
|
||||
function endOf() {
|
||||
var date = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
|
||||
var unit = arguments.length > 1 ? arguments[1] : undefined;
|
||||
var datePart = fixUnit(unit);
|
||||
if (datePart) {
|
||||
return dayjs(date).endOf(datePart).toDate();
|
||||
}
|
||||
return dayjs(date).toDate();
|
||||
}
|
||||
|
||||
// dayjs comparison operations *always* convert both sides to dayjs objects
|
||||
// prior to running the comparisons
|
||||
function eq(a, b, unit) {
|
||||
var _defineComparators = defineComparators(a, b, unit),
|
||||
_defineComparators2 = _slicedToArray(_defineComparators, 3),
|
||||
dtA = _defineComparators2[0],
|
||||
dtB = _defineComparators2[1],
|
||||
datePart = _defineComparators2[2];
|
||||
return dtA.isSame(dtB, datePart);
|
||||
}
|
||||
|
||||
function neq(a, b, unit) {
|
||||
return !eq(a, b, unit);
|
||||
}
|
||||
|
||||
function gt(a, b, unit) {
|
||||
var _defineComparators3 = defineComparators(a, b, unit),
|
||||
_defineComparators4 = _slicedToArray(_defineComparators3, 3),
|
||||
dtA = _defineComparators4[0],
|
||||
dtB = _defineComparators4[1],
|
||||
datePart = _defineComparators4[2];
|
||||
return dtA.isAfter(dtB, datePart);
|
||||
}
|
||||
|
||||
function lt(a, b, unit) {
|
||||
var _defineComparators5 = defineComparators(a, b, unit),
|
||||
_defineComparators6 = _slicedToArray(_defineComparators5, 3),
|
||||
dtA = _defineComparators6[0],
|
||||
dtB = _defineComparators6[1],
|
||||
datePart = _defineComparators6[2];
|
||||
return dtA.isBefore(dtB, datePart);
|
||||
}
|
||||
|
||||
function gte(a, b, unit) {
|
||||
var _defineComparators7 = defineComparators(a, b, unit),
|
||||
_defineComparators8 = _slicedToArray(_defineComparators7, 3),
|
||||
dtA = _defineComparators8[0],
|
||||
dtB = _defineComparators8[1],
|
||||
datePart = _defineComparators8[2];
|
||||
return dtA.isSameOrBefore(dtB, datePart);
|
||||
}
|
||||
|
||||
function lte(a, b, unit) {
|
||||
var _defineComparators9 = defineComparators(a, b, unit),
|
||||
_defineComparators10 = _slicedToArray(_defineComparators9, 3),
|
||||
dtA = _defineComparators10[0],
|
||||
dtB = _defineComparators10[1],
|
||||
datePart = _defineComparators10[2];
|
||||
return dtA.isSameOrBefore(dtB, datePart);
|
||||
}
|
||||
|
||||
function inRange(day, min, max) {
|
||||
var unit = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : "day";
|
||||
var datePart = fixUnit(unit);
|
||||
var djDay = dayjs(day);
|
||||
var djMin = dayjs(min);
|
||||
var djMax = dayjs(max);
|
||||
return djDay.isBetween(djMin, djMax, datePart, "[]");
|
||||
}
|
||||
|
||||
function min(dateA, dateB) {
|
||||
var dtA = dayjs(dateA);
|
||||
var dtB = dayjs(dateB);
|
||||
var minDt = dayjsLib.min(dtA, dtB);
|
||||
return minDt.toDate();
|
||||
}
|
||||
|
||||
function max(dateA, dateB) {
|
||||
var dtA = dayjs(dateA);
|
||||
var dtB = dayjs(dateB);
|
||||
var maxDt = dayjsLib.max(dtA, dtB);
|
||||
return maxDt.toDate();
|
||||
}
|
||||
|
||||
function merge(date, time) {
|
||||
if (!date && !time) return null;
|
||||
var tm = dayjs(time).format("HH:mm:ss");
|
||||
var dt = dayjs(date).startOf("day").format("MM/DD/YYYY");
|
||||
// We do it this way to avoid issues when timezone switching
|
||||
return dayjsLib("".concat(dt, " ").concat(tm), "MM/DD/YYYY HH:mm:ss").toDate();
|
||||
}
|
||||
|
||||
function add(date, adder, unit) {
|
||||
var datePart = fixUnit(unit);
|
||||
return dayjs(date).add(adder, datePart).toDate();
|
||||
}
|
||||
|
||||
function range(start, end) {
|
||||
var unit = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "day";
|
||||
var datePart = fixUnit(unit);
|
||||
// because the add method will put these in tz, we have to start that way
|
||||
var current = dayjs(start).toDate();
|
||||
var days = [];
|
||||
while (lte(current, end)) {
|
||||
days.push(current);
|
||||
current = add(current, 1, datePart);
|
||||
}
|
||||
return days;
|
||||
}
|
||||
|
||||
function ceil(date, unit) {
|
||||
var datePart = fixUnit(unit);
|
||||
var floor = startOf(date, datePart);
|
||||
return eq(floor, date) ? floor : add(floor, 1, datePart);
|
||||
}
|
||||
|
||||
function diff(a, b) {
|
||||
var unit = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "day";
|
||||
var datePart = fixUnit(unit);
|
||||
// don't use 'defineComparators' here, as we don't want to mutate the values
|
||||
var dtA = dayjs(a);
|
||||
var dtB = dayjs(b);
|
||||
return dtB.diff(dtA, datePart);
|
||||
}
|
||||
|
||||
function minutes(date) {
|
||||
var dt = dayjs(date);
|
||||
return dt.minutes();
|
||||
}
|
||||
|
||||
function firstOfWeek(culture) {
|
||||
var data = culture ? dayjsLib.localeData(culture) : dayjsLib.localeData();
|
||||
return data ? data.firstDayOfWeek() : 0;
|
||||
}
|
||||
|
||||
function firstVisibleDay(date) {
|
||||
return dayjs(date).startOf("month").startOf("week").toDate();
|
||||
}
|
||||
|
||||
function lastVisibleDay(date) {
|
||||
return dayjs(date).endOf("month").endOf("week").toDate();
|
||||
}
|
||||
|
||||
function visibleDays(date) {
|
||||
var current = firstVisibleDay(date);
|
||||
var last = lastVisibleDay(date);
|
||||
var days = [];
|
||||
while (lte(current, last)) {
|
||||
days.push(current);
|
||||
current = add(current, 1, "d");
|
||||
}
|
||||
return days;
|
||||
}
|
||||
|
||||
/*** END localized date arithmetic methods with dayjs ***/
|
||||
|
||||
/**
|
||||
* Moved from TimeSlots.js, this method overrides the method of the same name
|
||||
* in the localizer.js, using dayjs to construct the js Date
|
||||
* @param {Date} dt - date to start with
|
||||
* @param {Number} minutesFromMidnight
|
||||
* @param {Number} offset
|
||||
* @returns {Date}
|
||||
*/
|
||||
function getSlotDate(dt, minutesFromMidnight, offset) {
|
||||
return dayjs(dt)
|
||||
.startOf("day")
|
||||
.minute(minutesFromMidnight + offset)
|
||||
.toDate();
|
||||
}
|
||||
|
||||
// dayjs will automatically handle DST differences in it's calculations
|
||||
function getTotalMin(start, end) {
|
||||
return diff(start, end, "minutes");
|
||||
}
|
||||
|
||||
function getMinutesFromMidnight(start) {
|
||||
var dayStart = dayjs(start).startOf("day");
|
||||
var day = dayjs(start);
|
||||
return day.diff(dayStart, "minutes") + getDayStartDstOffset(start);
|
||||
}
|
||||
|
||||
// These two are used by DateSlotMetrics
|
||||
function continuesPrior(start, first) {
|
||||
var djStart = dayjs(start);
|
||||
var djFirst = dayjs(first);
|
||||
return djStart.isBefore(djFirst, "day");
|
||||
}
|
||||
|
||||
function continuesAfter(start, end, last) {
|
||||
var djEnd = dayjs(end);
|
||||
var djLast = dayjs(last);
|
||||
return djEnd.isSameOrAfter(djLast, "minutes");
|
||||
}
|
||||
|
||||
function daySpan(start, end) {
|
||||
var startDay = dayjs(start);
|
||||
var endDay = dayjs(end);
|
||||
return endDay.diff(startDay, "day");
|
||||
}
|
||||
|
||||
// These two are used by eventLevels
|
||||
function sortEvents(_ref6) {
|
||||
var _ref6$evtA = _ref6.evtA,
|
||||
aStart = _ref6$evtA.start,
|
||||
aEnd = _ref6$evtA.end,
|
||||
aAllDay = _ref6$evtA.allDay,
|
||||
_ref6$evtB = _ref6.evtB,
|
||||
bStart = _ref6$evtB.start,
|
||||
bEnd = _ref6$evtB.end,
|
||||
bAllDay = _ref6$evtB.allDay;
|
||||
var startSort = +startOf(aStart, "day") - +startOf(bStart, "day");
|
||||
var durA = daySpan(aStart, aEnd);
|
||||
var durB = daySpan(bStart, bEnd);
|
||||
return (
|
||||
startSort ||
|
||||
// sort by start Day first
|
||||
durB - durA ||
|
||||
// events spanning multiple days go first
|
||||
!!bAllDay - !!aAllDay ||
|
||||
// then allDay single day events
|
||||
+aStart - +bStart ||
|
||||
// then sort by start time *don't need dayjs conversion here
|
||||
+aEnd - +bEnd // then sort by end time *don't need dayjs conversion here either
|
||||
);
|
||||
}
|
||||
|
||||
function inEventRange(_ref7) {
|
||||
var _ref7$event = _ref7.event,
|
||||
start = _ref7$event.start,
|
||||
end = _ref7$event.end,
|
||||
_ref7$range = _ref7.range,
|
||||
rangeStart = _ref7$range.start,
|
||||
rangeEnd = _ref7$range.end;
|
||||
var startOfDay = dayjs(start).startOf("day");
|
||||
var eEnd = dayjs(end);
|
||||
var rStart = dayjs(rangeStart);
|
||||
var rEnd = dayjs(rangeEnd);
|
||||
var startsBeforeEnd = startOfDay.isSameOrBefore(rEnd, "day");
|
||||
// when the event is zero duration we need to handle a bit differently
|
||||
var sameMin = !startOfDay.isSame(eEnd, "minutes");
|
||||
var endsAfterStart = sameMin ? eEnd.isAfter(rStart, "minutes") : eEnd.isSameOrAfter(rStart, "minutes");
|
||||
return startsBeforeEnd && endsAfterStart;
|
||||
}
|
||||
|
||||
function isSameDate(date1, date2) {
|
||||
var dt = dayjs(date1);
|
||||
var dt2 = dayjs(date2);
|
||||
return dt.isSame(dt2, "day");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method, called once in the localizer constructor, is used by eventLevels
|
||||
* 'eventSegments()' to assist in determining the 'span' of the event in the display,
|
||||
* specifically when using a timezone that is greater than the browser native timezone.
|
||||
* @returns number
|
||||
*/
|
||||
function browserTZOffset() {
|
||||
/**
|
||||
* Date.prototype.getTimezoneOffset horrifically flips the positive/negative from
|
||||
* what you see in it's string, so we have to jump through some hoops to get a value
|
||||
* we can actually compare.
|
||||
*/
|
||||
var dt = new Date();
|
||||
var neg = /-/.test(dt.toString()) ? "-" : "";
|
||||
var dtOffset = dt.getTimezoneOffset();
|
||||
var comparator = Number("".concat(neg).concat(Math.abs(dtOffset)));
|
||||
// dayjs correctly provides positive/negative offset, as expected
|
||||
var mtOffset = dayjs().utcOffset();
|
||||
return mtOffset > comparator ? 1 : 0;
|
||||
}
|
||||
|
||||
return new DateLocalizer({
|
||||
formats: formats,
|
||||
firstOfWeek: firstOfWeek,
|
||||
firstVisibleDay: firstVisibleDay,
|
||||
lastVisibleDay: lastVisibleDay,
|
||||
visibleDays: visibleDays,
|
||||
format: function format(value, _format, culture) {
|
||||
return locale(dayjs(value), culture).format(_format);
|
||||
},
|
||||
lt: lt,
|
||||
lte: lte,
|
||||
gt: gt,
|
||||
gte: gte,
|
||||
eq: eq,
|
||||
neq: neq,
|
||||
merge: merge,
|
||||
inRange: inRange,
|
||||
startOf: startOf,
|
||||
endOf: endOf,
|
||||
range: range,
|
||||
add: add,
|
||||
diff: diff,
|
||||
ceil: ceil,
|
||||
min: min,
|
||||
max: max,
|
||||
minutes: minutes,
|
||||
getSlotDate: getSlotDate,
|
||||
getTimezoneOffset: getTimezoneOffset,
|
||||
getDstOffset: getDstOffset,
|
||||
getTotalMin: getTotalMin,
|
||||
getMinutesFromMidnight: getMinutesFromMidnight,
|
||||
continuesPrior: continuesPrior,
|
||||
continuesAfter: continuesAfter,
|
||||
sortEvents: sortEvents,
|
||||
inEventRange: inEventRange,
|
||||
isSameDate: isSameDate,
|
||||
browserTZOffset: browserTZOffset
|
||||
});
|
||||
};
|
||||
export default localizer;
|
||||
@@ -1,7 +1,7 @@
|
||||
import dayjs from "../../utils/day";
|
||||
import queryString from "query-string";
|
||||
import React from "react";
|
||||
import { Calendar, dayjsLocalizer } from "react-big-calendar";
|
||||
import { Calendar } from "react-big-calendar";
|
||||
import { connect } from "react-redux";
|
||||
import { Link, useLocation, useNavigate } from "react-router-dom";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
@@ -14,12 +14,13 @@ import { selectProblemJobs } from "../../redux/application/application.selectors
|
||||
import { Alert, Collapse, Space } from "antd";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
import local from "./localizer";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
problemJobs: selectProblemJobs
|
||||
});
|
||||
const localizer = dayjsLocalizer(dayjs);
|
||||
const localizer = local(dayjs);
|
||||
|
||||
export function ScheduleCalendarWrapperComponent({
|
||||
bodyshop,
|
||||
|
||||
@@ -7,13 +7,13 @@ import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import DatePickerRanges from "../../utils/DatePickerRanges";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
import FeatureWrapper, { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
||||
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
||||
import FormItemEmail from "../form-items-formatted/email-form-item.component";
|
||||
import PhoneFormItem, { PhoneItemFormatterValidation } from "../form-items-formatted/phone-form-item.component";
|
||||
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
|
||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
import FeatureWrapper, { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
||||
// TODO: Client Update, this might break
|
||||
const timeZonesList = Intl.supportedValuesOf("timeZone");
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
@@ -28,10 +28,10 @@ export function ShopInfoGeneral({ form, bodyshop }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const {
|
||||
treatments: { ClosingPeriod }
|
||||
treatments: { ClosingPeriod, ADPPayroll }
|
||||
} = useSplitTreatments({
|
||||
attributes: {},
|
||||
names: ["ClosingPeriod"],
|
||||
names: ["ClosingPeriod", "ADPPayroll"],
|
||||
splitKey: bodyshop && bodyshop.imexshopid
|
||||
});
|
||||
|
||||
@@ -98,7 +98,6 @@ export function ShopInfoGeneral({ form, bodyshop }) {
|
||||
<Form.Item label={t("bodyshop.fields.email")} name="email">
|
||||
<Input />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.phone")}
|
||||
name="phone"
|
||||
@@ -356,14 +355,22 @@ export function ShopInfoGeneral({ form, bodyshop }) {
|
||||
<Select mode="tags" />
|
||||
</Form.Item>
|
||||
{ClosingPeriod.treatment === "on" && (
|
||||
<>
|
||||
<Form.Item
|
||||
name={["accountingconfig", "ClosingPeriod"]}
|
||||
label={t("bodyshop.fields.closingperiod")} //{t("reportcenter.labels.dates")}
|
||||
>
|
||||
<DatePicker.RangePicker format="MM/DD/YYYY" presets={DatePickerRanges} />
|
||||
</Form.Item>
|
||||
</>
|
||||
<Form.Item
|
||||
name={["accountingconfig", "ClosingPeriod"]}
|
||||
label={t("bodyshop.fields.closingperiod")} //{t("reportcenter.labels.dates")}
|
||||
>
|
||||
<DatePicker.RangePicker format="MM/DD/YYYY" presets={DatePickerRanges} />
|
||||
</Form.Item>
|
||||
)}
|
||||
{ADPPayroll.treatment === "on" && (
|
||||
<Form.Item name={["accountingconfig", "companyCode"]} label={t("bodyshop.fields.companycode")}>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
)}
|
||||
{ADPPayroll.treatment === "on" && (
|
||||
<Form.Item name={["accountingconfig", "batchID"]} label={t("bodyshop.fields.batchid")}>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
)}
|
||||
</LayoutFormRow>
|
||||
</FeatureWrapper>
|
||||
|
||||
@@ -5,7 +5,7 @@ import PhoneNumberFormatter from "../../utils/PhoneFormatter";
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
//To be used as a form element only.
|
||||
// To be used as a form element only.
|
||||
|
||||
const VendorSearchSelect = ({ value, onChange, options, onSelect, disabled, preferredMake, showPhone }, ref) => {
|
||||
const [option, setOption] = useState(value);
|
||||
@@ -33,9 +33,25 @@ const VendorSearchSelect = ({ value, onChange, options, onSelect, disabled, pref
|
||||
if (!value || !options) return label;
|
||||
const discount = options?.find((o) => o.id === value)?.discount;
|
||||
return (
|
||||
<div className="imex-flex-row" style={{ width: "100%" }}>
|
||||
<div style={{ flex: 1 }}>{label}</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
flexWrap: "nowrap",
|
||||
width: "100%"
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
flex: 1,
|
||||
minWidth: 0,
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
whiteSpace: "nowrap"
|
||||
}}
|
||||
>
|
||||
{label}
|
||||
</div>
|
||||
{discount && discount !== 0 ? <Tag color="green">{`${discount * 100}%`}</Tag> : null}
|
||||
</div>
|
||||
);
|
||||
@@ -45,36 +61,67 @@ const VendorSearchSelect = ({ value, onChange, options, onSelect, disabled, pref
|
||||
optionFilterProp="name"
|
||||
onSelect={onSelect}
|
||||
disabled={disabled || false}
|
||||
optionLabelProp={"name"}
|
||||
optionLabelProp="name"
|
||||
>
|
||||
{favorites
|
||||
? favorites.map((o) => (
|
||||
<Option key={`favorite-${o.id}`} value={o.id} name={o.name} discount={o.discount}>
|
||||
<div className="imex-flex-row">
|
||||
<div style={{ flex: 1 }}>{o.name}</div>
|
||||
<Space style={{ marginLeft: "1rem" }}>
|
||||
<HeartOutlined style={{ color: "red" }} />
|
||||
{o.phone && showPhone && <PhoneNumberFormatter>{o.phone}</PhoneNumberFormatter>}
|
||||
{o.discount && o.discount !== 0 ? <Tag color="green">{`${o.discount * 100}%`}</Tag> : null}
|
||||
</Space>
|
||||
{favorites &&
|
||||
favorites.map((o) => (
|
||||
<Option key={`favorite-${o.id}`} value={o.id} name={o.name} discount={o.discount}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
flexWrap: "nowrap",
|
||||
width: "100%"
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
flex: 1,
|
||||
minWidth: 0,
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
whiteSpace: "nowrap"
|
||||
}}
|
||||
>
|
||||
{o.name}
|
||||
</div>
|
||||
</Option>
|
||||
))
|
||||
: null}
|
||||
{options
|
||||
? options.map((o) => (
|
||||
<Option key={o.id} value={o.id} name={o.name} discount={o.discount}>
|
||||
<div className="imex-flex-row" style={{ width: "100%" }}>
|
||||
<div style={{ flex: 1 }}>{o.name}</div>
|
||||
|
||||
<Space style={{ marginLeft: "1rem" }}>
|
||||
{o.phone && showPhone && <PhoneNumberFormatter>{o.phone}</PhoneNumberFormatter>}
|
||||
{o.discount && o.discount !== 0 ? <Tag color="green">{`${o.discount * 100}%`}</Tag> : null}
|
||||
</Space>
|
||||
<Space style={{ marginLeft: "1rem" }}>
|
||||
<HeartOutlined style={{ color: "red" }} />
|
||||
{o.phone && showPhone && <PhoneNumberFormatter>{o.phone}</PhoneNumberFormatter>}
|
||||
{o.discount && o.discount !== 0 ? <Tag color="green">{`${o.discount * 100}%`}</Tag> : null}
|
||||
</Space>
|
||||
</div>
|
||||
</Option>
|
||||
))}
|
||||
{options &&
|
||||
options.map((o) => (
|
||||
<Option key={o.id} value={o.id} name={o.name} discount={o.discount}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
flexWrap: "nowrap",
|
||||
width: "100%"
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
flex: 1,
|
||||
minWidth: 0,
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
whiteSpace: "nowrap"
|
||||
}}
|
||||
>
|
||||
{o.name}
|
||||
</div>
|
||||
</Option>
|
||||
))
|
||||
: null}
|
||||
<Space style={{ marginLeft: "1rem" }}>
|
||||
{o.phone && showPhone && <PhoneNumberFormatter>{o.phone}</PhoneNumberFormatter>}
|
||||
{o.discount && o.discount !== 0 ? <Tag color="green">{`${o.discount * 100}%`}</Tag> : null}
|
||||
</Space>
|
||||
</div>
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
);
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -2158,6 +2158,32 @@ export const TemplateList = (type, context) => {
|
||||
field: i18n.t("tasks.fields.created_at")
|
||||
},
|
||||
group: "jobs"
|
||||
},
|
||||
adp_payroll_flat: {
|
||||
title: i18n.t("reportcenter.templates.adp_payroll_flat"),
|
||||
subject: i18n.t("reportcenter.templates.adp_payroll_flat"),
|
||||
key: "adp_payroll_flat",
|
||||
reporttype: "text",
|
||||
disabled: false,
|
||||
rangeFilter: {
|
||||
object: i18n.t("reportcenter.labels.objects.timetickets"),
|
||||
field: i18n.t("timetickets.fields.committed_at")
|
||||
},
|
||||
group: "payroll",
|
||||
adp_payroll: true
|
||||
},
|
||||
adp_payroll_straight: {
|
||||
title: i18n.t("reportcenter.templates.adp_payroll_straight"),
|
||||
subject: i18n.t("reportcenter.templates.adp_payroll_straight"),
|
||||
key: "adp_payroll_straight",
|
||||
reporttype: "text",
|
||||
disabled: false,
|
||||
rangeFilter: {
|
||||
object: i18n.t("reportcenter.labels.objects.timetickets"),
|
||||
field: i18n.t("timetickets.fields.date")
|
||||
},
|
||||
group: "payroll",
|
||||
adp_payroll: true
|
||||
}
|
||||
}
|
||||
: {}),
|
||||
|
||||
@@ -94,7 +94,10 @@ exports.default = async (req, res) => {
|
||||
ret.push({
|
||||
billid: bill.id,
|
||||
success: false,
|
||||
errorMessage: (error && error.authResponse && error.authResponse.body) || (error && error.message)
|
||||
errorMessage:
|
||||
(error && error.authResponse && error.authResponse.body) ||
|
||||
error.response?.data?.Fault?.Error.map((e) => e.Detail).join(", ") ||
|
||||
(error && error.message)
|
||||
});
|
||||
|
||||
//Add the export log error.
|
||||
@@ -209,14 +212,14 @@ async function InsertBill(oauthClient, qbo_realmId, req, bill, vendor, bodyshop)
|
||||
AccountBasedExpenseLineDetail: {
|
||||
...(bill.job.class ? { ClassRef: { value: classes[bill.job.class] } } : {}),
|
||||
AccountRef: {
|
||||
value: accounts[bodyshop.md_responsibility_centers.taxes.federal.accountdesc]
|
||||
value: accounts[bodyshop.md_responsibility_centers.taxes.federal_itc.accountdesc]
|
||||
}
|
||||
},
|
||||
|
||||
Amount: Dinero({
|
||||
amount: Math.round(
|
||||
bill.billlines.reduce((acc, val) => {
|
||||
return acc + val.actual_cost * val.quantity;
|
||||
return acc + val.applicable_taxes?.federal ? (val.actual_cost * val.quantity ?? 0) : 0;
|
||||
}, 0) * 100
|
||||
)
|
||||
})
|
||||
@@ -274,6 +277,8 @@ async function InsertBill(oauthClient, qbo_realmId, req, bill, vendor, bodyshop)
|
||||
} catch (error) {
|
||||
logger.log("qbo-payables-error", "DEBUG", req.user.email, bill.id, {
|
||||
error: error, //(error && error.authResponse && error.authResponse.body) || (error && error.message),
|
||||
validationError: JSON.stringify(error?.response?.data),
|
||||
accountmeta: JSON.stringify({ accounts, taxCodes, classes }),
|
||||
method: "InsertBill"
|
||||
});
|
||||
throw error;
|
||||
|
||||
@@ -179,7 +179,11 @@ exports.default = async (req, res) => {
|
||||
ret.push({
|
||||
jobid: job.id,
|
||||
success: false,
|
||||
errorMessage: (error && error.authResponse && error.authResponse.body) || (error && error.message)
|
||||
errorMessage:
|
||||
error?.authResponse?.body ||
|
||||
error?.response?.data?.Fault?.Error.map((e) => e.Detail).join(", ") ||
|
||||
error?.response?.data ||
|
||||
error?.message
|
||||
});
|
||||
console.log(error);
|
||||
logger.log("qbo-receivable-create-error", "ERROR", req.user.email, {
|
||||
@@ -254,7 +258,6 @@ async function InsertInsuranceCo(oauthClient, qbo_realmId, req, job, bodyshop) {
|
||||
throw new Error(
|
||||
`Insurance Company '${job.ins_co_nm}' not found in shop configuration. Please make sure it exists or change the insurance company name on the job to one that exists.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
const Customer = {
|
||||
DisplayName: job.ins_co_nm.trim(),
|
||||
@@ -575,7 +578,9 @@ async function InsertInvoice(oauthClient, qbo_realmId, req, job, bodyshop, paren
|
||||
} catch (error) {
|
||||
logger.log("qbo-receivables-error", "DEBUG", req.user.email, job.id, {
|
||||
error,
|
||||
method: "InsertOwner"
|
||||
method: "InsertInvoice",
|
||||
validationError: JSON.stringify(error?.response?.data),
|
||||
accountmeta: JSON.stringify({ items, taxCodes, classes })
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user