@@ -19,3 +19,6 @@ npx deadfile ./src/index.js --exclude build templates
|
||||
hasura migrate create "Init" --from-server --endpoint https://db.imex.online/ --admin-secret 'Production-ImEXOnline!@#'
|
||||
hasura migrate apply --version "1620771761757" --skip-execution --endpoint https://db.imex.online/ --admin-secret 'Production-ImEXOnline!@#'
|
||||
hasura migrate status --endpoint https://db.imex.online/ --admin-secret 'Production-ImEXOnline!@#'
|
||||
|
||||
Generate the license file:
|
||||
$ generate-license-file --input package.json --output third-party-licenses.txt --overwrite
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -9,6 +9,7 @@ import { GET_DOCUMENTS_BY_JOB } from "../../graphql/documents.queries";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
import JobDocumentsGalleryExternal from "../jobs-documents-gallery/jobs-documents-gallery.external.component";
|
||||
import JobDocumentsLocalGalleryExternal from "../jobs-documents-local-gallery/jobs-documents-local-gallery.external.component";
|
||||
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
@@ -58,17 +59,24 @@ export function ChatMediaSelector({
|
||||
{selectedMedia.filter((s) => s.isSelected).length >= 10 ? (
|
||||
<div style={{ color: "red" }}>{t("messaging.labels.maxtenimages")}</div>
|
||||
) : null}
|
||||
{data && (
|
||||
{!bodyshop.uselocalmediaserver && data && (
|
||||
<JobDocumentsGalleryExternal
|
||||
data={data ? data.documents : []}
|
||||
externalMediaState={[selectedMedia, setSelectedMedia]}
|
||||
/>
|
||||
)}
|
||||
{bodyshop.uselocalmediaserver && visible && (
|
||||
<JobDocumentsLocalGalleryExternal
|
||||
externalMediaState={[selectedMedia, setSelectedMedia]}
|
||||
jobId={
|
||||
conversation.job_conversations[0] &&
|
||||
conversation.job_conversations[0].jobid
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
if (bodyshop.uselocalmediaserver) return null;
|
||||
|
||||
return (
|
||||
<Popover
|
||||
content={
|
||||
|
||||
@@ -5,12 +5,15 @@ import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { GET_DOCUMENTS_BY_JOB } from "../../graphql/documents.queries";
|
||||
import { selectEmailConfig } from "../../redux/email/email.selectors";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
import JobDocumentsGalleryExternal from "../jobs-documents-gallery/jobs-documents-gallery.external.component";
|
||||
import JobsDocumentsLocalGalleryExternalComponent from "../jobs-documents-local-gallery/jobs-documents-local-gallery.external.component";
|
||||
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
bodyshop: selectBodyshop,
|
||||
emailConfig: selectEmailConfig,
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
@@ -25,6 +28,7 @@ export function EmailDocumentsComponent({
|
||||
emailConfig,
|
||||
form,
|
||||
selectedMediaState,
|
||||
bodyshop,
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -52,12 +56,18 @@ export function EmailDocumentsComponent({
|
||||
10485760 - new Blob([form.getFieldValue("html")]).size ? (
|
||||
<div style={{ color: "red" }}>{t("general.errors.sizelimit")}</div>
|
||||
) : null}
|
||||
{data && (
|
||||
{!bodyshop.uselocalmediaserver && data && (
|
||||
<JobDocumentsGalleryExternal
|
||||
data={data ? data.documents : []}
|
||||
externalMediaState={[selectedMedia, setSelectedMedia]}
|
||||
/>
|
||||
)}
|
||||
{bodyshop.uselocalmediaserver && (
|
||||
<JobsDocumentsLocalGalleryExternalComponent
|
||||
externalMediaState={[selectedMedia, setSelectedMedia]}
|
||||
jobId={emailConfig.jobid}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -160,14 +160,13 @@ export function EmailOverlayComponent({
|
||||
</Form.Item>
|
||||
|
||||
<Tabs>
|
||||
{!bodyshop.uselocalmediaserver && (
|
||||
<Tabs.TabPane tab={t("emails.labels.documents")} key="documents">
|
||||
<EmailDocumentsComponent
|
||||
selectedMediaState={selectedMediaState}
|
||||
form={form}
|
||||
/>
|
||||
</Tabs.TabPane>
|
||||
)}
|
||||
<Tabs.TabPane tab={t("emails.labels.documents")} key="documents">
|
||||
<EmailDocumentsComponent
|
||||
selectedMediaState={selectedMediaState}
|
||||
form={form}
|
||||
/>
|
||||
</Tabs.TabPane>
|
||||
|
||||
<Tabs.TabPane tab={t("emails.labels.attachments")} key="attachments">
|
||||
{bodyshop.uselocalmediaserver && emailConfig.jobid && (
|
||||
<a href={CreateExplorerLinkForJob({ jobid: emailConfig.jobid })}>
|
||||
|
||||
@@ -95,7 +95,7 @@ mutation UNVOID_JOB($jobId: uuid!) {
|
||||
|
||||
insertAuditTrail({
|
||||
jobid: job.id,
|
||||
operation: AuditTrailMapping.admin_unvoicejob(),
|
||||
operation: AuditTrailMapping.admin_jobunvoid(),
|
||||
});
|
||||
} else {
|
||||
notification["error"]({
|
||||
|
||||
@@ -205,7 +205,7 @@ export default connect(mapStateToProps, mapDispatchToProps)(JobsCloseLines);
|
||||
|
||||
const HasBeenConvertedTolabor = ({ value }) => {
|
||||
const { t } = useTranslation();
|
||||
console.log(value);
|
||||
|
||||
if (!value) return null;
|
||||
return (
|
||||
<Tooltip title={t("joblines.labels.convertedtolabor")}>
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
import React, { useEffect } from "react";
|
||||
import Gallery from "react-grid-gallery";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import {
|
||||
getJobMedia,
|
||||
toggleMediaSelected,
|
||||
} from "../../redux/media/media.actions";
|
||||
import { selectAllMedia } from "../../redux/media/media.selectors";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
allMedia: selectAllMedia,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
getJobMedia: (id) => dispatch(getJobMedia(id)),
|
||||
|
||||
toggleMediaSelected: ({ jobid, filename }) =>
|
||||
dispatch(toggleMediaSelected({ jobid, filename })),
|
||||
});
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(JobDocumentsLocalGalleryExternal);
|
||||
|
||||
function JobDocumentsLocalGalleryExternal({
|
||||
jobId,
|
||||
externalMediaState,
|
||||
getJobMedia,
|
||||
toggleMediaSelected,
|
||||
allMedia,
|
||||
}) {
|
||||
const [galleryImages, setgalleryImages] = externalMediaState;
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
if ( jobId) {
|
||||
getJobMedia(jobId);
|
||||
}
|
||||
}, [jobId, getJobMedia]);
|
||||
|
||||
useEffect(() => {
|
||||
let documents =
|
||||
allMedia && allMedia[jobId]
|
||||
? allMedia[jobId].reduce((acc, val) => {
|
||||
if (
|
||||
val.type &&
|
||||
val.type.mime &&
|
||||
val.type.mime.startsWith("image")
|
||||
) {
|
||||
acc.push(val);
|
||||
}
|
||||
return acc;
|
||||
}, [])
|
||||
: [];
|
||||
|
||||
setgalleryImages(documents);
|
||||
}, [allMedia, jobId, setgalleryImages, t]);
|
||||
|
||||
return (
|
||||
<div className="clearfix">
|
||||
<Gallery
|
||||
images={galleryImages}
|
||||
backdropClosesModal={true}
|
||||
onSelectImage={(index, image) => {
|
||||
setgalleryImages(
|
||||
galleryImages.map((g, idx) =>
|
||||
index === idx ? { ...g, isSelected: !g.isSelected } : g
|
||||
)
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,12 +1,15 @@
|
||||
import React from "react";
|
||||
import RbacWrapperComponent from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import TechLookupJobsDrawer from "../../components/tech-lookup-jobs-drawer/tech-lookup-jobs-drawer.component";
|
||||
import TechLookupJobsList from "../../components/tech-lookup-jobs-list/tech-lookup-jobs-list.component";
|
||||
|
||||
export default function TechLookupContainer() {
|
||||
return (
|
||||
<div>
|
||||
<TechLookupJobsList />
|
||||
<TechLookupJobsDrawer />
|
||||
<RbacWrapperComponent action="jobs:list-active">
|
||||
<TechLookupJobsList />
|
||||
<TechLookupJobsDrawer />
|
||||
</RbacWrapperComponent>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ const AuditTrailMapping = {
|
||||
i18n.t("audit_trail.messages.admin_jobmarkforreexport"),
|
||||
admin_jobmarkexported: () =>
|
||||
i18n.t("audit_trail.messages.admin_jobmarkexported"),
|
||||
|
||||
};
|
||||
|
||||
export default AuditTrailMapping;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const DineroQbFormat = require("./accounting-constants").DineroQbFormat;
|
||||
|
||||
const Dinero = require("dinero.js");
|
||||
const { DiscountNotAlreadyCounted } = require("../job/job-totals");
|
||||
const logger = require("../utils/logger");
|
||||
|
||||
exports.default = function ({
|
||||
@@ -37,23 +38,22 @@ exports.default = function ({
|
||||
amount: Math.round((jobline.act_price || 0) * 100),
|
||||
}).multiply(jobline.part_qty || 1);
|
||||
|
||||
if (
|
||||
(jobline.prt_dsmk_p && jobline.prt_dsmk_p !== 0) ||
|
||||
((jobline.db_ref === "900511" ||
|
||||
jobline.db_ref === "900510" ||
|
||||
jobline.db_ref === "900500") &&
|
||||
jobline.prt_dsmk_m &&
|
||||
jobline.prt_dsmk_m !== 0)
|
||||
) {
|
||||
// console.log("Have a part discount", jobline);
|
||||
DineroAmount = DineroAmount.add(
|
||||
jobline.prt_dsmk_m && jobline.prt_dsmk_m !== 0
|
||||
// console.log("Have a part discount", jobline);
|
||||
DineroAmount = DineroAmount.add(
|
||||
((jobline.prt_dsmk_m && jobline.prt_dsmk_m !== 0) ||
|
||||
(jobline.prt_dsmk_p && jobline.prt_dsmk_p !== 0)) &&
|
||||
DiscountNotAlreadyCounted(jobline, jobs_by_pk.joblines)
|
||||
? jobline.prt_dsmk_m
|
||||
? Dinero({ amount: Math.round(jobline.prt_dsmk_m * 100) })
|
||||
: DineroAmount.percentage(
|
||||
Math.abs(jobline.prt_dsmk_p || 0)
|
||||
).multiply(jobline.prt_dsmk_p > 0 ? 1 : -1)
|
||||
);
|
||||
}
|
||||
: Dinero({
|
||||
amount: Math.round(jobline.act_price * 100),
|
||||
})
|
||||
.multiply(jobline.part_qty || 0)
|
||||
.percentage(Math.abs(jobline.prt_dsmk_p || 0))
|
||||
.multiply(jobline.prt_dsmk_p > 0 ? 1 : -1)
|
||||
: Dinero()
|
||||
);
|
||||
|
||||
const account = responsibilityCenters.profits.find(
|
||||
(i) => jobline.profitcenter_part.toLowerCase() === i.name.toLowerCase()
|
||||
);
|
||||
@@ -82,7 +82,11 @@ exports.default = function ({
|
||||
state:
|
||||
jobs_by_pk.state_tax_rate === 0
|
||||
? false
|
||||
: jobline.db_ref === "900511" || jobline.db_ref === "900510"
|
||||
: jobline.db_ref === "900511" ||
|
||||
jobline.db_ref === "900510" ||
|
||||
(jobline.mod_lb_hrs === 0 && //Extending IO-1375 as a part of IO-2023
|
||||
jobline.act_price > 0 &&
|
||||
jobline.lbr_op === "OP14")
|
||||
? true
|
||||
: jobline.tax_part,
|
||||
},
|
||||
|
||||
@@ -12,6 +12,7 @@ const CdkBase = require("../web-sockets/web-socket");
|
||||
|
||||
const Dinero = require("dinero.js");
|
||||
const _ = require("lodash");
|
||||
const { DiscountNotAlreadyCounted } = require("../job/job-totals");
|
||||
|
||||
exports.default = async function (socket, jobid) {
|
||||
try {
|
||||
@@ -70,23 +71,20 @@ exports.default = async function (socket, jobid) {
|
||||
amount: Math.round(val.act_price * 100),
|
||||
}).multiply(val.part_qty || 1);
|
||||
|
||||
if (
|
||||
(val.prt_dsmk_p && val.prt_dsmk_p !== 0) ||
|
||||
((val.db_ref === "900511" ||
|
||||
val.db_ref === "900510" ||
|
||||
val.db_ref === "900500") &&
|
||||
val.prt_dsmk_m &&
|
||||
val.prt_dsmk_m !== 0)
|
||||
) {
|
||||
// console.log("Have a part discount", val);
|
||||
DineroAmount = DineroAmount.add(
|
||||
val.prt_dsmk_m && val.prt_dsmk_m !== 0
|
||||
DineroAmount = DineroAmount.add(
|
||||
((val.prt_dsmk_m && val.prt_dsmk_m !== 0) ||
|
||||
(val.prt_dsmk_p && val.prt_dsmk_p !== 0)) &&
|
||||
DiscountNotAlreadyCounted(val, job.joblines)
|
||||
? val.prt_dsmk_m
|
||||
? Dinero({ amount: Math.round(val.prt_dsmk_m * 100) })
|
||||
: DineroAmount.percentage(Math.abs(val.prt_dsmk_p || 0)).multiply(
|
||||
val.prt_dsmk_p > 0 ? 1 : -1
|
||||
)
|
||||
);
|
||||
}
|
||||
: Dinero({
|
||||
amount: Math.round(val.act_price * 100),
|
||||
})
|
||||
.multiply(val.part_qty || 0)
|
||||
.percentage(Math.abs(val.prt_dsmk_p || 0))
|
||||
.multiply(val.prt_dsmk_p > 0 ? 1 : -1)
|
||||
: Dinero()
|
||||
);
|
||||
|
||||
acc[val.profitcenter_part] =
|
||||
acc[val.profitcenter_part].add(DineroAmount);
|
||||
|
||||
@@ -431,7 +431,7 @@ async function QueryDmsCustomerById(socket, JobData, CustomerId) {
|
||||
|
||||
async function QueryDmsCustomerByName(socket, JobData) {
|
||||
const ownerName = (
|
||||
JobData.ownr_co_nm
|
||||
JobData.ownr_co_nm && JobData.ownr_co_nm !== ""
|
||||
? JobData.ownr_co_nm
|
||||
: `${JobData.ownr_ln},${JobData.ownr_fn}`
|
||||
).replace(replaceSpecialRegex, "");
|
||||
@@ -725,7 +725,7 @@ async function InsertDmsVehicle(socket) {
|
||||
manufacturer: {},
|
||||
vehicle: {
|
||||
deliveryDate: moment()
|
||||
// .tz(socket.JobData.bodyshop.timezone)
|
||||
// .tz(socket.JobData.bodyshop.timezone)
|
||||
.format("YYYYMMDD"),
|
||||
licensePlateNo: socket.JobData.plate_no,
|
||||
make: socket.txEnvelope.dms_make,
|
||||
@@ -854,7 +854,7 @@ async function UpdateDmsVehicle(socket) {
|
||||
socket.DMSVeh.dealer.inServiceDate ||
|
||||
socket.txEnvelope.inservicedate
|
||||
)
|
||||
// .tz(socket.JobData.bodyshop.timezone)
|
||||
// .tz(socket.JobData.bodyshop.timezone)
|
||||
.toISOString(),
|
||||
}),
|
||||
},
|
||||
|
||||
@@ -209,6 +209,9 @@ query QUERY_JOBS_FOR_RECEIVABLES_EXPORT($ids: [uuid!]!) {
|
||||
prt_dsmk_p
|
||||
prt_dsmk_m
|
||||
tax_part
|
||||
line_ref
|
||||
unq_seq
|
||||
lbr_op
|
||||
}
|
||||
}
|
||||
bodyshops(where: {associations: {active: {_eq: true}}}) {
|
||||
@@ -402,6 +405,8 @@ query QUERY_JOBS_FOR_PBS_EXPORT($id: uuid!) {
|
||||
profitcenter_part
|
||||
db_ref
|
||||
prt_dsmk_p
|
||||
unq_seq
|
||||
line_ref
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1112,6 +1117,7 @@ exports.QUERY_JOB_COSTING_DETAILS = ` query QUERY_JOB_COSTING_DETAILS($id: uuid!
|
||||
joblines(where: { removed: { _eq: false } }) {
|
||||
id
|
||||
db_ref
|
||||
line_ref
|
||||
unq_seq
|
||||
line_ind
|
||||
tax_part
|
||||
@@ -1220,6 +1226,7 @@ exports.QUERY_JOB_COSTING_DETAILS_MULTI = ` query QUERY_JOB_COSTING_DETAILS_MULT
|
||||
id
|
||||
db_ref
|
||||
unq_seq
|
||||
line_ref
|
||||
line_ind
|
||||
tax_part
|
||||
line_desc
|
||||
@@ -1443,7 +1450,8 @@ exports.GET_CDK_ALLOCATIONS = `query QUERY_JOB_CLOSE_DETAILS($id: uuid!) {
|
||||
op_code_desc
|
||||
profitcenter_labor
|
||||
profitcenter_part
|
||||
prt_dsmk_p
|
||||
line_ref
|
||||
unq_seq
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ const queries = require("../graphql-client/queries");
|
||||
const _ = require("lodash");
|
||||
const GraphQLClient = require("graphql-request").GraphQLClient;
|
||||
const logger = require("../utils/logger");
|
||||
const { DiscountNotAlreadyCounted } = require("./job-totals");
|
||||
// Dinero.defaultCurrency = "USD";
|
||||
// Dinero.globalLocale = "en-CA";
|
||||
Dinero.globalRoundingMode = "HALF_EVEN";
|
||||
@@ -308,7 +309,8 @@ function GenerateCostingData(job) {
|
||||
job.bodyshop.md_responsibility_centers.defaults.profits;
|
||||
const allCenters = _.union(
|
||||
job.bodyshop.md_responsibility_centers.profits.map((p) => p.name),
|
||||
job.bodyshop.md_responsibility_centers.costs.map((p) => p.name)
|
||||
job.bodyshop.md_responsibility_centers.costs.map((p) => p.name),
|
||||
["Unknown"]
|
||||
);
|
||||
|
||||
const materialsHours = { mapaHrs: 0, mashHrs: 0 };
|
||||
@@ -330,12 +332,15 @@ function GenerateCostingData(job) {
|
||||
}
|
||||
if (val.mod_lbr_ty) {
|
||||
const laborProfitCenter =
|
||||
val.profitcenter_labor || defaultProfits[val.mod_lbr_ty] || "?";
|
||||
val.profitcenter_labor ||
|
||||
defaultProfits[val.mod_lbr_ty] ||
|
||||
"Unknown";
|
||||
|
||||
if (laborProfitCenter === "?")
|
||||
if (laborProfitCenter === "Unknown")
|
||||
console.log("Unknown type", val.line_desc, val.mod_lbr_ty);
|
||||
|
||||
const rateName = `rate_${(val.mod_lbr_ty || "").toLowerCase()}`;
|
||||
|
||||
const laborAmount = Dinero({
|
||||
amount: Math.round((job[rateName] || 0) * 100),
|
||||
}).multiply(val.mod_lb_hrs || 0);
|
||||
@@ -344,6 +349,19 @@ function GenerateCostingData(job) {
|
||||
acc.labor[laborProfitCenter] =
|
||||
acc.labor[laborProfitCenter].add(laborAmount);
|
||||
|
||||
if (
|
||||
val.mod_lb_hrs === 0 &&
|
||||
val.act_price > 0 &&
|
||||
val.lbr_op === "OP14"
|
||||
) {
|
||||
//Scenario where SGI may pay out hours using a part price.
|
||||
acc.labor[laborProfitCenter] = acc.labor[laborProfitCenter].add(
|
||||
Dinero({
|
||||
amount: Math.round((val.act_price || 0) * 100),
|
||||
}).multiply(val.part_qty)
|
||||
);
|
||||
}
|
||||
|
||||
if (val.mod_lbr_ty === "LAR") {
|
||||
materialsHours.mapaHrs += val.mod_lb_hrs || 0;
|
||||
}
|
||||
@@ -359,9 +377,9 @@ function GenerateCostingData(job) {
|
||||
val.part_type !== "PASL"
|
||||
) {
|
||||
const partsProfitCenter =
|
||||
val.profitcenter_part || defaultProfits[val.part_type] || "?";
|
||||
val.profitcenter_part || defaultProfits[val.part_type] || "Unknown";
|
||||
|
||||
if (partsProfitCenter === "?")
|
||||
if (partsProfitCenter === "Unknown")
|
||||
console.log("Unknown type", val.line_desc, val.part_type);
|
||||
|
||||
if (!partsProfitCenter)
|
||||
@@ -375,14 +393,18 @@ function GenerateCostingData(job) {
|
||||
})
|
||||
.multiply(val.part_qty || 1)
|
||||
.add(
|
||||
val.prt_dsmk_m && val.prt_dsmk_m !== 0
|
||||
? Dinero({ amount: Math.round(val.prt_dsmk_m * 100) })
|
||||
: Dinero({
|
||||
amount: Math.round(val.act_price * 100),
|
||||
})
|
||||
.multiply(val.part_qty || 0)
|
||||
.percentage(Math.abs(val.prt_dsmk_p || 0))
|
||||
.multiply(val.prt_dsmk_p > 0 ? 1 : -1)
|
||||
((val.prt_dsmk_m && val.prt_dsmk_m !== 0) ||
|
||||
(val.prt_dsmk_p && val.prt_dsmk_p !== 0)) &&
|
||||
DiscountNotAlreadyCounted(val, job.joblines)
|
||||
? val.prt_dsmk_m
|
||||
? Dinero({ amount: Math.round(val.prt_dsmk_m * 100) })
|
||||
: Dinero({
|
||||
amount: Math.round(val.act_price * 100),
|
||||
})
|
||||
.multiply(val.part_qty || 0)
|
||||
.percentage(Math.abs(val.prt_dsmk_p || 0))
|
||||
.multiply(val.prt_dsmk_p > 0 ? 1 : -1)
|
||||
: Dinero()
|
||||
);
|
||||
if (!acc.parts[partsProfitCenter])
|
||||
acc.parts[partsProfitCenter] = Dinero();
|
||||
@@ -395,9 +417,9 @@ function GenerateCostingData(job) {
|
||||
(val.part_type === "PAS" || val.part_type === "PASL")
|
||||
) {
|
||||
const partsProfitCenter =
|
||||
val.profitcenter_part || defaultProfits[val.part_type] || "?";
|
||||
val.profitcenter_part || defaultProfits[val.part_type] || "Unknown";
|
||||
|
||||
if (partsProfitCenter === "?")
|
||||
if (partsProfitCenter === "Unknown")
|
||||
console.log("Unknown type", val.line_desc, val.part_type);
|
||||
|
||||
if (!partsProfitCenter)
|
||||
@@ -411,14 +433,18 @@ function GenerateCostingData(job) {
|
||||
})
|
||||
.multiply(val.part_qty || 1)
|
||||
.add(
|
||||
val.prt_dsmk_m && val.prt_dsmk_m !== 0
|
||||
? Dinero({ amount: Math.round(val.prt_dsmk_m * 100) })
|
||||
: Dinero({
|
||||
amount: Math.round(val.act_price * 100),
|
||||
})
|
||||
.multiply(val.part_qty || 0)
|
||||
.percentage(Math.abs(val.prt_dsmk_p || 0))
|
||||
.multiply(val.prt_dsmk_p > 0 ? 1 : -1)
|
||||
((val.prt_dsmk_m && val.prt_dsmk_m !== 0) ||
|
||||
(val.prt_dsmk_p && val.prt_dsmk_p !== 0)) &&
|
||||
DiscountNotAlreadyCounted(val, job.joblines)
|
||||
? val.prt_dsmk_m
|
||||
? Dinero({ amount: Math.round(val.prt_dsmk_m * 100) })
|
||||
: Dinero({
|
||||
amount: Math.round(val.act_price * 100),
|
||||
})
|
||||
.multiply(val.part_qty || 0)
|
||||
.percentage(Math.abs(val.prt_dsmk_p || 0))
|
||||
.multiply(val.prt_dsmk_p > 0 ? 1 : -1)
|
||||
: Dinero()
|
||||
);
|
||||
if (!acc.sublet[partsProfitCenter])
|
||||
acc.sublet[partsProfitCenter] = Dinero();
|
||||
@@ -433,17 +459,20 @@ function GenerateCostingData(job) {
|
||||
const partsProfitCenter =
|
||||
val.profitcenter_part ||
|
||||
getAdditionalCostCenter(val, defaultProfits) ||
|
||||
"?";
|
||||
"Unknown";
|
||||
|
||||
if (partsProfitCenter === "?") {
|
||||
if (partsProfitCenter === "Unknown") {
|
||||
console.log("Unknown type", val.line_desc, val.part_type);
|
||||
} else {
|
||||
const partsAmount = Dinero({
|
||||
amount: Math.round((val.act_price || 0) * 100),
|
||||
})
|
||||
.multiply(val.part_qty || 1)
|
||||
.add(
|
||||
val.prt_dsmk_m && val.prt_dsmk_m !== 0
|
||||
}
|
||||
const partsAmount = Dinero({
|
||||
amount: Math.round((val.act_price || 0) * 100),
|
||||
})
|
||||
.multiply(val.part_qty || 1)
|
||||
.add(
|
||||
((val.prt_dsmk_m && val.prt_dsmk_m !== 0) ||
|
||||
(val.prt_dsmk_p && val.prt_dsmk_p !== 0)) &&
|
||||
DiscountNotAlreadyCounted(val, job.joblines)
|
||||
? val.prt_dsmk_m
|
||||
? Dinero({ amount: Math.round(val.prt_dsmk_m * 100) })
|
||||
: Dinero({
|
||||
amount: Math.round(val.act_price * 100),
|
||||
@@ -451,13 +480,13 @@ function GenerateCostingData(job) {
|
||||
.multiply(val.part_qty || 0)
|
||||
.percentage(Math.abs(val.prt_dsmk_p || 0))
|
||||
.multiply(val.prt_dsmk_p > 0 ? 1 : -1)
|
||||
);
|
||||
: Dinero()
|
||||
);
|
||||
|
||||
if (!acc.additional[partsProfitCenter])
|
||||
acc.additional[partsProfitCenter] = Dinero();
|
||||
acc.additional[partsProfitCenter] =
|
||||
acc.additional[partsProfitCenter].add(partsAmount);
|
||||
}
|
||||
if (!acc.additional[partsProfitCenter])
|
||||
acc.additional[partsProfitCenter] = Dinero();
|
||||
acc.additional[partsProfitCenter] =
|
||||
acc.additional[partsProfitCenter].add(partsAmount);
|
||||
}
|
||||
|
||||
return acc;
|
||||
|
||||
@@ -362,28 +362,27 @@ function CalculateRatesTotals(ratesList) {
|
||||
}
|
||||
|
||||
function CalculatePartsTotals(jobLines) {
|
||||
const ret = jobLines
|
||||
.filter((jl) => !jl.removed)
|
||||
.reduce(
|
||||
(acc, value) => {
|
||||
switch (value.part_type) {
|
||||
case "PAS":
|
||||
case "PASL":
|
||||
return {
|
||||
...acc,
|
||||
sublets: {
|
||||
...acc.sublets,
|
||||
subtotal: acc.sublets.subtotal.add(
|
||||
Dinero({
|
||||
amount: Math.round(value.act_price * 100),
|
||||
})
|
||||
.multiply(value.part_qty || 0)
|
||||
.add(
|
||||
(value.db_ref === "900511" ||
|
||||
value.db_ref === "900510" ||
|
||||
value.db_ref === "900500") &&
|
||||
value.prt_dsmk_m &&
|
||||
value.prt_dsmk_m !== 0
|
||||
const jl = jobLines.filter((jl) => !jl.removed);
|
||||
|
||||
const ret = jl.reduce(
|
||||
(acc, value) => {
|
||||
switch (value.part_type) {
|
||||
case "PAS":
|
||||
case "PASL":
|
||||
return {
|
||||
...acc,
|
||||
sublets: {
|
||||
...acc.sublets,
|
||||
subtotal: acc.sublets.subtotal.add(
|
||||
Dinero({
|
||||
amount: Math.round(value.act_price * 100),
|
||||
})
|
||||
.multiply(value.part_qty || 0)
|
||||
.add(
|
||||
((value.prt_dsmk_m && value.prt_dsmk_m !== 0) ||
|
||||
(value.prt_dsmk_p && value.prt_dsmk_p !== 0)) &&
|
||||
DiscountNotAlreadyCounted(value, jl)
|
||||
? value.prt_dsmk_m
|
||||
? Dinero({ amount: Math.round(value.prt_dsmk_m * 100) })
|
||||
: Dinero({
|
||||
amount: Math.round(value.act_price * 100),
|
||||
@@ -391,28 +390,28 @@ function CalculatePartsTotals(jobLines) {
|
||||
.multiply(value.part_qty || 0)
|
||||
.percentage(Math.abs(value.prt_dsmk_p || 0))
|
||||
.multiply(value.prt_dsmk_p > 0 ? 1 : -1)
|
||||
)
|
||||
),
|
||||
},
|
||||
};
|
||||
: Dinero()
|
||||
)
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
default:
|
||||
if (
|
||||
!value.part_type &&
|
||||
value.db_ref !== "900510" &&
|
||||
value.db_ref !== "900511"
|
||||
)
|
||||
return acc;
|
||||
return {
|
||||
...acc,
|
||||
parts: {
|
||||
...acc.parts,
|
||||
prt_dsmk_total: acc.parts.prt_dsmk_total.add(
|
||||
(value.db_ref === "900511" ||
|
||||
value.db_ref === "900510" ||
|
||||
value.db_ref === "900500") &&
|
||||
value.prt_dsmk_m &&
|
||||
value.prt_dsmk_m !== 0
|
||||
default:
|
||||
if (
|
||||
!value.part_type &&
|
||||
value.db_ref !== "900510" &&
|
||||
value.db_ref !== "900511"
|
||||
)
|
||||
return acc;
|
||||
return {
|
||||
...acc,
|
||||
parts: {
|
||||
...acc.parts,
|
||||
prt_dsmk_total: acc.parts.prt_dsmk_total.add(
|
||||
((value.prt_dsmk_m && value.prt_dsmk_m !== 0) ||
|
||||
(value.prt_dsmk_p && value.prt_dsmk_p !== 0)) &&
|
||||
DiscountNotAlreadyCounted(value, jl)
|
||||
? value.prt_dsmk_m
|
||||
? Dinero({ amount: Math.round(value.prt_dsmk_m * 100) })
|
||||
: Dinero({
|
||||
amount: Math.round(value.act_price * 100),
|
||||
@@ -420,47 +419,45 @@ function CalculatePartsTotals(jobLines) {
|
||||
.multiply(value.part_qty || 0)
|
||||
.percentage(Math.abs(value.prt_dsmk_p || 0))
|
||||
.multiply(value.prt_dsmk_p > 0 ? 1 : -1)
|
||||
),
|
||||
...(value.part_type
|
||||
? {
|
||||
list: {
|
||||
...acc.parts.list,
|
||||
[value.part_type]:
|
||||
acc.parts.list[value.part_type] &&
|
||||
acc.parts.list[value.part_type].total
|
||||
? {
|
||||
total: acc.parts.list[
|
||||
value.part_type
|
||||
].total.add(
|
||||
Dinero({
|
||||
amount: Math.round(
|
||||
(value.act_price || 0) * 100
|
||||
),
|
||||
}).multiply(value.part_qty || 0)
|
||||
),
|
||||
}
|
||||
: {
|
||||
total: Dinero({
|
||||
: Dinero()
|
||||
),
|
||||
...(value.part_type
|
||||
? {
|
||||
list: {
|
||||
...acc.parts.list,
|
||||
[value.part_type]:
|
||||
acc.parts.list[value.part_type] &&
|
||||
acc.parts.list[value.part_type].total
|
||||
? {
|
||||
total: acc.parts.list[value.part_type].total.add(
|
||||
Dinero({
|
||||
amount: Math.round(
|
||||
(value.act_price || 0) * 100
|
||||
),
|
||||
}).multiply(value.part_qty || 0),
|
||||
},
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
subtotal: acc.parts.subtotal
|
||||
.add(
|
||||
Dinero({
|
||||
amount: Math.round(value.act_price * 100),
|
||||
}).multiply(value.part_qty || 0)
|
||||
)
|
||||
.add(
|
||||
(value.db_ref === "900511" ||
|
||||
value.db_ref === "900510" ||
|
||||
value.db_ref === "900500") &&
|
||||
value.prt_dsmk_m &&
|
||||
value.prt_dsmk_m !== 0
|
||||
}).multiply(value.part_qty || 0)
|
||||
),
|
||||
}
|
||||
: {
|
||||
total: Dinero({
|
||||
amount: Math.round(
|
||||
(value.act_price || 0) * 100
|
||||
),
|
||||
}).multiply(value.part_qty || 0),
|
||||
},
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
subtotal: acc.parts.subtotal
|
||||
.add(
|
||||
Dinero({
|
||||
amount: Math.round(value.act_price * 100),
|
||||
}).multiply(value.part_qty || 0)
|
||||
)
|
||||
.add(
|
||||
((value.prt_dsmk_m && value.prt_dsmk_m !== 0) ||
|
||||
(value.prt_dsmk_p && value.prt_dsmk_p !== 0)) &&
|
||||
DiscountNotAlreadyCounted(value, jl)
|
||||
? value.prt_dsmk_m
|
||||
? Dinero({ amount: Math.round(value.prt_dsmk_m * 100) })
|
||||
: Dinero({
|
||||
amount: Math.round(value.act_price * 100),
|
||||
@@ -468,25 +465,26 @@ function CalculatePartsTotals(jobLines) {
|
||||
.multiply(value.part_qty || 0)
|
||||
.percentage(Math.abs(value.prt_dsmk_p || 0))
|
||||
.multiply(value.prt_dsmk_p > 0 ? 1 : -1)
|
||||
),
|
||||
},
|
||||
};
|
||||
}
|
||||
},
|
||||
{
|
||||
parts: {
|
||||
list: {},
|
||||
prt_dsmk_total: Dinero(),
|
||||
subtotal: Dinero({ amount: 0 }),
|
||||
total: Dinero({ amount: 0 }),
|
||||
},
|
||||
sublets: {
|
||||
subtotal: Dinero({ amount: 0 }),
|
||||
|
||||
total: Dinero({ amount: 0 }),
|
||||
},
|
||||
: Dinero()
|
||||
),
|
||||
},
|
||||
};
|
||||
}
|
||||
);
|
||||
},
|
||||
{
|
||||
parts: {
|
||||
list: {},
|
||||
prt_dsmk_total: Dinero(),
|
||||
subtotal: Dinero({ amount: 0 }),
|
||||
total: Dinero({ amount: 0 }),
|
||||
},
|
||||
sublets: {
|
||||
subtotal: Dinero({ amount: 0 }),
|
||||
|
||||
total: Dinero({ amount: 0 }),
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
return {
|
||||
parts: {
|
||||
@@ -706,7 +704,16 @@ function CalculateTaxesTotals(job, otherTotals) {
|
||||
exports.default = Totals;
|
||||
|
||||
function DiscountNotAlreadyCounted(jobline, joblines) {
|
||||
if (jobline.db_ref !== "900510") return true;
|
||||
if (
|
||||
//If it's not a discount line, then it definitely hasn't been counted yet.
|
||||
jobline.db_ref !== "900510" &&
|
||||
jobline.db_ref !== "900511"
|
||||
)
|
||||
return true;
|
||||
|
||||
const ParentLine = joblines.find((j) => j.unq_seq === jobline.line_ref);
|
||||
|
||||
return ParentLine && !(ParentLine.prt_dsmk_m && ParentLine.prt_dsmk_m !== 0);
|
||||
}
|
||||
|
||||
exports.DiscountNotAlreadyCounted = DiscountNotAlreadyCounted;
|
||||
|
||||
Reference in New Issue
Block a user