vr-commons 1.0.157 → 1.0.159

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.
@@ -1,23 +1,6 @@
1
1
  import { Device, UserRole } from "vr-models";
2
2
  import { Transaction } from "sequelize";
3
- import { StockChangeResult } from "./types";
4
- export interface LockAllDevicesResult {
5
- success: boolean;
6
- lockedCount: number;
7
- failedCount: number;
8
- failedDeviceIds: string[];
9
- errors: string[];
10
- message: string;
11
- totalProcessed: number;
12
- }
13
- export interface LockDevicesOptions {
14
- actorId?: string;
15
- actorRole?: UserRole | string;
16
- transaction?: any;
17
- batchSize?: number;
18
- maxRetries?: number;
19
- triggeredBy?: "cronjob" | "manual";
20
- }
3
+ import { LockAllDevicesResult, LockDevicesOptions, StockChangeResult } from "./types";
21
4
  export declare const stockUtil: {
22
5
  /**
23
6
  * Increment stock when devices are added/created
@@ -138,9 +121,9 @@ export declare const stockUtil: {
138
121
  devices: Device[];
139
122
  }>;
140
123
  /**
141
- * Lock ALL devices regardless of payment plan status
124
+ * Lock ALL device pairs regardless of payment plan status
125
+ * Locks both RIDER and PASSENGER devices in each pair together
142
126
  * Uses batch processing for large datasets
143
- * If no transaction is provided, runs without transaction
144
127
  */
145
128
  lockAllDevices(options?: LockDevicesOptions): Promise<LockAllDevicesResult>;
146
129
  };
@@ -453,33 +453,33 @@ exports.stockUtil = {
453
453
  };
454
454
  },
455
455
  /**
456
- * Lock ALL devices regardless of payment plan status
456
+ * Lock ALL device pairs regardless of payment plan status
457
+ * Locks both RIDER and PASSENGER devices in each pair together
457
458
  * Uses batch processing for large datasets
458
- * If no transaction is provided, runs without transaction
459
459
  */
460
460
  async lockAllDevices(options = {}) {
461
461
  const { actorId = "SYSTEM", actorRole = "SYSTEM", transaction, batchSize = 100, maxRetries = 3, triggeredBy = "manual", } = options;
462
462
  const isSystem = actorRole === "SYSTEM" || triggeredBy === "cronjob";
463
- const isAdmin = !isSystem;
464
463
  try {
465
- const lockedDeviceIds = [];
466
- const failedDeviceIds = [];
464
+ const lockedPairIds = [];
465
+ const failedPairIds = [];
467
466
  const errors = [];
468
- let totalLocked = 0;
469
- let totalProcessed = 0;
467
+ let totalLockedDevices = 0;
468
+ let totalProcessedPairs = 0;
470
469
  let batchNumber = 0;
471
470
  let hasMore = true;
472
- console.log(`🔒 Locking ALL devices at ${new Date().toISOString()}`);
471
+ let offset = 0;
472
+ console.log(`🔒 Locking ALL device pairs at ${new Date().toISOString()}`);
473
473
  // Log start of job
474
474
  if (isSystem) {
475
- await (0, systemLog_utils_1.logInfo)(`Lock all devices job started`, {
475
+ await (0, systemLog_utils_1.logInfo)(`Lock all device pairs job started`, {
476
476
  category: "CRONJOB",
477
477
  source: "device-lock.cronjob",
478
478
  details: { triggeredBy, batchSize, maxRetries },
479
479
  });
480
480
  }
481
481
  else {
482
- await (0, systemLog_utils_1.logInfo)(`Lock all devices triggered by ${actorRole}`, {
482
+ await (0, systemLog_utils_1.logInfo)(`Lock all device pairs triggered by ${actorRole}`, {
483
483
  category: "DEVICE",
484
484
  userId: actorId || undefined,
485
485
  userRole: actorRole,
@@ -487,132 +487,170 @@ exports.stockUtil = {
487
487
  details: { triggeredBy, batchSize, maxRetries },
488
488
  });
489
489
  }
490
+ // ✅ Get the sequelize instance from the model
491
+ const sequelizeInstance = vr_models_1.Device.sequelize;
492
+ if (!sequelizeInstance) {
493
+ throw new Error("Sequelize instance not available");
494
+ }
490
495
  // Process in batches
491
496
  while (hasMore) {
492
497
  batchNumber++;
493
- const offset = (batchNumber - 1) * batchSize;
494
- // Get devices for current batch (ALL devices except disabled)
495
- const devices = await vr_models_1.Device.findAll({
496
- where: {
497
- status: { [sequelize_1.Op.ne]: "disabled" },
498
- deletedAt: null,
498
+ offset = (batchNumber - 1) * batchSize;
499
+ // ✅ Use raw query to get distinct pairIds with both devices
500
+ const [pairIdsResult] = await sequelizeInstance.query(`
501
+ SELECT "pairId"
502
+ FROM "devices"
503
+ WHERE "status" != 'disabled'
504
+ AND "deletedAt" IS NULL
505
+ GROUP BY "pairId"
506
+ HAVING COUNT(*) = 2
507
+ ORDER BY "pairId" ASC
508
+ LIMIT :limit
509
+ OFFSET :offset
510
+ `, {
511
+ replacements: {
512
+ limit: batchSize,
513
+ offset: offset,
499
514
  },
500
- limit: batchSize,
501
- offset: offset,
502
- transaction: transaction, // Use transaction if provided, otherwise undefined
515
+ type: "SELECT",
516
+ transaction: transaction,
503
517
  });
504
- if (devices.length === 0) {
518
+ const pairIds = pairIdsResult.map((p) => p.pairId);
519
+ if (pairIds.length === 0) {
505
520
  hasMore = false;
506
521
  break;
507
522
  }
508
- totalProcessed += devices.length;
509
- console.log(`📦 Batch ${batchNumber}: Processing ${devices.length} devices (Total: ${totalProcessed})`);
510
- // Process each device with retry logic
511
- for (const device of devices) {
523
+ totalProcessedPairs += pairIds.length;
524
+ console.log(`📦 Batch ${batchNumber}: Processing ${pairIds.length} pairs (Total: ${totalProcessedPairs})`);
525
+ // Process each pair
526
+ for (const pairId of pairIds) {
512
527
  let retries = 0;
513
- let locked = false;
514
- while (!locked && retries < maxRetries) {
528
+ let pairLocked = false;
529
+ while (!pairLocked && retries < maxRetries) {
515
530
  try {
516
- // Skip if already locked
517
- if (device.status === "locked") {
518
- console.log(`🔒 Device ${device.serialNumber} already locked`);
519
- locked = true;
531
+ // Get both devices in the pair
532
+ const devices = await vr_models_1.Device.findAll({
533
+ where: {
534
+ pairId: pairId,
535
+ status: { [sequelize_1.Op.ne]: "disabled" },
536
+ deletedAt: null,
537
+ },
538
+ transaction: transaction,
539
+ });
540
+ if (devices.length !== 2) {
541
+ throw new Error(`Incomplete pair ${pairId}: expected 2 devices, found ${devices.length}`);
542
+ }
543
+ // Check if both devices are already locked
544
+ const allLocked = devices.every((d) => d.status === "locked");
545
+ if (allLocked) {
546
+ console.log(`🔒 Pair ${pairId} already fully locked`);
547
+ pairLocked = true;
520
548
  break;
521
549
  }
522
- // Lock the device
523
- await device.update({ status: "locked" }, { transaction: transaction } // Use transaction if provided
524
- );
525
- lockedDeviceIds.push(device.id);
526
- totalLocked++;
527
- locked = true;
528
- console.log(`🔒 Locked device ${device.serialNumber} (${device.id})`);
529
- // Log event for each lock
530
- await (0, eventLog_utils_1.logEvent)({
531
- actorId: isSystem ? null : actorId,
532
- actorType: isSystem ? "ADMIN" : actorRole,
533
- action: "DEVICES_LOCKED",
534
- entity: "Device",
535
- entityId: device.id,
536
- metadata: {
537
- serialNumber: device.serialNumber,
538
- pairId: device.pairId,
539
- productId: device.productId,
540
- lockedAt: new Date().toISOString(),
541
- reason: "Scheduled lock all devices",
542
- triggeredBy: triggeredBy,
543
- batchNumber,
544
- previousStatus: device.status,
550
+ // Lock both devices
551
+ const deviceIds = devices.map((d) => d.id);
552
+ await vr_models_1.Device.update({ status: "locked" }, {
553
+ where: {
554
+ id: { [sequelize_1.Op.in]: deviceIds },
545
555
  },
546
- deviceSession: null,
547
556
  transaction: transaction,
548
557
  });
558
+ lockedPairIds.push(pairId);
559
+ totalLockedDevices += devices.length;
560
+ pairLocked = true;
561
+ console.log(`🔒 Locked pair ${pairId} (${devices.length} devices)`);
562
+ // Log event for each device in the pair
563
+ for (const device of devices) {
564
+ await (0, eventLog_utils_1.logEvent)({
565
+ actorId: isSystem ? null : actorId,
566
+ actorType: isSystem ? "ADMIN" : actorRole,
567
+ action: "DEVICES_LOCKED",
568
+ entity: "Device",
569
+ entityId: device.id,
570
+ metadata: {
571
+ serialNumber: device.serialNumber,
572
+ pairId: device.pairId,
573
+ dedicatedUser: device.dedicatedUser,
574
+ productId: device.productId,
575
+ lockedAt: new Date().toISOString(),
576
+ reason: "Scheduled lock all devices",
577
+ triggeredBy: triggeredBy,
578
+ batchNumber,
579
+ previousStatus: device.status,
580
+ isPartOfPair: true,
581
+ },
582
+ deviceSession: null,
583
+ transaction: transaction,
584
+ });
585
+ }
549
586
  }
550
587
  catch (err) {
551
588
  retries++;
552
- console.error(`❌ Failed to lock device ${device.serialNumber} (attempt ${retries}/${maxRetries}):`, err instanceof Error ? err.message : "Unknown error");
589
+ console.error(`❌ Failed to lock pair ${pairId} (attempt ${retries}/${maxRetries}):`, err instanceof Error ? err.message : "Unknown error");
553
590
  if (retries >= maxRetries) {
554
- failedDeviceIds.push(device.id);
555
- errors.push(`Device ${device.serialNumber} (${device.id}): ${err instanceof Error ? err.message : "Unknown error"}`);
591
+ failedPairIds.push(pairId);
592
+ errors.push(`Pair ${pairId}: ${err instanceof Error ? err.message : "Unknown error"}`);
556
593
  }
557
594
  else {
558
- // Wait before retry (exponential backoff)
559
595
  await new Promise((resolve) => setTimeout(resolve, retries * 1000));
560
596
  }
561
597
  }
562
598
  }
563
599
  }
564
- // If we got fewer devices than batch size, we're done
565
- if (devices.length < batchSize) {
600
+ if (pairIds.length < batchSize) {
566
601
  hasMore = false;
567
602
  }
568
603
  }
569
604
  const result = {
570
605
  success: true,
571
- lockedCount: totalLocked,
572
- failedCount: failedDeviceIds.length,
573
- failedDeviceIds,
606
+ lockedCount: totalLockedDevices,
607
+ failedCount: failedPairIds.length,
608
+ failedPairIds,
574
609
  errors,
575
- totalProcessed,
576
- message: `Successfully locked ${totalLocked} devices out of ${totalProcessed} processed${failedDeviceIds.length > 0 ? `, ${failedDeviceIds.length} failed` : ""}`,
610
+ totalProcessed: totalProcessedPairs,
611
+ pairsProcessed: totalProcessedPairs,
612
+ message: `Successfully locked ${totalLockedDevices} devices (${lockedPairIds.length} pairs) out of ${totalProcessedPairs} pairs processed${failedPairIds.length > 0
613
+ ? `, ${failedPairIds.length} pairs failed`
614
+ : ""}`,
577
615
  };
578
- console.log(`✅ Lock all devices completed:`, result);
616
+ console.log(`✅ Lock all device pairs completed:`, result);
579
617
  // Log completion
580
618
  if (isSystem) {
581
- await (0, systemLog_utils_1.logInfo)(`Lock all devices job completed`, {
619
+ await (0, systemLog_utils_1.logInfo)(`Lock all device pairs job completed`, {
582
620
  category: "CRONJOB",
583
621
  source: "device-lock.cronjob",
584
622
  details: {
585
- lockedCount: result.lockedCount,
586
- failedCount: result.failedCount,
587
- totalProcessed: result.totalProcessed,
623
+ lockedDevices: result.lockedCount,
624
+ lockedPairs: lockedPairIds.length,
625
+ failedPairs: result.failedCount,
626
+ totalPairs: result.pairsProcessed,
588
627
  hasErrors: result.errors.length > 0,
589
628
  },
590
629
  });
591
630
  }
592
631
  else {
593
- await (0, systemLog_utils_1.logInfo)(`Lock all devices completed by ${actorRole}`, {
632
+ await (0, systemLog_utils_1.logInfo)(`Lock all device pairs completed by ${actorRole}`, {
594
633
  category: "DEVICE",
595
634
  userId: actorId || undefined,
596
635
  userRole: actorRole,
597
636
  source: "device-lock.manual",
598
637
  details: {
599
- lockedCount: result.lockedCount,
600
- failedCount: result.failedCount,
601
- totalProcessed: result.totalProcessed,
638
+ lockedDevices: result.lockedCount,
639
+ lockedPairs: lockedPairIds.length,
640
+ failedPairs: result.failedCount,
641
+ totalPairs: result.pairsProcessed,
602
642
  hasErrors: result.errors.length > 0,
603
643
  },
604
644
  });
605
645
  }
606
- // Log errors if any
607
646
  if (result.errors.length > 0) {
608
- await (0, systemLog_utils_1.logError)(`Lock all devices had ${result.errors.length} failures`, {
647
+ await (0, systemLog_utils_1.logError)(`Lock all device pairs had ${result.errors.length} failures`, {
609
648
  category: isSystem ? "CRONJOB" : "DEVICE",
610
649
  source: isSystem ? "device-lock.cronjob" : "device-lock.manual",
611
650
  userId: isSystem ? null : actorId || undefined,
612
651
  userRole: isSystem ? null : actorRole,
613
652
  details: {
614
- failedCount: result.failedCount,
615
- failedDeviceIds: result.failedDeviceIds,
653
+ failedPairs: result.failedPairIds,
616
654
  errors: result.errors,
617
655
  },
618
656
  });
@@ -620,27 +658,27 @@ exports.stockUtil = {
620
658
  return result;
621
659
  }
622
660
  catch (err) {
623
- console.error("❌ Lock all devices failed:", err);
661
+ console.error("❌ Lock all device pairs failed:", err);
624
662
  const errorMessage = err instanceof Error ? err.message : "Unknown error occurred";
625
663
  const result = {
626
664
  success: false,
627
665
  lockedCount: 0,
628
666
  failedCount: 0,
629
- failedDeviceIds: [],
667
+ failedPairIds: [],
630
668
  errors: [errorMessage],
631
669
  totalProcessed: 0,
632
- message: `Lock all devices job failed: ${errorMessage}`,
670
+ pairsProcessed: 0,
671
+ message: `Lock all device pairs job failed: ${errorMessage}`,
633
672
  };
634
- // Log failure
635
673
  if (isSystem) {
636
- await (0, systemLog_utils_1.logError)(`Lock all devices job failed`, {
674
+ await (0, systemLog_utils_1.logError)(`Lock all device pairs job failed`, {
637
675
  category: "CRONJOB",
638
676
  source: "device-lock.cronjob",
639
677
  details: { error: errorMessage },
640
678
  });
641
679
  }
642
680
  else {
643
- await (0, systemLog_utils_1.logError)(`Lock all devices failed`, {
681
+ await (0, systemLog_utils_1.logError)(`Lock all device pairs failed`, {
644
682
  category: "DEVICE",
645
683
  userId: actorId || undefined,
646
684
  userRole: actorRole,
@@ -1,3 +1,4 @@
1
+ import { UserRole } from "vr-models";
1
2
  export type VerificationMethod = "SMS" | "EMAIL";
2
3
  export interface PendingRegistration {
3
4
  id: string;
@@ -34,3 +35,21 @@ export interface StockChangeResult {
34
35
  productId: string;
35
36
  productName: string;
36
37
  }
38
+ export interface LockAllDevicesResult {
39
+ success: boolean;
40
+ lockedCount: number;
41
+ failedCount: number;
42
+ failedPairIds: string[];
43
+ errors: string[];
44
+ message: string;
45
+ totalProcessed: number;
46
+ pairsProcessed: number;
47
+ }
48
+ export interface LockDevicesOptions {
49
+ actorId?: string;
50
+ actorRole?: UserRole | string;
51
+ transaction?: any;
52
+ batchSize?: number;
53
+ maxRetries?: number;
54
+ triggeredBy?: "cronjob" | "manual";
55
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vr-commons",
3
- "version": "1.0.157",
3
+ "version": "1.0.159",
4
4
  "description": "Shared functions package",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",