Merged in development (pull request #19)

Development
This commit is contained in:
Patrick Fic
2021-02-26 05:28:34 +00:00
19 changed files with 176 additions and 100 deletions

16
.ebignore Normal file
View File

@@ -0,0 +1,16 @@
/node_modules
/_business_logic
/_reference
/.circleci
/.vscoe
/admin
/client
/firebase
/hasura
/jsreport
/node_modules
.env.local
.env.development.local
.env.test.local
.env.production.local
bodyshop_translations.babel

5
.gitignore vendored
View File

@@ -107,3 +107,8 @@ firebase/.yarn-integrity
# dotenv environment variables file
firebase/.env
# Elastic Beanstalk Files
.elasticbeanstalk/*
!.elasticbeanstalk/*.cfg.yml
!.elasticbeanstalk/*.global.yml

View File

@@ -4,10 +4,6 @@ Yarn Dependency Management:
To force upgrades for some packages:
yarn upgrade-interactive --latest
GraphQL API:
Hasura is hosted on another dyno. Several environmental variables are required, including disabling the console.
ALL CHANGES MUST BE MADE USING LOCAL CONSOLE TO ENSURE DATABASE MIGRATION FILES ARE CREATED.
To Start Hasura CLI:
npx hasura console --admin-secret Dev-BodyShopAppBySnaptSoftware!

View File

@@ -1,4 +1,4 @@
<babeledit_project be_version="2.7.1" version="1.2">
<babeledit_project version="1.2" be_version="2.7.1">
<!--
BabelEdit project file
@@ -24845,6 +24845,32 @@
<folder_node>
<name>printcenter</name>
<children>
<folder_node>
<name>appointments</name>
<children>
<concept_node>
<name>appointment_confirmation</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
</children>
</folder_node>
<folder_node>
<name>bills</name>
<children>

View File

@@ -32,6 +32,7 @@
"logrocket": "^1.0.13",
"moment-business-days": "^1.2.0",
"node-sass": "^4.14.1",
"phone": "^2.4.21",
"preval.macro": "^5.0.0",
"prop-types": "^15.7.2",
"query-string": "^6.14.0",
@@ -16202,6 +16203,14 @@
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
},
"node_modules/phone": {
"version": "2.4.21",
"resolved": "https://registry.npmjs.org/phone/-/phone-2.4.21.tgz",
"integrity": "sha512-vTHYwgeCoMuZOwDRQwQAdi2NOV72wSqsqw0k/EwUnE9YVZZnYzqMwVn8Nas2yjHR2JKzx9gqrEqoQeMYnh3/SA==",
"engines": {
"node": ">=6.10.0"
}
},
"node_modules/picomatch": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
@@ -38391,6 +38400,11 @@
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
},
"phone": {
"version": "2.4.21",
"resolved": "https://registry.npmjs.org/phone/-/phone-2.4.21.tgz",
"integrity": "sha512-vTHYwgeCoMuZOwDRQwQAdi2NOV72wSqsqw0k/EwUnE9YVZZnYzqMwVn8Nas2yjHR2JKzx9gqrEqoQeMYnh3/SA=="
},
"picomatch": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",

View File

@@ -28,6 +28,7 @@
"logrocket": "^1.0.13",
"moment-business-days": "^1.2.0",
"node-sass": "^4.14.1",
"phone": "^2.4.21",
"preval.macro": "^5.0.0",
"prop-types": "^15.7.2",
"query-string": "^6.14.0",

View File

@@ -48,7 +48,7 @@ export function Jobd3RdPartyModal({ bodyshop, jobId }) {
variables: { id: jobId },
context: restVals,
},
{},
{ subject: TemplateList("job_special").thirdpartypayer.subject },
sendtype
);
};

View File

@@ -5,14 +5,14 @@ import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
import FormDatePicker from "../form-date-picker/form-date-picker.component";
import InputNumberCalculator from "../form-input-number-calculator/form-input-number-calculator.component";
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
import FormItemEmail from "../form-items-formatted/email-form-item.component";
import FormItemPhone, {
PhoneItemFormatterValidation,
} from "../form-items-formatted/phone-form-item.component";
import JobsDetailRatesChangeButton from "../jobs-detail-rates-change-button/jobs-detail-rates-change-button.component";
import { JobsDetailRatesParts } from "../jobs-detail-rates/jobs-detail-rates.parts.component";
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
bodyshop: selectBodyshop,
@@ -92,7 +92,7 @@ export function JobsCreateJobsInfo({ bodyshop, form, selected }) {
>
<FormItemEmail email={getFieldValue("ins_ea")} />
</Form.Item>
Appraiser Info
<Form.Item label={t("jobs.fields.est_co_nm")} name="est_co_nm">
<Input />
</Form.Item>
@@ -188,9 +188,11 @@ export function JobsCreateJobsInfo({ bodyshop, form, selected }) {
key="financial"
header={t("menus.jobsdetail.financials")}
>
<JobsDetailRatesChangeButton form={form} />
<LayoutFormRow>
<Form.Item label={t("jobs.fields.ded_amt")} name="ded_amt">
<InputNumberCalculator />
<CurrencyInput />
</Form.Item>
<Form.Item label={t("jobs.fields.ded_status")} name="ded_status">
<Select>
@@ -206,7 +208,7 @@ export function JobsCreateJobsInfo({ bodyshop, form, selected }) {
label={t("jobs.fields.depreciation_taxes")}
name="depreciation_taxes"
>
<InputNumberCalculator />
<CurrencyInput />
</Form.Item>
<Form.Item
label={t("jobs.fields.ca_gst_registrant")}
@@ -219,98 +221,93 @@ export function JobsCreateJobsInfo({ bodyshop, form, selected }) {
label={t("jobs.fields.other_amount_payable")}
name="other_amount_payable"
>
<InputNumberCalculator />
<CurrencyInput />
</Form.Item>
<Form.Item
label={t("jobs.fields.towing_payable")}
name="towing_payable"
>
<InputNumberCalculator />
<CurrencyInput />
</Form.Item>
<Form.Item
label={t("jobs.fields.storage_payable")}
name="storage_payable"
>
<InputNumberCalculator />
<CurrencyInput />
</Form.Item>
<Form.Item
label={t("jobs.fields.adjustment_bottom_line")}
name="adjustment_bottom_line"
>
<InputNumberCalculator />
</Form.Item>
Totals Table
<Form.Item
label={t("jobs.fields.labor_rate_desc")}
name="labor_rate_desc"
>
<Input />
<CurrencyInput />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow>
<Form.Item label={t("jobs.fields.rate_lab")} name="rate_lab">
<InputNumberCalculator />
<CurrencyInput />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_lad")} name="rate_lad">
<InputNumberCalculator />
<CurrencyInput />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_lae")} name="rate_lae">
<InputNumberCalculator />
<CurrencyInput />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_lar")} name="rate_lar">
<InputNumberCalculator />
<CurrencyInput />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_las")} name="rate_las">
<InputNumberCalculator />
<CurrencyInput />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_laf")} name="rate_laf">
<InputNumberCalculator />
<CurrencyInput />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_lam")} name="rate_lam">
<InputNumberCalculator />
<CurrencyInput />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_lag")} name="rate_lag">
<InputNumberCalculator />
<CurrencyInput />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_lau")} name="rate_lau">
<InputNumberCalculator />
<CurrencyInput />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_la1")} name="rate_la1">
<InputNumberCalculator />
<CurrencyInput />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_la2")} name="rate_la2">
<InputNumberCalculator />
<CurrencyInput />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_la3")} name="rate_la3">
<InputNumberCalculator />
<CurrencyInput />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_la4")} name="rate_la4">
<InputNumberCalculator />
<CurrencyInput />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_mapa")} name="rate_mapa">
<InputNumberCalculator />
<CurrencyInput />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_mash")} name="rate_mash">
<InputNumberCalculator />
<CurrencyInput />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_mahw")} name="rate_mahw">
<InputNumberCalculator />
<CurrencyInput />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_ma2s")} name="rate_ma2s">
<InputNumberCalculator />
<CurrencyInput />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_ma3s")} name="rate_ma3s">
<InputNumberCalculator />
<CurrencyInput />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_mabl")} name="rate_mabl">
<InputNumberCalculator />
<CurrencyInput />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_macs")} name="rate_macs">
<InputNumberCalculator />
<CurrencyInput />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_matd")} name="rate_matd">
<InputNumberCalculator />
<CurrencyInput />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_laa")} name="rate_laa">
<InputNumberCalculator />
<CurrencyInput />
</Form.Item>
</LayoutFormRow>
</Collapse.Panel>

View File

@@ -156,6 +156,7 @@ export function PartsOrderModalContainer({
if (refetch) refetch();
toggleModalVisible();
const Templates = TemplateList("partsorder");
if (sendType === "e") {
const matchingVendor = data.vendors.filter(
@@ -165,8 +166,8 @@ export function PartsOrderModalContainer({
GenerateDocument(
{
name: isReturn
? TemplateList("partsorder").parts_return_slip.key
: TemplateList("partsorder").parts_order.key,
? Templates.parts_return_slip.key
: Templates.parts_order.key,
variables: {
id: insertResult.data.insert_parts_orders.returning[0].id,
},
@@ -174,7 +175,9 @@ export function PartsOrderModalContainer({
{
to: matchingVendor ? [matchingVendor.email] : null,
replyTo: bodyshop.email,
subject: TemplateList("partsorder", {}).parts_order.subject,
subject: isReturn
? Templates.parts_return_slip.subject
: Templates.parts_order.subject,
},
"e"
);
@@ -182,8 +185,8 @@ export function PartsOrderModalContainer({
GenerateDocument(
{
name: isReturn
? TemplateList("partsorder").parts_return_slip.key
: TemplateList("partsorder").parts_order.key,
? Templates.parts_return_slip.key
: Templates.parts_order.key,
variables: {
id: insertResult.data.insert_parts_orders.returning[0].id,
},

View File

@@ -118,10 +118,10 @@ function BillEnterModalContainer({
} else {
notification["error"]({ message: t("payments.errors.payment") });
}
const Templates = TemplateList("payment");
GenerateDocument(
{
name: TemplateList("payment").payment_receipt.key,
name: Templates.payment_receipt.key,
variables: {
id: newPayment.data.insert_payments.returning[0].id,
},
@@ -129,6 +129,7 @@ function BillEnterModalContainer({
{
// to: [appData.email],
replyTo: bodyshop.email,
subject: Templates.payment_receipt.subject,
},
sendby === "email" ? "e" : "p"
);

View File

@@ -36,7 +36,7 @@ export function PaymentsListPaginated({
sortedInfo: {},
filteredInfo: { text: "" },
});
const Templates = TemplateList("payment");
const { t } = useTranslation();
const columns = [
{
@@ -156,9 +156,10 @@ export function PaymentsListPaginated({
</Button>
<PrintWrapperComponent
templateObject={{
name: TemplateList("payment").payment_receipt.key,
name: Templates.payment_receipt.key,
variables: { id: record.id },
}}
messageObject={{ subject: Templates.payment_receipt.subject }}
/>
</Space>
),

View File

@@ -50,7 +50,7 @@ export function PrintCenterItemComponent({
name: item.key,
variables: { id: id },
},
{ to: context.job && context.job.ownr_ea },
{ to: context.job && context.job.ownr_ea, subject: item.subject },
"e"
);
}}

View File

@@ -1,6 +1,8 @@
import Icon from "@ant-design/icons";
import { Popover } from "antd";
import React from "react";
import _ from "lodash";
import moment from "moment";
import React, { useMemo } from "react";
import { useTranslation } from "react-i18next";
import { MdFileDownload, MdFileUpload } from "react-icons/md";
import { connect } from "react-redux";
@@ -15,8 +17,6 @@ import { DateTimeFormatter } from "../../utils/DateFormatter";
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
import ScheduleBlockDay from "../schedule-block-day/schedule-block-day.component";
import ScheduleCalendarHeaderGraph from "./schedule-calendar-header-graph.component";
import moment from "moment";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
load: selectScheduleLoad,
@@ -32,8 +32,17 @@ export function ScheduleCalendarHeaderComponent({
date,
load,
calculating,
events,
...otherProps
}) {
const ATSToday = useMemo(() => {
if (!events) return [];
return _.groupBy(
events.filter((e) => moment(date).isSame(moment(e.start), "day")),
"job.alt_transport"
);
}, [events, date]);
const { t } = useTranslation();
const loadData = load[date.toISOString().substr(0, 10)];
@@ -102,26 +111,37 @@ export function ScheduleCalendarHeaderComponent({
);
const LoadComponent = loadData ? (
<div className="imex-flex-row imex-flex-row__flex-space-around">
<Popover
placement={"bottom"}
content={jobsInPopup}
trigger="hover"
title={t("appointments.labels.arrivingjobs")}
>
<Icon component={MdFileDownload} style={{ color: "green" }} />
{(loadData.hoursIn || 0) && loadData.hoursIn.toFixed(2)}
</Popover>
<Popover
placement={"bottom"}
content={jobsOutPopup}
trigger="hover"
title={t("appointments.labels.completingjobs")}
>
<Icon component={MdFileUpload} style={{ color: "red" }} />
{(loadData.hoursOut || 0) && loadData.hoursOut.toFixed(2)}
</Popover>
<ScheduleCalendarHeaderGraph loadData={loadData} />
<div>
<div className="imex-flex-row imex-flex-row__flex-space-around">
<Popover
placement={"bottom"}
content={jobsInPopup}
trigger="hover"
title={t("appointments.labels.arrivingjobs")}
>
<Icon component={MdFileDownload} style={{ color: "green" }} />
{(loadData.hoursIn || 0) && loadData.hoursIn.toFixed(2)}
</Popover>
<Popover
placement={"bottom"}
content={jobsOutPopup}
trigger="hover"
title={t("appointments.labels.completingjobs")}
>
<Icon component={MdFileUpload} style={{ color: "red" }} />
{(loadData.hoursOut || 0) && loadData.hoursOut.toFixed(2)}
</Popover>
<ScheduleCalendarHeaderGraph loadData={loadData} />
</div>
<div>
<ul style={{ listStyleType: "none", columns: "2 auto", padding: 0 }}>
{Object.keys(ATSToday).map((key, idx) => (
<li key={idx}>{`${key === "null" ? "N/A" : key}: ${
ATSToday[key].length
}`}</li>
))}
</ul>
</div>
</div>
) : null;

View File

@@ -4,6 +4,9 @@
.rbc-time-view .rbc-allday-cell {
height: unset;
}
.rbc-row-content {
display: none;
}
.rbc-event-label {
display: none;

View File

@@ -27,16 +27,6 @@ export function ScheduleCalendarWrapperComponent({
const history = useHistory();
const handleEventPropStyles = (event, start, end, isSelected) => {
// if (!!!bodyshop.ssbuckets) {
// return {};
// }
// const defaultEventColor = "#3174ad";
// const jobHrs = result.jobs_by_pk.jobhrs.aggregate.sum.mod_lb_hrs;
// const JobBucket = bodyshop.ssbuckets.filter(
// (bucket) =>
// bucket.gte <= jobHrs && (!!bucket.lt ? bucket.lt > jobHrs : true)
// )[0];
return {
...(event.color
? {
@@ -70,15 +60,15 @@ export function ScheduleCalendarWrapperComponent({
search.view = view;
history.push({ search: queryString.stringify(search) });
}}
step={30}
timeslots={1}
step={15}
// timeslots={1}
showMultiDayTimes
localizer={localizer}
min={
bodyshop.schedule_start_time
? new Date(bodyshop.schedule_start_time)
: new Date("2020-01-01T06:00:00")
}
}
max={
bodyshop.schedule_end_time
? new Date(bodyshop.schedule_end_time)
@@ -86,8 +76,9 @@ export function ScheduleCalendarWrapperComponent({
}
eventPropGetter={handleEventPropStyles}
components={{
event: (e) => Event({ bodyshop: bodyshop, event: e.event, refetch: refetch }),
header: HeaderComponent,
event: (e) =>
Event({ bodyshop: bodyshop, event: e.event, refetch: refetch }),
header: (p) => <HeaderComponent {...p} events={data} />,
}}
{...otherProps}
/>

View File

@@ -1502,6 +1502,9 @@
}
},
"printcenter": {
"appointments": {
"appointment_confirmation": "Appointment Confirmation"
},
"bills": {
"inhouse_invoice": "In House Invoice"
},

View File

@@ -1502,6 +1502,9 @@
}
},
"printcenter": {
"appointments": {
"appointment_confirmation": ""
},
"bills": {
"inhouse_invoice": ""
},

View File

@@ -1502,6 +1502,9 @@
}
},
"printcenter": {
"appointments": {
"appointment_confirmation": ""
},
"bills": {
"inhouse_invoice": ""
},

View File

@@ -201,14 +201,7 @@ export const TemplateList = (type, context) => {
description: "Parts Order",
key: "parts_order",
subject: `${bodyshop && bodyshop.shopname} Parts Order ${
(context &&
context &&
context.job &&
context.job &&
context &&
context.job &&
context.job.ro_number) ||
""
(context && context.job && context.job.ro_number) || ""
}`,
disabled: false,
},