diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel
index 3bc1ff5f1..46f5e9f32 100644
--- a/bodyshop_translations.babel
+++ b/bodyshop_translations.babel
@@ -3014,6 +3014,27 @@
+
+ attach_pdf_to_email
+ false
+
+
+
+
+
+ en-US
+ false
+
+
+ es-MX
+ false
+
+
+ fr-CA
+ false
+
+
+
bill_federal_tax_rate
false
diff --git a/client/src/components/email-overlay/email-overlay.container.jsx b/client/src/components/email-overlay/email-overlay.container.jsx
index e776a156e..f931728d9 100644
--- a/client/src/components/email-overlay/email-overlay.container.jsx
+++ b/client/src/components/email-overlay/email-overlay.container.jsx
@@ -43,6 +43,10 @@ export function EmailOverlayContainer({
const [loading, setLoading] = useState(false);
const [sending, setSending] = useState(false);
const [rawHtml, setRawHtml] = useState("");
+ const [pdfCopytoAttach, setPdfCopytoAttach] = useState({
+ filename: null,
+ pdf: null,
+ });
const [selectedMedia, setSelectedMedia] = useState([]);
const defaultEmailFrom = {
@@ -59,17 +63,17 @@ export function EmailOverlayContainer({
const handleFinish = async (values) => {
logImEXEvent("email_send_from_modal");
- const attachments = [];
+ //const attachments = [];
- if (values.fileList)
- await asyncForEach(values.fileList, async (f) => {
- const t = {
- ContentType: f.type,
- Filename: f.name,
- Base64Content: (await toBase64(f.originFileObj)).split(",")[1],
- };
- attachments.push(t);
- });
+ // if (values.fileList)
+ // await asyncForEach(values.fileList, async (f) => {
+ // const t = {
+ // ContentType: f.type,
+ // Filename: f.name,
+ // Base64Content: (await toBase64(f.originFileObj)).split(",")[1],
+ // };
+ // attachments.push(t);
+ // });
setSending(true);
try {
@@ -77,11 +81,28 @@ export function EmailOverlayContainer({
...defaultEmailFrom,
...values,
html: rawHtml,
- attachments:
- values.fileList &&
- (await Promise.all(
- values.fileList.map(async (f) => await toBase64(f.originFileObj))
- )),
+ attachments: [
+ ...(values.fileList
+ ? await Promise.all(
+ values.fileList.map(async (f) => {
+ return {
+ filename: f.name,
+ path: await toBase64(f.originFileObj),
+ };
+ })
+ )
+ : []),
+ ...(pdfCopytoAttach.pdf
+ ? [
+ {
+ path: pdfCopytoAttach.pdf,
+ filename:
+ pdfCopytoAttach.filename &&
+ `${pdfCopytoAttach.filename}.pdf`,
+ },
+ ]
+ : []),
+ ],
media: selectedMedia.filter((m) => m.isSelected).map((m) => m.src),
//attachments,
});
@@ -99,13 +120,22 @@ export function EmailOverlayContainer({
const render = async () => {
logImEXEvent("email_render_template", { template: emailConfig.template });
setLoading(true);
- let html = await RenderTemplate(emailConfig.template, bodyshop, true);
+ let { html, pdf, filename } = await RenderTemplate(
+ emailConfig.template,
+ bodyshop,
+ true
+ );
const response = await axios.post("/render/inlinecss", {
html: html,
url: `${window.location.protocol}://${window.location.host}/`,
});
setRawHtml(response.data);
+
+ if (pdf) {
+ setPdfCopytoAttach({ pdf, filename });
+ }
+
form.setFieldsValue({
...emailConfig.messageOptions,
cc:
@@ -166,8 +196,8 @@ const toBase64 = (file) =>
reader.onerror = (error) => reject(error);
});
-const asyncForEach = async (array, callback) => {
- for (let index = 0; index < array.length; index++) {
- await callback(array[index], index, array);
- }
-};
+// const asyncForEach = async (array, callback) => {
+// for (let index = 0; index < array.length; index++) {
+// await callback(array[index], index, array);
+// }
+// };
diff --git a/client/src/components/shop-info/shop-info.general.component.jsx b/client/src/components/shop-info/shop-info.general.component.jsx
index d7b40f1d8..26a92dcab 100644
--- a/client/src/components/shop-info/shop-info.general.component.jsx
+++ b/client/src/components/shop-info/shop-info.general.component.jsx
@@ -436,6 +436,14 @@ export default function ShopInfoGeneral({ form }) {
>
+
+
+
+
diff --git a/client/src/graphql/bodyshop.queries.js b/client/src/graphql/bodyshop.queries.js
index 3916c029e..0b65d35d8 100644
--- a/client/src/graphql/bodyshop.queries.js
+++ b/client/src/graphql/bodyshop.queries.js
@@ -91,6 +91,7 @@ export const QUERY_BODYSHOP = gql`
md_jobline_presets
cdk_dealerid
features
+ attach_pdf_to_email
employees {
id
active
@@ -178,6 +179,7 @@ export const UPDATE_SHOP = gql`
jc_hourly_rates
md_jobline_presets
cdk_dealerid
+ attach_pdf_to_email
employees {
id
first_name
diff --git a/client/src/graphql/jobs.queries.js b/client/src/graphql/jobs.queries.js
index 7a8974a5b..8bbcc6e1a 100644
--- a/client/src/graphql/jobs.queries.js
+++ b/client/src/graphql/jobs.queries.js
@@ -689,6 +689,8 @@ export const QUERY_JOB_CARD_DETAILS = gql`
v_make_desc
v_model_desc
v_color
+ v_vin
+ plate_st
plate_no
vehicle {
id
diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json
index 20653eb85..8c444c2cd 100644
--- a/client/src/translations/en_us/common.json
+++ b/client/src/translations/en_us/common.json
@@ -199,6 +199,7 @@
"label": "Label"
},
"appt_length": "Default Appointment Length",
+ "attach_pdf_to_email": "Attach PDF copy to sent emails?",
"bill_federal_tax_rate": "Bills - Federal Tax Rate %",
"bill_local_tax_rate": "Bill - Provincial/State Tax Rate %",
"bill_state_tax_rate": "Bill - Provincial/State Tax Rate %",
diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json
index 2b093063c..d8eb746a4 100644
--- a/client/src/translations/es/common.json
+++ b/client/src/translations/es/common.json
@@ -199,6 +199,7 @@
"label": ""
},
"appt_length": "",
+ "attach_pdf_to_email": "",
"bill_federal_tax_rate": "",
"bill_local_tax_rate": "",
"bill_state_tax_rate": "",
diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json
index a25172c23..811471037 100644
--- a/client/src/translations/fr/common.json
+++ b/client/src/translations/fr/common.json
@@ -199,6 +199,7 @@
"label": ""
},
"appt_length": "",
+ "attach_pdf_to_email": "",
"bill_federal_tax_rate": "",
"bill_local_tax_rate": "",
"bill_state_tax_rate": "",
diff --git a/client/src/utils/RenderTemplate.js b/client/src/utils/RenderTemplate.js
index 1e886fcdc..78452b1b6 100644
--- a/client/src/utils/RenderTemplate.js
+++ b/client/src/utils/RenderTemplate.js
@@ -8,6 +8,7 @@ import { setEmailOptions } from "../redux/email/email.actions";
import { store } from "../redux/store";
import client from "../utils/GraphQLClient";
import { TemplateList } from "./TemplateConstants";
+import _ from "lodash";
const server = process.env.REACT_APP_REPORTS_SERVER_URL;
jsreport.serverUrl = server;
@@ -39,8 +40,10 @@ export default async function RenderTemplate(
offset: moment().utcOffset(),
},
};
+
try {
const render = await jsreport.renderAsync(reportRequest);
+
if (!renderAsHtml) {
render.download(
(Templates[templateObject.name] &&
@@ -48,8 +51,21 @@ export default async function RenderTemplate(
""
);
} else {
+ let pdf;
+ if (bodyshop.attach_pdf_to_email) {
+ const pdfRequest = _.cloneDeep(reportRequest);
+ pdfRequest.template.recipe = "chrome-pdf";
+ const pdfRender = await jsreport.renderAsync(pdfRequest);
+ pdf = pdfRender.toDataURI();
+ }
return new Promise((resolve, reject) => {
- resolve(render.toString());
+ resolve({
+ pdf,
+ filename:
+ Templates[templateObject.name] &&
+ Templates[templateObject.name].title,
+ html: render.toString(),
+ });
});
}
} catch (error) {
diff --git a/hasura/migrations/1626795754549_alter_table_public_bodyshops_add_column_attach_pdf_to_email/down.yaml b/hasura/migrations/1626795754549_alter_table_public_bodyshops_add_column_attach_pdf_to_email/down.yaml
new file mode 100644
index 000000000..611f63c09
--- /dev/null
+++ b/hasura/migrations/1626795754549_alter_table_public_bodyshops_add_column_attach_pdf_to_email/down.yaml
@@ -0,0 +1,5 @@
+- args:
+ cascade: false
+ read_only: false
+ sql: ALTER TABLE "public"."bodyshops" DROP COLUMN "attach_pdf_to_email";
+ type: run_sql
diff --git a/hasura/migrations/1626795754549_alter_table_public_bodyshops_add_column_attach_pdf_to_email/up.yaml b/hasura/migrations/1626795754549_alter_table_public_bodyshops_add_column_attach_pdf_to_email/up.yaml
new file mode 100644
index 000000000..0730da959
--- /dev/null
+++ b/hasura/migrations/1626795754549_alter_table_public_bodyshops_add_column_attach_pdf_to_email/up.yaml
@@ -0,0 +1,6 @@
+- args:
+ cascade: false
+ read_only: false
+ sql: ALTER TABLE "public"."bodyshops" ADD COLUMN "attach_pdf_to_email" boolean
+ NOT NULL DEFAULT False;
+ type: run_sql
diff --git a/hasura/migrations/1626795768315_update_permission_user_public_table_bodyshops/down.yaml b/hasura/migrations/1626795768315_update_permission_user_public_table_bodyshops/down.yaml
new file mode 100644
index 000000000..24984ef56
--- /dev/null
+++ b/hasura/migrations/1626795768315_update_permission_user_public_table_bodyshops/down.yaml
@@ -0,0 +1,87 @@
+- args:
+ role: user
+ table:
+ name: bodyshops
+ schema: public
+ type: drop_select_permission
+- args:
+ permission:
+ allow_aggregations: false
+ columns:
+ - accountingconfig
+ - address1
+ - address2
+ - appt_alt_transport
+ - appt_colors
+ - appt_length
+ - bill_tax_rates
+ - cdk_dealerid
+ - city
+ - country
+ - created_at
+ - default_adjustment_rate
+ - deliverchecklist
+ - email
+ - enforce_class
+ - enforce_referral
+ - features
+ - federal_tax_id
+ - id
+ - imexshopid
+ - inhousevendorid
+ - insurance_vendor_id
+ - intakechecklist
+ - jc_hourly_rates
+ - jobsizelimit
+ - logo_img_path
+ - md_categories
+ - md_ccc_rates
+ - md_classes
+ - md_hour_split
+ - md_ins_cos
+ - md_jobline_presets
+ - md_labor_rates
+ - md_messaging_presets
+ - md_notes_presets
+ - md_order_statuses
+ - md_parts_locations
+ - md_payment_types
+ - md_rbac
+ - md_referral_sources
+ - md_responsibility_centers
+ - md_ro_statuses
+ - messagingservicesid
+ - phone
+ - prodtargethrs
+ - production_config
+ - region_config
+ - schedule_end_time
+ - schedule_start_time
+ - scoreboard_target
+ - shopname
+ - shoprates
+ - speedprint
+ - ssbuckets
+ - state
+ - state_tax_id
+ - stripe_acct_id
+ - sub_status
+ - target_touchtime
+ - template_header
+ - textid
+ - updated_at
+ - use_fippa
+ - website
+ - workingdays
+ - zip_post
+ computed_fields: []
+ filter:
+ associations:
+ user:
+ authid:
+ _eq: X-Hasura-User-Id
+ role: user
+ table:
+ name: bodyshops
+ schema: public
+ type: create_select_permission
diff --git a/hasura/migrations/1626795768315_update_permission_user_public_table_bodyshops/up.yaml b/hasura/migrations/1626795768315_update_permission_user_public_table_bodyshops/up.yaml
new file mode 100644
index 000000000..c8a09ddd4
--- /dev/null
+++ b/hasura/migrations/1626795768315_update_permission_user_public_table_bodyshops/up.yaml
@@ -0,0 +1,88 @@
+- args:
+ role: user
+ table:
+ name: bodyshops
+ schema: public
+ type: drop_select_permission
+- args:
+ permission:
+ allow_aggregations: false
+ columns:
+ - accountingconfig
+ - address1
+ - address2
+ - appt_alt_transport
+ - appt_colors
+ - appt_length
+ - attach_pdf_to_email
+ - bill_tax_rates
+ - cdk_dealerid
+ - city
+ - country
+ - created_at
+ - default_adjustment_rate
+ - deliverchecklist
+ - email
+ - enforce_class
+ - enforce_referral
+ - features
+ - federal_tax_id
+ - id
+ - imexshopid
+ - inhousevendorid
+ - insurance_vendor_id
+ - intakechecklist
+ - jc_hourly_rates
+ - jobsizelimit
+ - logo_img_path
+ - md_categories
+ - md_ccc_rates
+ - md_classes
+ - md_hour_split
+ - md_ins_cos
+ - md_jobline_presets
+ - md_labor_rates
+ - md_messaging_presets
+ - md_notes_presets
+ - md_order_statuses
+ - md_parts_locations
+ - md_payment_types
+ - md_rbac
+ - md_referral_sources
+ - md_responsibility_centers
+ - md_ro_statuses
+ - messagingservicesid
+ - phone
+ - prodtargethrs
+ - production_config
+ - region_config
+ - schedule_end_time
+ - schedule_start_time
+ - scoreboard_target
+ - shopname
+ - shoprates
+ - speedprint
+ - ssbuckets
+ - state
+ - state_tax_id
+ - stripe_acct_id
+ - sub_status
+ - target_touchtime
+ - template_header
+ - textid
+ - updated_at
+ - use_fippa
+ - website
+ - workingdays
+ - zip_post
+ computed_fields: []
+ filter:
+ associations:
+ user:
+ authid:
+ _eq: X-Hasura-User-Id
+ role: user
+ table:
+ name: bodyshops
+ schema: public
+ type: create_select_permission
diff --git a/hasura/migrations/1626795775694_update_permission_user_public_table_bodyshops/down.yaml b/hasura/migrations/1626795775694_update_permission_user_public_table_bodyshops/down.yaml
new file mode 100644
index 000000000..b09c84f9e
--- /dev/null
+++ b/hasura/migrations/1626795775694_update_permission_user_public_table_bodyshops/down.yaml
@@ -0,0 +1,79 @@
+- args:
+ role: user
+ table:
+ name: bodyshops
+ schema: public
+ type: drop_update_permission
+- args:
+ permission:
+ columns:
+ - accountingconfig
+ - address1
+ - address2
+ - appt_alt_transport
+ - appt_colors
+ - appt_length
+ - bill_tax_rates
+ - city
+ - country
+ - created_at
+ - default_adjustment_rate
+ - deliverchecklist
+ - email
+ - enforce_class
+ - enforce_referral
+ - federal_tax_id
+ - id
+ - inhousevendorid
+ - insurance_vendor_id
+ - intakechecklist
+ - jc_hourly_rates
+ - logo_img_path
+ - md_categories
+ - md_ccc_rates
+ - md_classes
+ - md_hour_split
+ - md_ins_cos
+ - md_jobline_presets
+ - md_labor_rates
+ - md_messaging_presets
+ - md_notes_presets
+ - md_order_statuses
+ - md_parts_locations
+ - md_payment_types
+ - md_rbac
+ - md_referral_sources
+ - md_responsibility_centers
+ - md_ro_statuses
+ - phone
+ - prodtargethrs
+ - production_config
+ - schedule_end_time
+ - schedule_start_time
+ - scoreboard_target
+ - shopname
+ - shoprates
+ - speedprint
+ - ssbuckets
+ - state
+ - state_tax_id
+ - target_touchtime
+ - updated_at
+ - use_fippa
+ - website
+ - workingdays
+ - zip_post
+ filter:
+ associations:
+ _and:
+ - user:
+ authid:
+ _eq: X-Hasura-User-Id
+ - active:
+ _eq: true
+ set: {}
+ role: user
+ table:
+ name: bodyshops
+ schema: public
+ type: create_update_permission
diff --git a/hasura/migrations/1626795775694_update_permission_user_public_table_bodyshops/up.yaml b/hasura/migrations/1626795775694_update_permission_user_public_table_bodyshops/up.yaml
new file mode 100644
index 000000000..adce758ee
--- /dev/null
+++ b/hasura/migrations/1626795775694_update_permission_user_public_table_bodyshops/up.yaml
@@ -0,0 +1,80 @@
+- args:
+ role: user
+ table:
+ name: bodyshops
+ schema: public
+ type: drop_update_permission
+- args:
+ permission:
+ columns:
+ - accountingconfig
+ - address1
+ - address2
+ - appt_alt_transport
+ - appt_colors
+ - appt_length
+ - attach_pdf_to_email
+ - bill_tax_rates
+ - city
+ - country
+ - created_at
+ - default_adjustment_rate
+ - deliverchecklist
+ - email
+ - enforce_class
+ - enforce_referral
+ - federal_tax_id
+ - id
+ - inhousevendorid
+ - insurance_vendor_id
+ - intakechecklist
+ - jc_hourly_rates
+ - logo_img_path
+ - md_categories
+ - md_ccc_rates
+ - md_classes
+ - md_hour_split
+ - md_ins_cos
+ - md_jobline_presets
+ - md_labor_rates
+ - md_messaging_presets
+ - md_notes_presets
+ - md_order_statuses
+ - md_parts_locations
+ - md_payment_types
+ - md_rbac
+ - md_referral_sources
+ - md_responsibility_centers
+ - md_ro_statuses
+ - phone
+ - prodtargethrs
+ - production_config
+ - schedule_end_time
+ - schedule_start_time
+ - scoreboard_target
+ - shopname
+ - shoprates
+ - speedprint
+ - ssbuckets
+ - state
+ - state_tax_id
+ - target_touchtime
+ - updated_at
+ - use_fippa
+ - website
+ - workingdays
+ - zip_post
+ filter:
+ associations:
+ _and:
+ - user:
+ authid:
+ _eq: X-Hasura-User-Id
+ - active:
+ _eq: true
+ set: {}
+ role: user
+ table:
+ name: bodyshops
+ schema: public
+ type: create_update_permission
diff --git a/hasura/migrations/metadata.yaml b/hasura/migrations/metadata.yaml
index 3481eec42..bd0c4200f 100644
--- a/hasura/migrations/metadata.yaml
+++ b/hasura/migrations/metadata.yaml
@@ -756,6 +756,7 @@ tables:
- appt_alt_transport
- appt_colors
- appt_length
+ - attach_pdf_to_email
- bill_tax_rates
- cdk_dealerid
- city
@@ -831,6 +832,7 @@ tables:
- appt_alt_transport
- appt_colors
- appt_length
+ - attach_pdf_to_email
- bill_tax_rates
- city
- country
diff --git a/server/email/sendemail.js b/server/email/sendemail.js
index 6f54b00f1..39acfaeac 100644
--- a/server/email/sendemail.js
+++ b/server/email/sendemail.js
@@ -48,7 +48,8 @@ exports.sendEmail = async (req, res) => {
...((req.body.attachments &&
req.body.attachments.map((a) => {
return {
- path: a,
+ filename: a.filename,
+ path: a.path,
};
})) ||
[]),