IO-2543 AR Aging

This commit is contained in:
Allan Carr
2024-01-24 16:01:48 -08:00
parent 9274742520
commit 03d4e4dcd1
9 changed files with 366 additions and 275 deletions

View File

@@ -0,0 +1,63 @@
import { gql, useMutation } from "@apollo/client";
import { Form, Switch, notification } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
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 [updateJob] = useMutation(gql`
mutation REMOVE_FROM_AR_JOB($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
}
}
`);
const handleChange = async (value) => {
setLoading(true);
const result = await updateJob({
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 (
<Form.Item name="remove_from_ar" label={t("jobs.labels.remove_from_ar")}>
<Switch checked={switchValue} loading={loading} onChange={handleChange} />
</Form.Item>
);
}

View File

@@ -239,20 +239,30 @@ export function ReportCenterModalComponent({ reportCenterModal }) {
else return null;
}}
</Form.Item>
<Form.Item
name="dates"
label={t("reportcenter.labels.dates")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<DatePicker.RangePicker
format="MM/DD/YYYY"
ranges={DatePIckerRanges}
/>
<Form.Item style={{ margin: 0, padding: 0 }} dependencies={["key"]}>
{() => {
const key = form.getFieldValue("key");
const datedisable = Templates[key] && Templates[key].datedisable;
if (datedisable !== true) {
return (
<Form.Item
name="dates"
label={t("reportcenter.labels.dates")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<DatePicker.RangePicker
format="MM/DD/YYYY"
ranges={DatePIckerRanges}
/>
</Form.Item>
);
} else return null;
}}
</Form.Item>
<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`
query GET_JOB_BY_PK($id: uuid!) {
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 {
id
first_name
last_name
}
employee_refinish_rel {
id
first_name
last_name
}
employee_prep_rel {
id
first_name
last_name
}
employee_csr
employee_csr_rel {
id
first_name
last_name
}
employee_csr
employee_prep
employee_prep_rel {
id
first_name
last_name
}
employee_refinish
employee_body
alt_transport
intakechecklist
invoice_final_note
comment
loss_desc
kmin
kmout
referral_source
referral_source_extra
unit_number
po_number
special_coverage_policy
scheduled_delivery
converted
lbr_adjustments
ro_number
po_number
clm_total
employee_refinish_rel {
id
first_name
last_name
}
est_co_nm
est_ct_fn
est_ct_ln
est_ea
est_ph1
federal_tax_rate
id
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_city
ins_co_id
ins_co_nm
ins_ct_ln
ins_ct_fn
ins_ea
ins_ph1
est_co_nm
est_ct_fn
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
intakechecklist
invoice_final_note
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 {
id
ownr_fn
@@ -702,7 +721,40 @@ export const GET_JOB_BY_PK = gql`
ownr_ph2
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_la2
rate_la3
@@ -726,121 +778,64 @@ export const GET_JOB_BY_PK = gql`
rate_mapa
rate_mash
rate_matd
actual_in
federal_tax_rate
local_tax_rate
state_tax_rate
regie_number
referral_source
referral_source_extra
remove_from_ar
ro_number
scheduled_completion
scheduled_in
actual_completion
scheduled_delivery
actual_delivery
date_estimated
date_open
date_scheduled
date_invoiced
date_last_contacted
date_lost_sale
date_next_contact
date_towin
date_rentalresp
date_exported
date_repairstarted
date_void
scheduled_in
selling_dealer
servicing_dealer
selling_dealer_contact
servicing_dealer_contact
special_coverage_policy
state_tax_rate
status
owner_owing
tax_registration_number
class
category
deliverchecklist
voided
ca_bc_pvrt
ca_customer_gst
storage_payable
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
alt_partm
line_no
unq_seq
line_ind
line_desc
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
jobs {
clm_no
id
ro_number
status
}
notes
location
tax_part
db_ref
manual_line
prt_dsmk_p
prt_dsmk_m
ioucreated
convertedtolbr
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
plate_no
plate_st
v_color
v_make_desc
v_model_desc
v_model_yr
v_paint_codes
v_vin
}
voided
}
}
`;
export const GET_JOB_RECONCILIATION_BY_PK = gql`
query GET_JOB_RECONCILIATION_BY_PK($id: uuid!) {
bills(where: { jobid: { _eq: $id } }) {
@@ -905,6 +900,7 @@ export const GET_JOB_RECONCILIATION_BY_PK = gql`
}
}
`;
export const QUERY_JOB_CARD_DETAILS = gql`
query QUERY_JOB_CARD_DETAILS($id: uuid!) {
jobs_by_pk(id: $id) {

View File

@@ -7,16 +7,16 @@ import { useParams } from "react-router-dom";
import AlertComponent from "../../components/alert/alert.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 JobsAdminStatus from "../../components/jobs-admin-change-status/jobs-admin-change.status.component";
import JobsAdminClass from "../../components/jobs-admin-class/jobs-admin-class.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 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 JobsAdminRemoveAR from "../../components/jobs-admin-remove-ar/jobs-admin-remove-ar.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 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 RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
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 : {}} />
<JobsAdminUnvoid job={data ? data.jobs_by_pk : {}} />
<JobsAdminStatus job={data ? data.jobs_by_pk : {}} />
<JobsAdminRemoveAR job={data ? data.jobs_by_pk : {}} />
</Space>
</Card>
</Col>

View File

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

View File

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

View File

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

View File

@@ -1,54 +1,56 @@
import i18n from "i18next";
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) =>
i18n.t("audit_trail.messages.appointmentcancel", { lost_sale_reason }),
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) =>
i18n.t("audit_trail.messages.billposted", { invoice_number }),
billupdated: (invoice_number) =>
i18n.t("audit_trail.messages.billupdated", { invoice_number }),
failedpayment: () => i18n.t("audit_trail.messages.failedpayment"),
jobassignmentchange: (operation, name) =>
i18n.t("audit_trail.messages.jobassignmentchange", { operation, name }),
jobassignmentremoved: (operation) =>
i18n.t("audit_trail.messages.jobassignmentremoved", { operation }),
jobinproductionchange: (inproduction) =>
i18n.t("audit_trail.messages.jobinproductionchange", { inproduction }),
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"),
jobnoteupdated: () => i18n.t("audit_trail.messages.jobnoteupdated"),
jobnotedeleted: () => i18n.t("audit_trail.messages.jobnotedeleted"),
admin_jobunvoid: () => i18n.t("audit_trail.messages.admin_jobunvoid"),
admin_jobuninvoice: () => i18n.t("audit_trail.messages.admin_jobuninvoice"),
admin_jobmarkforreexport: () =>
i18n.t("audit_trail.messages.admin_jobmarkforreexport"),
admin_jobmarkexported: () =>
i18n.t("audit_trail.messages.admin_jobmarkexported"),
failedpayment: () => i18n.t("audit_trail.messages.failedpayment"),
jobnoteupdated: () => i18n.t("audit_trail.messages.jobnoteupdated"),
jobspartsorder: (order_number) =>
i18n.t("audit_trail.messages.jobspartsorder", { order_number }),
jobspartsreturn: (order_number) =>
i18n.t("audit_trail.messages.jobspartsreturn", { order_number }),
jobstatuschange: (status) =>
i18n.t("audit_trail.messages.jobstatuschange", { status }),
jobsupplement: () => i18n.t("audit_trail.messages.jobsupplement"),
};
export default AuditTrailMapping;

View File

@@ -2020,6 +2020,7 @@ export const TemplateList = (type, context) => {
key: "lost_sales",
//idtype: "vendor",
disabled: false,
datedisable: true,
rangeFilter: {
object: i18n.t("reportcenter.labels.objects.jobs"),
field: i18n.t("jobs.fields.date_lost_sale"),
@@ -2039,6 +2040,15 @@ export const TemplateList = (type, context) => {
},
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"