Merged in feature/IO-2543-AR-Aging (pull request #1210)

IO-2543 AR Aging

Approved-by: Dave Richer
Approved-by: Patrick Fic
This commit is contained in:
Allan Carr
2024-01-25 18:33:20 +00:00
committed by Dave Richer
13 changed files with 581 additions and 447 deletions

View File

@@ -53,12 +53,14 @@ export function JobsAdminStatus({ insertAuditTrail, bodyshop, job }) {
); );
return ( return (
<Dropdown overlay={statusmenu} trigger={["click"]} key="changestatus"> <>
<Button shape="round"> <Dropdown overlay={statusmenu} trigger={["click"]} key="changestatus">
<span>{job.status}</span> <Button shape="round">
<span>{job.status}</span>
<DownCircleFilled /> <DownCircleFilled />
</Button> </Button>
</Dropdown> </Dropdown>
</>
); );
} }

View File

@@ -1,34 +1,18 @@
import { useMutation } from "@apollo/client"; import { useMutation } from "@apollo/client";
import { Button, notification } from "antd"; import { Button, Space, notification } from "antd";
import { gql } from "@apollo/client";
import React, { useState } from "react"; import React, { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import {
DELETE_DELIVERY_CHECKLIST,
DELETE_INTAKE_CHECKLIST,
} from "../../graphql/jobs.queries";
export default function JobAdminDeleteIntake({ job }) { export default function JobAdminDeleteIntake({ job }) {
const { t } = useTranslation(); const { t } = useTranslation();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [deleteIntake] = useMutation(gql`
mutation DELETE_INTAKE($jobId: uuid!) {
update_jobs_by_pk(
pk_columns: { id: $jobId }
_set: { intakechecklist: null }
) {
id
intakechecklist
}
}
`);
const [DELETE_DELIVERY] = useMutation(gql` const [deleteIntake] = useMutation(DELETE_INTAKE_CHECKLIST);
mutation DELETE_DELIVERY($jobId: uuid!) { const [deleteDelivery] = useMutation(DELETE_DELIVERY_CHECKLIST);
update_jobs_by_pk(
pk_columns: { id: $jobId }
_set: { deliverchecklist: null }
) {
id
deliverchecklist
}
}
`);
const handleDelete = async (values) => { const handleDelete = async (values) => {
setLoading(true); setLoading(true);
@@ -50,7 +34,7 @@ export default function JobAdminDeleteIntake({ job }) {
const handleDeleteDelivery = async (values) => { const handleDeleteDelivery = async (values) => {
setLoading(true); setLoading(true);
const result = await DELETE_DELIVERY({ const result = await deleteDelivery({
variables: { jobId: job.id }, variables: { jobId: job.id },
}); });
@@ -68,12 +52,22 @@ export default function JobAdminDeleteIntake({ job }) {
return ( return (
<> <>
<Button loading={loading} onClick={handleDelete}> <Space>
{t("jobs.labels.deleteintake")} <Button
</Button> loading={loading}
<Button loading={loading} onClick={handleDeleteDelivery}> onClick={handleDelete}
{t("jobs.labels.deletedelivery")} disabled={!job.intakechecklist}
</Button> >
{t("jobs.labels.deleteintake")}
</Button>
<Button
loading={loading}
onClick={handleDeleteDelivery}
disabled={!job.deliverychecklist}
>
{t("jobs.labels.deletedelivery")}
</Button>
</Space>
</> </>
); );
} }

View File

@@ -1,5 +1,5 @@
import { gql, useMutation } from "@apollo/client"; import { useMutation } from "@apollo/client";
import { Button, notification } from "antd"; import { Button, Space, notification } from "antd";
import React, { useState } from "react"; import React, { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@@ -7,6 +7,11 @@ import moment from "moment";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries"; import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries";
import {
MARK_JOB_AS_EXPORTED,
MARK_JOB_AS_UNINVOICED,
MARK_JOB_FOR_REEXPORT,
} from "../../graphql/jobs.queries";
import { insertAuditTrail } from "../../redux/application/application.actions"; import { insertAuditTrail } from "../../redux/application/application.actions";
import { import {
selectBodyshop, selectBodyshop,
@@ -35,58 +40,18 @@ export function JobAdminMarkReexport({
const { t } = useTranslation(); const { t } = useTranslation();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [insertExportLog] = useMutation(INSERT_EXPORT_LOG); const [insertExportLog] = useMutation(INSERT_EXPORT_LOG);
const [markJobForReexport] = useMutation(gql`
mutation MARK_JOB_FOR_REEXPORT($jobId: uuid!) {
update_jobs_by_pk(
pk_columns: { id: $jobId }
_set: { date_exported: null
status: "${bodyshop.md_ro_statuses.default_invoiced}"
}
) {
id
date_exported
status
date_invoiced
}
}
`);
const [markJobExported] = useMutation(gql` const [markJobForReexport] = useMutation(MARK_JOB_FOR_REEXPORT);
mutation MARK_JOB_AS_EXPORTED($jobId: uuid!, $date_exported: timestamptz!) { const [markJobExported] = useMutation(MARK_JOB_AS_EXPORTED);
update_jobs_by_pk( const [markJobUninvoiced] = useMutation(MARK_JOB_AS_UNINVOICED);
pk_columns: { id: $jobId }
_set: { date_exported: $date_exported
status: "${bodyshop.md_ro_statuses.default_exported}"
}
) {
id
date_exported
date_invoiced
status
}
}
`);
const [markJobUninvoiced] = useMutation(gql`
mutation MARK_JOB_AS_UNINVOICED($jobId: uuid!, ) {
update_jobs_by_pk(
pk_columns: { id: $jobId }
_set: { date_exported: null
date_invoiced: null
status: "${bodyshop.md_ro_statuses.default_delivered}"
}
) {
id
date_exported
date_invoiced
status
}
}
`);
const handleMarkForExport = async () => { const handleMarkForExport = async () => {
setLoading(true); setLoading(true);
const result = await markJobForReexport({ const result = await markJobForReexport({
variables: { jobId: job.id }, variables: {
jobId: job.id,
default_invoiced: bodyshop.md_ro_statuses.default_invoiced,
},
}); });
if (!result.errors) { if (!result.errors) {
@@ -108,7 +73,11 @@ export function JobAdminMarkReexport({
const handleMarkExported = async () => { const handleMarkExported = async () => {
setLoading(true); setLoading(true);
const result = await markJobExported({ const result = await markJobExported({
variables: { jobId: job.id, date_exported: moment() }, variables: {
jobId: job.id,
date_exported: moment(),
default_exported: bodyshop.md_ro_statuses.default_exported,
},
}); });
await insertExportLog({ await insertExportLog({
@@ -144,7 +113,10 @@ export function JobAdminMarkReexport({
const handleUninvoice = async () => { const handleUninvoice = async () => {
setLoading(true); setLoading(true);
const result = await markJobUninvoiced({ const result = await markJobUninvoiced({
variables: { jobId: job.id }, variables: {
jobId: job.id,
default_delivered: bodyshop.md_ro_statuses.default_delivered,
},
}); });
if (!result.errors) { if (!result.errors) {
@@ -165,27 +137,29 @@ export function JobAdminMarkReexport({
return ( return (
<> <>
<Button <Space>
loading={loading} <Button
disabled={!job.date_exported} loading={loading}
onClick={handleMarkForExport} disabled={!job.date_exported}
> onClick={handleMarkForExport}
{t("jobs.labels.markforreexport")} >
</Button> {t("jobs.labels.markforreexport")}
<Button </Button>
loading={loading} <Button
disabled={job.date_exported} loading={loading}
onClick={handleMarkExported} disabled={job.date_exported}
> onClick={handleMarkExported}
{t("jobs.actions.markasexported")} >
</Button> {t("jobs.actions.markasexported")}
<Button </Button>
loading={loading} <Button
disabled={!job.date_invoiced || job.date_exported} loading={loading}
onClick={handleUninvoice} disabled={!job.date_invoiced || job.date_exported}
> onClick={handleUninvoice}
{t("jobs.actions.uninvoice")} >
</Button> {t("jobs.actions.uninvoice")}
</Button>
</Space>
</> </>
); );
} }

View File

@@ -0,0 +1,65 @@
import { useMutation } from "@apollo/client";
import { Switch, notification } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { UPDATE_REMOVE_FROM_AR } from "../../graphql/jobs.queries";
import { insertAuditTrail } from "../../redux/application/application.actions";
import AuditTrailMapping from "../../utils/AuditTrailMappings";
const mapStateToProps = createStructuredSelector({});
const mapDispatchToProps = (dispatch) => ({
insertAuditTrail: ({ jobid, operation }) =>
dispatch(insertAuditTrail({ jobid, operation })),
});
export default connect(mapStateToProps, mapDispatchToProps)(JobsAdminRemoveAR);
export function JobsAdminRemoveAR({ insertAuditTrail, job }) {
const { t } = useTranslation();
const [loading, setLoading] = useState(false);
const [switchValue, setSwitchValue] = useState(job.remove_from_ar);
const [mutationUpdateRemoveFromAR] = useMutation(UPDATE_REMOVE_FROM_AR);
const handleChange = async (value) => {
setLoading(true);
const result = await mutationUpdateRemoveFromAR({
variables: { jobId: job.id, remove_from_ar: value },
});
if (!result.errors) {
notification["success"]({ message: t("jobs.successes.save") });
insertAuditTrail({
jobid: job.id,
operation: AuditTrailMapping.admin_job_remove_from_ar(value),
});
setSwitchValue(value);
} else {
notification["error"]({
message: t("jobs.errors.saving", {
error: JSON.stringify(result.errors),
}),
});
}
setLoading(false);
};
return (
<>
<div style={{ display: "flex", alignItems: "center" }}>
<div style={{ marginRight: "10px" }}>
{t("jobs.labels.remove_from_ar")}:
</div>
<div>
<Switch
checked={switchValue}
loading={loading}
onChange={handleChange}
/>
</div>
</div>
</>
);
}

View File

@@ -1,9 +1,10 @@
import { gql, useMutation } from "@apollo/client"; import { useMutation } from "@apollo/client";
import { Button, notification } from "antd"; import { Button, notification } from "antd";
import React, { useState } from "react"; import React, { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { UNVOID_JOB } from "../../graphql/jobs.queries";
import { insertAuditTrail } from "../../redux/application/application.actions"; import { insertAuditTrail } from "../../redux/application/application.actions";
import { import {
selectBodyshop, selectBodyshop,
@@ -29,66 +30,17 @@ export function JobsAdminUnvoid({
}) { }) {
const { t } = useTranslation(); const { t } = useTranslation();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [updateJob] = useMutation(gql` const [mutationUnvoidJob] = useMutation(UNVOID_JOB);
mutation UNVOID_JOB($jobId: uuid!) {
update_jobs_by_pk(pk_columns: {id: $jobId}, _set: {voided: false, status: "${
bodyshop.md_ro_statuses.default_imported
}", date_void: null}) {
id
date_void
voided
status
}
insert_notes(objects: {jobid: $jobId, audit: true, created_by: "${
currentUser.email
}", text: "${t("jobs.labels.unvoidnote")}"}) {
returning {
id
}
}
}
`);
// const result = await voidJob({
// variables: {
// jobId: job.id,
// job: {
// status: bodyshop.md_ro_statuses.default_void,
// voided: true,
// },
// note: [
// {
// jobid: job.id,
// created_by: currentUser.email,
// audit: true,
// text: t("jobs.labels.voidnote", {
// date: moment().format("MM/DD/yyy"),
// time: moment().format("hh:mm a"),
// }),
// },
// ],
// },
// });
// if (!!!result.errors) {
// notification["success"]({
// message: t("jobs.successes.voided"),
// });
// //go back to jobs list.
// history.push(`/manage/`);
// } else {
// notification["error"]({
// message: t("jobs.errors.voiding", {
// error: JSON.stringify(result.errors),
// }),
// });
// }
const handleUpdate = async (values) => { const handleUpdate = async (values) => {
setLoading(true); setLoading(true);
const result = await updateJob({ const result = await mutationUnvoidJob({
variables: { jobId: job.id }, variables: {
jobId: job.id,
default_imported: bodyshop.md_ro_statuses.default_imported,
currentUserEmail: currentUser.email,
text: t("jobs.labels.unvoidnote"),
},
}); });
if (!result.errors) { if (!result.errors) {
@@ -110,8 +62,10 @@ mutation UNVOID_JOB($jobId: uuid!) {
}; };
return ( return (
<Button loading={loading} disabled={!job.voided} onClick={handleUpdate}> <>
{t("jobs.actions.unvoid")} <Button loading={loading} disabled={!job.voided} onClick={handleUpdate}>
</Button> {t("jobs.actions.unvoid")}
</Button>
</>
); );
} }

View File

@@ -68,8 +68,8 @@ export function ReportCenterModalComponent({ reportCenterModal }) {
const handleFinish = async (values) => { const handleFinish = async (values) => {
setLoading(true); setLoading(true);
const start = values.dates[0]; const start = values.dates ? values.dates[0] : null;
const end = values.dates[1]; const end = values.dates ? values.dates[1] : null;
const { id } = values; const { id } = values;
await GenerateDocument( await GenerateDocument(
@@ -239,20 +239,30 @@ export function ReportCenterModalComponent({ reportCenterModal }) {
else return null; else return null;
}} }}
</Form.Item> </Form.Item>
<Form.Item <Form.Item style={{ margin: 0, padding: 0 }} dependencies={["key"]}>
name="dates" {() => {
label={t("reportcenter.labels.dates")} const key = form.getFieldValue("key");
rules={[ const datedisable = Templates[key] && Templates[key].datedisable;
{ if (datedisable !== true) {
required: true, return (
//message: t("general.validation.required"), <Form.Item
}, name="dates"
]} label={t("reportcenter.labels.dates")}
> rules={[
<DatePicker.RangePicker {
format="MM/DD/YYYY" required: true,
ranges={DatePIckerRanges} //message: t("general.validation.required"),
/> },
]}
>
<DatePicker.RangePicker
format="MM/DD/YYYY"
ranges={DatePIckerRanges}
/>
</Form.Item>
);
} else return null;
}}
</Form.Item> </Form.Item>
<Form.Item style={{ margin: 0, padding: 0 }} dependencies={["key"]}> <Form.Item style={{ margin: 0, padding: 0 }} dependencies={["key"]}>
{() => { {() => {

View File

@@ -545,147 +545,166 @@ export const QUERY_JOB_COSTING_DETAILS = gql`
export const GET_JOB_BY_PK = gql` export const GET_JOB_BY_PK = gql`
query GET_JOB_BY_PK($id: uuid!) { query GET_JOB_BY_PK($id: uuid!) {
jobs_by_pk(id: $id) { jobs_by_pk(id: $id) {
updated_at actual_completion
actual_delivery
actual_in
adjustment_bottom_line
area_of_damage
auto_add_ats
available_jobs {
id
}
alt_transport
ca_bc_pvrt
ca_customer_gst
ca_gst_registrant
category
cccontracts {
agreementnumber
courtesycar {
fleetnumber
id
make
model
plate
year
}
id
scheduledreturn
start
status
}
cieca_ttl
class
clm_no
clm_total
comment
converted
csiinvites {
completedon
id
}
date_estimated
date_exported
date_invoiced
date_last_contacted
date_lost_sale
date_next_contact
date_open
date_rentalresp
date_repairstarted
date_scheduled
date_towin
date_void
ded_amt
ded_note
ded_status
deliverchecklist
depreciation_taxes
driveable
employee_body
employee_body_rel { employee_body_rel {
id id
first_name first_name
last_name last_name
} }
employee_refinish_rel { employee_csr
id
first_name
last_name
}
employee_prep_rel {
id
first_name
last_name
}
employee_csr_rel { employee_csr_rel {
id id
first_name first_name
last_name last_name
} }
employee_csr
employee_prep employee_prep
employee_prep_rel {
id
first_name
last_name
}
employee_refinish employee_refinish
employee_body employee_refinish_rel {
alt_transport id
intakechecklist first_name
invoice_final_note last_name
comment }
loss_desc est_co_nm
kmin est_ct_fn
kmout est_ct_ln
referral_source est_ea
referral_source_extra est_ph1
unit_number federal_tax_rate
po_number id
special_coverage_policy
scheduled_delivery
converted
lbr_adjustments
ro_number
po_number
clm_total
inproduction inproduction
vehicleid
plate_no
plate_st
v_vin
v_model_yr
v_model_desc
v_make_desc
v_color
vehicleid
driveable
towin
loss_of_use
lost_sale_reason
vehicle {
id
plate_no
plate_st
v_vin
v_model_yr
v_model_desc
v_make_desc
v_color
notes
v_paint_codes
jobs {
id
ro_number
status
clm_no
}
}
available_jobs {
id
}
ins_co_id
policy_no
loss_date
clm_no
area_of_damage
ins_co_nm
ins_addr1 ins_addr1
ins_city ins_city
ins_co_id
ins_co_nm
ins_ct_ln ins_ct_ln
ins_ct_fn ins_ct_fn
ins_ea ins_ea
ins_ph1 ins_ph1
est_co_nm intakechecklist
est_ct_fn invoice_final_note
est_ct_ln
est_ph1
est_ea
selling_dealer
servicing_dealer
selling_dealer_contact
servicing_dealer_contact
regie_number
scheduled_completion
id
ded_amt
ded_status
depreciation_taxes
other_amount_payable
towing_payable
storage_payable
adjustment_bottom_line
federal_tax_rate
state_tax_rate
local_tax_rate
tax_tow_rt
tax_str_rt
tax_paint_mat_rt
tax_shop_mat_rt
tax_sub_rt
tax_lbr_rt
tax_levies_rt
parts_tax_rates
job_totals
ownr_fn
ownr_ln
ownr_co_nm
ownr_ea
ownr_addr1
ownr_addr2
ownr_city
ownr_st
ownr_zip
ownr_ctry
ownr_ph1
ownr_ph2
production_vars
ca_gst_registrant
ownerid
ded_note
materials
auto_add_ats
rate_ats
iouparent iouparent
job_totals
joblines(where: { removed: { _eq: false } }, order_by: { line_no: asc }) {
act_price
ah_detail_line
alt_partm
alt_partno
billlines(limit: 1, order_by: { bill: { date: desc } }) {
actual_cost
actual_price
bill {
id
invoice_number
vendor {
id
name
}
}
joblineid
id
quantity
}
convertedtolbr
critical
db_hrs
db_price
db_ref
id
ioucreated
lbr_amt
lbr_op
line_desc
line_ind
line_no
line_ref
location
manual_line
mod_lb_hrs
mod_lbr_ty
notes
oem_partno
op_code_desc
part_qty
part_type
prt_dsmk_m
prt_dsmk_p
status
tax_part
unq_seq
}
kmin
kmout
labor_rate_desc
lbr_adjustments
local_tax_rate
loss_date
loss_desc
loss_of_use
lost_sale_reason
materials
other_amount_payable
owner { owner {
id id
ownr_fn ownr_fn
@@ -702,7 +721,40 @@ export const GET_JOB_BY_PK = gql`
ownr_ph2 ownr_ph2
tax_number tax_number
} }
labor_rate_desc owner_owing
ownerid
ownr_addr1
ownr_addr2
ownr_ctry
ownr_city
ownr_co_nm
ownr_ea
ownr_fn
ownr_ln
ownr_ph1
ownr_ph2
ownr_st
ownr_zip
parts_tax_rates
payments {
amount
created_at
date
exportedat
id
jobid
memo
payer
paymentnum
transactionid
type
}
plate_no
plate_st
po_number
policy_no
production_vars
rate_ats
rate_la1 rate_la1
rate_la2 rate_la2
rate_la3 rate_la3
@@ -726,121 +778,64 @@ export const GET_JOB_BY_PK = gql`
rate_mapa rate_mapa
rate_mash rate_mash
rate_matd rate_matd
actual_in regie_number
federal_tax_rate referral_source
local_tax_rate referral_source_extra
state_tax_rate remove_from_ar
ro_number
scheduled_completion scheduled_completion
scheduled_in
actual_completion
scheduled_delivery scheduled_delivery
actual_delivery scheduled_in
date_estimated selling_dealer
date_open servicing_dealer
date_scheduled selling_dealer_contact
date_invoiced servicing_dealer_contact
date_last_contacted special_coverage_policy
date_lost_sale state_tax_rate
date_next_contact
date_towin
date_rentalresp
date_exported
date_repairstarted
date_void
status status
owner_owing storage_payable
tax_registration_number
class
category
deliverchecklist
voided
ca_bc_pvrt
ca_customer_gst
suspended suspended
joblines(where: { removed: { _eq: false } }, order_by: { line_no: asc }) { tax_lbr_rt
tax_levies_rt
tax_paint_mat_rt
tax_registration_number
tax_shop_mat_rt
tax_str_rt
tax_sub_rt
tax_tow_rt
towin
towing_payable
unit_number
updated_at
v_vin
v_model_yr
v_model_desc
v_make_desc
v_color
vehicleid
vehicle {
id id
alt_partm jobs {
line_no clm_no
unq_seq id
line_ind ro_number
line_desc status
line_ref }
part_type
oem_partno
alt_partno
db_price
act_price
part_qty
mod_lbr_ty
db_hrs
mod_lb_hrs
lbr_op
lbr_amt
op_code_desc
status
notes notes
location plate_no
tax_part plate_st
db_ref v_color
manual_line v_make_desc
prt_dsmk_p v_model_desc
prt_dsmk_m v_model_yr
ioucreated v_paint_codes
convertedtolbr v_vin
ah_detail_line
critical
billlines(limit: 1, order_by: { bill: { date: desc } }) {
id
quantity
actual_cost
actual_price
joblineid
bill {
id
invoice_number
vendor {
id
name
}
}
}
}
payments {
id
jobid
amount
payer
paymentnum
created_at
transactionid
memo
date
type
exportedat
}
cccontracts {
id
status
start
scheduledreturn
agreementnumber
courtesycar {
id
make
model
year
plate
fleetnumber
}
}
cieca_ttl
csiinvites {
id
completedon
} }
voided
} }
} }
`; `;
export const GET_JOB_RECONCILIATION_BY_PK = gql` export const GET_JOB_RECONCILIATION_BY_PK = gql`
query GET_JOB_RECONCILIATION_BY_PK($id: uuid!) { query GET_JOB_RECONCILIATION_BY_PK($id: uuid!) {
bills(where: { jobid: { _eq: $id } }) { bills(where: { jobid: { _eq: $id } }) {
@@ -905,6 +900,7 @@ export const GET_JOB_RECONCILIATION_BY_PK = gql`
} }
} }
`; `;
export const QUERY_JOB_CARD_DETAILS = gql` export const QUERY_JOB_CARD_DETAILS = gql`
query QUERY_JOB_CARD_DETAILS($id: uuid!) { query QUERY_JOB_CARD_DETAILS($id: uuid!) {
jobs_by_pk(id: $id) { jobs_by_pk(id: $id) {
@@ -2225,3 +2221,120 @@ export const GET_JOB_LINE_ORDERS = gql`
} }
} }
`; `;
export const UPDATE_REMOVE_FROM_AR = gql`
mutation UPDATE_REMOVE_FROM_AR($jobId: uuid!, $remove_from_ar: Boolean!) {
update_jobs_by_pk(
pk_columns: { id: $jobId }
_set: { remove_from_ar: $remove_from_ar }
) {
id
remove_from_ar
}
}
`;
export const UNVOID_JOB = gql`
mutation UNVOID_JOB(
$jobId: uuid!
$default_imported: String!
$currentUserEmail: String!
$text: String!
) {
update_jobs_by_pk(
pk_columns: { id: $jobId }
_set: { voided: false, status: $default_imported, date_void: null }
) {
id
date_void
voided
status
}
insert_notes(
objects: {
jobid: $jobId
audit: true
created_by: $currentUserEmail
text: $text
}
) {
returning {
id
}
}
}
`;
export const DELETE_INTAKE_CHECKLIST = gql`
mutation DELETE_INTAKE($jobId: uuid!) {
update_jobs_by_pk(
pk_columns: { id: $jobId }
_set: { intakechecklist: null }
) {
id
intakechecklist
}
}
`;
export const DELETE_DELIVERY_CHECKLIST = gql`
mutation DELETE_DELIVERY($jobId: uuid!) {
update_jobs_by_pk(
pk_columns: { id: $jobId }
_set: { deliverchecklist: null }
) {
id
deliverchecklist
}
}
`;
export const MARK_JOB_FOR_REEXPORT = gql`
mutation MARK_JOB_FOR_REEXPORT($jobId: uuid!, $default_invoiced: String!) {
update_jobs_by_pk(
pk_columns: { id: $jobId }
_set: { date_exported: null, status: $default_invoiced }
) {
id
date_exported
status
date_invoiced
}
}
`;
export const MARK_JOB_AS_EXPORTED = gql`
mutation MARK_JOB_AS_EXPORTED(
$jobId: uuid!
$date_exported: timestamptz!
$default_exported: String!
) {
update_jobs_by_pk(
pk_columns: { id: $jobId }
_set: { date_exported: $date_exported, status: $default_exported }
) {
id
date_exported
date_invoiced
status
}
}
`;
export const MARK_JOB_AS_UNINVOICED = gql`
mutation MARK_JOB_AS_UNINVOICED($jobId: uuid!, $default_delivered: String!) {
update_jobs_by_pk(
pk_columns: { id: $jobId }
_set: {
date_exported: null
date_invoiced: null
status: $default_delivered
}
) {
id
date_exported
date_invoiced
status
}
}
`;

View File

@@ -7,16 +7,16 @@ import { useParams } from "react-router-dom";
import AlertComponent from "../../components/alert/alert.component"; import AlertComponent from "../../components/alert/alert.component";
import JobCalculateTotals from "../../components/job-calculate-totals/job-calculate-totals.component"; import JobCalculateTotals from "../../components/job-calculate-totals/job-calculate-totals.component";
import ScoreboardAddButton from "../../components/job-scoreboard-add-button/job-scoreboard-add-button.component"; import ScoreboardAddButton from "../../components/job-scoreboard-add-button/job-scoreboard-add-button.component";
import JobsAdminStatus from "../../components/jobs-admin-change-status/jobs-admin-change.status.component";
import JobsAdminClass from "../../components/jobs-admin-class/jobs-admin-class.component"; import JobsAdminClass from "../../components/jobs-admin-class/jobs-admin-class.component";
import JobsAdminDatesChange from "../../components/jobs-admin-dates/jobs-admin-dates.component"; import JobsAdminDatesChange from "../../components/jobs-admin-dates/jobs-admin-dates.component";
import JobsAdminDeleteIntake from "../../components/jobs-admin-delete-intake/jobs-admin-delete-intake.component"; import JobsAdminDeleteIntake from "../../components/jobs-admin-delete-intake/jobs-admin-delete-intake.component";
import JobsAdminMarkReexport from "../../components/jobs-admin-mark-reexport/jobs-admin-mark-reexport.component"; import JobsAdminMarkReexport from "../../components/jobs-admin-mark-reexport/jobs-admin-mark-reexport.component";
import JobAdminOwnerReassociate from "../../components/jobs-admin-owner-reassociate/jobs-admin-owner-reassociate.component"; import JobAdminOwnerReassociate from "../../components/jobs-admin-owner-reassociate/jobs-admin-owner-reassociate.component";
import JobsAdminRemoveAR from "../../components/jobs-admin-remove-ar/jobs-admin-remove-ar.component";
import JobsAdminUnvoid from "../../components/jobs-admin-unvoid/jobs-admin-unvoid.component"; import JobsAdminUnvoid from "../../components/jobs-admin-unvoid/jobs-admin-unvoid.component";
import JobAdminVehicleReassociate from "../../components/jobs-admin-vehicle-reassociate/jobs-admin-vehicle-reassociate.component"; import JobAdminVehicleReassociate from "../../components/jobs-admin-vehicle-reassociate/jobs-admin-vehicle-reassociate.component";
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component"; import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
import JobsAdminStatus from "../../components/jobs-admin-change-status/jobs-admin-change.status.component";
import NotFound from "../../components/not-found/not-found.component"; import NotFound from "../../components/not-found/not-found.component";
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component"; import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
import { GET_JOB_BY_PK } from "../../graphql/jobs.queries"; import { GET_JOB_BY_PK } from "../../graphql/jobs.queries";
@@ -104,6 +104,7 @@ export function JobsCloseContainer({ setBreadcrumbs, setSelectedHeader }) {
<JobsAdminMarkReexport job={data ? data.jobs_by_pk : {}} /> <JobsAdminMarkReexport job={data ? data.jobs_by_pk : {}} />
<JobsAdminUnvoid job={data ? data.jobs_by_pk : {}} /> <JobsAdminUnvoid job={data ? data.jobs_by_pk : {}} />
<JobsAdminStatus job={data ? data.jobs_by_pk : {}} /> <JobsAdminStatus job={data ? data.jobs_by_pk : {}} />
<JobsAdminRemoveAR job={data ? data.jobs_by_pk : {}} />
</Space> </Space>
</Card> </Card>
</Col> </Col>

View File

@@ -99,6 +99,7 @@
}, },
"audit_trail": { "audit_trail": {
"messages": { "messages": {
"admin_job_remove_from_ar": "ADMIN: Remove from AR updated to: {{status}}",
"admin_jobmarkexported": "ADMIN: Job marked as exported.", "admin_jobmarkexported": "ADMIN: Job marked as exported.",
"admin_jobmarkforreexport": "ADMIN: Job marked for re-export.", "admin_jobmarkforreexport": "ADMIN: Job marked for re-export.",
"admin_jobuninvoice": "ADMIN: Job has been uninvoiced.", "admin_jobuninvoice": "ADMIN: Job has been uninvoiced.",
@@ -1833,6 +1834,7 @@
}, },
"reconciliationheader": "Parts & Sublet Reconciliation", "reconciliationheader": "Parts & Sublet Reconciliation",
"relatedros": "Related ROs", "relatedros": "Related ROs",
"remove_from_ar": "Remove from AR",
"returntotals": "Return Totals", "returntotals": "Return Totals",
"rosaletotal": "RO Parts Total", "rosaletotal": "RO Parts Total",
"sale_additional": "Sales - Additional", "sale_additional": "Sales - Additional",
@@ -2563,6 +2565,7 @@
}, },
"templates": { "templates": {
"anticipated_revenue": "Anticipated Revenue", "anticipated_revenue": "Anticipated Revenue",
"ar_aging": "AR Aging",
"attendance_detail": "Attendance (All Employees)", "attendance_detail": "Attendance (All Employees)",
"attendance_employee": "Employee Attendance", "attendance_employee": "Employee Attendance",
"attendance_summary": "Attendance Summary (All Employees)", "attendance_summary": "Attendance Summary (All Employees)",

View File

@@ -99,6 +99,7 @@
}, },
"audit_trail": { "audit_trail": {
"messages": { "messages": {
"admin_job_remove_from_ar": "",
"admin_jobmarkexported": "", "admin_jobmarkexported": "",
"admin_jobmarkforreexport": "", "admin_jobmarkforreexport": "",
"admin_jobuninvoice": "", "admin_jobuninvoice": "",
@@ -1833,6 +1834,7 @@
}, },
"reconciliationheader": "", "reconciliationheader": "",
"relatedros": "", "relatedros": "",
"remove_from_ar": "",
"returntotals": "", "returntotals": "",
"rosaletotal": "", "rosaletotal": "",
"sale_additional": "", "sale_additional": "",
@@ -2563,6 +2565,7 @@
}, },
"templates": { "templates": {
"anticipated_revenue": "", "anticipated_revenue": "",
"ar_aging": "",
"attendance_detail": "", "attendance_detail": "",
"attendance_employee": "", "attendance_employee": "",
"attendance_summary": "", "attendance_summary": "",

View File

@@ -99,6 +99,7 @@
}, },
"audit_trail": { "audit_trail": {
"messages": { "messages": {
"admin_job_remove_from_ar": "",
"admin_jobmarkexported": "", "admin_jobmarkexported": "",
"admin_jobmarkforreexport": "", "admin_jobmarkforreexport": "",
"admin_jobuninvoice": "", "admin_jobuninvoice": "",
@@ -1833,6 +1834,7 @@
}, },
"reconciliationheader": "", "reconciliationheader": "",
"relatedros": "", "relatedros": "",
"remove_from_ar": "",
"returntotals": "", "returntotals": "",
"rosaletotal": "", "rosaletotal": "",
"sale_additional": "", "sale_additional": "",
@@ -2563,6 +2565,7 @@
}, },
"templates": { "templates": {
"anticipated_revenue": "", "anticipated_revenue": "",
"ar_aging": "",
"attendance_detail": "", "attendance_detail": "",
"attendance_employee": "", "attendance_employee": "",
"attendance_summary": "", "attendance_summary": "",

View File

@@ -1,54 +1,56 @@
import i18n from "i18next"; import i18n from "i18next";
const AuditTrailMapping = { const AuditTrailMapping = {
alertToggle: (status) => i18n.t("audit_trail.messages.alerttoggle", { status }), admin_job_remove_from_ar: (status) =>
i18n.t("audit_trail.messages.admin_job_remove_from_ar", { status }),
admin_jobfieldchange: (field, value) =>
"ADMIN: " +
i18n.t("audit_trail.messages.jobfieldchanged", { field, value }),
admin_jobmarkexported: () =>
i18n.t("audit_trail.messages.admin_jobmarkexported"),
admin_jobmarkforreexport: () =>
i18n.t("audit_trail.messages.admin_jobmarkforreexport"),
admin_jobstatuschange: (status) =>
"ADMIN: " + i18n.t("audit_trail.messages.jobstatuschange", { status }),
admin_jobuninvoice: () => i18n.t("audit_trail.messages.admin_jobuninvoice"),
admin_jobunvoid: () => i18n.t("audit_trail.messages.admin_jobunvoid"),
alertToggle: (status) =>
i18n.t("audit_trail.messages.alerttoggle", { status }),
appointmentcancel: (lost_sale_reason) => appointmentcancel: (lost_sale_reason) =>
i18n.t("audit_trail.messages.appointmentcancel", { lost_sale_reason }), i18n.t("audit_trail.messages.appointmentcancel", { lost_sale_reason }),
appointmentinsert: (start) => appointmentinsert: (start) =>
i18n.t("audit_trail.messages.appointmentinsert", { start }), i18n.t("audit_trail.messages.appointmentinsert", { start }),
jobstatuschange: (status) =>
i18n.t("audit_trail.messages.jobstatuschange", { status }),
admin_jobstatuschange: (status) =>
"ADMIN: " + i18n.t("audit_trail.messages.jobstatuschange", { status }),
jobsupplement: () => i18n.t("audit_trail.messages.jobsupplement"),
jobimported: () => i18n.t("audit_trail.messages.jobimported"),
jobinvoiced: () =>
i18n.t("audit_trail.messages.jobinvoiced"),
jobconverted: (ro_number) =>
i18n.t("audit_trail.messages.jobconverted", { ro_number }),
jobfieldchange: (field, value) =>
i18n.t("audit_trail.messages.jobfieldchanged", { field, value }),
admin_jobfieldchange: (field, value) =>
"ADMIN: " +
i18n.t("audit_trail.messages.jobfieldchanged", { field, value }),
jobspartsorder: (order_number) =>
i18n.t("audit_trail.messages.jobspartsorder", { order_number }),
jobspartsreturn: (order_number) =>
i18n.t("audit_trail.messages.jobspartsreturn", { order_number }),
jobmodifylbradj: ({ mod_lbr_ty, hours }) =>
i18n.t("audit_trail.messages.jobmodifylbradj", { mod_lbr_ty, hours }),
billposted: (invoice_number) => billposted: (invoice_number) =>
i18n.t("audit_trail.messages.billposted", { invoice_number }), i18n.t("audit_trail.messages.billposted", { invoice_number }),
billupdated: (invoice_number) => billupdated: (invoice_number) =>
i18n.t("audit_trail.messages.billupdated", { invoice_number }), i18n.t("audit_trail.messages.billupdated", { invoice_number }),
failedpayment: () => i18n.t("audit_trail.messages.failedpayment"),
jobassignmentchange: (operation, name) => jobassignmentchange: (operation, name) =>
i18n.t("audit_trail.messages.jobassignmentchange", { operation, name }), i18n.t("audit_trail.messages.jobassignmentchange", { operation, name }),
jobassignmentremoved: (operation) => jobassignmentremoved: (operation) =>
i18n.t("audit_trail.messages.jobassignmentremoved", { operation }), i18n.t("audit_trail.messages.jobassignmentremoved", { operation }),
jobinproductionchange: (inproduction) =>
i18n.t("audit_trail.messages.jobinproductionchange", { inproduction }),
jobchecklist: (type, inproduction, status) => jobchecklist: (type, inproduction, status) =>
i18n.t("audit_trail.messages.jobchecklist", { type, inproduction, status }), i18n.t("audit_trail.messages.jobchecklist", { type, inproduction, status }),
jobconverted: (ro_number) =>
i18n.t("audit_trail.messages.jobconverted", { ro_number }),
jobfieldchange: (field, value) =>
i18n.t("audit_trail.messages.jobfieldchanged", { field, value }),
jobimported: () => i18n.t("audit_trail.messages.jobimported"),
jobinproductionchange: (inproduction) =>
i18n.t("audit_trail.messages.jobinproductionchange", { inproduction }),
jobinvoiced: () => i18n.t("audit_trail.messages.jobinvoiced"),
jobmodifylbradj: ({ mod_lbr_ty, hours }) =>
i18n.t("audit_trail.messages.jobmodifylbradj", { mod_lbr_ty, hours }),
jobnoteadded: () => i18n.t("audit_trail.messages.jobnoteadded"), jobnoteadded: () => i18n.t("audit_trail.messages.jobnoteadded"),
jobnoteupdated: () => i18n.t("audit_trail.messages.jobnoteupdated"),
jobnotedeleted: () => i18n.t("audit_trail.messages.jobnotedeleted"), jobnotedeleted: () => i18n.t("audit_trail.messages.jobnotedeleted"),
admin_jobunvoid: () => i18n.t("audit_trail.messages.admin_jobunvoid"), jobnoteupdated: () => i18n.t("audit_trail.messages.jobnoteupdated"),
admin_jobuninvoice: () => i18n.t("audit_trail.messages.admin_jobuninvoice"), jobspartsorder: (order_number) =>
admin_jobmarkforreexport: () => i18n.t("audit_trail.messages.jobspartsorder", { order_number }),
i18n.t("audit_trail.messages.admin_jobmarkforreexport"), jobspartsreturn: (order_number) =>
admin_jobmarkexported: () => i18n.t("audit_trail.messages.jobspartsreturn", { order_number }),
i18n.t("audit_trail.messages.admin_jobmarkexported"), jobstatuschange: (status) =>
failedpayment: () => i18n.t("audit_trail.messages.failedpayment"), i18n.t("audit_trail.messages.jobstatuschange", { status }),
jobsupplement: () => i18n.t("audit_trail.messages.jobsupplement"),
}; };
export default AuditTrailMapping; export default AuditTrailMapping;

View File

@@ -2020,6 +2020,7 @@ export const TemplateList = (type, context) => {
key: "lost_sales", key: "lost_sales",
//idtype: "vendor", //idtype: "vendor",
disabled: false, disabled: false,
datedisable: true,
rangeFilter: { rangeFilter: {
object: i18n.t("reportcenter.labels.objects.jobs"), object: i18n.t("reportcenter.labels.objects.jobs"),
field: i18n.t("jobs.fields.date_lost_sale"), field: i18n.t("jobs.fields.date_lost_sale"),
@@ -2039,6 +2040,15 @@ export const TemplateList = (type, context) => {
}, },
group: "jobs", group: "jobs",
}, },
ar_aging: {
title: i18n.t("reportcenter.templates.ar_aging"),
subject: i18n.t("reportcenter.templates.ar_aging"),
key: "ar_aging",
//idtype: "vendor",
disabled: false,
datedisable: true,
group: "customers",
},
} }
: {}), : {}),
...(!type || type === "courtesycarcontract" ...(!type || type === "courtesycarcontract"