generate-past-orders.ts 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. import {
  2. bootstrapWorker,
  3. CustomerService,
  4. isGraphQlErrorResult,
  5. Logger,
  6. OrderService,
  7. ProductVariantService,
  8. RequestContextService,
  9. ShippingMethodService,
  10. TransactionalConnection,
  11. } from '@vendure/core';
  12. import dayjs from 'dayjs';
  13. import { devConfig } from '../dev-config';
  14. const loggerCtx = 'DataSync script';
  15. generatePastOrders()
  16. .then(() => process.exit(0))
  17. .catch(() => process.exit(1));
  18. const DAYS_TO_COVER = 30;
  19. const MIN_ORDERS_PER_DAY = 5;
  20. const MAX_ORDERS_PER_DAY = 10;
  21. const MAX_RETRIES = 3;
  22. // This script generates a large number of past Orders over the past <DAYS_TO_COVER> days.
  23. // It is useful for testing scenarios where there are a large number of Orders in the system.
  24. async function generatePastOrders() {
  25. const { app } = await bootstrapWorker(devConfig);
  26. const requestContextService = app.get(RequestContextService);
  27. const orderService = app.get(OrderService);
  28. const customerService = app.get(CustomerService);
  29. const productVariantService = app.get(ProductVariantService);
  30. const shippingMethodService = app.get(ShippingMethodService);
  31. const connection = app.get(TransactionalConnection);
  32. const ctx = await requestContextService.create({
  33. apiType: 'shop',
  34. });
  35. const ctxAdmin = await requestContextService.create({
  36. apiType: 'admin',
  37. });
  38. const { items: variants } = await productVariantService.findAll(ctxAdmin, { take: 500 });
  39. const { items: customers } = await customerService.findAll(ctxAdmin, { take: 500 }, ['user']);
  40. for (let i = DAYS_TO_COVER; i > 0; i--) {
  41. const targetDate = dayjs().subtract(DAYS_TO_COVER - i, 'day');
  42. const numberOfOrders =
  43. Math.floor(Math.random() * (MAX_ORDERS_PER_DAY - MIN_ORDERS_PER_DAY + 1)) + MIN_ORDERS_PER_DAY;
  44. Logger.info(`Generating ${numberOfOrders} orders for ${targetDate.format('YYYY-MM-DD')}`);
  45. let successfulOrders = 0;
  46. let retryCount = 0;
  47. while (successfulOrders < numberOfOrders && retryCount < MAX_RETRIES) {
  48. const customer = getRandomItem(customers);
  49. if (!customer.user) {
  50. retryCount++;
  51. continue;
  52. }
  53. try {
  54. const order = await orderService.create(ctx, customer.user.id);
  55. const result = await orderService.addItemToOrder(
  56. ctx,
  57. order.id,
  58. getRandomItem(variants).id,
  59. Math.floor(Math.random() * 3) + 1,
  60. );
  61. if (isGraphQlErrorResult(result)) {
  62. Logger.error(`Failed to add item to order: ${result.message}`);
  63. retryCount++;
  64. continue;
  65. }
  66. const eligibleShippingMethods = await orderService.getEligibleShippingMethods(ctx, order.id);
  67. if (eligibleShippingMethods.length === 0) {
  68. Logger.error('No eligible shipping methods found');
  69. retryCount++;
  70. continue;
  71. }
  72. await orderService.setShippingMethod(ctx, order.id, [
  73. getRandomItem(eligibleShippingMethods).id,
  74. ]);
  75. const transitionResult = await orderService.transitionToState(
  76. ctx,
  77. order.id,
  78. 'ArrangingPayment',
  79. );
  80. if (isGraphQlErrorResult(transitionResult)) {
  81. Logger.error(`Failed to transition order state: ${transitionResult.message}`);
  82. retryCount++;
  83. continue;
  84. }
  85. const eligiblePaymentMethods = await orderService.getEligiblePaymentMethods(ctx, order.id);
  86. if (eligiblePaymentMethods.length === 0) {
  87. Logger.error('No eligible payment methods found');
  88. retryCount++;
  89. continue;
  90. }
  91. const paymentResult = await orderService.addPaymentToOrder(ctx, order.id, {
  92. method: getRandomItem(eligiblePaymentMethods).code,
  93. metadata: {},
  94. });
  95. if (isGraphQlErrorResult(paymentResult)) {
  96. Logger.error(`Failed to add payment: ${paymentResult.message}`);
  97. retryCount++;
  98. continue;
  99. }
  100. const randomHourOfDay = Math.floor(Math.random() * 24);
  101. const placedAt = targetDate.startOf('day').add(randomHourOfDay, 'hour').toDate();
  102. await connection.getRepository(ctx, 'Order').update(order.id, {
  103. orderPlacedAt: placedAt,
  104. });
  105. successfulOrders++;
  106. retryCount = 0; // Reset retry count on success
  107. } catch (error: unknown) {
  108. Logger.error(
  109. `Error creating order: ${error instanceof Error ? error.message : String(error)}`,
  110. );
  111. retryCount++;
  112. }
  113. }
  114. if (successfulOrders < numberOfOrders) {
  115. Logger.warn(
  116. `Failed to generate all ${numberOfOrders} orders for ${targetDate.format('YYYY-MM-DD')}. Generated ${successfulOrders} orders.`,
  117. );
  118. } else {
  119. Logger.info(
  120. `Successfully generated ${successfulOrders} orders for ${targetDate.format('YYYY-MM-DD')}`,
  121. );
  122. }
  123. }
  124. }
  125. // get random item from array
  126. function getRandomItem<T>(array: T[]): T {
  127. return array[Math.floor(Math.random() * array.length)];
  128. }