IO-710 Export Log page & insert actions on export

This commit is contained in:
Patrick Fic
2021-04-21 14:31:40 -07:00
parent 6d9576b9a4
commit 09e1ab7f83
38 changed files with 653 additions and 180 deletions

View File

@@ -1 +1 @@
client_max_body_size 50M; client_max_body_size 15M;

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
@@ -12354,6 +12354,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>created_at</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>
@@ -12627,6 +12648,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>message</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>monday</name> <name>monday</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -13073,6 +13115,27 @@
</concept_node> </concept_node>
</children> </children>
</folder_node> </folder_node>
<concept_node>
<name>successful</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>sunday</name> <name>sunday</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -23055,6 +23118,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>export-logs</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>home</name> <name>home</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -31520,6 +31604,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>export-logs</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>jobs</name> <name>jobs</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -32236,6 +32341,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>export-logs</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>jobs</name> <name>jobs</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>

View File

@@ -6,7 +6,7 @@ import { logImEXEvent } from "../../firebase/firebase.utils";
import CurrencyFormatter from "../../utils/CurrencyFormatter"; import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { alphaSort } from "../../utils/sorters"; import { alphaSort } from "../../utils/sorters";
import JobExportButton from "../jobs-close-export-button/jobs-close-export-button.component"; import JobExportButton from "../jobs-close-export-button/jobs-close-export-button.component";
import { JobsExportAllButton } from "../jobs-export-all-button/jobs-export-all-button.component"; import JobsExportAllButton from "../jobs-export-all-button/jobs-export-all-button.component";
export default function AccountingReceivablesTableComponent({ loading, jobs }) { export default function AccountingReceivablesTableComponent({ loading, jobs }) {
const { t } = useTranslation(); const { t } = useTranslation();

View File

@@ -7,15 +7,24 @@ import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { auth } from "../../firebase/firebase.utils"; import { auth } from "../../firebase/firebase.utils";
import { UPDATE_JOB } from "../../graphql/jobs.queries"; import { UPDATE_JOB } from "../../graphql/jobs.queries";
import { selectBodyshop } from "../../redux/user/user.selectors"; import {
selectBodyshop,
selectCurrentUser,
} from "../../redux/user/user.selectors";
import { logImEXEvent } from "../../firebase/firebase.utils"; import { logImEXEvent } from "../../firebase/firebase.utils";
import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries"; import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
currentUser: selectCurrentUser,
}); });
export function JobsCloseExportButton({ bodyshop, jobId, disabled }) { export function JobsCloseExportButton({
bodyshop,
currentUser,
jobId,
disabled,
}) {
const { t } = useTranslation(); const { t } = useTranslation();
const [updateJob] = useMutation(UPDATE_JOB); const [updateJob] = useMutation(UPDATE_JOB);
const [insertExportLog] = useMutation(INSERT_EXPORT_LOG); const [insertExportLog] = useMutation(INSERT_EXPORT_LOG);
@@ -77,35 +86,39 @@ export function JobsCloseExportButton({ bodyshop, jobId, disabled }) {
failedTransactions.forEach((ft) => { failedTransactions.forEach((ft) => {
//insert failed export log //insert failed export log
notification.open({ notification.open({
key: "failedexports", // key: "failedexports",
type: "error", type: "error",
message: t("jobs.errors.exporting", { message: t("jobs.errors.exporting", {
error: ft.errorMessage || "", error: ft.errorMessage || "",
}), }),
}); });
//Call is not awaited as it is not critical to finish before proceeding.
insertExportLog({
variables: {
logs: [
{
bodyshopid: bodyshop.id,
jobid: jobId,
success: false,
message: JSON.stringify(ft.errorMessage),
},
],
},
});
}); });
} else {
//Insert success export log. await insertExportLog({
insertExportLog({
variables: { variables: {
logs: [ logs: [
{ {
bodyshopid: bodyshop.id, bodyshopid: bodyshop.id,
jobid: jobId, jobid: jobId,
success: true, successful: false,
message: JSON.stringify(
failedTransactions.map((ft) => ft.errorMessage)
),
useremail: currentUser.email,
},
],
},
});
} else {
//Insert success export log.
await insertExportLog({
variables: {
logs: [
{
bodyshopid: bodyshop.id,
jobid: jobId,
successful: true,
useremail: currentUser.email,
}, },
], ],
}, },
@@ -123,7 +136,7 @@ export function JobsCloseExportButton({ bodyshop, jobId, disabled }) {
if (!jobUpdateResponse.errors) { if (!jobUpdateResponse.errors) {
notification.open({ notification.open({
type: "error", type: "success",
key: "jobsuccessexport", key: "jobsuccessexport",
message: t("jobs.successes.exported"), message: t("jobs.successes.exported"),
}); });

View File

@@ -7,15 +7,21 @@ import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { auth, logImEXEvent } from "../../firebase/firebase.utils"; import { auth, logImEXEvent } from "../../firebase/firebase.utils";
import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries";
import { UPDATE_JOBS } from "../../graphql/jobs.queries"; import { UPDATE_JOBS } from "../../graphql/jobs.queries";
import { selectBodyshop } from "../../redux/user/user.selectors"; import {
selectBodyshop,
selectCurrentUser,
} from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
currentUser: selectCurrentUser,
}); });
export function JobsExportAllButton({ export function JobsExportAllButton({
bodyshop, bodyshop,
currentUser,
jobIds, jobIds,
disabled, disabled,
loadingCallback, loadingCallback,
@@ -23,6 +29,8 @@ export function JobsExportAllButton({
}) { }) {
const { t } = useTranslation(); const { t } = useTranslation();
const [updateJob] = useMutation(UPDATE_JOBS); const [updateJob] = useMutation(UPDATE_JOBS);
const [insertExportLog] = useMutation(INSERT_EXPORT_LOG);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const handleQbxml = async () => { const handleQbxml = async () => {
logImEXEvent("jobs_export_all"); logImEXEvent("jobs_export_all");
@@ -73,35 +81,67 @@ export function JobsExportAllButton({
console.log("PartnerResponse", PartnerResponse); console.log("PartnerResponse", PartnerResponse);
const groupedData = _.groupBy(PartnerResponse.data, "id"); const groupedData = _.groupBy(PartnerResponse.data, "id");
const proms = [];
Object.keys(groupedData).forEach((key) => { await Promise.all(
proms.push(async () => { Object.keys(groupedData).map(async (key) => {
//Check to see if any of them failed. If they didn't don't execute the update. //Check to see if any of them failed. If they didn't don't execute the update.
const failedTransactions = groupedData[key].filter((r) => !r.success); const failedTransactions = groupedData[key].filter((r) => !r.success);
if (failedTransactions.length > 0) { if (failedTransactions.length > 0) {
//Uh oh. At least one was no good. //Uh oh. At least one was no good.
failedTransactions.map((ft) => failedTransactions.forEach((ft) => {
notification["error"]({ notification.open({
// key: "failedexports",
type: "error",
message: t("jobs.errors.exporting", { message: t("jobs.errors.exporting", {
error: ft.errorMessage || "", error: ft.errorMessage || "",
}), }),
}) });
); //Call is not awaited as it is not critical to finish before proceeding.
});
await insertExportLog({
variables: {
logs: [
{
bodyshopid: bodyshop.id,
jobid: key,
successful: false,
message: JSON.stringify(
failedTransactions.map((ft) => ft.errorMessage)
),
useremail: currentUser.email,
},
],
},
});
} else { } else {
await insertExportLog({
variables: {
logs: [
{
bodyshopid: bodyshop.id,
jobid: key,
successful: true,
useremail: currentUser.email,
},
],
},
});
const jobUpdateResponse = await updateJob({ const jobUpdateResponse = await updateJob({
variables: { variables: {
jobIds: [key], jobIds: [key],
job: { fields: {
status: bodyshop.md_ro_statuses.default_exported || "Exported*", status: bodyshop.md_ro_statuses.default_exported || "Exported*",
date_exported: new Date(), date_exported: new Date(),
}, },
}, },
}); });
if (!!!jobUpdateResponse.errors) { if (!jobUpdateResponse.errors) {
notification["success"]({ notification.open({
type: "success",
key: "jobsuccessexport",
message: t("jobs.successes.exported"), message: t("jobs.successes.exported"),
}); });
} else { } else {
@@ -112,9 +152,8 @@ export function JobsExportAllButton({
}); });
} }
} }
}); })
}); );
await Promise.all(proms);
if (!!completedCallback) completedCallback([]); if (!!completedCallback) completedCallback([]);
if (!!loadingCallback) loadingCallback(false); if (!!loadingCallback) loadingCallback(false);

View File

@@ -7,16 +7,22 @@ import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { auth } from "../../firebase/firebase.utils"; import { auth } from "../../firebase/firebase.utils";
import { UPDATE_BILLS } from "../../graphql/bills.queries"; import { UPDATE_BILLS } from "../../graphql/bills.queries";
import { selectBodyshop } from "../../redux/user/user.selectors"; import {
selectBodyshop,
selectCurrentUser,
} from "../../redux/user/user.selectors";
import { logImEXEvent } from "../../firebase/firebase.utils"; import { logImEXEvent } from "../../firebase/firebase.utils";
import _ from "lodash"; import _ from "lodash";
import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
currentUser: selectCurrentUser,
}); });
export function PayableExportAll({ export function PayableExportAll({
bodyshop, bodyshop,
currentUser,
billids, billids,
disabled, disabled,
loadingCallback, loadingCallback,
@@ -25,6 +31,7 @@ export function PayableExportAll({
const { t } = useTranslation(); const { t } = useTranslation();
const [updateBill] = useMutation(UPDATE_BILLS); const [updateBill] = useMutation(UPDATE_BILLS);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [insertExportLog] = useMutation(INSERT_EXPORT_LOG);
const handleQbxml = async () => { const handleQbxml = async () => {
logImEXEvent("accounting_payables_export_all"); logImEXEvent("accounting_payables_export_all");
@@ -89,7 +96,36 @@ export function PayableExportAll({
}), }),
}) })
); );
await insertExportLog({
variables: {
logs: [
{
bodyshopid: bodyshop.id,
billid: key,
successful: false,
message: JSON.stringify(
failedTransactions.map((ft) => ft.errorMessage)
),
useremail: currentUser.email,
},
],
},
});
} else { } else {
await insertExportLog({
variables: {
logs: [
{
bodyshopid: bodyshop.id,
billid: key,
successful: true,
useremail: currentUser.email,
},
],
},
});
const billUpdateResponse = await updateBill({ const billUpdateResponse = await updateBill({
variables: { variables: {
billIdList: [key], billIdList: [key],
@@ -100,7 +136,9 @@ export function PayableExportAll({
}, },
}); });
if (!!!billUpdateResponse.errors) { if (!!!billUpdateResponse.errors) {
notification["success"]({ notification.open({
type: "success",
key: "billsuccessexport",
message: t("bills.successes.exported"), message: t("bills.successes.exported"),
}); });
} else { } else {

View File

@@ -7,15 +7,21 @@ import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { auth } from "../../firebase/firebase.utils"; import { auth } from "../../firebase/firebase.utils";
import { UPDATE_BILLS } from "../../graphql/bills.queries"; import { UPDATE_BILLS } from "../../graphql/bills.queries";
import { selectBodyshop } from "../../redux/user/user.selectors"; import {
selectBodyshop,
selectCurrentUser,
} from "../../redux/user/user.selectors";
import { logImEXEvent } from "../../firebase/firebase.utils"; import { logImEXEvent } from "../../firebase/firebase.utils";
import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
currentUser: selectCurrentUser,
}); });
export function PayableExportButton({ export function PayableExportButton({
bodyshop, bodyshop,
currentUser,
billId, billId,
disabled, disabled,
loadingCallback, loadingCallback,
@@ -23,6 +29,7 @@ export function PayableExportButton({
const { t } = useTranslation(); const { t } = useTranslation();
const [updateBill] = useMutation(UPDATE_BILLS); const [updateBill] = useMutation(UPDATE_BILLS);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [insertExportLog] = useMutation(INSERT_EXPORT_LOG);
const handleQbxml = async () => { const handleQbxml = async () => {
logImEXEvent("accounting_export_payable"); logImEXEvent("accounting_export_payable");
@@ -84,8 +91,35 @@ export function PayableExportButton({
}), }),
}) })
); );
await insertExportLog({
variables: {
logs: [
{
bodyshopid: bodyshop.id,
billid: billId,
successful: false,
message: JSON.stringify(
failedTransactions.map((ft) => ft.errorMessage)
),
useremail: currentUser.email,
},
],
},
});
} }
if (successfulTransactions.length > 0) { if (successfulTransactions.length > 0) {
await insertExportLog({
variables: {
logs: [
{
bodyshopid: bodyshop.id,
billid: billId,
successful: true,
useremail: currentUser.email,
},
],
},
});
const billUpdateResponse = await updateBill({ const billUpdateResponse = await updateBill({
variables: { variables: {
billIdList: successfulTransactions.map((st) => st.id), billIdList: successfulTransactions.map((st) => st.id),
@@ -96,7 +130,9 @@ export function PayableExportButton({
}, },
}); });
if (!!!billUpdateResponse.errors) { if (!!!billUpdateResponse.errors) {
notification["success"]({ notification.open({
type: "success",
key: "billsuccessexport",
message: t("bills.successes.exported"), message: t("bills.successes.exported"),
}); });
} else { } else {

View File

@@ -6,15 +6,21 @@ import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { auth, logImEXEvent } from "../../firebase/firebase.utils"; import { auth, logImEXEvent } from "../../firebase/firebase.utils";
import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries";
import { UPDATE_PAYMENTS } from "../../graphql/payments.queries"; import { UPDATE_PAYMENTS } from "../../graphql/payments.queries";
import { selectBodyshop } from "../../redux/user/user.selectors"; import {
selectBodyshop,
selectCurrentUser,
} from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
currentUser: selectCurrentUser,
}); });
export function PaymentExportButton({ export function PaymentExportButton({
bodyshop, bodyshop,
currentUser,
paymentId, paymentId,
disabled, disabled,
loadingCallback, loadingCallback,
@@ -22,6 +28,7 @@ export function PaymentExportButton({
const { t } = useTranslation(); const { t } = useTranslation();
const [updatePayment] = useMutation(UPDATE_PAYMENTS); const [updatePayment] = useMutation(UPDATE_PAYMENTS);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [insertExportLog] = useMutation(INSERT_EXPORT_LOG);
const handleQbxml = async () => { const handleQbxml = async () => {
logImEXEvent("accounting_payment_export"); logImEXEvent("accounting_payment_export");
@@ -83,7 +90,36 @@ export function PaymentExportButton({
}), }),
}) })
); );
await insertExportLog({
variables: {
logs: [
{
bodyshopid: bodyshop.id,
paymentid: paymentId,
successful: false,
message: JSON.stringify(
failedTransactions.map((ft) => ft.errorMessage)
),
useremail: currentUser.email,
},
],
},
});
} else { } else {
await insertExportLog({
variables: {
logs: [
{
bodyshopid: bodyshop.id,
paymentid: paymentId,
successful: true,
useremail: currentUser.email,
},
],
},
});
const paymentUpdateResponse = await updatePayment({ const paymentUpdateResponse = await updatePayment({
variables: { variables: {
paymentIdList: [paymentId], paymentIdList: [paymentId],
@@ -93,7 +129,9 @@ export function PaymentExportButton({
}, },
}); });
if (!!!paymentUpdateResponse.errors) { if (!!!paymentUpdateResponse.errors) {
notification["success"]({ notification.open({
type: "success",
key: "paymentsuccessexport",
message: t("payments.successes.exported"), message: t("payments.successes.exported"),
}); });
} else { } else {

View File

@@ -7,14 +7,20 @@ import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { auth } from "../../firebase/firebase.utils"; import { auth } from "../../firebase/firebase.utils";
import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries";
import { UPDATE_PAYMENTS } from "../../graphql/payments.queries"; import { UPDATE_PAYMENTS } from "../../graphql/payments.queries";
import { selectBodyshop } from "../../redux/user/user.selectors"; import {
selectBodyshop,
selectCurrentUser,
} from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
currentUser: selectCurrentUser,
}); });
export function PaymentsExportAllButton({ export function PaymentsExportAllButton({
bodyshop, bodyshop,
currentUser,
paymentIds, paymentIds,
disabled, disabled,
loadingCallback, loadingCallback,
@@ -23,6 +29,7 @@ export function PaymentsExportAllButton({
const { t } = useTranslation(); const { t } = useTranslation();
const [updatePayments] = useMutation(UPDATE_PAYMENTS); const [updatePayments] = useMutation(UPDATE_PAYMENTS);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [insertExportLog] = useMutation(INSERT_EXPORT_LOG);
const handleQbxml = async () => { const handleQbxml = async () => {
setLoading(true); setLoading(true);
@@ -84,7 +91,34 @@ export function PaymentsExportAllButton({
}), }),
}) })
); );
await insertExportLog({
variables: {
logs: [
{
bodyshopid: bodyshop.id,
paymentid: key,
successful: false,
message: JSON.stringify(
failedTransactions.map((ft) => ft.errorMessage)
),
useremail: currentUser.email,
},
],
},
});
} else { } else {
await insertExportLog({
variables: {
logs: [
{
bodyshopid: bodyshop.id,
paymentid: key,
successful: true,
useremail: currentUser.email,
},
],
},
});
const paymentUpdateResponse = await updatePayments({ const paymentUpdateResponse = await updatePayments({
variables: { variables: {
paymentIdList: [key], paymentIdList: [key],
@@ -94,7 +128,9 @@ export function PaymentsExportAllButton({
}, },
}); });
if (!!!paymentUpdateResponse.errors) { if (!!!paymentUpdateResponse.errors) {
notification["success"]({ notification.open({
type: "success",
key: "paymentsuccessexport",
message: t("payments.successes.exported"), message: t("payments.successes.exported"),
}); });
} else { } else {

View File

@@ -86,11 +86,17 @@ export const INSERT_EXPORT_LOG = gql`
export const QUERY_EXPORT_LOG_PAGINATED = gql` export const QUERY_EXPORT_LOG_PAGINATED = gql`
query QUERY_ALL_EXPORTLOG_PAGINATED( query QUERY_ALL_EXPORTLOG_PAGINATED(
$search: String
$offset: Int $offset: Int
$limit: Int $limit: Int
$order: [exportlog_order_by!] $order: [exportlog_order_by!]
) { ) {
exportlog(offset: $offset, limit: $limit, order_by: $order) { search_exportlog(
offset: $offset
limit: $limit
order_by: $order
args: { search: $search }
) {
id id
job { job {
ro_number ro_number
@@ -107,8 +113,9 @@ export const QUERY_EXPORT_LOG_PAGINATED = gql`
successful successful
message message
created_at created_at
useremail
} }
exportlog_aggregate { search_exportlog_aggregate(args: { search: $search }) {
aggregate { aggregate {
count(distinct: true) count(distinct: true)
} }

View File

@@ -860,6 +860,8 @@ export const UPDATE_JOBS = gql`
update_jobs(where: { id: { _in: $jobIds } }, _set: $fields) { update_jobs(where: { id: { _in: $jobIds } }, _set: $fields) {
returning { returning {
id id
date_exported
status
} }
} }
} }

View File

@@ -1,6 +1,6 @@
import { SyncOutlined } from "@ant-design/icons"; import { SyncOutlined } from "@ant-design/icons";
import { useQuery } from "@apollo/client"; import { useQuery } from "@apollo/client";
import { Button, Card, Input, Space, Table, Typography } from "antd"; import { Button, Card, Checkbox, Input, Space, Table, Typography } from "antd";
import _ from "lodash"; import _ from "lodash";
import queryString from "query-string"; import queryString from "query-string";
import React from "react"; import React from "react";
@@ -9,18 +9,16 @@ import { connect } from "react-redux";
import { Link, useHistory, useLocation } from "react-router-dom"; import { Link, useHistory, useLocation } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import AlertComponent from "../../components/alert/alert.component"; import AlertComponent from "../../components/alert/alert.component";
import JobRemoveFromPartsQueue from "../../components/job-remove-from-parst-queue/job-remove-from-parts-queue.component";
import { QUERY_EXPORT_LOG_PAGINATED } from "../../graphql/accounting.queries"; import { QUERY_EXPORT_LOG_PAGINATED } from "../../graphql/accounting.queries";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter"; import { DateTimeFormatter } from "../../utils/DateFormatter";
import { TimeAgoFormatter } from "../../utils/DateFormatter";
import { alphaSort } from "../../utils/sorters"; import { alphaSort } from "../../utils/sorters";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
}); });
export function PartsQueuePageComponent({ bodyshop }) { export function ExportLogsPageComponent({ bodyshop }) {
const searchParams = queryString.parse(useLocation().search); const searchParams = queryString.parse(useLocation().search);
const { page, sortcolumn, sortorder, search } = searchParams; const { page, sortcolumn, sortorder, search } = searchParams;
const history = useHistory(); const history = useHistory();
@@ -29,10 +27,10 @@ export function PartsQueuePageComponent({ bodyshop }) {
QUERY_EXPORT_LOG_PAGINATED, QUERY_EXPORT_LOG_PAGINATED,
{ {
variables: { variables: {
//search: search || "", search: search || "",
offset: page ? (page - 1) * 25 : 0, offset: page ? (page - 1) * 25 : 0,
limit: 25, limit: 25,
order: sortcolumn && [ order: [
{ {
[sortcolumn || "created_at"]: sortorder [sortcolumn || "created_at"]: sortorder
? sortorder === "descend" ? sortorder === "descend"
@@ -64,6 +62,19 @@ export function PartsQueuePageComponent({ bodyshop }) {
}; };
const columns = [ const columns = [
{
title: t("general.labels.created_at"),
dataIndex: "created_at",
key: "created_at",
render: (text, record) => (
<DateTimeFormatter>{record.created_at}</DateTimeFormatter>
),
},
{
title: t("employees.fields.user_email"),
dataIndex: "useremail",
key: "useremail",
},
{ {
title: t("jobs.fields.ro_number"), title: t("jobs.fields.ro_number"),
dataIndex: "ro_number", dataIndex: "ro_number",
@@ -71,106 +82,62 @@ export function PartsQueuePageComponent({ bodyshop }) {
sorter: (a, b) => alphaSort(a.ro_number, b.ro_number), sorter: (a, b) => alphaSort(a.ro_number, b.ro_number),
sortOrder: sortcolumn === "ro_number" && sortorder, sortOrder: sortcolumn === "ro_number" && sortorder,
render: (text, record) => ( render: (text, record) =>
<Link to={"/manage/jobs/" + record.id}> record.job && (
{(record.job && record.job.ro_number) || t("general.labels.na")} <Link to={"/manage/jobs/" + record.job && record.job.id}>
</Link> {(record.job && record.job.ro_number) || t("general.labels.na")}
),
},
{
title: t("jobs.fields.owner"),
dataIndex: "owner",
key: "owner",
// sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln),
// sortOrder: sortcolumn === "owner" && sortorder,
render: (text, record) => {
return record.owner ? (
<Link to={"/manage/owners/" + record.owner.id}>
{`${record.ownr_fn || ""} ${record.ownr_ln || ""} ${
record.ownr_co_nm || ""
}`}
</Link> </Link>
) : ( ),
<span>{`${record.ownr_fn || ""} ${record.ownr_ln || ""} ${
record.ownr_co_nm || ""
}`}</span>
);
},
}, },
{ {
title: t("jobs.fields.vehicle"), title: t("bills.fields.invoice_number"),
dataIndex: "vehicle", dataIndex: "invoice_number",
key: "vehicle", key: "invoice_number",
ellipsis: true, render: (text, record) =>
render: (text, record) => { record.bill && (
return record.vehicleid ? ( <Link to={"/manage/bills?billid=" + (record.bill && record.bill.id)}>
<Link to={"/manage/vehicles/" + record.vehicleid}> {record.bill && record.bill.invoice_number}
{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
record.v_model_desc || ""
}`}
</Link> </Link>
) : ( ),
<span>{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
record.v_model_desc || ""
}`}</span>
);
},
}, },
{ {
title: t("vehicles.fields.plate_no"), title: t("payments.fields.paymentnum"),
dataIndex: "plate_no", dataIndex: "paymentnum",
key: "plate_no", key: "paymentnum",
sorter: (a, b) => alphaSort(a.plate_no, b.plate_no), render: (text, record) =>
sortOrder: sortcolumn === "plate_no" && sortorder, record.payment && (
render: (text, record) => { <Link
return record.plate_no ? record.plate_no : ""; to={
}, "/manage/payments?search=" +
(record.payment && record.payment.paymentnum)
}
>
{record.payment && record.payment.paymentnum}
</Link>
),
}, },
{ {
title: t("jobs.fields.clm_no"), title: t("general.labels.successful"),
dataIndex: "clm_no", dataIndex: "successful",
key: "clm_no", key: "successful",
ellipsis: true,
sorter: (a, b) => alphaSort(a.clm_no, b.clm_no),
sortOrder: sortcolumn === "clm_no" && sortorder,
render: (text, record) => {
return record.clm_no ? (
<span>{record.clm_no}</span>
) : (
t("general.labels.unknown")
);
},
},
{
title: t("jobs.fields.clm_total"),
dataIndex: "clm_total",
key: "clm_total",
sorter: (a, b) => a.clm_total - b.clm_total,
sortOrder: sortcolumn === "clm_total" && sortorder,
render: (text, record) => {
return record.clm_total ? (
<CurrencyFormatter>{record.clm_total}</CurrencyFormatter>
) : (
t("general.labels.unknown")
);
},
},
{
title: t("jobs.fields.updated_at"),
dataIndex: "updated_at",
key: "updated_at",
render: (text, record) => ( render: (text, record) => (
<TimeAgoFormatter>{record.updated_at}</TimeAgoFormatter> <Checkbox disabled checked={record.successful} />
), ),
}, },
{ {
title: t("general.labels.actions"), title: t("general.labels.message"),
dataIndex: "actions", dataIndex: "message",
key: "actions", key: "message",
render: (text, record) => ( render: (text, record) =>
<JobRemoveFromPartsQueue jobId={record.id} refetch={refetch} /> record.message && (
), <div>
<ul>
{JSON.parse(record.message).map((m, idx) => (
<li key={idx}>{m}</li>
))}
</ul>
</div>
),
}, },
]; ];
@@ -214,11 +181,11 @@ export function PartsQueuePageComponent({ bodyshop }) {
position: "top", position: "top",
pageSize: 25, pageSize: 25,
current: parseInt(page || 1), current: parseInt(page || 1),
total: data && data.exportlog_aggregate.aggregate.count, total: data && data.search_exportlog_aggregate.aggregate.count,
}} }}
columns={columns} columns={columns}
rowKey="id" rowKey="id"
dataSource={data && data.exportlog} dataSource={data && data.search_exportlog}
style={{ height: "100%" }} style={{ height: "100%" }}
scroll={{ x: true }} scroll={{ x: true }}
onChange={handleTableChange} onChange={handleTableChange}
@@ -227,4 +194,4 @@ export function PartsQueuePageComponent({ bodyshop }) {
); );
} }
export default connect(mapStateToProps, null)(PartsQueuePageComponent); export default connect(mapStateToProps, null)(ExportLogsPageComponent);

View File

@@ -35,7 +35,7 @@ export function AllJobs({ setBreadcrumbs, setSelectedHeader }) {
offset: page ? (page - 1) * 25 : 0, offset: page ? (page - 1) * 25 : 0,
limit: 25, limit: 25,
...(statusFilters ? { statusList: JSON.parse(statusFilters) } : {}), ...(statusFilters ? { statusList: JSON.parse(statusFilters) } : {}),
order: sortcolumn && [ order: [
{ {
[sortcolumn || "created_at"]: sortorder [sortcolumn || "created_at"]: sortorder
? sortorder === "descend" ? sortorder === "descend"

View File

@@ -33,7 +33,7 @@ export function PartsQueuePageComponent({ bodyshop }) {
limit: 25, limit: 25,
statuses: (statusFilters && JSON.parse(statusFilters)) || statuses: (statusFilters && JSON.parse(statusFilters)) ||
bodyshop.md_ro_statuses.active_statuses || ["Open", "Open*"], bodyshop.md_ro_statuses.active_statuses || ["Open", "Open*"],
order: sortcolumn && [ order: [
{ {
[sortcolumn || "updated_at"]: sortorder [sortcolumn || "updated_at"]: sortorder
? sortorder === "descend" ? sortorder === "descend"

View File

@@ -790,6 +790,7 @@
"cancel": "Are you sure you want to cancel? Your changes will not be saved.", "cancel": "Are you sure you want to cancel? Your changes will not be saved.",
"clear": "Clear", "clear": "Clear",
"confirmpassword": "Confirm Password", "confirmpassword": "Confirm Password",
"created_at": "Created At",
"email": "Email", "email": "Email",
"errors": "Errors", "errors": "Errors",
"exceptiontitle": "An error has occurred.", "exceptiontitle": "An error has occurred.",
@@ -803,6 +804,7 @@
"loadingapp": "Loading $t(titles.app)", "loadingapp": "Loading $t(titles.app)",
"loadingshop": "Loading shop data...", "loadingshop": "Loading shop data...",
"loggingin": "Authorizing...", "loggingin": "Authorizing...",
"message": "Message",
"monday": "Monday", "monday": "Monday",
"na": "N/A", "na": "N/A",
"no": "No", "no": "No",
@@ -826,6 +828,7 @@
"sub_status": { "sub_status": {
"expired": "The subscription for this shop has expired. Please contact technical support to reactivate the subscription. " "expired": "The subscription for this shop has expired. Please contact technical support to reactivate the subscription. "
}, },
"successful": "Successful",
"sunday": "Sunday", "sunday": "Sunday",
"text": "Text", "text": "Text",
"thursday": "Thursday", "thursday": "Thursday",
@@ -1363,6 +1366,7 @@
"enterpayment": "Enter Payments", "enterpayment": "Enter Payments",
"entertimeticket": "Enter Time Tickets", "entertimeticket": "Enter Time Tickets",
"export": "Export", "export": "Export",
"export-logs": "Export Logs",
"home": "Home", "home": "Home",
"jobs": "Jobs", "jobs": "Jobs",
"owners": "Owners", "owners": "Owners",
@@ -1900,6 +1904,7 @@
"courtesycars": "Courtesy Cars", "courtesycars": "Courtesy Cars",
"courtesycars-detail": "Courtesy Car {{number}}", "courtesycars-detail": "Courtesy Car {{number}}",
"courtesycars-new": "New Courtesy Car", "courtesycars-new": "New Courtesy Car",
"export-logs": "Export Logs",
"jobs": "Jobs", "jobs": "Jobs",
"jobs-active": "Active Jobs", "jobs-active": "Active Jobs",
"jobs-admin": "Admin", "jobs-admin": "Admin",
@@ -1935,6 +1940,7 @@
"courtesycars": "Courtesy Cars | $t(titles.app)", "courtesycars": "Courtesy Cars | $t(titles.app)",
"courtesycars-create": "New Courtesy Car | $t(titles.app)", "courtesycars-create": "New Courtesy Car | $t(titles.app)",
"courtesycars-detail": "Courtesy Car {{id}} | $t(titles.app)", "courtesycars-detail": "Courtesy Car {{id}} | $t(titles.app)",
"export-logs": "Export Logs | $t(titles.app)",
"jobs": "Active Jobs | $t(titles.app)", "jobs": "Active Jobs | $t(titles.app)",
"jobs-admin": "Job {{ro_number}} - Admin | $t(titles.app)", "jobs-admin": "Job {{ro_number}} - Admin | $t(titles.app)",
"jobs-all": "All Jobs | $t(titles.app)", "jobs-all": "All Jobs | $t(titles.app)",

View File

@@ -790,6 +790,7 @@
"cancel": "", "cancel": "",
"clear": "", "clear": "",
"confirmpassword": "", "confirmpassword": "",
"created_at": "",
"email": "", "email": "",
"errors": "", "errors": "",
"exceptiontitle": "", "exceptiontitle": "",
@@ -803,6 +804,7 @@
"loadingapp": "Cargando $t(titles.app)", "loadingapp": "Cargando $t(titles.app)",
"loadingshop": "Cargando datos de la tienda ...", "loadingshop": "Cargando datos de la tienda ...",
"loggingin": "Iniciando sesión ...", "loggingin": "Iniciando sesión ...",
"message": "",
"monday": "", "monday": "",
"na": "N / A", "na": "N / A",
"no": "", "no": "",
@@ -826,6 +828,7 @@
"sub_status": { "sub_status": {
"expired": "" "expired": ""
}, },
"successful": "",
"sunday": "", "sunday": "",
"text": "", "text": "",
"thursday": "", "thursday": "",
@@ -1363,6 +1366,7 @@
"enterpayment": "", "enterpayment": "",
"entertimeticket": "", "entertimeticket": "",
"export": "", "export": "",
"export-logs": "",
"home": "Casa", "home": "Casa",
"jobs": "Trabajos", "jobs": "Trabajos",
"owners": "propietarios", "owners": "propietarios",
@@ -1900,6 +1904,7 @@
"courtesycars": "", "courtesycars": "",
"courtesycars-detail": "", "courtesycars-detail": "",
"courtesycars-new": "", "courtesycars-new": "",
"export-logs": "",
"jobs": "", "jobs": "",
"jobs-active": "", "jobs-active": "",
"jobs-admin": "", "jobs-admin": "",
@@ -1935,6 +1940,7 @@
"courtesycars": "", "courtesycars": "",
"courtesycars-create": "", "courtesycars-create": "",
"courtesycars-detail": "", "courtesycars-detail": "",
"export-logs": "",
"jobs": "Todos los trabajos | $t(titles.app)", "jobs": "Todos los trabajos | $t(titles.app)",
"jobs-admin": "", "jobs-admin": "",
"jobs-all": "", "jobs-all": "",

View File

@@ -790,6 +790,7 @@
"cancel": "", "cancel": "",
"clear": "", "clear": "",
"confirmpassword": "", "confirmpassword": "",
"created_at": "",
"email": "", "email": "",
"errors": "", "errors": "",
"exceptiontitle": "", "exceptiontitle": "",
@@ -803,6 +804,7 @@
"loadingapp": "Chargement de $t(titles.app)", "loadingapp": "Chargement de $t(titles.app)",
"loadingshop": "Chargement des données de la boutique ...", "loadingshop": "Chargement des données de la boutique ...",
"loggingin": "Vous connecter ...", "loggingin": "Vous connecter ...",
"message": "",
"monday": "", "monday": "",
"na": "N / A", "na": "N / A",
"no": "", "no": "",
@@ -826,6 +828,7 @@
"sub_status": { "sub_status": {
"expired": "" "expired": ""
}, },
"successful": "",
"sunday": "", "sunday": "",
"text": "", "text": "",
"thursday": "", "thursday": "",
@@ -1363,6 +1366,7 @@
"enterpayment": "", "enterpayment": "",
"entertimeticket": "", "entertimeticket": "",
"export": "", "export": "",
"export-logs": "",
"home": "Accueil", "home": "Accueil",
"jobs": "Emplois", "jobs": "Emplois",
"owners": "Propriétaires", "owners": "Propriétaires",
@@ -1900,6 +1904,7 @@
"courtesycars": "", "courtesycars": "",
"courtesycars-detail": "", "courtesycars-detail": "",
"courtesycars-new": "", "courtesycars-new": "",
"export-logs": "",
"jobs": "", "jobs": "",
"jobs-active": "", "jobs-active": "",
"jobs-admin": "", "jobs-admin": "",
@@ -1935,6 +1940,7 @@
"courtesycars": "", "courtesycars": "",
"courtesycars-create": "", "courtesycars-create": "",
"courtesycars-detail": "", "courtesycars-detail": "",
"export-logs": "",
"jobs": "Tous les emplois | $t(titles.app)", "jobs": "Tous les emplois | $t(titles.app)",
"jobs-admin": "", "jobs-admin": "",
"jobs-all": "", "jobs-all": "",

View File

@@ -7,40 +7,29 @@ exports.processSignUp = functions.auth.user().onCreate((user) => {
// Check if user meets role criteria: // Check if user meets role criteria:
// Your custom logic here: to decide what roles and other `x-hasura-*` should the user get // Your custom logic here: to decide what roles and other `x-hasura-*` should the user get
let customClaims; let customClaims;
// if (user.email && user.email.indexOf("@thinkimex.com") !== -1) { if (user.email && user.email.indexOf("@admin.imex.online") !== -1) {
// customClaims = { customClaims = {
// "https://hasura.io/jwt/claims": { "https://hasura.io/jwt/claims": {
// "x-hasura-default-role": "admin", "x-hasura-default-role": "admin",
// "x-hasura-allowed-roles": ["user", "admin"], "x-hasura-allowed-roles": ["user", "admin"],
// "x-hasura-user-id": user.uid, "x-hasura-user-id": user.uid,
// }, },
// }; };
// } else { } else {
customClaims = { customClaims = {
"https://hasura.io/jwt/claims": { "https://hasura.io/jwt/claims": {
"x-hasura-default-role": "user", "x-hasura-default-role": "user",
"x-hasura-allowed-roles": ["user"], "x-hasura-allowed-roles": ["user"],
"x-hasura-user-id": user.uid, "x-hasura-user-id": user.uid,
}, },
}; };
//} }
//Removed for now - outbound connections are not free on firebase.
// fetch(GRAPHQL_ENDPOINT, {
// method: "POST",
// headers: {
// "Content-Type": "application/json",
// Accept: "application/json",
// "x-hasura-admin-secret": HASURA_SECRET_ADMIN_KEY
// },
// body: JSON.stringify({
// query: UPSERT_USER,
// variables: { authEmail: user.email, authToken: user.uid }
// })
// });
// Set custom user claims on this newly created user. // Set custom user claims on this newly created user.
return admin.auth().setCustomUserClaims(user.uid, customClaims); return admin.auth().setCustomUserClaims(user.uid, customClaims);
//exports.test = functions.auth.
// .then(() => { // .then(() => {
// // Update real-time database to notify client to force refresh. // // Update real-time database to notify client to force refresh.
// const metadataRef = admin.database().ref("metadata/" + user.uid); // const metadataRef = admin.database().ref("metadata/" + user.uid);

View File

@@ -0,0 +1,5 @@
- args:
cascade: false
read_only: false
sql: ALTER TABLE "public"."exportlog" ALTER COLUMN "message" SET NOT NULL;
type: run_sql

View File

@@ -0,0 +1,5 @@
- args:
cascade: false
read_only: false
sql: ALTER TABLE "public"."exportlog" ALTER COLUMN "message" DROP NOT NULL;
type: run_sql

View File

@@ -0,0 +1 @@
[]

View File

@@ -0,0 +1,17 @@
- args:
cascade: false
read_only: false
sql: "CREATE\r\nOR REPLACE FUNCTION public.search_exportlog(search text) RETURNS
SETOF exportlog LANGUAGE plpgsql STABLE AS $function$ BEGIN IF search = '' THEN
RETURN query\r\nSELECT\r\n *\r\nFROM\r\n exportlog e;\r\n ELSE RETURN query\r\nSELECT\r\n
\ exportlog.*\r\nFROM\r\n exportlog e,\r\n jobs j,\r\n payments p,\r\n bills
b,\r\n users u\r\nWHERE\r\n (\r\n j.ro_number ILIKE '%' || search || '%'\r\n
\ OR b.invoice_number ILIKE '%' || search || '%'\r\n OR p.paymentnum ILIKE
'%' || search || '%'\r\n OR u.email ILIKE '%' || search || '%'\r\n\r\n )\r\n
\ AND (e.jobid = j.id\r\n or e.paymentid = p.id\r\n or e.billid = b.id\r\nor
e.useremail = u.email)\r\n;\r\nEND IF;\r\nEND $function$;"
type: run_sql
- args:
name: search_exportlog
schema: public
type: track_function

View File

@@ -0,0 +1 @@
[]

View File

@@ -0,0 +1,18 @@
- args:
cascade: false
read_only: false
sql: "drop function public.search_exportlog;\r\n\r\nCREATE\r\nOR REPLACE FUNCTION
public.search_exportlog(search text) RETURNS SETOF exportlog LANGUAGE plpgsql
STABLE AS $function$ BEGIN IF search = '' THEN RETURN query\r\nSELECT\r\n *\r\nFROM\r\n
\ exportlog e;\r\n ELSE RETURN query\r\nSELECT\r\n exportlog.*\r\nFROM\r\n
\ exportlog e,\r\n jobs j,\r\n payments p,\r\n bills b,\r\n users u\r\nWHERE\r\n
\ (\r\n j.ro_number ILIKE '%' || search || '%'\r\n OR b.invoice_number
ILIKE '%' || search || '%'\r\n OR p.paymentnum ILIKE '%' || search || '%'\r\n
\ OR u.email ILIKE '%' || search || '%'\r\n\r\n )\r\n AND (e.jobid = j.id\r\n
\ or e.paymentid = p.id\r\n or e.billid = b.id\r\nor u.useremail = u.email)\r\n;\r\nEND
IF;\r\nEND $function$;"
type: run_sql
- args:
name: search_exportlog
schema: public
type: track_function

View File

@@ -0,0 +1 @@
[]

View File

@@ -0,0 +1,18 @@
- args:
cascade: false
read_only: false
sql: "drop function public.search_exportlog;\r\n\r\nCREATE\r\nOR REPLACE FUNCTION
public.search_exportlog(search text) RETURNS SETOF exportlog LANGUAGE plpgsql
STABLE AS $function$ BEGIN IF search = '' THEN RETURN query\r\nSELECT\r\n *\r\nFROM\r\n
\ exportlog e;\r\n ELSE RETURN query\r\nSELECT\r\n e.*\r\nFROM\r\n exportlog
e,\r\n jobs j,\r\n payments p,\r\n bills b,\r\n users u\r\nWHERE\r\n (\r\n
\ j.ro_number ILIKE '%' || search || '%'\r\n OR b.invoice_number ILIKE
'%' || search || '%'\r\n OR p.paymentnum ILIKE '%' || search || '%'\r\n OR
u.email ILIKE '%' || search || '%'\r\n\r\n )\r\n AND (e.jobid = j.id\r\n or
e.paymentid = p.id\r\n or e.billid = b.id\r\nor u.useremail = u.email)\r\n;\r\nEND
IF;\r\nEND $function$;"
type: run_sql
- args:
name: search_exportlog
schema: public
type: track_function

View File

@@ -0,0 +1 @@
[]

View File

@@ -0,0 +1,17 @@
- args:
cascade: false
read_only: false
sql: "drop function public.search_exportlog;\r\n\r\nCREATE\r\nOR REPLACE FUNCTION
public.search_exportlog(search text) RETURNS SETOF exportlog LANGUAGE plpgsql
STABLE AS $function$ BEGIN IF search = '' THEN RETURN query\r\nSELECT\r\n *\r\nFROM\r\n
\ exportlog e;\r\n ELSE RETURN query\r\nSELECT\r\n e.*\r\nFROM\r\n exportlog
e,\r\n jobs j,\r\n payments p,\r\n bills b\r\nWHERE\r\n (\r\n j.ro_number
ILIKE '%' || search || '%'\r\n OR b.invoice_number ILIKE '%' || search ||
'%'\r\n OR p.paymentnum ILIKE '%' || search || '%'\r\n OR e.useremail
ILIKE '%' || search || '%'\r\n\r\n )\r\n AND (e.jobid = j.id\r\n or e.paymentid
= p.id\r\n or e.billid = b.id)\r\n;\r\nEND IF;\r\nEND $function$;"
type: run_sql
- args:
name: search_exportlog
schema: public
type: track_function

View File

@@ -0,0 +1 @@
[]

View File

@@ -0,0 +1,17 @@
- args:
cascade: false
read_only: false
sql: "drop function public.search_exportlog;\r\n\r\nCREATE\r\nOR REPLACE FUNCTION
public.search_exportlog(search text) RETURNS SETOF exportlog LANGUAGE plpgsql
STABLE AS $function$ BEGIN IF search = '' THEN RETURN query\r\nSELECT\r\n *\r\nFROM\r\n
\ exportlog e;\r\n ELSE RETURN query\r\nSELECT\r\n e.*\r\nFROM\r\n exportlog
e,\r\n jobs j,\r\n payments p,\r\n bills b\r\nWHERE\r\n(e.jobid = j.id and
\ j.ro_number ILIKE '%' || search || '%') OR\r\n(e.paymentid = p.id and p.paymentnum
ILIKE '%' || search || '%') OR\r\n(e.billid = b.id and b.invoice_number ILIKE
'%' || search || '%') OR\r\n e.useremail ILIKE '%' || search || '%'\r\n\r\n
\r\n \r\n;\r\nEND IF;\r\nEND $function$;"
type: run_sql
- args:
name: search_exportlog
schema: public
type: track_function

View File

@@ -0,0 +1 @@
[]

View File

@@ -0,0 +1,18 @@
- args:
cascade: false
read_only: false
sql: "drop function public.search_exportlog;\r\n\r\nCREATE\r\nOR REPLACE FUNCTION
public.search_exportlog(search text) RETURNS SETOF exportlog LANGUAGE plpgsql
STABLE AS $function$ BEGIN IF search = '' THEN RETURN query\r\nSELECT\r\n *\r\nFROM\r\n
\ exportlog e;\r\n ELSE RETURN query\r\nSELECT\r\n e.*\r\nFROM\r\n exportlog
e\r\nINNER JOIN payments p \r\n ON p.id = e.paymentid\r\nINNER JOIN bills
b\r\n ON e.billid = b.id\r\n \r\nWHERE\r\n\r\n\r\n\r\n (\r\n j.ro_number
ILIKE '%' || search || '%'\r\n OR b.invoice_number ILIKE '%' || search ||
'%'\r\n OR p.paymentnum ILIKE '%' || search || '%'\r\n OR e.useremail
ILIKE '%' || search || '%'\r\n\r\n )\r\n AND (e.jobid = j.id\r\n or e.paymentid
= p.id\r\n \r\n or e.billid = b.id)\r\n \r\n \r\n;\r\nEND IF;\r\nEND $function$;"
type: run_sql
- args:
name: search_exportlog
schema: public
type: track_function

View File

@@ -0,0 +1 @@
[]

View File

@@ -0,0 +1,19 @@
- args:
cascade: false
read_only: false
sql: "drop function public.search_exportlog;\r\n\r\nCREATE\r\nOR REPLACE FUNCTION
public.search_exportlog(search text) RETURNS SETOF exportlog LANGUAGE plpgsql
STABLE AS $function$ BEGIN IF search = '' THEN RETURN query\r\nSELECT\r\n *\r\nFROM\r\n
\ exportlog e;\r\n ELSE RETURN query\r\nSELECT\r\n e.*\r\nFROM\r\n exportlog
e\r\n INNER JOIN jobs j on j.id = e.jobid\r\nINNER JOIN payments p \r\n ON
p.id = e.paymentid\r\nINNER JOIN bills b\r\n ON e.billid = b.id\r\n \r\nWHERE\r\n\r\n\r\n\r\n
\ (\r\n j.ro_number ILIKE '%' || search || '%'\r\n OR b.invoice_number
ILIKE '%' || search || '%'\r\n OR p.paymentnum ILIKE '%' || search || '%'\r\n
\ OR e.useremail ILIKE '%' || search || '%'\r\n\r\n )\r\n AND (e.jobid =
j.id\r\n or e.paymentid = p.id\r\n \r\n or e.billid = b.id)\r\n \r\n \r\n;\r\nEND
IF;\r\nEND $function$;"
type: run_sql
- args:
name: search_exportlog
schema: public
type: track_function

View File

@@ -0,0 +1 @@
[]

View File

@@ -0,0 +1,19 @@
- args:
cascade: false
read_only: false
sql: "drop function public.search_exportlog;\r\n\r\nCREATE\r\nOR REPLACE FUNCTION
public.search_exportlog(search text) RETURNS SETOF exportlog LANGUAGE plpgsql
STABLE AS $function$ BEGIN IF search = '' THEN RETURN query\r\nSELECT\r\n *\r\nFROM\r\n
\ exportlog e;\r\n ELSE RETURN query\r\nSELECT\r\n e.*\r\nFROM\r\n exportlog
e\r\n LEFT JOIN jobs j on j.id = e.jobid\r\nLEFT JOIN payments p \r\n ON
p.id = e.paymentid\r\nLEFT JOIN bills b\r\n ON e.billid = b.id\r\n \r\nWHERE\r\n\r\n\r\n\r\n
\ (\r\n j.ro_number ILIKE '%' || search || '%'\r\n OR b.invoice_number
ILIKE '%' || search || '%'\r\n OR p.paymentnum ILIKE '%' || search || '%'\r\n
\ OR e.useremail ILIKE '%' || search || '%'\r\n\r\n )\r\n AND (e.jobid =
j.id\r\n or e.paymentid = p.id\r\n \r\n or e.billid = b.id)\r\n \r\n \r\n;\r\nEND
IF;\r\nEND $function$;"
type: run_sql
- args:
name: search_exportlog
schema: public
type: track_function

View File

@@ -4334,6 +4334,9 @@ functions:
- function: - function:
schema: public schema: public
name: search_cccontracts name: search_cccontracts
- function:
schema: public
name: search_exportlog
- function: - function:
schema: public schema: public
name: search_jobs name: search_jobs

View File

@@ -201,7 +201,7 @@ const generateInvoiceQbxml = (
if (!account) { if (!account) {
throw new Error( throw new Error(
`A matching account does not exist for the allocation. Center: ${center}` `A matching account does not exist for the allocation. Center: ${jobline.profitcenter_part}`
); );
} }