@movalib/movalib-commons 1.62.3 → 1.63.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/devIndex.tsx +15 -4
  2. package/dist/devIndex.js +10 -2
  3. package/dist/index.d.ts +2 -1
  4. package/dist/index.js +6 -4
  5. package/dist/src/components/MovaTableBack/MovaTableBack.d.ts +25 -0
  6. package/dist/src/components/MovaTableBack/MovaTableBack.js +95 -0
  7. package/dist/src/components/vehicle/VehicleFullCard.js +5 -3
  8. package/dist/src/components/vehicle/VehiclePlateField.d.ts +5 -1
  9. package/dist/src/components/vehicle/VehiclePlateField.js +74 -16
  10. package/dist/src/helpers/Enums.d.ts +4 -2
  11. package/dist/src/helpers/Enums.js +2 -0
  12. package/dist/src/helpers/Tools.d.ts +1 -1
  13. package/dist/src/helpers/Tools.js +18 -9
  14. package/dist/src/models/Customer.d.ts +3 -1
  15. package/dist/src/models/Customer.js +9 -5
  16. package/dist/src/models/Document.d.ts +4 -1
  17. package/dist/src/models/Document.js +10 -2
  18. package/dist/src/models/Garage.d.ts +11 -7
  19. package/dist/src/models/Garage.js +5 -1
  20. package/dist/src/models/Vehicle.d.ts +2 -1
  21. package/dist/src/models/Vehicle.js +2 -1
  22. package/dist/src/services/GarageService.types.d.ts +2 -0
  23. package/index.ts +2 -1
  24. package/package.json +1 -1
  25. package/src/components/MovaTableBack/MovaTableBack.tsx +249 -0
  26. package/src/components/vehicle/VehicleFullCard.tsx +47 -43
  27. package/src/components/vehicle/VehiclePlateField.tsx +112 -28
  28. package/src/helpers/Enums.ts +2 -0
  29. package/src/helpers/Tools.ts +18 -8
  30. package/src/models/Customer.ts +49 -45
  31. package/src/models/Document.ts +20 -2
  32. package/src/models/Garage.ts +121 -104
  33. package/src/models/Vehicle.ts +4 -1
  34. package/src/services/GarageService.types.ts +2 -0
  35. package/dist/src/VehiclePlateField.d.ts +0 -8
  36. package/dist/src/VehiclePlateField.js +0 -122
  37. package/src/VehiclePlateField.tsx +0 -165
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  var Document = /** @class */ (function () {
4
- function Document(id, ownerId, state, fileName, originalFileName, fileType, fileSignedUrl, type, creationDate, updateDate, reference, validateToken, remindersCount, totalAmountInclVat, lastSendingTime, firstSendingTime) {
4
+ function Document(id, ownerId, state, fileName, originalFileName, fileType, fileSignedUrl, type, creationDate, updateDate, reference, validateToken, remindersCount, totalAmountInclVat, lastSendingTime, firstSendingTime, eventId, sinaoDocumentId) {
5
5
  this.id = id;
6
6
  this.state = state;
7
7
  this.ownerId = ownerId;
@@ -22,10 +22,18 @@ var Document = /** @class */ (function () {
22
22
  this.firstSendingTime = firstSendingTime
23
23
  ? new Date(firstSendingTime)
24
24
  : undefined;
25
+ this.eventId = eventId;
26
+ this.sinaoDocumentId = sinaoDocumentId;
25
27
  }
26
28
  Document.findByTypeAndReference = function (documents, type, reference) {
27
29
  if (documents && type && reference) {
28
- return documents.find(function (document) { return document.type === type && document.reference === reference; });
30
+ return documents.find(function (document) { return document.type === type && document.eventId === reference; });
31
+ }
32
+ return undefined;
33
+ };
34
+ Document.findManyByTypeAndReference = function (documents, type, reference) {
35
+ if (documents && type && reference) {
36
+ return documents.filter(function (document) { return document.type === type && document.eventId === reference; });
29
37
  }
30
38
  return undefined;
31
39
  };
@@ -1,13 +1,13 @@
1
+ import { OrderPreference, RegistrationState, SlotAlgorithm, SubscriptionPaymentInterval } from "../helpers/Enums";
1
2
  import Address from "./Address";
2
- import Schedule from "./Schedule";
3
+ import CategoryPrestation from "./CategoryPrestation";
4
+ import Document from "./Document";
5
+ import Employee from "./Employee";
3
6
  import Prestation from "./Prestation";
7
+ import Schedule from "./Schedule";
8
+ import Subscription from "./Subscription";
4
9
  import Supplier from "./Supplier";
5
- import Document from "./Document";
6
- import { OrderPreference, RegistrationState, SlotAlgorithm, SubscriptionPaymentInterval } from "../helpers/Enums";
7
10
  import User from "./User";
8
- import Subscription from "./Subscription";
9
- import Employee from "./Employee";
10
- import CategoryPrestation from "./CategoryPrestation";
11
11
  import VehicleGarage from "./VehicleGarage";
12
12
  export default class Garage {
13
13
  id: string;
@@ -55,5 +55,9 @@ export default class Garage {
55
55
  timezone: string;
56
56
  customStyle?: string;
57
57
  mailCustomization?: boolean;
58
- constructor(id: string, adminId: string, name: string, address: Address, workforce: number, prestations: Prestation[], schedules: Schedule[], contactPhone: string, prestationCategories: CategoryPrestation[], dayPeriodFastServiceExcluded: boolean, loanerVehicleFastServiceExcluded: boolean, fastServiceThreshold: number, timezone: string, vehicles?: VehicleGarage[], contactEmail?: string, logo?: string, suppliers?: Supplier[], documents?: Document[], subscriptions?: Subscription[], loanerVehicleActive?: boolean, loanerVehicleRequestActive?: boolean, customStyle?: string, subscription?: Subscription, partialWorkforce?: number, mailCustomization?: boolean);
58
+ billingActive?: boolean;
59
+ billingToken?: string;
60
+ billingSimulationActive?: boolean;
61
+ appId?: number;
62
+ constructor(id: string, adminId: string, name: string, address: Address, workforce: number, prestations: Prestation[], schedules: Schedule[], contactPhone: string, prestationCategories: CategoryPrestation[], dayPeriodFastServiceExcluded: boolean, loanerVehicleFastServiceExcluded: boolean, fastServiceThreshold: number, timezone: string, vehicles?: VehicleGarage[], contactEmail?: string, logo?: string, suppliers?: Supplier[], documents?: Document[], subscriptions?: Subscription[], loanerVehicleActive?: boolean, loanerVehicleRequestActive?: boolean, customStyle?: string, subscription?: Subscription, partialWorkforce?: number, mailCustomization?: boolean, billingActive?: boolean, billingToken?: string, billingSimulationActive?: boolean, appId?: number);
59
63
  }
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  var Garage = /** @class */ (function () {
4
- function Garage(id, adminId, name, address, workforce, prestations, schedules, contactPhone, prestationCategories, dayPeriodFastServiceExcluded, loanerVehicleFastServiceExcluded, fastServiceThreshold, timezone, vehicles, contactEmail, logo, suppliers, documents, subscriptions, loanerVehicleActive, loanerVehicleRequestActive, customStyle, subscription, partialWorkforce, mailCustomization) {
4
+ function Garage(id, adminId, name, address, workforce, prestations, schedules, contactPhone, prestationCategories, dayPeriodFastServiceExcluded, loanerVehicleFastServiceExcluded, fastServiceThreshold, timezone, vehicles, contactEmail, logo, suppliers, documents, subscriptions, loanerVehicleActive, loanerVehicleRequestActive, customStyle, subscription, partialWorkforce, mailCustomization, billingActive, billingToken, billingSimulationActive, appId) {
5
5
  this.id = id;
6
6
  this.adminId = adminId;
7
7
  this.name = name;
@@ -27,6 +27,10 @@ var Garage = /** @class */ (function () {
27
27
  this.customStyle = customStyle;
28
28
  this.timezone = timezone;
29
29
  this.mailCustomization = mailCustomization;
30
+ this.billingActive = billingActive;
31
+ this.billingToken = billingToken;
32
+ this.billingSimulationActive = billingSimulationActive;
33
+ this.appId = appId;
30
34
  }
31
35
  return Garage;
32
36
  }());
@@ -22,6 +22,7 @@ export default class Vehicle {
22
22
  tireSize: VehicleTire;
23
23
  lastInspectionDate: Date;
24
24
  lastMaintenanceDate: Date;
25
- constructor(id: number, ownerId: number, averageMileagePerYear: number, plate: string, brand: string, model: string, version: string, vin: string, currentMileage: number, digitalPassportIndex: DigitalPassportIndex, firstRegistrationDate: Date, ktype: string, tireDiameter: string, tireHeight: string, tireSpeedIndex: string, tireWidth: string, documents: Document[], tireSize: VehicleTire, lastInspectionDate: Date, lastMaintenanceDate: Date);
25
+ foreignPlate: boolean;
26
+ constructor(id: number, ownerId: number, averageMileagePerYear: number, plate: string, brand: string, model: string, version: string, vin: string, currentMileage: number, digitalPassportIndex: DigitalPassportIndex, firstRegistrationDate: Date, ktype: string, tireDiameter: string, tireHeight: string, tireSpeedIndex: string, tireWidth: string, documents: Document[], tireSize: VehicleTire, lastInspectionDate: Date, lastMaintenanceDate: Date, foreignPlate: boolean);
26
27
  getVehicleLabel(): string;
27
28
  }
@@ -11,7 +11,7 @@ Carburant : Essence
11
11
  Cylindrée : 1984 cm3
12
12
  Puissance : 140 KW (190 HP) */
13
13
  var Vehicle = /** @class */ (function () {
14
- function Vehicle(id, ownerId, averageMileagePerYear, plate, brand, model, version, vin, currentMileage, digitalPassportIndex, firstRegistrationDate, ktype, tireDiameter, tireHeight, tireSpeedIndex, tireWidth, documents, tireSize, lastInspectionDate, lastMaintenanceDate) {
14
+ function Vehicle(id, ownerId, averageMileagePerYear, plate, brand, model, version, vin, currentMileage, digitalPassportIndex, firstRegistrationDate, ktype, tireDiameter, tireHeight, tireSpeedIndex, tireWidth, documents, tireSize, lastInspectionDate, lastMaintenanceDate, foreignPlate) {
15
15
  this.id = id;
16
16
  this.ownerId = ownerId;
17
17
  this.averageMileagePerYear = averageMileagePerYear;
@@ -32,6 +32,7 @@ var Vehicle = /** @class */ (function () {
32
32
  this.tireSize = tireSize;
33
33
  this.lastInspectionDate = lastInspectionDate;
34
34
  this.lastMaintenanceDate = lastMaintenanceDate;
35
+ this.foreignPlate = foreignPlate;
35
36
  }
36
37
  Vehicle.prototype.getVehicleLabel = function () {
37
38
  return "".concat(this.brand, " ").concat(this.model, " ").concat(this.version);
@@ -16,6 +16,8 @@ export type AddCustomerVehicleParams = {
16
16
  tireSpeedIndex?: string;
17
17
  lastMaintenanceDate?: string;
18
18
  lastInspectionDate?: string;
19
+ isForeignPlate?: boolean;
20
+ model?: string;
19
21
  };
20
22
  export type DeleteCustomerVehicleParams = {
21
23
  /** L'identifiant unique du garage */
package/index.ts CHANGED
@@ -32,6 +32,7 @@ export { QrCodePLVContainer } from './src/components/QrCodePLVContainer/QrCodePL
32
32
  export { PLVComponent, PrintSize } from './src/components/QrCodePLVContainer/PLVComponent';
33
33
  export {LinkedDocumentDialog} from './src/components/LinkedDocumentDialog';
34
34
  export { default as MovaTable } from './src/components/MovaTable/MovaTable';
35
+ export {default as MovaTableBack} from "./src/components/MovaTableBack/MovaTableBack"
35
36
 
36
37
  // Export des classes
37
38
  export { default as Subscription } from './src/models/Subscription';
@@ -71,7 +72,7 @@ export { readCookie, deleteCookie } from './src/helpers/CookieUtils';
71
72
  export {
72
73
  validateField,
73
74
  formatVehicleTire,
74
- formatFrenchVehiclePlate,
75
+ formatVehiclePlate,
75
76
  isEmpty,
76
77
  getApplicationShortLabel,
77
78
  capitalizeFirstLetter,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@movalib/movalib-commons",
3
- "version": "1.62.3",
3
+ "version": "1.63.0",
4
4
  "description": "Bibliothèque d'objets communs à l'ensemble des projets React de Movalib",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -0,0 +1,249 @@
1
+ import { Refresh } from "@mui/icons-material";
2
+ import SearchIcon from "@mui/icons-material/Search";
3
+ import {
4
+ Box,
5
+ Button,
6
+ InputAdornment,
7
+ LinearProgress,
8
+ Paper,
9
+ Table,
10
+ TableBody,
11
+ TableCell,
12
+ TableContainer,
13
+ TableFooter,
14
+ TableHead,
15
+ TablePagination,
16
+ TableRow,
17
+ TextField,
18
+ debounce,
19
+ } from "@mui/material";
20
+ import {
21
+ ChangeEvent,
22
+ ComponentType,
23
+ MouseEvent,
24
+ useCallback,
25
+ useRef,
26
+ useState,
27
+ } from "react";
28
+
29
+ type TMovaTable<T> = {
30
+ useDataHook: (
31
+ page: number,
32
+ rowsPerPage: number,
33
+ search?: string
34
+ ) => {
35
+ data: T[];
36
+ totalElements: number;
37
+ isLoading: boolean;
38
+ refresh: () => void;
39
+ };
40
+ displayedColumns: {
41
+ displayName: string;
42
+ component: ComponentType<{ element: T }>;
43
+ autoWidth?: boolean;
44
+ }[];
45
+ pagination?: number[];
46
+ compact?: boolean;
47
+ onRowClick?: (data: T) => void;
48
+ onRowRightClick?: (data: T, event: MouseEvent<HTMLTableRowElement>) => void;
49
+ isClickable?: (data: T) => boolean;
50
+ onRowDoubleClick?: (data: T) => void;
51
+ filterChildren?: React.ReactNode;
52
+ };
53
+
54
+ export default function MovaTableBack<T>({
55
+ useDataHook,
56
+ displayedColumns,
57
+ pagination,
58
+ compact,
59
+ onRowClick,
60
+ onRowRightClick,
61
+ onRowDoubleClick,
62
+ isClickable,
63
+ filterChildren,
64
+ }: TMovaTable<T>) {
65
+ const [currentPageIndex, setCurrentPageIndex] = useState<number>(0);
66
+ const [rowsPerPage, setRowsPerPage] = useState<number>(25);
67
+ const [search, setSearch] = useState("");
68
+ const clickTimeout = useRef<ReturnType<typeof setTimeout> | null>(null);
69
+
70
+ const { data, totalElements, isLoading, refresh } = useDataHook(
71
+ currentPageIndex,
72
+ rowsPerPage,
73
+ search
74
+ );
75
+
76
+ const handleDoubleClick = useCallback(
77
+ (element: T) => {
78
+ if (!onRowDoubleClick) return;
79
+
80
+ if (clickTimeout.current) {
81
+ clearTimeout(clickTimeout.current);
82
+ clickTimeout.current = null;
83
+ }
84
+
85
+ onRowDoubleClick(element);
86
+ },
87
+ [onRowDoubleClick]
88
+ );
89
+
90
+ const handleRowClick = useCallback(
91
+ (element: T) => {
92
+ if (!onRowClick) return;
93
+
94
+ if (clickTimeout.current) return;
95
+
96
+ clickTimeout.current = setTimeout(() => {
97
+ onRowClick(element);
98
+ clickTimeout.current = null;
99
+ }, 200);
100
+ },
101
+ [onRowClick]
102
+ );
103
+
104
+ const handlePageChange = (
105
+ event: MouseEvent<HTMLButtonElement> | null,
106
+ page: number
107
+ ) => {
108
+ setCurrentPageIndex(page);
109
+ };
110
+
111
+ const handleRowsPerPageChange = (
112
+ event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
113
+ ) => {
114
+ setCurrentPageIndex(0);
115
+ setRowsPerPage(Number(event.target.value));
116
+ };
117
+
118
+ const handleSearchChange = debounce((event) => {
119
+ const search = event?.target.value;
120
+ if (search.length > 2) {
121
+ setSearch(search);
122
+ setCurrentPageIndex(0);
123
+ } else {
124
+ setSearch("");
125
+ setCurrentPageIndex(0);
126
+ }
127
+ }, 700);
128
+
129
+ return (
130
+ <div style={{ height: "100%", display: "flex", flexDirection: "column" }}>
131
+ <Box
132
+ sx={{
133
+ width: "50%",
134
+ my: 2,
135
+ px: 2,
136
+ display: "flex",
137
+ gap: 2,
138
+ }}
139
+ >
140
+ <TextField
141
+ size="small"
142
+ type="search"
143
+ onChange={handleSearchChange}
144
+ inputProps={{
145
+ startAdornment: (
146
+ <InputAdornment position="start">
147
+ <SearchIcon />
148
+ </InputAdornment>
149
+ ),
150
+ }}
151
+ sx={{ width: "100%" }}
152
+ placeholder="Rechercher"
153
+ />
154
+ {refresh && (
155
+ <Button size="small" onClick={refresh} variant="contained">
156
+ <Refresh />
157
+ </Button>
158
+ )}
159
+ </Box>
160
+ {filterChildren && filterChildren}
161
+ <TableContainer sx={{ height: "100%" }} component={Paper}>
162
+ <Table
163
+ size={compact ? "small" : "medium"}
164
+ sx={{ height: "100%" }}
165
+ stickyHeader
166
+ >
167
+ <TableHead>
168
+ <TableRow>
169
+ {displayedColumns.map((column, index) => (
170
+ <TableCell key={index}>{column.displayName}</TableCell>
171
+ ))}
172
+ </TableRow>
173
+ </TableHead>
174
+ <TableBody sx={{ overflowY: "auto" }}>
175
+ {isLoading && (
176
+ <TableRow>
177
+ <TableCell colSpan={5} sx={{ padding: 0 }}>
178
+ <LinearProgress />
179
+ </TableCell>
180
+ </TableRow>
181
+ )}
182
+
183
+ {data?.length !== 0 &&
184
+ data?.map((element, index) => (
185
+ <TableRow
186
+ onDoubleClick={() => {
187
+ handleDoubleClick(element);
188
+ }}
189
+ onClick={() => handleRowClick(element)}
190
+ onContextMenu={(event) =>
191
+ onRowRightClick && onRowRightClick(element, event)
192
+ }
193
+ sx={{
194
+ backgroundColor: "white",
195
+ cursor: isClickable
196
+ ? isClickable(element)
197
+ ? "pointer"
198
+ : "default"
199
+ : "pointer",
200
+ height: "auto",
201
+ }}
202
+ hover
203
+ key={index}
204
+ >
205
+ {displayedColumns.map((column, index) => (
206
+ <TableCell
207
+ key={index}
208
+ sx={
209
+ column.autoWidth
210
+ ? {
211
+ whiteSpace: "nowrap",
212
+ width: "1%",
213
+ maxWidth: "fit-content",
214
+ }
215
+ : {}
216
+ }
217
+ >
218
+ {column.component && (
219
+ <column.component element={element} />
220
+ )}
221
+ </TableCell>
222
+ ))}
223
+ </TableRow>
224
+ ))}
225
+ <TableRow sx={{ height: "100%" }} />
226
+ </TableBody>
227
+
228
+ {pagination && pagination.length > 0 && (
229
+ <TableFooter
230
+ sx={{ position: "sticky", bottom: 0, backgroundColor: "white" }}
231
+ >
232
+ <TableRow>
233
+ <TablePagination
234
+ count={totalElements}
235
+ onPageChange={handlePageChange}
236
+ page={currentPageIndex}
237
+ rowsPerPage={rowsPerPage}
238
+ labelRowsPerPage="Lignes par page :"
239
+ onRowsPerPageChange={handleRowsPerPageChange}
240
+ rowsPerPageOptions={pagination}
241
+ />
242
+ </TableRow>
243
+ </TableFooter>
244
+ )}
245
+ </Table>
246
+ </TableContainer>
247
+ </div>
248
+ );
249
+ }
@@ -38,7 +38,7 @@ import {
38
38
  } from "../../helpers/Enums";
39
39
  import Logger from "../../helpers/Logger";
40
40
  import {
41
- formatFrenchVehiclePlate,
41
+ formatVehiclePlate,
42
42
  formatVehicleTire,
43
43
  } from "../../helpers/Tools";
44
44
  import { MovaFormField, MovaVehicleForm } from "../../helpers/Types";
@@ -438,7 +438,7 @@ const VehicleFullCard: FC<VehicleFullCardProps> = ({
438
438
  color={theme.palette.text.primary}
439
439
  sx={{ position: "absolute", top: "8px", left: "76px" }}
440
440
  >
441
- <b>{formatFrenchVehiclePlate(vehicle.plate)}</b>
441
+ <b>{formatVehiclePlate(vehicle.plate, vehicle.foreignPlate)}</b>
442
442
  </Typography>
443
443
  </Grid>
444
444
  {onDelete && (
@@ -692,51 +692,55 @@ const VehicleFullCard: FC<VehicleFullCardProps> = ({
692
692
  </Grid>
693
693
 
694
694
  {vehicle.documents &&
695
- vehicle.documents?.map((invoice, index) => (
696
- <Grid
697
- container
698
- sx={{
699
- justifyContent: "space-between",
700
- alignItems: "center",
701
- }}
702
- key={index + 1}
703
- >
704
- <Grid
705
- item
706
- xs={11}
707
- key={(index + 1) * 50}
708
- sx={{ textAlign: "left" }}
709
- >
710
- <Tooltip title={invoice.originalFileName}>
711
- <Link
712
- color={darken("#F29ABA", 0.2)}
713
- href={invoice.fileSignedUrl}
714
- target="_blank"
715
- rel="noopener"
716
- >
717
- <Typography variant="body1">
718
- {invoice.fileName}
719
- </Typography>
720
- </Link>
721
- </Tooltip>
722
- </Grid>
695
+ vehicle.documents
696
+ ?.filter((doc) => doc.fileSignedUrl)
697
+ .map((invoice, index) => (
723
698
  <Grid
724
- item
725
- xs={1}
726
- key={(index + 1) * 100}
727
- sx={{ textAlign: "right" }}
699
+ container
700
+ sx={{
701
+ justifyContent: "space-between",
702
+ alignItems: "center",
703
+ }}
704
+ key={index + 1}
728
705
  >
729
- <IconButton
730
- disabled={
731
- !(invoice.ownerId.toString() == currentUser.id)
732
- }
733
- onClick={(e) => handleDeleteDocument(e, invoice?.id)}
706
+ <Grid
707
+ item
708
+ xs={11}
709
+ key={(index + 1) * 50}
710
+ sx={{ textAlign: "left" }}
734
711
  >
735
- <CloseIcon />
736
- </IconButton>
712
+ <Tooltip title={invoice.originalFileName}>
713
+ <Link
714
+ color={darken("#F29ABA", 0.2)}
715
+ href={invoice.fileSignedUrl}
716
+ target="_blank"
717
+ rel="noopener"
718
+ >
719
+ <Typography variant="body1">
720
+ {invoice.fileName}
721
+ </Typography>
722
+ </Link>
723
+ </Tooltip>
724
+ </Grid>
725
+ <Grid
726
+ item
727
+ xs={1}
728
+ key={(index + 1) * 100}
729
+ sx={{ textAlign: "right" }}
730
+ >
731
+ <IconButton
732
+ disabled={
733
+ !(invoice.ownerId.toString() == currentUser.id)
734
+ }
735
+ onClick={(e) =>
736
+ handleDeleteDocument(e, invoice?.id)
737
+ }
738
+ >
739
+ <CloseIcon />
740
+ </IconButton>
741
+ </Grid>
737
742
  </Grid>
738
- </Grid>
739
- ))}
743
+ ))}
740
744
 
741
745
  {/* * Les FACTURES du véhicule
742
746
  {vehicle.documents && vehicle.documents?.filter(doc => doc.type === DocumentType.VEHICLE_MAINTENANCE_INVOICE)