diff --git a/.prettierrc.js b/.prettierrc.js
new file mode 100644
index 000000000..a2bd52a34
--- /dev/null
+++ b/.prettierrc.js
@@ -0,0 +1,16 @@
+exports.default = {
+ printWidth: 120,
+ useTabs: false,
+ tabWidth: 2,
+ trailingComma: "es5",
+ semi: true,
+ singleQuote: false,
+ bracketSpacing: true,
+ arrowParens: "always",
+ jsxSingleQuote: false,
+ bracketSameLine: false,
+ endOfLine: "lf",
+ importOrder: ["^@core/(.*)$", "^@server/(.*)$", "^@ui/(.*)$", "^[./]"],
+ importOrderSeparation: true,
+ importOrderSortSpecifiers: true,
+};
diff --git a/_reference/reportFiltersAndSorters.md b/_reference/reportFiltersAndSorters.md
index bcaa08ade..2aea3f11a 100644
--- a/_reference/reportFiltersAndSorters.md
+++ b/_reference/reportFiltersAndSorters.md
@@ -3,6 +3,15 @@
This documentation details the schema required for `.filters` files on the report server. It is used to dynamically
modify the graphQL query and provide the user more power over their reports.
+For filters and sorters, valid types include (`type` key in the schema):
+- string (default)
+- number
+- bool or boolean
+- date
+
+## Special Notes
+- When passing the data to the template server, the property filters and sorters is added to the data object and will reflect the filters and sorters the user has selected
+
## High level Schema Overview
```javascript
@@ -36,6 +45,38 @@ const schema = {
Filters effect the where clause of the graphQL query. They are used to filter the data returned from the server.
A note on special notation used in the `name` field.
+## Reflection
+
+Filters can make use of reflection to pre-fill select boxes, the following is an example of that in the filters file.
+
+```json
+ {
+ "name": "jobs.status",
+ "translation": "jobs.fields.status",
+ "label": "Status",
+ "type": "string",
+ "reflector": {
+ "type": "internal",
+ "name": "special.job_statuses"
+ }
+ },
+```
+
+in this example, a reflector with the type 'internal' (all types at the moment require this, and it is used for future functionality), with a name of `special.job_statuses`
+
+The following cases are available
+
+- `special.job_statuses` - This will reflect the statuses of the jobs table `bodyshop.md_ro_statuses.statuses'`
+- `special.cost_centers` - This will reflect the cost centers `bodyshop.md_responsibility_centers.costs`
+- `special.categories` - This will reflect the categories `bodyshop.md_categories`
+- `special.insurance_companies` - This will reflect the insurance companies `bodyshop.md_ins_cos`'
+- `special.employee_teams` - This will reflect the employee teams `bodyshop.employee_teams`
+- `special.employees` - This will reflect the employees `bodyshop.employees`
+- `special.first_names` - This will reflect the first names `bodyshop.employees`
+- `special.last_names` - This will reflect the last names `bodyshop.employees`
+- `special.referral_sources` - This will reflect the referral sources `bodyshop.md_referral_sources
+- `special.class`- This will reflect the class `bodyshop.md_classes`
+-
### Path without brackets, multi level
`"name": "jobs.joblines.mod_lb_hrs",`
@@ -71,8 +112,8 @@ query gendoc_hours_sold_detail_open($starttz: timestamptz!, $endtz: timestamptz!
}
```
-
### Path with brackets,top level
+
`"name": "[jobs].joblines.mod_lb_hrs",`
This will produce a where clause at the `jobs` level of the graphQL query.
@@ -107,14 +148,37 @@ query gendoc_hours_sold_detail_open($starttz: timestamptz!, $endtz: timestamptz!
```
## Known Caveats
-- Will only support two level of nesting in the graphQL query `jobs.joblines.mod_lb_hrs` vs `[jobs].joblines.mod_lb_hrs` is fine, but `jobs.[joblines.].some_table.mod_lb_hrs` is not.
-- The `dates` object is not yet implemented and will be added in a future release.
-- The type object must be 'string' or 'number' and is case-sensitive.
+
+- Will only support two level of nesting in the graphQL query `jobs.joblines.mod_lb_hrs` vs `[jobs].joblines.mod_lb_hrs`
+ is fine, but `jobs.[joblines.].some_table.mod_lb_hrs` is not.
+- The type object must be 'string' or 'number' or 'bool' or 'boolean' or 'date' and is case-sensitive.
- The `translation` key is used to look up the label in the GUI, if it is not found, the `label` key is used.
-- Do not add the ability to filter things that are already filtered as part of the original query, this would be redundant and could cause issues.
+- Do not add the ability to filter things that are already filtered as part of the original query, this would be
+ redundant and could cause issues.
- Do not add the ability to filter on things like FK constraints, must like the above example.
-
## Sorters
-- Sorters follow the same schema as filters, however, they do not do square bracket wrapping to indicate level hoisting, a filter added on `job.md_status` would be added at the top level, and a filter added on `jobs.joblines.mod_lb_hrs` would be added at the `joblines` level.
-- Most of the reports currently do sorting on a template level, this will need to change to actually see the results using the sorters.
+
+- Sorters follow the same schema as filters, however, they do not do square bracket wrapping to indicate level hoisting,
+ a filter added on `job.md_status` would be added at the top level, and a filter added on `jobs.joblines.mod_lb_hrs`
+ would be added at the `joblines` level.
+- Most of the reports currently do sorting on a template level, this will need to change to actually see the results
+ using the sorters.
+
+### Default Sorters
+
+- A sorter can be given a default object containing a `order` and `direction` key value. This will be used to sort the report if the user does not select any of the sorters themselves.
+- The `order` key is the order in which the sorters are applied, and the `direction` key is the direction of the sort, either `asc` or `desc`.
+
+```json
+{
+ "name": "jobs.joblines.mod_lb_hrs",
+ "translation": "jobs.joblines.mod_lb_hrs_1",
+ "label": "mod_lb_hrs_1",
+ "type": "number",
+ "default": {
+ "order": 1,
+ "direction": "asc"
+ }
+}
+```
diff --git a/client/src/components/bill-delete-button/bill-delete-button.component.jsx b/client/src/components/bill-delete-button/bill-delete-button.component.jsx
index 5d2d154f6..ca3f3822d 100644
--- a/client/src/components/bill-delete-button/bill-delete-button.component.jsx
+++ b/client/src/components/bill-delete-button/bill-delete-button.component.jsx
@@ -3,10 +3,22 @@ import { useMutation } from "@apollo/client";
import { Button, notification, Popconfirm } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
+import { connect } from "react-redux";
+import { createStructuredSelector } from "reselect";
import { DELETE_BILL } from "../../graphql/bills.queries";
+import { insertAuditTrail } from "../../redux/application/application.actions";
+import AuditTrailMapping from "../../utils/AuditTrailMappings";
import RbacWrapper from "../rbac-wrapper/rbac-wrapper.component";
-export default function BillDeleteButton({ bill, callback }) {
+const mapStateToProps = createStructuredSelector({});
+const mapDispatchToProps = (dispatch) => ({
+ insertAuditTrail: ({ jobid, operation }) =>
+ dispatch(insertAuditTrail({ jobid, operation })),
+});
+
+export default connect(mapStateToProps, mapDispatchToProps)(BillDeleteButton);
+
+export function BillDeleteButton({ bill, jobid, callback, insertAuditTrail }) {
const [loading, setLoading] = useState(false);
const { t } = useTranslation();
const [deleteBill] = useMutation(DELETE_BILL);
@@ -36,6 +48,10 @@ export default function BillDeleteButton({ bill, callback }) {
if (!!!result.errors) {
notification["success"]({ message: t("bills.successes.deleted") });
+ insertAuditTrail({
+ jobid: jobid,
+ operation: AuditTrailMapping.billdeleted(bill.invoice_number),
+ });
if (callback && typeof callback === "function") callback(bill.id);
} else {
diff --git a/client/src/components/bills-list-table/bills-list-table.component.jsx b/client/src/components/bills-list-table/bills-list-table.component.jsx
index 9dea48f71..5f5bd7011 100644
--- a/client/src/components/bills-list-table/bills-list-table.component.jsx
+++ b/client/src/components/bills-list-table/bills-list-table.component.jsx
@@ -9,8 +9,8 @@ import { setModalContext } from "../../redux/modals/modals.actions";
import { selectBodyshop } from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { DateFormatter } from "../../utils/DateFormatter";
-import { alphaSort, dateSort } from "../../utils/sorters";
import { TemplateList } from "../../utils/TemplateConstants";
+import { alphaSort, dateSort } from "../../utils/sorters";
import BillDeleteButton from "../bill-delete-button/bill-delete-button.component";
import BillDetailEditReturnComponent from "../bill-detail-edit/bill-detail-edit-return.component";
import PrintWrapperComponent from "../print-wrapper/print-wrapper.component";
@@ -58,7 +58,7 @@ export function BillsListTableComponent({