@fabriktor/fx 0.0.141 → 0.0.143
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.
- package/dist/src/routes/departure.d.ts +1 -0
- package/dist/src/routes/departure.js +33 -14
- package/dist/src/routes/planning.js +1 -0
- package/dist/src/routes/routes.d.ts +2 -0
- package/dist/src/routes/routes.js +6 -1
- package/dist/src/routes/validation.d.ts +1 -0
- package/dist/src/routes/validation.js +27 -2
- package/package.json +3 -3
|
@@ -68,20 +68,39 @@ export function validateRoutePlanLocation(location, owner_id, timezone) {
|
|
|
68
68
|
// Re-read saved operational addresses before optimization. A queued draft must
|
|
69
69
|
// not submit stale location ownership, Place IDs or address timezones.
|
|
70
70
|
export async function validateRoutePlanAddresses(readers, opts) {
|
|
71
|
-
const { input,
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
current
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
71
|
+
const { input, current, signal } = opts;
|
|
72
|
+
const endpoints = [
|
|
73
|
+
{
|
|
74
|
+
place: input.start_place_id,
|
|
75
|
+
reference: opts.departure,
|
|
76
|
+
saved: current?.start_place_id,
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
place: input.end_place_id,
|
|
80
|
+
reference: opts.end,
|
|
81
|
+
saved: current?.end_place_id,
|
|
82
|
+
},
|
|
83
|
+
];
|
|
84
|
+
for (const { place, reference, saved } of endpoints) {
|
|
85
|
+
if (!place)
|
|
86
|
+
continue;
|
|
87
|
+
if (!reference)
|
|
88
|
+
throw new PreActionBlocked(RoutePlanningBlock.Departure);
|
|
89
|
+
if (reference.source === RouteDepartureSource.SavedRoute) {
|
|
90
|
+
// Returning to an unchanged saved departure also works on existing routes.
|
|
91
|
+
if (!current ||
|
|
92
|
+
current.id !== reference.route_id ||
|
|
93
|
+
current.owner_id !== opts.owner_id ||
|
|
94
|
+
current.timezone !== input.timezone ||
|
|
95
|
+
(place !== saved && place !== current.start_place_id))
|
|
96
|
+
throw new PreActionBlocked(RoutePlanningBlock.DepartureChanged);
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
const endpoint = await loadRouteDeparture(readers, opts.owner_id, reference, signal);
|
|
100
|
+
if (endpoint.address.place_id !== place ||
|
|
101
|
+
addressTimezone(endpoint.address) !== input.timezone)
|
|
102
|
+
throw new PreActionBlocked(RoutePlanningBlock.DepartureChanged);
|
|
103
|
+
}
|
|
85
104
|
}
|
|
86
105
|
for (const destination of input.destinations) {
|
|
87
106
|
const location = (await readers.jobs.findOneLocation({
|
|
@@ -39,6 +39,7 @@ export function newRoutePlan(opts) {
|
|
|
39
39
|
from: { ...opts.day, h: opts.company.work_day_start_hour, min: 0 },
|
|
40
40
|
to: { ...opts.day, h: opts.company.work_day_end_hour, min: 0 },
|
|
41
41
|
start_place_id: opts.start_place_id,
|
|
42
|
+
end_place_id: "",
|
|
42
43
|
vehicles: [],
|
|
43
44
|
destinations: [],
|
|
44
45
|
consider_traffic: routePlanningDefaults.consider_traffic,
|
|
@@ -23,6 +23,7 @@ export type CreateRouteResult = CreateValidatedRouteResult;
|
|
|
23
23
|
export type CreatePlannedRouteOptions = Omit<PrepareRouteOptions, "request"> & {
|
|
24
24
|
attempt: MultiCreateAttempt;
|
|
25
25
|
departure: RouteDepartureReference;
|
|
26
|
+
end?: RouteDepartureReference;
|
|
26
27
|
};
|
|
27
28
|
export type ReplaceRouteOptions = RouteReplaceOptions & {
|
|
28
29
|
availability?: RPRoutesAvailability;
|
|
@@ -39,6 +40,7 @@ export type ReplacePlannedRouteOptions = RouteMutationOptions & {
|
|
|
39
40
|
in: InRoute;
|
|
40
41
|
days_ago: PrepareRouteOptions["days_ago"];
|
|
41
42
|
departure: RouteDepartureReference;
|
|
43
|
+
end?: RouteDepartureReference;
|
|
42
44
|
};
|
|
43
45
|
export type CreateTagOptions = TagInsertOptions & Pick<MultiCreateCheckpoint, "before_request" | "on_created">;
|
|
44
46
|
export type ReplaceTagOptions = TagReplaceOptions;
|
|
@@ -60,6 +60,7 @@ export class RoutesFX {
|
|
|
60
60
|
owner_id: actor.owner_id,
|
|
61
61
|
input: opts.in,
|
|
62
62
|
departure: opts.departure,
|
|
63
|
+
end: opts.end,
|
|
63
64
|
signal: attempt.signal,
|
|
64
65
|
});
|
|
65
66
|
}
|
|
@@ -124,6 +125,9 @@ export class RoutesFX {
|
|
|
124
125
|
...(opts.in.start_place_id !== undefined
|
|
125
126
|
? { start_place_id: input.start_place_id }
|
|
126
127
|
: {}),
|
|
128
|
+
...(opts.in.end_place_id !== undefined
|
|
129
|
+
? { end_place_id: input.end_place_id }
|
|
130
|
+
: {}),
|
|
127
131
|
override_itinerary,
|
|
128
132
|
},
|
|
129
133
|
});
|
|
@@ -140,6 +144,7 @@ export class RoutesFX {
|
|
|
140
144
|
owner_id: opts.actor.owner_id,
|
|
141
145
|
input,
|
|
142
146
|
departure: opts.departure,
|
|
147
|
+
end: opts.end,
|
|
143
148
|
current,
|
|
144
149
|
signal: opts.signal,
|
|
145
150
|
});
|
|
@@ -150,7 +155,7 @@ export class RoutesFX {
|
|
|
150
155
|
days_ago: opts.days_ago,
|
|
151
156
|
request: { signal: opts.signal },
|
|
152
157
|
});
|
|
153
|
-
//
|
|
158
|
+
// Repeated locations are allowed; employee conflicts remain enforced.
|
|
154
159
|
validateRouteInput(input, availability, current.id);
|
|
155
160
|
const result = await this.replaceRoute({
|
|
156
161
|
id: current.id,
|
|
@@ -6,6 +6,7 @@ export declare function routeInput(input: InRoute): InRoute;
|
|
|
6
6
|
export declare function validateRouteInput(input: InRoute, availability?: RPRoutesAvailability, replacing_route_id?: string): void;
|
|
7
7
|
export declare function validateRouteDestination(destination: InRoute["destinations"][number], window: WindowInput): void;
|
|
8
8
|
export declare function availableRouteIDs(availability: RPRoutesAvailability, kind: keyof RPRoutesAvailability["availables"], replacing_route_id?: string): Set<string>;
|
|
9
|
+
export declare function routeAssignmentsByEntity(assignments: RPRoutesAvailability["assignations"]["locations"], replacing_route_id?: string): Map<string, string[]>;
|
|
9
10
|
export declare function validateClientAvailabilityInput(input: InClientAvailability): void;
|
|
10
11
|
export declare function validateRouteTeamInput(input: InRouteTeam): void;
|
|
11
12
|
export declare function normalizedTagInput(input: InTag): InTag;
|
|
@@ -78,6 +78,7 @@ export function routeInput(input) {
|
|
|
78
78
|
employee_ids: vehicle.employee_ids.map((id) => id.trim()),
|
|
79
79
|
})),
|
|
80
80
|
start_place_id: input.start_place_id.trim(),
|
|
81
|
+
end_place_id: input.end_place_id?.trim() ?? "",
|
|
81
82
|
destinations: input.destinations.map((destination) => ({
|
|
82
83
|
tags: normalizeRouteTags(destination.tags),
|
|
83
84
|
location_id: destination.location_id.trim(),
|
|
@@ -165,10 +166,17 @@ export function validateRouteDestination(destination, window) {
|
|
|
165
166
|
});
|
|
166
167
|
}
|
|
167
168
|
}
|
|
168
|
-
//
|
|
169
|
-
//
|
|
169
|
+
// Locations may be visited on several routes. Employees stay exclusive for
|
|
170
|
+
// the checked day; editing may retain only this route's employee assignments.
|
|
170
171
|
export function availableRouteIDs(availability, kind, replacing_route_id) {
|
|
171
172
|
const ids = new Set(normalizeIDs(availability.availables[kind]));
|
|
173
|
+
if (kind === "locations") {
|
|
174
|
+
for (const assignment of availability.assignations.locations) {
|
|
175
|
+
for (const id of normalizeIDs(assignment.entity_ids))
|
|
176
|
+
ids.add(id);
|
|
177
|
+
}
|
|
178
|
+
return ids;
|
|
179
|
+
}
|
|
172
180
|
for (const assignment of availability.assignations[kind]) {
|
|
173
181
|
if (assignment.route_id === replacing_route_id) {
|
|
174
182
|
for (const id of normalizeIDs(assignment.entity_ids))
|
|
@@ -183,6 +191,23 @@ export function availableRouteIDs(availability, kind, replacing_route_id) {
|
|
|
183
191
|
}
|
|
184
192
|
return ids;
|
|
185
193
|
}
|
|
194
|
+
// Group the backend's existing route references for informational display.
|
|
195
|
+
// Exclude the route being edited and count each route only once per entity.
|
|
196
|
+
export function routeAssignmentsByEntity(assignments, replacing_route_id) {
|
|
197
|
+
const out = new Map();
|
|
198
|
+
for (const assignment of assignments) {
|
|
199
|
+
const routeID = resolvedID(assignment.route_id);
|
|
200
|
+
if (!routeID || routeID === replacing_route_id)
|
|
201
|
+
continue;
|
|
202
|
+
for (const entityID of normalizeIDs(assignment.entity_ids)) {
|
|
203
|
+
const routes = out.get(entityID) ?? [];
|
|
204
|
+
if (!routes.includes(routeID))
|
|
205
|
+
routes.push(routeID);
|
|
206
|
+
out.set(entityID, routes);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return out;
|
|
210
|
+
}
|
|
186
211
|
export function validateClientAvailabilityInput(input) {
|
|
187
212
|
validateRouteTimeWindow(input);
|
|
188
213
|
for (const field of ["employer_id", "location_id"]) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fabriktor/fx",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.143",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -17,9 +17,9 @@
|
|
|
17
17
|
"typescript": "^6.0.3"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@fabriktor/client": "0.0.
|
|
20
|
+
"@fabriktor/client": "0.0.99",
|
|
21
21
|
"@fabriktor/fx": "0.0.94",
|
|
22
|
-
"@fabriktor/schema": "0.0.
|
|
22
|
+
"@fabriktor/schema": "0.0.69",
|
|
23
23
|
"convert": "8.0.2"
|
|
24
24
|
}
|
|
25
25
|
}
|