Merged in releaase/2022-09-02 (pull request #571)

Releaase/2022 09 02
This commit is contained in:
Patrick Fic
2022-08-31 21:10:18 +00:00
13 changed files with 575 additions and 75 deletions

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 BabelEdit project file
@@ -15416,6 +15416,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>send</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>
<concept_node> <concept_node>
<name>senderrortosupport</name> <name>senderrortosupport</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -34329,6 +34350,48 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>custompercent</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>
<concept_node>
<name>discount</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>
<concept_node> <concept_node>
<name>email</name> <name>email</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -34476,6 +34539,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>order_type</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>
<concept_node> <concept_node>
<name>orderhistory</name> <name>orderhistory</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -34497,6 +34581,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>parts_order</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>
<concept_node> <concept_node>
<name>parts_orders</name> <name>parts_orders</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -34602,6 +34707,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>sublet_order</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> </children>
</folder_node> </folder_node>
<folder_node> <folder_node>
@@ -35220,6 +35346,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>markexported</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>
<concept_node> <concept_node>
<name>payment</name> <name>payment</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -37390,6 +37537,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>sublet_order</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>
<concept_node> <concept_node>
<name>supplement_request</name> <name>supplement_request</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -38006,6 +38174,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>sublet_order</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> </children>
</folder_node> </folder_node>
</children> </children>

View File

@@ -1,19 +1,20 @@
import { Card, Input, Space, Table } from "antd"; import { Card, Input, Space, Table } from "antd";
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 { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import { logImEXEvent } from "../../firebase/firebase.utils"; import { logImEXEvent } from "../../firebase/firebase.utils";
import { selectBodyshop } from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter"; import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { DateFormatter, DateTimeFormatter } from "../../utils/DateFormatter"; import { DateFormatter, DateTimeFormatter } from "../../utils/DateFormatter";
import { alphaSort, dateSort } from "../../utils/sorters"; import { alphaSort, dateSort } from "../../utils/sorters";
import ExportLogsCountDisplay from "../export-logs-count-display/export-logs-count-display.component";
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
import PaymentExportButton from "../payment-export-button/payment-export-button.component"; import PaymentExportButton from "../payment-export-button/payment-export-button.component";
import PaymentMarkSelectedExported from "../payment-mark-selected-exported/payment-mark-selected-exported.component";
import PaymentsExportAllButton from "../payments-export-all-button/payments-export-all-button.component"; import PaymentsExportAllButton from "../payments-export-all-button/payments-export-all-button.component";
import QboAuthorizeComponent from "../qbo-authorize/qbo-authorize.component"; import QboAuthorizeComponent from "../qbo-authorize/qbo-authorize.component";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
import ExportLogsCountDisplay from "../export-logs-count-display/export-logs-count-display.component";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
@@ -184,6 +185,13 @@ export function AccountingPayablesTableComponent({
<Card <Card
extra={ extra={
<Space wrap> <Space wrap>
<PaymentMarkSelectedExported
paymentIds={selectedPayments}
disabled={transInProgress || selectedPayments.length === 0}
loadingCallback={setTransInProgress}
completedCallback={setSelectedPayments}
refetch={refetch}
/>
<PaymentsExportAllButton <PaymentsExportAllButton
paymentIds={selectedPayments} paymentIds={selectedPayments}
disabled={transInProgress || selectedPayments.length === 0} disabled={transInProgress || selectedPayments.length === 0}

View File

@@ -1,4 +1,4 @@
import { Divider, Form, Modal, notification } from "antd"; import { Button, Divider, Form, Modal, notification, Space } from "antd";
import axios from "axios"; import axios from "axios";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@@ -180,8 +180,10 @@ export function EmailOverlayContainer({
onCancel={() => { onCancel={() => {
toggleEmailOverlayVisible(); toggleEmailOverlayVisible();
}} }}
okText={t("general.actions.send")}
okButtonProps={{ okButtonProps={{
loading: sending, loading: sending,
disabled: disabled:
selectedMedia && selectedMedia &&
(selectedMedia (selectedMedia
@@ -191,21 +193,56 @@ export function EmailOverlayContainer({
selectedMedia.filter((s) => s.isSelected).length > 10), selectedMedia.filter((s) => s.isSelected).length > 10),
}} }}
> >
<Form layout="vertical" form={form} onFinish={handleFinish}> <div>
{loading && ( <div
<div> style={{
<LoadingSkeleton /> marginTop: "1rem",
<Divider>{t("emails.labels.preview")}</Divider> display: "flex",
<LoadingSpinner message={t("emails.labels.generatingemail")} /> justifyContent: "flex-end",
</div> }}
)} >
{!loading && ( <Space style={{ alignSelf: "flex-end" }} align="right">
<EmailOverlayComponent <Button
form={form} onClick={() => {
selectedMediaState={[selectedMedia, setSelectedMedia]} toggleEmailOverlayVisible();
/> }}
)} >
</Form> {t("general.actions.cancel")}
</Button>
<Button
loading={sending}
onClick={() => form.submit()}
disabled={
selectedMedia &&
(selectedMedia
.filter((s) => s.isSelected)
.reduce((acc, val) => (acc = acc + val.size), 0) >=
10485760 - new Blob([form.getFieldValue("html")]).size ||
selectedMedia.filter((s) => s.isSelected).length > 10)
}
type="primary"
>
{t("general.actions.send")}
</Button>
</Space>
</div>
<Form layout="vertical" form={form} onFinish={handleFinish}>
{loading && (
<div>
<LoadingSkeleton />
<Divider>{t("emails.labels.preview")}</Divider>
<LoadingSpinner message={t("emails.labels.generatingemail")} />
</div>
)}
{!loading && (
<EmailOverlayComponent
form={form}
selectedMediaState={[selectedMedia, setSelectedMedia]}
/>
)}
</Form>
</div>
</Modal> </Modal>
); );
} }

View File

@@ -19,7 +19,7 @@ const mapDispatchToProps = (dispatch) => ({
}); });
export default connect(mapStateToProps, mapDispatchToProps)(Jobd3RdPartyModal); export default connect(mapStateToProps, mapDispatchToProps)(Jobd3RdPartyModal);
export function Jobd3RdPartyModal({ bodyshop, jobId }) { export function Jobd3RdPartyModal({ bodyshop, jobId, job }) {
const [isModalVisible, setIsModalVisible] = useState(false); const [isModalVisible, setIsModalVisible] = useState(false);
const { t } = useTranslation(); const { t } = useTranslation();
const [form] = Form.useForm(); const [form] = Form.useForm();
@@ -33,6 +33,11 @@ export function Jobd3RdPartyModal({ bodyshop, jobId }) {
); );
const showModal = () => { const showModal = () => {
form.setFieldsValue({
ded_amt: job.ded_amt,
deprecieation: job.depreciation_taxes,
cust_gst: job.cust_gst,
});
setIsModalVisible(true); setIsModalVisible(true);
}; };
@@ -42,6 +47,7 @@ export function Jobd3RdPartyModal({ bodyshop, jobId }) {
}; };
const handleCancel = () => { const handleCancel = () => {
form.resetFields();
setIsModalVisible(false); setIsModalVisible(false);
}; };
const handleFinish = (values) => { const handleFinish = (values) => {

View File

@@ -0,0 +1,97 @@
import { DownOutlined } from "@ant-design/icons";
import { Dropdown, InputNumber, Menu, Space } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
export default function PartsOrderModalPriceChange({ form, field }) {
const { t } = useTranslation();
const menu = (
<Menu
onClick={({ key }) => {
if (key === "custom") return;
const values = form.getFieldsValue();
const { parts_order_lines } = values;
form.setFieldsValue({
parts_order_lines: {
data: parts_order_lines.data.map((p, idx) => {
if (idx !== field.name) return p;
return {
...p,
act_price: (p.act_price || 0) * ((100 - key) / 100),
};
}),
},
});
}}
items={[
{
key: "5",
label: t("parts_orders.labels.discount", { percent: "5%" }),
},
{
key: "10",
label: t("parts_orders.labels.discount", { percent: "10%" }),
},
{
key: "15",
label: t("parts_orders.labels.discount", { percent: "15%" }),
},
{
key: "20",
label: t("parts_orders.labels.discount", { percent: "20%" }),
},
{
key: "25",
label: t("parts_orders.labels.discount", { percent: "25%" }),
},
{
key: "custom",
label: (
<InputNumber
onClick={(e) => e.stopPropagation()}
addonAfter="%"
onKeyUp={(e) => {
if (e.key === "Enter") {
const values = form.getFieldsValue();
const { parts_order_lines } = values;
form.setFieldsValue({
parts_order_lines: {
data: parts_order_lines.data.map((p, idx) => {
if (idx !== field.name) return p;
console.log(
p,
e.target.value,
(p.act_price || 0) *
((100 - (e.target.value || 0)) / 100)
);
return {
...p,
act_price:
(p.act_price || 0) *
((100 - (e.target.value || 0)) / 100),
};
}),
},
});
e.target.value = 0;
}
}}
min={0}
max={100}
/>
),
},
]}
/>
);
return (
<Dropdown overlay={menu} trigger="click">
<Space>
%
<DownOutlined />
</Space>
</Dropdown>
);
}

View File

@@ -23,6 +23,7 @@ import CurrencyInput from "../form-items-formatted/currency-form-item.component"
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component"; import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
import LayoutFormRow from "../layout-form-row/layout-form-row.component"; import LayoutFormRow from "../layout-form-row/layout-form-row.component";
import VendorSearchSelect from "../vendor-search-select/vendor-search-select.component"; import VendorSearchSelect from "../vendor-search-select/vendor-search-select.component";
import PartsOrderModalPriceChange from "./parts-order-modal-price-change.component";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
@@ -133,6 +134,18 @@ export function PartsOrderModalComponent({
<Checkbox /> <Checkbox />
</Form.Item> </Form.Item>
)} )}
<Form.Item
name="order_type"
initialValue="parts_order"
label={t("parts_orders.labels.order_type")}
>
<Radio.Group>
<Radio value={"parts_order"}>
{t("parts_orders.labels.parts_order")}
</Radio>
<Radio value={"sublet"}>{t("parts_orders.labels.sublet")}</Radio>
</Radio.Group>
</Form.Item>
</LayoutFormRow> </LayoutFormRow>
<Divider orientation="left"> <Divider orientation="left">
{t("parts_orders.labels.inthisorder")} {t("parts_orders.labels.inthisorder")}
@@ -246,7 +259,14 @@ export function PartsOrderModalComponent({
key={`${index}act_price`} key={`${index}act_price`}
name={[field.name, "act_price"]} name={[field.name, "act_price"]}
> >
<CurrencyInput /> <CurrencyInput
addonBefore={
<PartsOrderModalPriceChange
form={form}
field={field}
/>
}
/>
</Form.Item> </Form.Item>
{isReturn && ( {isReturn && (
<Form.Item <Form.Item

View File

@@ -94,6 +94,7 @@ export function PartsOrderModalContainer({
const [updateJob] = useMutation(UPDATE_JOB); const [updateJob] = useMutation(UPDATE_JOB);
const handleFinish = async ({ const handleFinish = async ({
order_type,
removefrompartsqueue, removefrompartsqueue,
is_quote, is_quote,
...values ...values
@@ -102,47 +103,46 @@ export function PartsOrderModalContainer({
setSaving(true); setSaving(true);
let insertResult; let insertResult;
insertResult = await insertPartOrder({ insertResult = await insertPartOrder({
variables: { variables: {
po: [ po: [
{ {
...values, ...values,
order_date: moment().format("YYYY-MM-DD"), order_date: moment().format("YYYY-MM-DD"),
orderedby: currentUser.email, orderedby: currentUser.email,
jobid: jobId, jobid: jobId,
user_email: currentUser.email, user_email: currentUser.email,
return: isReturn, return: isReturn,
status: is_quote status: is_quote
? bodyshop.md_order_statuses.default_quote || "Quote" ? bodyshop.md_order_statuses.default_quote || "Quote"
: bodyshop.md_order_statuses.default_ordered || "Ordered*", : bodyshop.md_order_statuses.default_ordered || "Ordered*",
}, },
], ],
}, },
refetchQueries: ["QUERY_PARTS_BILLS_BY_JOBID"], refetchQueries: ["QUERY_PARTS_BILLS_BY_JOBID"],
});
if (!!insertResult.errors) {
notification["error"]({
message: t("parts_orders.errors.creating"),
description: JSON.stringify(insertResult.errors),
}); });
if (!!insertResult.errors) { return;
notification["error"]({ }
message: t("parts_orders.errors.creating"), notification["success"]({
description: JSON.stringify(insertResult.errors), message: values.isReturn
}); ? t("parts_orders.successes.return_created")
return; : t("parts_orders.successes.created"),
} });
notification["success"]({ insertAuditTrail({
message: values.isReturn jobid: jobId,
? t("parts_orders.successes.return_created") operation: isReturn
: t("parts_orders.successes.created"), ? AuditTrailMapping.jobspartsreturn(
}); insertResult.data.insert_parts_orders.returning[0].order_number
insertAuditTrail({ )
jobid: jobId, : AuditTrailMapping.jobspartsorder(
operation: isReturn insertResult.data.insert_parts_orders.returning[0].order_number
? AuditTrailMapping.jobspartsreturn( ),
insertResult.data.insert_parts_orders.returning[0].order_number });
)
: AuditTrailMapping.jobspartsorder(
insertResult.data.insert_parts_orders.returning[0].order_number
),
});
const jobLinesResult = await updateJobLines({ const jobLinesResult = await updateJobLines({
variables: { variables: {
@@ -228,7 +228,9 @@ export function PartsOrderModalContainer({
{ {
name: isReturn name: isReturn
? Templates.parts_return_slip.key ? Templates.parts_return_slip.key
: Templates.parts_order.key, : order_type === "parts_order"
? Templates.parts_order.key
: Templates.sublet_order.key,
variables: { variables: {
id: insertResult.data.insert_parts_orders.returning[0].id, id: insertResult.data.insert_parts_orders.returning[0].id,
}, },
@@ -238,7 +240,9 @@ export function PartsOrderModalContainer({
replyTo: bodyshop.email, replyTo: bodyshop.email,
subject: isReturn subject: isReturn
? Templates.parts_return_slip.subject ? Templates.parts_return_slip.subject
: Templates.parts_order.subject, : order_type === "parts_order"
? Templates.parts_order.subject
: Templates.sublet_order.subject,
}, },
"e", "e",
jobId jobId
@@ -248,7 +252,9 @@ export function PartsOrderModalContainer({
{ {
name: isReturn name: isReturn
? Templates.parts_return_slip.key ? Templates.parts_return_slip.key
: Templates.parts_order.key, : order_type === "parts_order"
? Templates.parts_order.key
: Templates.sublet_order.key,
variables: { variables: {
id: insertResult.data.insert_parts_orders.returning[0].id, id: insertResult.data.insert_parts_orders.returning[0].id,
}, },

View File

@@ -0,0 +1,96 @@
import { gql, useMutation } from "@apollo/client";
import { Button, notification } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries";
import {
selectBodyshop,
selectCurrentUser,
} from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
currentUser: selectCurrentUser,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(PaymentMarkSelectedExported);
export function PaymentMarkSelectedExported({
bodyshop,
currentUser,
paymentIds,
disabled,
loadingCallback,
completedCallback,
refetch,
}) {
const { t } = useTranslation();
const [loading, setLoading] = useState(false);
const [insertExportLog] = useMutation(INSERT_EXPORT_LOG);
const [updatePayments] = useMutation(gql`
mutation UPDATE_PAYMENTS($paymentIds: [uuid!]!, $exportedat: timestamptz!) {
update_payments(
where: { id: { _in: $paymentIds } }
_set: { exportedat: $exportedat }
) {
returning {
id
exportedat
}
}
}
`);
const handleUpdate = async () => {
setLoading(true);
loadingCallback(true);
const result = await updatePayments({
variables: { paymentIds: paymentIds, exportedat: new Date() },
update(cache) {},
});
await insertExportLog({
variables: {
logs: paymentIds.map((id) => {
return {
bodyshopid: bodyshop.id,
paymentid: id,
successful: true,
message: JSON.stringify([t("general.labels.markedexported")]),
useremail: currentUser.email,
};
}),
},
});
if (!result.errors) {
notification["success"]({
message: t("payments.successes.markexported"),
});
} else {
notification["error"]({
message: t("bills.errors.saving", {
error: JSON.stringify(result.errors),
}),
});
}
loadingCallback(false);
completedCallback && completedCallback([]);
setLoading(false);
refetch && refetch();
};
return (
<Button loading={loading} disabled={disabled} onClick={handleUpdate}>
{t("bills.labels.markexported")}
</Button>
);
}

View File

@@ -20,7 +20,7 @@ const mapDispatchToProps = (dispatch) => ({});
export function PrintCenterJobsComponent({ printCenterModal, bodyshop }) { export function PrintCenterJobsComponent({ printCenterModal, bodyshop }) {
const [search, setSearch] = useState(""); const [search, setSearch] = useState("");
const { id: jobId } = printCenterModal.context; const { id: jobId, job } = printCenterModal.context;
const tempList = TemplateList("job", {}); const tempList = TemplateList("job", {});
const { t } = useTranslation(); const { t } = useTranslation();
const JobsReportsList = Object.keys(tempList) const JobsReportsList = Object.keys(tempList)
@@ -54,7 +54,7 @@ export function PrintCenterJobsComponent({ printCenterModal, bodyshop }) {
extra={ extra={
<Space wrap> <Space wrap>
<PrintCenterJobsLabels jobId={jobId} /> <PrintCenterJobsLabels jobId={jobId} />
<Jobd3RdPartyModal jobId={jobId} /> <Jobd3RdPartyModal jobId={jobId} job={job} />
<Input.Search <Input.Search
onChange={(e) => setSearch(e.target.value)} onChange={(e) => setSearch(e.target.value)}
value={search} value={search}

View File

@@ -964,6 +964,7 @@
"save": "Save", "save": "Save",
"saveandnew": "Save and New", "saveandnew": "Save and New",
"selectall": "Select All", "selectall": "Select All",
"send": "Send",
"senderrortosupport": "Send Error to Support", "senderrortosupport": "Send Error to Support",
"submit": "Submit", "submit": "Submit",
"tryagain": "Try Again", "tryagain": "Try Again",
@@ -2032,6 +2033,8 @@
"labels": { "labels": {
"allpartsto": "All Parts Location", "allpartsto": "All Parts Location",
"confirmdelete": "Are you sure you want to delete this item? It cannot be recovered. Job line statuses will not be updated and may require manual review. ", "confirmdelete": "Are you sure you want to delete this item? It cannot be recovered. Job line statuses will not be updated and may require manual review. ",
"custompercent": "Custom %",
"discount": "Discount {{percent}}",
"email": "Send by Email", "email": "Send by Email",
"inthisorder": "Parts in this Order", "inthisorder": "Parts in this Order",
"is_quote": "Parts Quote?", "is_quote": "Parts Quote?",
@@ -2039,12 +2042,15 @@
"newpartsorder": "New Parts Order", "newpartsorder": "New Parts Order",
"notyetordered": "This part has not yet been ordered.", "notyetordered": "This part has not yet been ordered.",
"oec": "Order via OEC", "oec": "Order via OEC",
"order_type": "Order Type",
"orderhistory": "Order History", "orderhistory": "Order History",
"parts_order": "Parts Order",
"parts_orders": "Parts Orders", "parts_orders": "Parts Orders",
"print": "Show Printed Form", "print": "Show Printed Form",
"receive": "Receive Parts Order", "receive": "Receive Parts Order",
"removefrompartsqueue": "Remove from Parts Queue?", "removefrompartsqueue": "Remove from Parts Queue?",
"returnpartsorder": "Return Parts Order" "returnpartsorder": "Return Parts Order",
"sublet_order": "Sublet Order"
}, },
"successes": { "successes": {
"created": "Parts order created successfully. ", "created": "Parts order created successfully. ",
@@ -2085,6 +2091,7 @@
}, },
"successes": { "successes": {
"exported": "Payment(s) exported successfully.", "exported": "Payment(s) exported successfully.",
"markexported": "Payment(s) marked exported.",
"payment": "Payment created successfully. ", "payment": "Payment created successfully. ",
"stripe": "Credit card transaction charged successfully." "stripe": "Credit card transaction charged successfully."
} }
@@ -2213,6 +2220,7 @@
"sgi_certificate_of_repairs": "SGI - Certificate of Repairs", "sgi_certificate_of_repairs": "SGI - Certificate of Repairs",
"sgi_windshield_auth": "SGI - Windshield Authorization", "sgi_windshield_auth": "SGI - Windshield Authorization",
"stolen_recovery_checklist": "Stolen Recovery Checklist", "stolen_recovery_checklist": "Stolen Recovery Checklist",
"sublet_order": "Sublet Order",
"supplement_request": "Supplement Request", "supplement_request": "Supplement Request",
"thank_you_ro": "Thank You Letter", "thank_you_ro": "Thank You Letter",
"thirdpartypayer": "Third Party Payer", "thirdpartypayer": "Third Party Payer",
@@ -2251,7 +2259,8 @@
}, },
"subjects": { "subjects": {
"jobs": { "jobs": {
"parts_order": "Parts Order PO: {{ro_number}} - {{name}}" "parts_order": "Parts Order PO: {{ro_number}} - {{name}}",
"sublet_order": "Sublet Order PO: {{ro_number}} - {{name}}"
} }
}, },
"vendors": { "vendors": {

View File

@@ -964,6 +964,7 @@
"save": "Salvar", "save": "Salvar",
"saveandnew": "", "saveandnew": "",
"selectall": "", "selectall": "",
"send": "",
"senderrortosupport": "", "senderrortosupport": "",
"submit": "", "submit": "",
"tryagain": "", "tryagain": "",
@@ -2032,6 +2033,8 @@
"labels": { "labels": {
"allpartsto": "", "allpartsto": "",
"confirmdelete": "", "confirmdelete": "",
"custompercent": "",
"discount": "",
"email": "Enviar por correo electrónico", "email": "Enviar por correo electrónico",
"inthisorder": "Partes en este pedido", "inthisorder": "Partes en este pedido",
"is_quote": "", "is_quote": "",
@@ -2039,12 +2042,15 @@
"newpartsorder": "", "newpartsorder": "",
"notyetordered": "", "notyetordered": "",
"oec": "", "oec": "",
"order_type": "",
"orderhistory": "Historial de pedidos", "orderhistory": "Historial de pedidos",
"parts_order": "",
"parts_orders": "", "parts_orders": "",
"print": "Mostrar formulario impreso", "print": "Mostrar formulario impreso",
"receive": "", "receive": "",
"removefrompartsqueue": "", "removefrompartsqueue": "",
"returnpartsorder": "" "returnpartsorder": "",
"sublet_order": ""
}, },
"successes": { "successes": {
"created": "Pedido de piezas creado con éxito.", "created": "Pedido de piezas creado con éxito.",
@@ -2085,6 +2091,7 @@
}, },
"successes": { "successes": {
"exported": "", "exported": "",
"markexported": "",
"payment": "", "payment": "",
"stripe": "" "stripe": ""
} }
@@ -2213,6 +2220,7 @@
"sgi_certificate_of_repairs": "", "sgi_certificate_of_repairs": "",
"sgi_windshield_auth": "", "sgi_windshield_auth": "",
"stolen_recovery_checklist": "", "stolen_recovery_checklist": "",
"sublet_order": "",
"supplement_request": "", "supplement_request": "",
"thank_you_ro": "", "thank_you_ro": "",
"thirdpartypayer": "", "thirdpartypayer": "",
@@ -2251,7 +2259,8 @@
}, },
"subjects": { "subjects": {
"jobs": { "jobs": {
"parts_order": "" "parts_order": "",
"sublet_order": ""
} }
}, },
"vendors": { "vendors": {

View File

@@ -964,6 +964,7 @@
"save": "sauvegarder", "save": "sauvegarder",
"saveandnew": "", "saveandnew": "",
"selectall": "", "selectall": "",
"send": "",
"senderrortosupport": "", "senderrortosupport": "",
"submit": "", "submit": "",
"tryagain": "", "tryagain": "",
@@ -2032,6 +2033,8 @@
"labels": { "labels": {
"allpartsto": "", "allpartsto": "",
"confirmdelete": "", "confirmdelete": "",
"custompercent": "",
"discount": "",
"email": "Envoyé par email", "email": "Envoyé par email",
"inthisorder": "Pièces dans cette commande", "inthisorder": "Pièces dans cette commande",
"is_quote": "", "is_quote": "",
@@ -2039,12 +2042,15 @@
"newpartsorder": "", "newpartsorder": "",
"notyetordered": "", "notyetordered": "",
"oec": "", "oec": "",
"order_type": "",
"orderhistory": "Historique des commandes", "orderhistory": "Historique des commandes",
"parts_order": "",
"parts_orders": "", "parts_orders": "",
"print": "Afficher le formulaire imprimé", "print": "Afficher le formulaire imprimé",
"receive": "", "receive": "",
"removefrompartsqueue": "", "removefrompartsqueue": "",
"returnpartsorder": "" "returnpartsorder": "",
"sublet_order": ""
}, },
"successes": { "successes": {
"created": "Commande de pièces créée avec succès.", "created": "Commande de pièces créée avec succès.",
@@ -2085,6 +2091,7 @@
}, },
"successes": { "successes": {
"exported": "", "exported": "",
"markexported": "",
"payment": "", "payment": "",
"stripe": "" "stripe": ""
} }
@@ -2213,6 +2220,7 @@
"sgi_certificate_of_repairs": "", "sgi_certificate_of_repairs": "",
"sgi_windshield_auth": "", "sgi_windshield_auth": "",
"stolen_recovery_checklist": "", "stolen_recovery_checklist": "",
"sublet_order": "",
"supplement_request": "", "supplement_request": "",
"thank_you_ro": "", "thank_you_ro": "",
"thirdpartypayer": "", "thirdpartypayer": "",
@@ -2251,7 +2259,8 @@
}, },
"subjects": { "subjects": {
"jobs": { "jobs": {
"parts_order": "" "parts_order": "",
"sublet_order": ""
} }
}, },
"vendors": { "vendors": {

View File

@@ -551,6 +551,20 @@ export const TemplateList = (type, context) => {
}), }),
disabled: false, disabled: false,
}, },
sublet_order: {
title: i18n.t("printcenter.jobs.sublet_order"),
description: "Parts Order",
key: "sublet_order",
subject: i18n.t("printcenter.subjects.jobs.sublet_order", {
ro_number: context && context.job && context.job.ro_number,
name: (
(context && context.job && context.job.ownr_ln) ||
(context && context.job && context.job.ownr_co_nm) ||
""
).trim(),
}),
disabled: false,
},
parts_return_slip: { parts_return_slip: {
title: i18n.t("printcenter.jobs.parts_return_slip"), title: i18n.t("printcenter.jobs.parts_return_slip"),
subject: i18n.t("printcenter.jobs.parts_return_slip"), subject: i18n.t("printcenter.jobs.parts_return_slip"),