Skip to content

Commit 03a0635

Browse files
committed
inventory validation retrieval
1 parent ae8d2e2 commit 03a0635

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+895
-137
lines changed

data/config.defaultValues.d.ts

+4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ export declare const configDefaultValues: {
1313
'modules.integrityChecker.nhtsaVehicles.isEnabled': boolean;
1414
'modules.integrityChecker.worktechEquipment.isEnabled': boolean;
1515
'modules.integrityChecker.worktechEquipment.mappingFunctions': import("../modules/integrityChecker/config/types.js").ConfigModuleIntegrityCheckerMappingFunctions;
16+
'modules.integrityChecker.fasterInventory.isEnabled': boolean;
17+
'modules.integrityChecker.fasterInventory.validation.source': string;
18+
'modules.integrityChecker.fasterInventory.validation.gpLocationCodesToFasterStorerooms': Record<string, string>;
19+
'modules.integrityChecker.fasterInventory.validation.gpItemFilter': ((item: import("@cityssm/dynamics-gp").GPItemWithQuantity) => boolean) | undefined;
1620
'modules.inventoryScanner.isEnabled': boolean;
1721
'modules.inventoryScanner.scannerIpAddressRegex': RegExp;
1822
'modules.inventoryScanner.fasterSync.integrationId': number | undefined;

helpers/tasks.helpers.js

+8-2
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,15 @@
33
import { minutesToMillis } from '@cityssm/to-millis';
44
const scheduledTaskMinutes = {
55
5: ['inventoryScanner_workOrderValidation_fasterApi'],
6-
10: ['inventoryScanner_workOrderValidation_worktech'],
6+
10: [
7+
'inventoryScanner_workOrderValidation_worktech',
8+
'integrityChecker_fasterInventory'
9+
],
710
15: ['inventoryScanner_itemValidation_dynamicsGp'],
8-
35: ['inventoryScanner_workOrderValidation_fasterApi'],
11+
35: [
12+
'inventoryScanner_workOrderValidation_fasterApi',
13+
'integrityChecker_dynamicsGpInventory'
14+
],
915
40: ['inventoryScanner_workOrderValidation_worktech'],
1016
50: ['integrityChecker_fasterAssets'],
1117
53: ['integrityChecker_worktechEquipment'],

helpers/tasks.helpers.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,15 @@ import type { TaskName } from '../types/tasks.types.js'
77

88
const scheduledTaskMinutes: Record<`${number}`, TaskName[]> = {
99
5: ['inventoryScanner_workOrderValidation_fasterApi'],
10-
10: ['inventoryScanner_workOrderValidation_worktech'],
10+
10: [
11+
'inventoryScanner_workOrderValidation_worktech',
12+
'integrityChecker_fasterInventory'
13+
],
1114
15: ['inventoryScanner_itemValidation_dynamicsGp'],
12-
35: ['inventoryScanner_workOrderValidation_fasterApi'],
15+
35: [
16+
'inventoryScanner_workOrderValidation_fasterApi',
17+
'integrityChecker_dynamicsGpInventory'
18+
],
1319
40: ['inventoryScanner_workOrderValidation_worktech'],
1420
50: ['integrityChecker_fasterAssets'],
1521
53: ['integrityChecker_worktechEquipment'],

modules/integrityChecker/README.md

+8
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
11
# Integrity Checker
22

3+
🧑‍💻 **Under development**
4+
35
Performs various integrity checks on data in FASTER Web.
46

7+
## Asset Checks
8+
59
- Reports on assets with invalid VIN numbers.
610
- Reports on assets in FASTER Web that have no complimentary record in WorkTech,
711
and vice versa.
812

13+
## Item Checks
14+
15+
**Under development**
16+
917
## General Requirements
1018

1119
- 🔗 **SQL Server access** to the WorkTech database.
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
1+
import type { GPItemWithQuantity } from '@cityssm/dynamics-gp';
12
import type { ConfigModuleIntegrityCheckerMappingFunctions } from './types.js';
3+
type GpItemFilterFunction = (item: GPItemWithQuantity) => boolean;
24
declare const _default: {
35
'modules.integrityChecker.isEnabled': boolean;
46
'modules.integrityChecker.fasterAssets.isEnabled': boolean;
57
'modules.integrityChecker.nhtsaVehicles.isEnabled': boolean;
68
'modules.integrityChecker.worktechEquipment.isEnabled': boolean;
79
'modules.integrityChecker.worktechEquipment.mappingFunctions': ConfigModuleIntegrityCheckerMappingFunctions;
10+
'modules.integrityChecker.fasterInventory.isEnabled': boolean;
11+
'modules.integrityChecker.fasterInventory.validation.source': string;
12+
'modules.integrityChecker.fasterInventory.validation.gpLocationCodesToFasterStorerooms': Record<string, string>;
13+
'modules.integrityChecker.fasterInventory.validation.gpItemFilter': GpItemFilterFunction | undefined;
814
};
915
export default _default;

modules/integrityChecker/config/defaultValues.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,9 @@ export default {
55
'modules.integrityChecker.fasterAssets.isEnabled': true,
66
'modules.integrityChecker.nhtsaVehicles.isEnabled': true,
77
'modules.integrityChecker.worktechEquipment.isEnabled': false,
8-
'modules.integrityChecker.worktechEquipment.mappingFunctions': {}
8+
'modules.integrityChecker.worktechEquipment.mappingFunctions': {},
9+
'modules.integrityChecker.fasterInventory.isEnabled': true,
10+
'modules.integrityChecker.fasterInventory.validation.source': '',
11+
'modules.integrityChecker.fasterInventory.validation.gpLocationCodesToFasterStorerooms': {},
12+
'modules.integrityChecker.fasterInventory.validation.gpItemFilter': undefined
913
};

modules/integrityChecker/config/defaultValues.ts

+15-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
// eslint-disable-next-line @eslint-community/eslint-comments/disable-enable-pair
22
/* eslint-disable no-secrets/no-secrets */
33

4+
import type { GPItemWithQuantity } from '@cityssm/dynamics-gp'
5+
46
import type { ConfigModuleIntegrityCheckerMappingFunctions } from './types.js'
57

8+
type GpItemFilterFunction = (item: GPItemWithQuantity) => boolean
9+
610
export default {
711
'modules.integrityChecker.isEnabled': false,
812

@@ -13,5 +17,15 @@ export default {
1317
'modules.integrityChecker.worktechEquipment.isEnabled': false,
1418

1519
'modules.integrityChecker.worktechEquipment.mappingFunctions':
16-
{} as unknown as ConfigModuleIntegrityCheckerMappingFunctions
20+
{} as unknown as ConfigModuleIntegrityCheckerMappingFunctions,
21+
22+
'modules.integrityChecker.fasterInventory.isEnabled': true,
23+
24+
'modules.integrityChecker.fasterInventory.validation.source': '',
25+
26+
'modules.integrityChecker.fasterInventory.validation.gpLocationCodesToFasterStorerooms':
27+
{} as unknown as Record<string, string>,
28+
29+
'modules.integrityChecker.fasterInventory.validation.gpItemFilter':
30+
undefined as unknown as GpItemFilterFunction | undefined
1731
} satisfies Record<`modules.integrityChecker.${string}`, unknown>

modules/integrityChecker/config/types.d.ts

+13
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
1+
import type { GPItemWithQuantity } from '@cityssm/dynamics-gp';
12
import type { AssetResult } from '@cityssm/faster-api';
23
export type FasterAssetMappingFunction = (fasterAsset: AssetResult) => string | undefined;
34
type FasterAssetMappingFunctionName = 'fasterAssetToEquipmentId' | 'fasterAssetToEquipmentClass' | 'fasterAssetToEquipmentDescription' | 'fasterAssetToDepartment';
45
export type ConfigModuleIntegrityCheckerMappingFunctions = Partial<Record<FasterAssetMappingFunctionName, FasterAssetMappingFunction>>;
6+
export interface ConfigItemValidationDynamicsGP {
7+
source: 'dynamicsGP';
8+
gpLocationCodesToFasterStorerooms: Record<string, string>;
9+
gpItemFilter?: (item: GPItemWithQuantity) => boolean;
10+
}
511
export interface ConfigModuleIntegrityChecker {
612
fasterAssets?: {
713
isEnabled?: boolean;
@@ -10,5 +16,12 @@ export interface ConfigModuleIntegrityChecker {
1016
isEnabled?: boolean;
1117
mappingFunctions?: ConfigModuleIntegrityCheckerMappingFunctions;
1218
};
19+
nhtsaVehicles?: {
20+
isEnabled?: boolean;
21+
};
22+
fasterInventory?: {
23+
isEnabled?: boolean;
24+
validation?: ConfigItemValidationDynamicsGP;
25+
};
1326
}
1427
export {};

modules/integrityChecker/config/types.ts

+18
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { GPItemWithQuantity } from '@cityssm/dynamics-gp'
12
import type { AssetResult } from '@cityssm/faster-api'
23

34
export type FasterAssetMappingFunction = (
@@ -14,6 +15,13 @@ export type ConfigModuleIntegrityCheckerMappingFunctions = Partial<
1415
Record<FasterAssetMappingFunctionName, FasterAssetMappingFunction>
1516
>
1617

18+
export interface ConfigItemValidationDynamicsGP {
19+
source: 'dynamicsGP'
20+
gpLocationCodesToFasterStorerooms: Record<string, string>
21+
gpItemFilter?: (item: GPItemWithQuantity) => boolean
22+
}
23+
24+
1725
export interface ConfigModuleIntegrityChecker {
1826
fasterAssets?: {
1927
isEnabled?: boolean
@@ -22,4 +30,14 @@ export interface ConfigModuleIntegrityChecker {
2230
isEnabled?: boolean
2331
mappingFunctions?: ConfigModuleIntegrityCheckerMappingFunctions
2432
}
33+
34+
nhtsaVehicles?: {
35+
isEnabled?: boolean
36+
}
37+
38+
fasterInventory?: {
39+
isEnabled?: boolean
40+
validation?: ConfigItemValidationDynamicsGP
41+
}
42+
2543
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import type sqlite from 'better-sqlite3';
2+
import type { IntegrityDynamicsGpInventoryItem } from '../types.js';
3+
export declare function createOrUpdateDynamicsGpInventoryItem(gpInventoryItem: IntegrityDynamicsGpInventoryItem, connectedDatabase: sqlite.Database): boolean;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
export function createOrUpdateDynamicsGpInventoryItem(gpInventoryItem, connectedDatabase) {
2+
const sql = `insert or replace into DynamicsGpInventoryItems (
3+
itemNumber, locationCode, fasterStoreroom,
4+
itemDescription,
5+
itemShortName,
6+
itemType,
7+
binNumber,
8+
currentCost,
9+
quantityOnHand,
10+
recordUpdate_timeMillis
11+
)
12+
values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`;
13+
const statement = connectedDatabase.prepare(sql);
14+
const success = statement.run(gpInventoryItem.itemNumber, gpInventoryItem.locationCode, gpInventoryItem.fasterStoreroom, gpInventoryItem.itemDescription, gpInventoryItem.itemShortName, gpInventoryItem.itemType, gpInventoryItem.binNumber, gpInventoryItem.currentCost, gpInventoryItem.quantityOnHand, gpInventoryItem.recordUpdate_timeMillis);
15+
return success.changes > 0;
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import type sqlite from 'better-sqlite3'
2+
3+
import type { IntegrityDynamicsGpInventoryItem } from '../types.js'
4+
5+
export function createOrUpdateDynamicsGpInventoryItem(
6+
gpInventoryItem: IntegrityDynamicsGpInventoryItem,
7+
connectedDatabase: sqlite.Database
8+
): boolean {
9+
const sql = `insert or replace into DynamicsGpInventoryItems (
10+
itemNumber, locationCode, fasterStoreroom,
11+
itemDescription,
12+
itemShortName,
13+
itemType,
14+
binNumber,
15+
currentCost,
16+
quantityOnHand,
17+
recordUpdate_timeMillis
18+
)
19+
values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
20+
21+
const statement = connectedDatabase.prepare(sql)
22+
23+
const success = statement.run(
24+
gpInventoryItem.itemNumber,
25+
gpInventoryItem.locationCode,
26+
gpInventoryItem.fasterStoreroom,
27+
gpInventoryItem.itemDescription,
28+
gpInventoryItem.itemShortName,
29+
gpInventoryItem.itemType,
30+
gpInventoryItem.binNumber,
31+
gpInventoryItem.currentCost,
32+
gpInventoryItem.quantityOnHand,
33+
gpInventoryItem.recordUpdate_timeMillis
34+
)
35+
36+
return success.changes > 0
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import type sqlite from 'better-sqlite3';
2+
import type { IntegrityFasterInventoryItem } from '../types.js';
3+
export declare function createOrUpdateFasterInventoryItem(fasterInventoryItem: IntegrityFasterInventoryItem, connectedDatabase: sqlite.Database): boolean;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
export function createOrUpdateFasterInventoryItem(fasterInventoryItem, connectedDatabase) {
2+
const sql = `insert or replace into FasterInventoryItems (
3+
itemNumber, storeroom,
4+
itemName,
5+
binLocation,
6+
averageTrueCost,
7+
quantityInStock,
8+
recordUpdate_timeMillis
9+
)
10+
values (?, ?, ?, ?, ?, ?, ?)`;
11+
const statement = connectedDatabase.prepare(sql);
12+
const success = statement.run(fasterInventoryItem.itemNumber, fasterInventoryItem.storeroom, fasterInventoryItem.itemName, fasterInventoryItem.binLocation, fasterInventoryItem.averageTrueCost, fasterInventoryItem.quantityInStock, fasterInventoryItem.recordUpdate_timeMillis);
13+
return success.changes > 0;
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import type sqlite from 'better-sqlite3'
2+
3+
import type { IntegrityFasterInventoryItem } from '../types.js'
4+
5+
export function createOrUpdateFasterInventoryItem(
6+
fasterInventoryItem: IntegrityFasterInventoryItem,
7+
connectedDatabase: sqlite.Database
8+
): boolean {
9+
const sql = `insert or replace into FasterInventoryItems (
10+
itemNumber, storeroom,
11+
itemName,
12+
binLocation,
13+
averageTrueCost,
14+
quantityInStock,
15+
recordUpdate_timeMillis
16+
)
17+
values (?, ?, ?, ?, ?, ?, ?)`
18+
19+
const statement = connectedDatabase.prepare(sql)
20+
21+
const success = statement.run(
22+
fasterInventoryItem.itemNumber,
23+
fasterInventoryItem.storeroom,
24+
fasterInventoryItem.itemName,
25+
fasterInventoryItem.binLocation,
26+
fasterInventoryItem.averageTrueCost,
27+
fasterInventoryItem.quantityInStock,
28+
fasterInventoryItem.recordUpdate_timeMillis
29+
)
30+
31+
return success.changes > 0
32+
}
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
import type sqlite from 'better-sqlite3';
2-
type RecordTable = 'FasterAssets' | 'WorktechEquipment';
2+
type RecordTable = 'FasterAssets' | 'WorktechEquipment' | 'FasterInventoryItems' | 'DynamicsGpInventoryItems';
33
export declare function deleteExpiredRecords(recordTable: RecordTable, recordUpdateTimeMillis: number, connectedDatabase: sqlite.Database): number;
44
export {};

modules/integrityChecker/database/deleteExpiredRecords.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import type sqlite from 'better-sqlite3'
22

3-
type RecordTable = 'FasterAssets' | 'WorktechEquipment'
3+
type RecordTable =
4+
| 'FasterAssets'
5+
| 'WorktechEquipment'
6+
| 'FasterInventoryItems'
7+
| 'DynamicsGpInventoryItems'
48

59
export function deleteExpiredRecords(
610
recordTable: RecordTable,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export default function getMaxDynamicsGpInventoryItemUpdateMillis(): number;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import sqlite from 'better-sqlite3';
2+
import { databasePath } from './helpers.database.js';
3+
export default function getMaxDynamicsGpInventoryItemUpdateMillis() {
4+
const database = sqlite(databasePath);
5+
const result = database
6+
.prepare(`select max(recordUpdate_timeMillis)
7+
from DynamicsGpInventoryItems`)
8+
.pluck()
9+
.get();
10+
database.close();
11+
return result ?? 0;
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import sqlite from 'better-sqlite3'
2+
3+
import { databasePath } from './helpers.database.js'
4+
5+
export default function getMaxDynamicsGpInventoryItemUpdateMillis(): number {
6+
const database = sqlite(databasePath)
7+
8+
const result = database
9+
.prepare(
10+
`select max(recordUpdate_timeMillis)
11+
from DynamicsGpInventoryItems`
12+
)
13+
.pluck()
14+
.get() as number | undefined
15+
16+
database.close()
17+
18+
return result ?? 0
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export default function getMaxFasterInventoryItemUpdateMillis(): number;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import sqlite from 'better-sqlite3';
2+
import { databasePath } from './helpers.database.js';
3+
export default function getMaxFasterInventoryItemUpdateMillis() {
4+
const database = sqlite(databasePath);
5+
const result = database
6+
.prepare(`select max(recordUpdate_timeMillis)
7+
from FasterInventoryItems`)
8+
.pluck()
9+
.get();
10+
database.close();
11+
return result ?? 0;
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import sqlite from 'better-sqlite3'
2+
3+
import { databasePath } from './helpers.database.js'
4+
5+
export default function getMaxFasterInventoryItemUpdateMillis(): number {
6+
const database = sqlite(databasePath)
7+
8+
const result = database
9+
.prepare(
10+
`select max(recordUpdate_timeMillis)
11+
from FasterInventoryItems`
12+
)
13+
.pluck()
14+
.get() as number | undefined
15+
16+
database.close()
17+
18+
return result ?? 0
19+
}
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export declare const databasePath = "data/integrityChecker.db";
2+
export declare const timeoutMillis: number;
23
export declare function initializeIntegrityCheckerDatabase(): boolean;

0 commit comments

Comments
 (0)