diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index 8e654c027..10c74fa83 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -10211,6 +10211,48 @@ + + reassign_limitexceeded + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + reassign_limitexceeded_title + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + storageexceeded false @@ -28533,6 +28575,27 @@ + + supplement_ratio_source + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + timetickets false diff --git a/client/src/components/documents-upload/documents-upload.component.jsx b/client/src/components/documents-upload/documents-upload.component.jsx index 9c6ea830b..1fc105127 100644 --- a/client/src/components/documents-upload/documents-upload.component.jsx +++ b/client/src/components/documents-upload/documents-upload.component.jsx @@ -24,6 +24,7 @@ export function DocumentsUploadComponent({ billId, callbackAfterUpload, totalSize, + ignoreSizeLimit = false, }) { const { t } = useTranslation(); @@ -33,7 +34,7 @@ export function DocumentsUploadComponent({ ); }, [bodyshop, totalSize]); - if (pct > 100) + if (pct > 100 && !ignoreSizeLimit) return ( { + if (ignoreSizeLimit) return true; const newFiles = fileList.reduce((acc, val) => acc + val.size, 0); const shouldStopUpload = (totalSize + newFiles) / ((bodyshop && bodyshop.jobsizelimit) || 1) >= @@ -84,16 +86,18 @@ export function DocumentsUploadComponent({ Click or drag files to this area to upload. - - - - {t("documents.labels.usage", { - percent: pct, - used: formatBytes(totalSize), - total: formatBytes(bodyshop && bodyshop.jobsizelimit), - })} - - + {!ignoreSizeLimit && ( + + + + {t("documents.labels.usage", { + percent: pct, + used: formatBytes(totalSize), + total: formatBytes(bodyshop && bodyshop.jobsizelimit), + })} + + + )} > )} diff --git a/client/src/components/jobs-documents-gallery/jobs-document-gallery.reassign.component.jsx b/client/src/components/jobs-documents-gallery/jobs-document-gallery.reassign.component.jsx index 58c847cdf..d56c733c9 100644 --- a/client/src/components/jobs-documents-gallery/jobs-document-gallery.reassign.component.jsx +++ b/client/src/components/jobs-documents-gallery/jobs-document-gallery.reassign.component.jsx @@ -1,12 +1,29 @@ -import { Button, Form, Popover, notification, Space } from "antd"; -import React, { useState, useMemo } from "react"; -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 { useApolloClient, useMutation } from "@apollo/client"; +import { Button, Form, notification, Popover, Space } from "antd"; 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 [form] = Form.useForm(); @@ -16,7 +33,7 @@ export default function JobsDocumentsGalleryReassign({ galleryImages }) { ...galleryImages.other.filter((image) => image.isSelected), ]; }, [galleryImages]); - + const client = useApolloClient(); const [visible, setVisible] = useState(false); const [loading, setLoading] = useState(false); const [updateDocument] = useMutation(UPDATE_DOCUMENT); @@ -48,10 +65,37 @@ export default function JobsDocumentsGalleryReassign({ galleryImages }) { }); } }; - + console.log("selectedImages :>> ", selectedImages); const handleFinish = async ({ jobid }) => { 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", { documents: selectedImages.map((i) => { //Need to check if the current key folder is null, or another job. diff --git a/client/src/components/jobs-documents-gallery/jobs-documents-gallery.component.jsx b/client/src/components/jobs-documents-gallery/jobs-documents-gallery.component.jsx index dc8bede19..9d017c71f 100644 --- a/client/src/components/jobs-documents-gallery/jobs-documents-gallery.component.jsx +++ b/client/src/components/jobs-documents-gallery/jobs-documents-gallery.component.jsx @@ -18,6 +18,7 @@ function JobsDocumentsComponent({ billsCallback, totalSize, bodyshop, + ignoreSizeLimit, }) { const [galleryImages, setgalleryImages] = useState({ images: [], other: [] }); const { t } = useTranslation(); @@ -43,6 +44,7 @@ function JobsDocumentsComponent({ extension: value.extension, id: value.id, type: value.type, + size: value.size, tags: [{ value: value.type, title: value.type }], }); } else { @@ -95,6 +97,7 @@ function JobsDocumentsComponent({ key: value.key, id: value.id, type: value.type, + size: value.size, }); } @@ -131,6 +134,7 @@ function JobsDocumentsComponent({ totalSize={totalSize} billId={billId} callbackAfterUpload={billsCallback || refetch} + ignoreSizeLimit={ignoreSizeLimit} /> diff --git a/client/src/graphql/bills.queries.js b/client/src/graphql/bills.queries.js index 5bb4f0099..69648c933 100644 --- a/client/src/graphql/bills.queries.js +++ b/client/src/graphql/bills.queries.js @@ -167,6 +167,7 @@ export const QUERY_BILL_BY_PK = gql` key name type + size } } } diff --git a/client/src/graphql/documents.queries.js b/client/src/graphql/documents.queries.js index 3903f1d2f..443025ce9 100644 --- a/client/src/graphql/documents.queries.js +++ b/client/src/graphql/documents.queries.js @@ -14,6 +14,7 @@ export const GET_DOCUMENTS_BY_JOB = gql` name key type + size bill { id 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` mutation INSERT_NEW_DOCUMENT($docInput: [documents_insert_input!]!) { insert_documents(objects: $docInput) { @@ -34,6 +47,7 @@ export const INSERT_NEW_DOCUMENT = gql` id name key + size } } } @@ -60,6 +74,7 @@ export const QUERY_TEMPORARY_DOCS = gql` key type extension + size } } `; @@ -75,6 +90,7 @@ export const UPDATE_DOCUMENT = gql` name type key + size } } `; diff --git a/client/src/graphql/jobs.queries.js b/client/src/graphql/jobs.queries.js index 148938192..6dc3dc82f 100644 --- a/client/src/graphql/jobs.queries.js +++ b/client/src/graphql/jobs.queries.js @@ -811,6 +811,7 @@ export const QUERY_TECH_JOB_DETAILS = gql` documents(order_by: { created_at: desc }) { id key + size } } } diff --git a/client/src/pages/temporary-docs/temporary-docs.component.jsx b/client/src/pages/temporary-docs/temporary-docs.component.jsx index d54898375..bec1287d9 100644 --- a/client/src/pages/temporary-docs/temporary-docs.component.jsx +++ b/client/src/pages/temporary-docs/temporary-docs.component.jsx @@ -17,6 +17,7 @@ export default function TemporaryDocsComponent() { jobId={null} billId={null} refetch={refetch} + ignoreSizeLimit /> ); } diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index 6830d07e2..99da29928 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -658,11 +658,13 @@ "confirmdelete": "Are you sure you want to delete these documents. This CANNOT be undone.", "doctype": "Document Type", "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_title": "Storage Limit Exceeded", "upload": "Upload", - "upload_limitexceeded": "Uploading all selected files will exceed the job storage limit for your shop. ", - "upload_limitexceeded_title": "Unable to upload file(s)", + "upload_limitexceeded": "Uploading all selected documents will exceed the job storage limit for your shop. ", + "upload_limitexceeded_title": "Unable to upload document(s)", "usage": "of job storage used. ({{used}} / {{total}})" }, "successes": { @@ -1719,6 +1721,7 @@ "purchases_by_vendor_detailed_date_range": "Purchases By Vendor - Detailed", "purchases_by_vendor_summary_date_range": "Purchases by Vendor - Summary", "schedule": "Appointment Schedule", + "supplement_ratio_source": "Supplement Ratio by Source", "timetickets": "Time Tickets", "timetickets_employee": "Employee Time Tickets", "timetickets_summary": "Time Tickets Summary" diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index e12ada3d4..225b47151 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -658,6 +658,8 @@ "confirmdelete": "", "doctype": "", "newjobid": "", + "reassign_limitexceeded": "", + "reassign_limitexceeded_title": "", "storageexceeded": "", "storageexceeded_title": "", "upload": "Subir", @@ -1719,6 +1721,7 @@ "purchases_by_vendor_detailed_date_range": "", "purchases_by_vendor_summary_date_range": "", "schedule": "", + "supplement_ratio_source": "", "timetickets": "", "timetickets_employee": "", "timetickets_summary": "" diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index 9e0e9f0c5..6ca6cbff4 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -658,6 +658,8 @@ "confirmdelete": "", "doctype": "", "newjobid": "", + "reassign_limitexceeded": "", + "reassign_limitexceeded_title": "", "storageexceeded": "", "storageexceeded_title": "", "upload": "Télécharger", @@ -1719,6 +1721,7 @@ "purchases_by_vendor_detailed_date_range": "", "purchases_by_vendor_summary_date_range": "", "schedule": "", + "supplement_ratio_source": "", "timetickets": "", "timetickets_employee": "", "timetickets_summary": "" diff --git a/client/src/utils/TemplateConstants.js b/client/src/utils/TemplateConstants.js index 6ba044339..e6f5d9453 100644 --- a/client/src/utils/TemplateConstants.js +++ b/client/src/utils/TemplateConstants.js @@ -511,6 +511,14 @@ export const TemplateList = (type, context) => { //idtype: "vendor", 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"
Click or drag files to this area to upload.