Compare commits

..

3 Commits

Author SHA1 Message Date
Patrick Fic
92103df2a9 IO-2348 add http auth for media. 2023-07-11 15:46:58 -07:00
Patrick Fic
cd4f7ffb9c Merged in feature/IO-2349-pbs-ap-cogs-wip (pull request #885)
IO-2349 Allow PBS AP Posting to WIP
2023-07-11 16:16:27 +00:00
Patrick Fic
400dc79ed6 IO-2349 Allow PBS AP Posting to WIP 2023-07-11 09:10:26 -07:00
14 changed files with 362 additions and 72 deletions

View File

@@ -4318,6 +4318,27 @@
<folder_node>
<name>dms</name>
<children>
<concept_node>
<name>appostingaccount</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>cashierid</name>
<definition_loaded>false</definition_loaded>
@@ -6622,6 +6643,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>void</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
</children>
</folder_node>
<folder_node>
@@ -14004,6 +14046,48 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>scheduledintoday</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>scheduledouttoday</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
</children>
</folder_node>
</children>
@@ -23844,6 +23928,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>dms_unsold</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>dms_wip_acctnumber</name>
<definition_loaded>false</definition_loaded>
@@ -37411,6 +37516,48 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>markexported</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>markforreexport</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>new</name>
<definition_loaded>false</definition_loaded>
@@ -37542,6 +37689,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>markreexported</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>payment</name>
<definition_loaded>false</definition_loaded>
@@ -39355,6 +39523,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>mpi_final_repair_acct_sheet</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>paint_grid</name>
<definition_loaded>false</definition_loaded>
@@ -40433,6 +40622,27 @@
<folder_node>
<name>jobs</name>
<children>
<concept_node>
<name>individual_job_note</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>parts_order</name>
<definition_loaded>false</definition_loaded>
@@ -43276,6 +43486,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>jobs_scheduled_completion</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>lag_time</name>
<definition_loaded>false</definition_loaded>
@@ -44378,6 +44609,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>estimators</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>ins_co_nm_filter</name>
<definition_loaded>false</definition_loaded>

View File

@@ -1,5 +1,5 @@
import Icon from "@ant-design/icons";
import { Tooltip } from "antd";
import { Spin, Tooltip } from "antd";
import i18n from "i18next";
import moment from "moment";
import React, { useEffect, useRef } from "react";
@@ -12,6 +12,8 @@ import {
} from "react-virtualized";
import { DateTimeFormatter } from "../../utils/DateFormatter";
import "./chat-message-list.styles.scss";
import { useState } from "react";
import axios from "axios";
export default function ChatMessageListComponent({ messages }) {
const virtualizedListRef = useRef(null);
@@ -95,9 +97,7 @@ const MessageRender = (message) => {
key={idx}
style={{ display: "flex", justifyContent: "center" }}
>
<a href={i} target="__blank">
<img alt="Received" className="message-img" src={i} />
</a>
<ImageDisplay src={i} />
</div>
))}
<div>{message.text}</div>
@@ -116,3 +116,21 @@ const StatusRender = (status) => {
return null;
}
};
const ImageDisplay = ({ src }) => {
const [state, setstate] = useState({ loading: true, url: null });
useEffect(() => {
axios
.post("/sms/fetchmedia", { mediaUrl: src })
.then(({ data }) => setstate({ loading: false, url: data }));
}, [src]);
if (state.loading === true) return <Spin />;
return (
<a href={i} target="__blank">
<img alt="Received" className="message-img" src={state.url} />
</a>
);
};

View File

@@ -162,6 +162,19 @@ export function ShopInfoResponsibilityCenterComponent({ bodyshop, form }) {
<Switch />
</Form.Item>
)}
{bodyshop.pbs_serialnumber && (
<Form.Item
label={t("bodyshop.fields.dms.appostingaccount")}
name={["pbs_configuration", "appostingaccount"]}
>
<Select
options={[
{ value: "wip", label: "WIP" },
{ value: "cogs", label: "COGS" },
]}
/>
</Form.Item>
)}
</LayoutFormRow>
<LayoutFormRow header={t("bodyshop.labels.dms.cdk.payers")}>
<Form.List name={["cdk_configuration", "payers"]}>

View File

@@ -5,10 +5,10 @@ import {
Col,
Form,
InputNumber,
notification,
Popover,
Row,
Select,
notification,
} from "antd";
import axios from "axios";
import React, { useState } from "react";
@@ -16,14 +16,13 @@ import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { logImEXEvent } from "../../firebase/firebase.utils";
import { GET_LINE_TICKET_BY_PK } from "../../graphql/jobs-lines.queries";
import { UPDATE_JOB_STATUS } from "../../graphql/jobs.queries";
import { UPDATE_TIME_TICKET } from "../../graphql/timetickets.queries";
import { selectTechnician } from "../../redux/tech/tech.selectors";
import { selectBodyshop } from "../../redux/user/user.selectors";
import { CalculateAllocationsTotals } from "../labor-allocations-table/labor-allocations-table.utility";
import TechJobClockoutDelete from "../tech-job-clock-out-delete/tech-job-clock-out-delete.component";
import { LaborAllocationContainer } from "../time-ticket-modal/time-ticket-modal.component";
import { GET_LINE_TICKET_BY_PK } from "../../graphql/jobs-lines.queries";
import { CalculateAllocationsTotals } from "../labor-allocations-table/labor-allocations-table.utility";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
@@ -41,7 +40,6 @@ export function TechClockOffButton({
}) {
const [loading, setLoading] = useState(false);
const [updateTimeticket] = useMutation(UPDATE_TIME_TICKET);
const [updateJobStatus] = useMutation(UPDATE_JOB_STATUS);
const [form] = Form.useForm();
const { queryLoading, data: lineTicketData } = useQuery(
GET_LINE_TICKET_BY_PK,
@@ -61,8 +59,7 @@ export function TechClockOffButton({
const handleFinish = async (values) => {
logImEXEvent("tech_clock_out_job");
const status = values.status;
delete values.status;
setLoading(true);
const result = await updateTimeticket({
variables: {
@@ -101,26 +98,6 @@ export function TechClockOffButton({
message: t("timetickets.successes.clockedout"),
});
}
if (!isShiftTicket) {
const job_update_result = await updateJobStatus({
variables: {
jobId: jobId,
status: status,
},
});
if (!!job_update_result.errors) {
notification["error"]({
message: t("jobs.errors.updating", {
message: JSON.stringify(result.errors),
}),
});
} else {
notification["success"]({
message: t("jobs.successes.updated"),
});
}
}
setLoading(false);
if (completedCallback) completedCallback();
};
@@ -218,6 +195,7 @@ export function TechClockOffButton({
</Form.Item>
</div>
) : null}
<Form.Item
name="cost_center"
label={t("timetickets.fields.cost_center")}
@@ -250,29 +228,6 @@ export function TechClockOffButton({
</Select>
</Form.Item>
{isShiftTicket ? (
<div></div>
) : (
<Form.Item
name="status"
label={t("jobs.fields.status")}
initialValue={
lineTicketData && lineTicketData.jobs_by_pk.status
}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<Select>
{bodyshop.md_ro_statuses.production_statuses.map((item) => (
<Select.Option key={item}></Select.Option>
))}
</Select>
</Form.Item>
)}
<Button type="primary" htmlType="submit" loading={loading}>
{t("general.actions.save")}
</Button>

View File

@@ -34,7 +34,6 @@ export const GET_LINE_TICKET_BY_PK = gql`
id
lbr_adjustments
converted
status
}
joblines(where: { jobid: { _eq: $id }, removed: { _eq: false } }) {
id

View File

@@ -269,6 +269,7 @@
"templates": "Delivery Templates"
},
"dms": {
"appostingaccount": "AP Posting Account",
"cashierid": "Cashier ID",
"default_journal": "Default Journal",
"disablebillwip": "Disable bill WIP for A/P Posting",
@@ -1452,8 +1453,8 @@
"cost_dms_acctnumber": "Cost DMS Acct #",
"dms_make": "DMS Make",
"dms_model": "DMS Model",
"dms_wip_acctnumber": "Cost WIP DMS Acct #",
"dms_unsold": "New, Unsold Vehicle",
"dms_wip_acctnumber": "Cost WIP DMS Acct #",
"id": "DMS ID",
"inservicedate": "In Service Date",
"journal": "Journal #",
@@ -2218,17 +2219,17 @@
"external": "External",
"findermodal": "ICBC Payment Finder",
"insurance": "Insurance",
"markexported": "Mark Exported",
"markforreexport": "Mark for Re-export",
"new": "New Payment",
"signup": "Please contact support to sign up for electronic payments.",
"title": "Payments",
"totalpayments": "Total Payments",
"markexported": "Mark Exported",
"markforreexport": "Mark for Re-export"
"totalpayments": "Total Payments"
},
"successes": {
"exported": "Payment(s) exported successfully.",
"markreexported": "Payment marked for re-export successfully",
"markexported": "Payment(s) marked exported.",
"markreexported": "Payment marked for re-export successfully",
"payment": "Payment created successfully. ",
"stripe": "Credit card transaction charged successfully."
}
@@ -2570,8 +2571,8 @@
"job_costing_ro_ins_co": "Job Costing by RO Source",
"jobs_completed_not_invoiced": "Jobs Completed not Invoiced",
"jobs_invoiced_not_exported": "Jobs Invoiced not Exported",
"jobs_scheduled_completion": "Jobs Scheduled Completion",
"jobs_reconcile": "Parts/Sublet/Labor Reconciliation",
"jobs_scheduled_completion": "Jobs Scheduled Completion",
"lag_time": "Lag Time",
"open_orders": "Open Orders by Date",
"open_orders_csr": "Open Orders by CSR",
@@ -2628,8 +2629,8 @@
"labels": {
"atssummary": "ATS Summary",
"employeevacation": "Employee Vacations",
"ins_co_nm_filter": "Filter by Insurance Company",
"estimators": "Filter by Writer/Customer Rep.",
"ins_co_nm_filter": "Filter by Insurance Company",
"intake": "Intake Events",
"manual": "Manual Events",
"manualevent": "Add Manual Event"

View File

@@ -269,6 +269,7 @@
"templates": ""
},
"dms": {
"appostingaccount": "",
"cashierid": "",
"default_journal": "",
"disablebillwip": "",
@@ -1452,8 +1453,8 @@
"cost_dms_acctnumber": "",
"dms_make": "",
"dms_model": "",
"dms_wip_acctnumber": "",
"dms_unsold": "",
"dms_wip_acctnumber": "",
"id": "",
"inservicedate": "",
"journal": "",
@@ -2218,6 +2219,8 @@
"external": "",
"findermodal": "",
"insurance": "",
"markexported": "",
"markforreexport": "",
"new": "",
"signup": "",
"title": "",
@@ -2226,6 +2229,7 @@
"successes": {
"exported": "",
"markexported": "",
"markreexported": "",
"payment": "",
"stripe": ""
}
@@ -2567,8 +2571,8 @@
"job_costing_ro_ins_co": "",
"jobs_completed_not_invoiced": "",
"jobs_invoiced_not_exported": "",
"jobs_scheduled_completion": "",
"jobs_reconcile": "",
"jobs_scheduled_completion": "",
"lag_time": "",
"open_orders": "",
"open_orders_csr": "",
@@ -2625,6 +2629,7 @@
"labels": {
"atssummary": "",
"employeevacation": "",
"estimators": "",
"ins_co_nm_filter": "",
"intake": "",
"manual": "",

View File

@@ -269,6 +269,7 @@
"templates": ""
},
"dms": {
"appostingaccount": "",
"cashierid": "",
"default_journal": "",
"disablebillwip": "",
@@ -1452,8 +1453,8 @@
"cost_dms_acctnumber": "",
"dms_make": "",
"dms_model": "",
"dms_wip_acctnumber": "",
"dms_unsold": "",
"dms_wip_acctnumber": "",
"id": "",
"inservicedate": "",
"journal": "",
@@ -2218,6 +2219,8 @@
"external": "",
"findermodal": "",
"insurance": "",
"markexported": "",
"markforreexport": "",
"new": "",
"signup": "",
"title": "",
@@ -2226,6 +2229,7 @@
"successes": {
"exported": "",
"markexported": "",
"markreexported": "",
"payment": "",
"stripe": ""
}
@@ -2567,8 +2571,8 @@
"job_costing_ro_ins_co": "",
"jobs_completed_not_invoiced": "",
"jobs_invoiced_not_exported": "",
"jobs_scheduled_completion": "",
"jobs_reconcile": "",
"jobs_scheduled_completion": "",
"lag_time": "",
"open_orders": "",
"open_orders_csr": "",
@@ -2625,6 +2629,7 @@
"labels": {
"atssummary": "",
"employeevacation": "",
"estimators": "",
"ins_co_nm_filter": "",
"intake": "",
"manual": "",

View File

@@ -53,7 +53,7 @@
"socket.io": "^4.6.1",
"ssh2-sftp-client": "^9.0.4",
"stripe": "^9.15.0",
"twilio": "^4.8.0",
"twilio": "^4.13.0",
"uuid": "^9.0.0",
"xml2js": "^0.4.23",
"xmlbuilder2": "^3.0.2"

View File

@@ -123,6 +123,13 @@ app.post(
twilio.webhook({ validate: process.env.NODE_ENV === "PRODUCTION" }),
smsStatus.status
);
const smsFetchMedia = require("./server/sms/fetch-media");
app.post(
"/sms/fetchmedia",
fb.validateFirebaseIdToken,
smsFetchMedia.fetchmedia
);
app.post(
"/sms/markConversationRead",
fb.validateFirebaseIdToken,

View File

@@ -123,7 +123,10 @@ async function PbsCalculateAllocationsAp(socket, billids) {
if (!billHash[cc.name]) {
billHash[cc.name] = {
Account: cc.dms_acctnumber,
Account:
bodyshop.pbs_configuration.appostingaccount === "wip"
? cc.dms_wip_acctnumber
: cc.dms_acctnumber,
ControlNumber: bill.vendor.dmsid,
Amount: Dinero(),
// Comment: "String",

View File

@@ -1697,6 +1697,7 @@ query GET_PBS_AP_ALLOCATIONS($billids: [uuid!]) {
md_responsibility_centers
timezone
pbs_serialnumber
pbs_configuration
id
}
bills(where: {id: {_in: $billids}, exported:{_eq: false}}) {

31
server/sms/fetch-media.js Normal file
View File

@@ -0,0 +1,31 @@
const path = require("path");
require("dotenv").config({
path: path.resolve(
process.cwd(),
`.env.${process.env.NODE_ENV || "development"}`
),
});
const twilio = require("twilio");
const client = twilio(
process.env.TWILIO_AUTH_TOKEN,
process.env.TWILIO_AUTH_KEY
);
const logger = require("../utils/logger");
exports.fetchmedia = async (req, res) => {
try {
const r = await client.request({
method: "get",
uri: req.body.mediaUrl, //|| "https://api.twilio.com/2010-04-01/Accounts/AC59171266556bbd507234b5fc6a23e4ee/Messages/MMa287a6e411c873e9177953e630f21df0/Media/ME18357bbec8c0092bfbc805aa8e6c6185",
});
res.send(r.headers.location);
} catch (error) {
console.log(error);
logger.log("sms-fetch-media-error", "ERROR", req.user?.email, null, {
// conversationid,
error: error.message,
});
res.sendStatus(500);
}
};

View File

@@ -4338,10 +4338,10 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0:
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==
twilio@^4.8.0:
version "4.10.0"
resolved "https://registry.yarnpkg.com/twilio/-/twilio-4.10.0.tgz#4a0e744045e54934c5cf69033df8e3c5193268a3"
integrity sha512-j6reVBUqwrGHBKnCIoL1hUDPl/Yw6EYVvkYLmFBpVQ74AGf/9BCKXnvlkAgIkwFXzZikpNuo0mqIY/k9oMiFsA==
twilio@^4.13.0:
version "4.13.0"
resolved "https://registry.yarnpkg.com/twilio/-/twilio-4.13.0.tgz#6b8f9f14d4def821ca02abb2c561ed3e4dde7a4d"
integrity sha512-fecPGy2lXnULwle4iXcCH3rP5z4fgkirzp+rRIXsFi45+y3qjkY5DBZSzmYr5T4vUOzZ2djmODZJ2jpRfgIBSw==
dependencies:
axios "^0.26.1"
dayjs "^1.8.29"