IO-134 Prevent doc reassignment with limit

This commit is contained in:
Patrick Fic
2021-04-06 09:26:31 -07:00
parent 50581c98e0
commit 9af6311d52
12 changed files with 173 additions and 22 deletions

View File

@@ -10211,6 +10211,48 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>reassign_limitexceeded</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>reassign_limitexceeded_title</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>storageexceeded</name> <name>storageexceeded</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -28533,6 +28575,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>supplement_ratio_source</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>timetickets</name> <name>timetickets</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>

View File

@@ -24,6 +24,7 @@ export function DocumentsUploadComponent({
billId, billId,
callbackAfterUpload, callbackAfterUpload,
totalSize, totalSize,
ignoreSizeLimit = false,
}) { }) {
const { t } = useTranslation(); const { t } = useTranslation();
@@ -33,7 +34,7 @@ export function DocumentsUploadComponent({
); );
}, [bodyshop, totalSize]); }, [bodyshop, totalSize]);
if (pct > 100) if (pct > 100 && !ignoreSizeLimit)
return ( return (
<Result <Result
status="error" status="error"
@@ -46,6 +47,7 @@ export function DocumentsUploadComponent({
<Upload.Dragger <Upload.Dragger
multiple={true} multiple={true}
beforeUpload={(file, fileList) => { beforeUpload={(file, fileList) => {
if (ignoreSizeLimit) return true;
const newFiles = fileList.reduce((acc, val) => acc + val.size, 0); const newFiles = fileList.reduce((acc, val) => acc + val.size, 0);
const shouldStopUpload = const shouldStopUpload =
(totalSize + newFiles) / ((bodyshop && bodyshop.jobsizelimit) || 1) >= (totalSize + newFiles) / ((bodyshop && bodyshop.jobsizelimit) || 1) >=
@@ -84,16 +86,18 @@ export function DocumentsUploadComponent({
<p className="ant-upload-text"> <p className="ant-upload-text">
Click or drag files to this area to upload. Click or drag files to this area to upload.
</p> </p>
<Space wrap className="ant-upload-text"> {!ignoreSizeLimit && (
<Progress type="dashboard" percent={pct} size="small" /> <Space wrap className="ant-upload-text">
<span> <Progress type="dashboard" percent={pct} size="small" />
{t("documents.labels.usage", { <span>
percent: pct, {t("documents.labels.usage", {
used: formatBytes(totalSize), percent: pct,
total: formatBytes(bodyshop && bodyshop.jobsizelimit), used: formatBytes(totalSize),
})} total: formatBytes(bodyshop && bodyshop.jobsizelimit),
</span> })}
</Space> </span>
</Space>
)}
</> </>
)} )}
</Upload.Dragger> </Upload.Dragger>

View File

@@ -1,12 +1,29 @@
import { Button, Form, Popover, notification, Space } from "antd"; import { useApolloClient, useMutation } from "@apollo/client";
import React, { useState, useMemo } from "react"; import { Button, Form, notification, Popover, Space } from "antd";
import { useTranslation } from "react-i18next";
import JobSearchSelect from "../job-search-select/job-search-select.component";
import { useMutation } from "@apollo/client";
import { UPDATE_DOCUMENT } from "../../graphql/documents.queries";
import axios from "axios"; import axios from "axios";
import React, { useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import {
GET_DOC_SIZE_BY_JOB,
UPDATE_DOCUMENT,
} from "../../graphql/documents.queries";
import { selectBodyshop } from "../../redux/user/user.selectors";
import JobSearchSelect from "../job-search-select/job-search-select.component";
export default function JobsDocumentsGalleryReassign({ galleryImages }) { const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(JobsDocumentsGalleryReassign);
export function JobsDocumentsGalleryReassign({ bodyshop, galleryImages }) {
const { t } = useTranslation(); const { t } = useTranslation();
const [form] = Form.useForm(); const [form] = Form.useForm();
@@ -16,7 +33,7 @@ export default function JobsDocumentsGalleryReassign({ galleryImages }) {
...galleryImages.other.filter((image) => image.isSelected), ...galleryImages.other.filter((image) => image.isSelected),
]; ];
}, [galleryImages]); }, [galleryImages]);
const client = useApolloClient();
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [updateDocument] = useMutation(UPDATE_DOCUMENT); const [updateDocument] = useMutation(UPDATE_DOCUMENT);
@@ -48,10 +65,37 @@ export default function JobsDocumentsGalleryReassign({ galleryImages }) {
}); });
} }
}; };
console.log("selectedImages :>> ", selectedImages);
const handleFinish = async ({ jobid }) => { const handleFinish = async ({ jobid }) => {
setLoading(true); setLoading(true);
//Check to see if the space remaining on the new job is sufficient. If it isn't cancel this.
const newJobData = await client.query({
query: GET_DOC_SIZE_BY_JOB,
variables: { jobId: jobid },
});
const transferedDocSizeTotal = selectedImages.reduce(
(acc, val) => acc + val.size,
0
);
const shouldPreventTransfer =
bodyshop.jobsizelimit -
newJobData.data.documents_aggregate.aggregate.sum.size <
transferedDocSizeTotal;
if (shouldPreventTransfer) {
notification.open({
key: "cannotuploaddocuments",
type: "error",
message: t("documents.labels.reassign_limitexceeded_title"),
description: t("documents.labels.reassign_limitexceeded"),
});
setLoading(false);
return;
}
const res = await axios.post("/media/rename", { const res = await axios.post("/media/rename", {
documents: selectedImages.map((i) => { documents: selectedImages.map((i) => {
//Need to check if the current key folder is null, or another job. //Need to check if the current key folder is null, or another job.

View File

@@ -18,6 +18,7 @@ function JobsDocumentsComponent({
billsCallback, billsCallback,
totalSize, totalSize,
bodyshop, bodyshop,
ignoreSizeLimit,
}) { }) {
const [galleryImages, setgalleryImages] = useState({ images: [], other: [] }); const [galleryImages, setgalleryImages] = useState({ images: [], other: [] });
const { t } = useTranslation(); const { t } = useTranslation();
@@ -43,6 +44,7 @@ function JobsDocumentsComponent({
extension: value.extension, extension: value.extension,
id: value.id, id: value.id,
type: value.type, type: value.type,
size: value.size,
tags: [{ value: value.type, title: value.type }], tags: [{ value: value.type, title: value.type }],
}); });
} else { } else {
@@ -95,6 +97,7 @@ function JobsDocumentsComponent({
key: value.key, key: value.key,
id: value.id, id: value.id,
type: value.type, type: value.type,
size: value.size,
}); });
} }
@@ -131,6 +134,7 @@ function JobsDocumentsComponent({
totalSize={totalSize} totalSize={totalSize}
billId={billId} billId={billId}
callbackAfterUpload={billsCallback || refetch} callbackAfterUpload={billsCallback || refetch}
ignoreSizeLimit={ignoreSizeLimit}
/> />
</Card> </Card>
</Col> </Col>

View File

@@ -167,6 +167,7 @@ export const QUERY_BILL_BY_PK = gql`
key key
name name
type type
size
} }
} }
} }

View File

@@ -14,6 +14,7 @@ export const GET_DOCUMENTS_BY_JOB = gql`
name name
key key
type type
size
bill { bill {
id id
invoice_number invoice_number
@@ -27,6 +28,18 @@ export const GET_DOCUMENTS_BY_JOB = gql`
} }
`; `;
export const GET_DOC_SIZE_BY_JOB = gql`
query GET_DOC_SIZE_BY_JOB($jobId: uuid!) {
documents_aggregate(where: { jobid: { _eq: $jobId } }) {
aggregate {
sum {
size
}
}
}
}
`;
export const INSERT_NEW_DOCUMENT = gql` export const INSERT_NEW_DOCUMENT = gql`
mutation INSERT_NEW_DOCUMENT($docInput: [documents_insert_input!]!) { mutation INSERT_NEW_DOCUMENT($docInput: [documents_insert_input!]!) {
insert_documents(objects: $docInput) { insert_documents(objects: $docInput) {
@@ -34,6 +47,7 @@ export const INSERT_NEW_DOCUMENT = gql`
id id
name name
key key
size
} }
} }
} }
@@ -60,6 +74,7 @@ export const QUERY_TEMPORARY_DOCS = gql`
key key
type type
extension extension
size
} }
} }
`; `;
@@ -75,6 +90,7 @@ export const UPDATE_DOCUMENT = gql`
name name
type type
key key
size
} }
} }
`; `;

View File

@@ -811,6 +811,7 @@ export const QUERY_TECH_JOB_DETAILS = gql`
documents(order_by: { created_at: desc }) { documents(order_by: { created_at: desc }) {
id id
key key
size
} }
} }
} }

View File

@@ -17,6 +17,7 @@ export default function TemporaryDocsComponent() {
jobId={null} jobId={null}
billId={null} billId={null}
refetch={refetch} refetch={refetch}
ignoreSizeLimit
/> />
); );
} }

View File

@@ -658,11 +658,13 @@
"confirmdelete": "Are you sure you want to delete these documents. This CANNOT be undone.", "confirmdelete": "Are you sure you want to delete these documents. This CANNOT be undone.",
"doctype": "Document Type", "doctype": "Document Type",
"newjobid": "Assign to Job", "newjobid": "Assign to Job",
"reassign_limitexceeded": "Reassigning all selected documents will exceed the job storage limit for your shop. ",
"reassign_limitexceeded_title": "Unable to reassign document(s)",
"storageexceeded": "You've exceeded your storage limit for this job. Please remove documents, or increase your storage plan.", "storageexceeded": "You've exceeded your storage limit for this job. Please remove documents, or increase your storage plan.",
"storageexceeded_title": "Storage Limit Exceeded", "storageexceeded_title": "Storage Limit Exceeded",
"upload": "Upload", "upload": "Upload",
"upload_limitexceeded": "Uploading all selected files will exceed the job storage limit for your shop. ", "upload_limitexceeded": "Uploading all selected documents will exceed the job storage limit for your shop. ",
"upload_limitexceeded_title": "Unable to upload file(s)", "upload_limitexceeded_title": "Unable to upload document(s)",
"usage": "of job storage used. ({{used}} / {{total}})" "usage": "of job storage used. ({{used}} / {{total}})"
}, },
"successes": { "successes": {
@@ -1719,6 +1721,7 @@
"purchases_by_vendor_detailed_date_range": "Purchases By Vendor - Detailed", "purchases_by_vendor_detailed_date_range": "Purchases By Vendor - Detailed",
"purchases_by_vendor_summary_date_range": "Purchases by Vendor - Summary", "purchases_by_vendor_summary_date_range": "Purchases by Vendor - Summary",
"schedule": "Appointment Schedule", "schedule": "Appointment Schedule",
"supplement_ratio_source": "Supplement Ratio by Source",
"timetickets": "Time Tickets", "timetickets": "Time Tickets",
"timetickets_employee": "Employee Time Tickets", "timetickets_employee": "Employee Time Tickets",
"timetickets_summary": "Time Tickets Summary" "timetickets_summary": "Time Tickets Summary"

View File

@@ -658,6 +658,8 @@
"confirmdelete": "", "confirmdelete": "",
"doctype": "", "doctype": "",
"newjobid": "", "newjobid": "",
"reassign_limitexceeded": "",
"reassign_limitexceeded_title": "",
"storageexceeded": "", "storageexceeded": "",
"storageexceeded_title": "", "storageexceeded_title": "",
"upload": "Subir", "upload": "Subir",
@@ -1719,6 +1721,7 @@
"purchases_by_vendor_detailed_date_range": "", "purchases_by_vendor_detailed_date_range": "",
"purchases_by_vendor_summary_date_range": "", "purchases_by_vendor_summary_date_range": "",
"schedule": "", "schedule": "",
"supplement_ratio_source": "",
"timetickets": "", "timetickets": "",
"timetickets_employee": "", "timetickets_employee": "",
"timetickets_summary": "" "timetickets_summary": ""

View File

@@ -658,6 +658,8 @@
"confirmdelete": "", "confirmdelete": "",
"doctype": "", "doctype": "",
"newjobid": "", "newjobid": "",
"reassign_limitexceeded": "",
"reassign_limitexceeded_title": "",
"storageexceeded": "", "storageexceeded": "",
"storageexceeded_title": "", "storageexceeded_title": "",
"upload": "Télécharger", "upload": "Télécharger",
@@ -1719,6 +1721,7 @@
"purchases_by_vendor_detailed_date_range": "", "purchases_by_vendor_detailed_date_range": "",
"purchases_by_vendor_summary_date_range": "", "purchases_by_vendor_summary_date_range": "",
"schedule": "", "schedule": "",
"supplement_ratio_source": "",
"timetickets": "", "timetickets": "",
"timetickets_employee": "", "timetickets_employee": "",
"timetickets_summary": "" "timetickets_summary": ""

View File

@@ -511,6 +511,14 @@ export const TemplateList = (type, context) => {
//idtype: "vendor", //idtype: "vendor",
disabled: false, disabled: false,
}, },
supplement_ratio_source: {
title: i18n.t("reportcenter.templates.supplement_ratio_source"),
description: "",
subject: i18n.t("reportcenter.templates.supplement_ratio_source"),
key: "supplement_ratio_source",
//idtype: "vendor",
disabled: false,
},
} }
: {}), : {}),
...(!type || type === "courtesycarcontract" ...(!type || type === "courtesycarcontract"