/ src / scripts / seed.ts
seed.ts
  1  import { CreateInventoryLevelInput, ExecArgs } from "@medusajs/framework/types";
  2  import {
  3    ContainerRegistrationKeys,
  4    Modules,
  5    ProductStatus,
  6  } from "@medusajs/framework/utils";
  7  import {
  8    createApiKeysWorkflow,
  9    createInventoryLevelsWorkflow,
 10    createProductCategoriesWorkflow,
 11    createProductsWorkflow,
 12    createRegionsWorkflow,
 13    createSalesChannelsWorkflow,
 14    createShippingOptionsWorkflow,
 15    createShippingProfilesWorkflow,
 16    createStockLocationsWorkflow,
 17    createTaxRegionsWorkflow,
 18    linkSalesChannelsToApiKeyWorkflow,
 19    linkSalesChannelsToStockLocationWorkflow,
 20    updateStoresWorkflow,
 21  } from "@medusajs/medusa/core-flows";
 22  
 23  export default async function seedDemoData({ container }: ExecArgs) {
 24    const logger = container.resolve(ContainerRegistrationKeys.LOGGER);
 25    const link = container.resolve(ContainerRegistrationKeys.LINK);
 26    const query = container.resolve(ContainerRegistrationKeys.QUERY);
 27    const fulfillmentModuleService = container.resolve(Modules.FULFILLMENT);
 28    const salesChannelModuleService = container.resolve(Modules.SALES_CHANNEL);
 29    const storeModuleService = container.resolve(Modules.STORE);
 30  
 31    const countries = ["gb", "de", "dk", "se", "fr", "es", "it"];
 32  
 33    logger.info("Seeding store data...");
 34    const [store] = await storeModuleService.listStores();
 35    let defaultSalesChannel = await salesChannelModuleService.listSalesChannels({
 36      name: "Default Sales Channel",
 37    });
 38  
 39    if (!defaultSalesChannel.length) {
 40      // create the default sales channel
 41      const { result: salesChannelResult } = await createSalesChannelsWorkflow(
 42        container
 43      ).run({
 44        input: {
 45          salesChannelsData: [
 46            {
 47              name: "Default Sales Channel",
 48            },
 49          ],
 50        },
 51      });
 52      defaultSalesChannel = salesChannelResult;
 53    }
 54  
 55    await updateStoresWorkflow(container).run({
 56      input: {
 57        selector: { id: store.id },
 58        update: {
 59          supported_currencies: [
 60            {
 61              currency_code: "eur",
 62              is_default: true,
 63            },
 64            {
 65              currency_code: "usd",
 66            },
 67          ],
 68          default_sales_channel_id: defaultSalesChannel[0].id,
 69        },
 70      },
 71    });
 72    logger.info("Seeding region data...");
 73    const { result: regionResult } = await createRegionsWorkflow(container).run({
 74      input: {
 75        regions: [
 76          {
 77            name: "Europe",
 78            currency_code: "eur",
 79            countries,
 80            payment_providers: ["pp_system_default"],
 81          },
 82        ],
 83      },
 84    });
 85    const region = regionResult[0];
 86    logger.info("Finished seeding regions.");
 87  
 88    logger.info("Seeding tax regions...");
 89    await createTaxRegionsWorkflow(container).run({
 90      input: countries.map((country_code) => ({
 91        country_code,
 92        provider_id: "tp_system"
 93      })),
 94    });
 95    logger.info("Finished seeding tax regions.");
 96  
 97    logger.info("Seeding stock location data...");
 98    const { result: stockLocationResult } = await createStockLocationsWorkflow(
 99      container
100    ).run({
101      input: {
102        locations: [
103          {
104            name: "European Warehouse",
105            address: {
106              city: "Copenhagen",
107              country_code: "DK",
108              address_1: "",
109            },
110          },
111        ],
112      },
113    });
114    const stockLocation = stockLocationResult[0];
115  
116    await link.create({
117      [Modules.STOCK_LOCATION]: {
118        stock_location_id: stockLocation.id,
119      },
120      [Modules.FULFILLMENT]: {
121        fulfillment_provider_id: "manual_manual",
122      },
123    });
124  
125    logger.info("Seeding fulfillment data...");
126    const shippingProfiles = await fulfillmentModuleService.listShippingProfiles({
127      type: "default"
128    })
129    let shippingProfile = shippingProfiles.length ? shippingProfiles[0] : null
130  
131    if (!shippingProfile) {
132      const { result: shippingProfileResult } =
133      await createShippingProfilesWorkflow(container).run({
134        input: {
135          data: [
136            {
137              name: "Default Shipping Profile",
138              type: "default",
139            },
140          ],
141        },
142      });
143      shippingProfile = shippingProfileResult[0];
144    }
145  
146    const fulfillmentSet = await fulfillmentModuleService.createFulfillmentSets({
147      name: "European Warehouse delivery",
148      type: "shipping",
149      service_zones: [
150        {
151          name: "Europe",
152          geo_zones: [
153            {
154              country_code: "gb",
155              type: "country",
156            },
157            {
158              country_code: "de",
159              type: "country",
160            },
161            {
162              country_code: "dk",
163              type: "country",
164            },
165            {
166              country_code: "se",
167              type: "country",
168            },
169            {
170              country_code: "fr",
171              type: "country",
172            },
173            {
174              country_code: "es",
175              type: "country",
176            },
177            {
178              country_code: "it",
179              type: "country",
180            },
181          ],
182        },
183      ],
184    });
185  
186    await link.create({
187      [Modules.STOCK_LOCATION]: {
188        stock_location_id: stockLocation.id,
189      },
190      [Modules.FULFILLMENT]: {
191        fulfillment_set_id: fulfillmentSet.id,
192      },
193    });
194  
195    await createShippingOptionsWorkflow(container).run({
196      input: [
197        {
198          name: "Standard Shipping",
199          price_type: "flat",
200          provider_id: "manual_manual",
201          service_zone_id: fulfillmentSet.service_zones[0].id,
202          shipping_profile_id: shippingProfile.id,
203          type: {
204            label: "Standard",
205            description: "Ship in 2-3 days.",
206            code: "standard",
207          },
208          prices: [
209            {
210              currency_code: "usd",
211              amount: 10,
212            },
213            {
214              currency_code: "eur",
215              amount: 10,
216            },
217            {
218              region_id: region.id,
219              amount: 10,
220            },
221          ],
222          rules: [
223            {
224              attribute: "enabled_in_store",
225              value: "true",
226              operator: "eq",
227            },
228            {
229              attribute: "is_return",
230              value: "false",
231              operator: "eq",
232            },
233          ],
234        },
235        {
236          name: "Express Shipping",
237          price_type: "flat",
238          provider_id: "manual_manual",
239          service_zone_id: fulfillmentSet.service_zones[0].id,
240          shipping_profile_id: shippingProfile.id,
241          type: {
242            label: "Express",
243            description: "Ship in 24 hours.",
244            code: "express",
245          },
246          prices: [
247            {
248              currency_code: "usd",
249              amount: 10,
250            },
251            {
252              currency_code: "eur",
253              amount: 10,
254            },
255            {
256              region_id: region.id,
257              amount: 10,
258            },
259          ],
260          rules: [
261            {
262              attribute: "enabled_in_store",
263              value: "true",
264              operator: "eq",
265            },
266            {
267              attribute: "is_return",
268              value: "false",
269              operator: "eq",
270            },
271          ],
272        },
273      ],
274    });
275    logger.info("Finished seeding fulfillment data.");
276  
277    await linkSalesChannelsToStockLocationWorkflow(container).run({
278      input: {
279        id: stockLocation.id,
280        add: [defaultSalesChannel[0].id],
281      },
282    });
283    logger.info("Finished seeding stock location data.");
284  
285    logger.info("Seeding publishable API key data...");
286    const { result: publishableApiKeyResult } = await createApiKeysWorkflow(
287      container
288    ).run({
289      input: {
290        api_keys: [
291          {
292            title: "Webshop",
293            type: "publishable",
294            created_by: "",
295          },
296        ],
297      },
298    });
299    const publishableApiKey = publishableApiKeyResult[0];
300  
301    await linkSalesChannelsToApiKeyWorkflow(container).run({
302      input: {
303        id: publishableApiKey.id,
304        add: [defaultSalesChannel[0].id],
305      },
306    });
307    logger.info("Finished seeding publishable API key data.");
308  
309    logger.info("Seeding product data...");
310  
311    const { result: categoryResult } = await createProductCategoriesWorkflow(
312      container
313    ).run({
314      input: {
315        product_categories: [
316          {
317            name: "Shirts",
318            is_active: true,
319          },
320          {
321            name: "Sweatshirts",
322            is_active: true,
323          },
324          {
325            name: "Pants",
326            is_active: true,
327          },
328          {
329            name: "Merch",
330            is_active: true,
331          },
332        ],
333      },
334    });
335  
336    await createProductsWorkflow(container).run({
337      input: {
338        products: [
339          {
340            title: "Medusa T-Shirt",
341            category_ids: [
342              categoryResult.find((cat) => cat.name === "Shirts")!.id,
343            ],
344            description:
345              "Reimagine the feeling of a classic T-shirt. With our cotton T-shirts, everyday essentials no longer have to be ordinary.",
346            handle: "t-shirt",
347            weight: 400,
348            status: ProductStatus.PUBLISHED,
349            shipping_profile_id: shippingProfile.id,
350            images: [
351              {
352                url: "https://medusa-public-images.s3.eu-west-1.amazonaws.com/tee-black-front.png",
353              },
354              {
355                url: "https://medusa-public-images.s3.eu-west-1.amazonaws.com/tee-black-back.png",
356              },
357              {
358                url: "https://medusa-public-images.s3.eu-west-1.amazonaws.com/tee-white-front.png",
359              },
360              {
361                url: "https://medusa-public-images.s3.eu-west-1.amazonaws.com/tee-white-back.png",
362              },
363            ],
364            options: [
365              {
366                title: "Size",
367                values: ["S", "M", "L", "XL"],
368              },
369              {
370                title: "Color",
371                values: ["Black", "White"],
372              },
373            ],
374            variants: [
375              {
376                title: "S / Black",
377                sku: "SHIRT-S-BLACK",
378                options: {
379                  Size: "S",
380                  Color: "Black",
381                },
382                prices: [
383                  {
384                    amount: 10,
385                    currency_code: "eur",
386                  },
387                  {
388                    amount: 15,
389                    currency_code: "usd",
390                  },
391                ],
392              },
393              {
394                title: "S / White",
395                sku: "SHIRT-S-WHITE",
396                options: {
397                  Size: "S",
398                  Color: "White",
399                },
400                prices: [
401                  {
402                    amount: 10,
403                    currency_code: "eur",
404                  },
405                  {
406                    amount: 15,
407                    currency_code: "usd",
408                  },
409                ],
410              },
411              {
412                title: "M / Black",
413                sku: "SHIRT-M-BLACK",
414                options: {
415                  Size: "M",
416                  Color: "Black",
417                },
418                prices: [
419                  {
420                    amount: 10,
421                    currency_code: "eur",
422                  },
423                  {
424                    amount: 15,
425                    currency_code: "usd",
426                  },
427                ],
428              },
429              {
430                title: "M / White",
431                sku: "SHIRT-M-WHITE",
432                options: {
433                  Size: "M",
434                  Color: "White",
435                },
436                prices: [
437                  {
438                    amount: 10,
439                    currency_code: "eur",
440                  },
441                  {
442                    amount: 15,
443                    currency_code: "usd",
444                  },
445                ],
446              },
447              {
448                title: "L / Black",
449                sku: "SHIRT-L-BLACK",
450                options: {
451                  Size: "L",
452                  Color: "Black",
453                },
454                prices: [
455                  {
456                    amount: 10,
457                    currency_code: "eur",
458                  },
459                  {
460                    amount: 15,
461                    currency_code: "usd",
462                  },
463                ],
464              },
465              {
466                title: "L / White",
467                sku: "SHIRT-L-WHITE",
468                options: {
469                  Size: "L",
470                  Color: "White",
471                },
472                prices: [
473                  {
474                    amount: 10,
475                    currency_code: "eur",
476                  },
477                  {
478                    amount: 15,
479                    currency_code: "usd",
480                  },
481                ],
482              },
483              {
484                title: "XL / Black",
485                sku: "SHIRT-XL-BLACK",
486                options: {
487                  Size: "XL",
488                  Color: "Black",
489                },
490                prices: [
491                  {
492                    amount: 10,
493                    currency_code: "eur",
494                  },
495                  {
496                    amount: 15,
497                    currency_code: "usd",
498                  },
499                ],
500              },
501              {
502                title: "XL / White",
503                sku: "SHIRT-XL-WHITE",
504                options: {
505                  Size: "XL",
506                  Color: "White",
507                },
508                prices: [
509                  {
510                    amount: 10,
511                    currency_code: "eur",
512                  },
513                  {
514                    amount: 15,
515                    currency_code: "usd",
516                  },
517                ],
518              },
519            ],
520            sales_channels: [
521              {
522                id: defaultSalesChannel[0].id,
523              },
524            ],
525          },
526          {
527            title: "Medusa Sweatshirt",
528            category_ids: [
529              categoryResult.find((cat) => cat.name === "Sweatshirts")!.id,
530            ],
531            description:
532              "Reimagine the feeling of a classic sweatshirt. With our cotton sweatshirt, everyday essentials no longer have to be ordinary.",
533            handle: "sweatshirt",
534            weight: 400,
535            status: ProductStatus.PUBLISHED,
536            shipping_profile_id: shippingProfile.id,
537            images: [
538              {
539                url: "https://medusa-public-images.s3.eu-west-1.amazonaws.com/sweatshirt-vintage-front.png",
540              },
541              {
542                url: "https://medusa-public-images.s3.eu-west-1.amazonaws.com/sweatshirt-vintage-back.png",
543              },
544            ],
545            options: [
546              {
547                title: "Size",
548                values: ["S", "M", "L", "XL"],
549              },
550            ],
551            variants: [
552              {
553                title: "S",
554                sku: "SWEATSHIRT-S",
555                options: {
556                  Size: "S",
557                },
558                prices: [
559                  {
560                    amount: 10,
561                    currency_code: "eur",
562                  },
563                  {
564                    amount: 15,
565                    currency_code: "usd",
566                  },
567                ],
568              },
569              {
570                title: "M",
571                sku: "SWEATSHIRT-M",
572                options: {
573                  Size: "M",
574                },
575                prices: [
576                  {
577                    amount: 10,
578                    currency_code: "eur",
579                  },
580                  {
581                    amount: 15,
582                    currency_code: "usd",
583                  },
584                ],
585              },
586              {
587                title: "L",
588                sku: "SWEATSHIRT-L",
589                options: {
590                  Size: "L",
591                },
592                prices: [
593                  {
594                    amount: 10,
595                    currency_code: "eur",
596                  },
597                  {
598                    amount: 15,
599                    currency_code: "usd",
600                  },
601                ],
602              },
603              {
604                title: "XL",
605                sku: "SWEATSHIRT-XL",
606                options: {
607                  Size: "XL",
608                },
609                prices: [
610                  {
611                    amount: 10,
612                    currency_code: "eur",
613                  },
614                  {
615                    amount: 15,
616                    currency_code: "usd",
617                  },
618                ],
619              },
620            ],
621            sales_channels: [
622              {
623                id: defaultSalesChannel[0].id,
624              },
625            ],
626          },
627          {
628            title: "Medusa Sweatpants",
629            category_ids: [
630              categoryResult.find((cat) => cat.name === "Pants")!.id,
631            ],
632            description:
633              "Reimagine the feeling of classic sweatpants. With our cotton sweatpants, everyday essentials no longer have to be ordinary.",
634            handle: "sweatpants",
635            weight: 400,
636            status: ProductStatus.PUBLISHED,
637            shipping_profile_id: shippingProfile.id,
638            images: [
639              {
640                url: "https://medusa-public-images.s3.eu-west-1.amazonaws.com/sweatpants-gray-front.png",
641              },
642              {
643                url: "https://medusa-public-images.s3.eu-west-1.amazonaws.com/sweatpants-gray-back.png",
644              },
645            ],
646            options: [
647              {
648                title: "Size",
649                values: ["S", "M", "L", "XL"],
650              },
651            ],
652            variants: [
653              {
654                title: "S",
655                sku: "SWEATPANTS-S",
656                options: {
657                  Size: "S",
658                },
659                prices: [
660                  {
661                    amount: 10,
662                    currency_code: "eur",
663                  },
664                  {
665                    amount: 15,
666                    currency_code: "usd",
667                  },
668                ],
669              },
670              {
671                title: "M",
672                sku: "SWEATPANTS-M",
673                options: {
674                  Size: "M",
675                },
676                prices: [
677                  {
678                    amount: 10,
679                    currency_code: "eur",
680                  },
681                  {
682                    amount: 15,
683                    currency_code: "usd",
684                  },
685                ],
686              },
687              {
688                title: "L",
689                sku: "SWEATPANTS-L",
690                options: {
691                  Size: "L",
692                },
693                prices: [
694                  {
695                    amount: 10,
696                    currency_code: "eur",
697                  },
698                  {
699                    amount: 15,
700                    currency_code: "usd",
701                  },
702                ],
703              },
704              {
705                title: "XL",
706                sku: "SWEATPANTS-XL",
707                options: {
708                  Size: "XL",
709                },
710                prices: [
711                  {
712                    amount: 10,
713                    currency_code: "eur",
714                  },
715                  {
716                    amount: 15,
717                    currency_code: "usd",
718                  },
719                ],
720              },
721            ],
722            sales_channels: [
723              {
724                id: defaultSalesChannel[0].id,
725              },
726            ],
727          },
728          {
729            title: "Medusa Shorts",
730            category_ids: [
731              categoryResult.find((cat) => cat.name === "Merch")!.id,
732            ],
733            description:
734              "Reimagine the feeling of classic shorts. With our cotton shorts, everyday essentials no longer have to be ordinary.",
735            handle: "shorts",
736            weight: 400,
737            status: ProductStatus.PUBLISHED,
738            shipping_profile_id: shippingProfile.id,
739            images: [
740              {
741                url: "https://medusa-public-images.s3.eu-west-1.amazonaws.com/shorts-vintage-front.png",
742              },
743              {
744                url: "https://medusa-public-images.s3.eu-west-1.amazonaws.com/shorts-vintage-back.png",
745              },
746            ],
747            options: [
748              {
749                title: "Size",
750                values: ["S", "M", "L", "XL"],
751              },
752            ],
753            variants: [
754              {
755                title: "S",
756                sku: "SHORTS-S",
757                options: {
758                  Size: "S",
759                },
760                prices: [
761                  {
762                    amount: 10,
763                    currency_code: "eur",
764                  },
765                  {
766                    amount: 15,
767                    currency_code: "usd",
768                  },
769                ],
770              },
771              {
772                title: "M",
773                sku: "SHORTS-M",
774                options: {
775                  Size: "M",
776                },
777                prices: [
778                  {
779                    amount: 10,
780                    currency_code: "eur",
781                  },
782                  {
783                    amount: 15,
784                    currency_code: "usd",
785                  },
786                ],
787              },
788              {
789                title: "L",
790                sku: "SHORTS-L",
791                options: {
792                  Size: "L",
793                },
794                prices: [
795                  {
796                    amount: 10,
797                    currency_code: "eur",
798                  },
799                  {
800                    amount: 15,
801                    currency_code: "usd",
802                  },
803                ],
804              },
805              {
806                title: "XL",
807                sku: "SHORTS-XL",
808                options: {
809                  Size: "XL",
810                },
811                prices: [
812                  {
813                    amount: 10,
814                    currency_code: "eur",
815                  },
816                  {
817                    amount: 15,
818                    currency_code: "usd",
819                  },
820                ],
821              },
822            ],
823            sales_channels: [
824              {
825                id: defaultSalesChannel[0].id,
826              },
827            ],
828          },
829        ],
830      },
831    });
832    logger.info("Finished seeding product data.");
833  
834    logger.info("Seeding inventory levels.");
835  
836    const { data: inventoryItems } = await query.graph({
837      entity: "inventory_item",
838      fields: ["id"],
839    });
840  
841    const inventoryLevels: CreateInventoryLevelInput[] = [];
842    for (const inventoryItem of inventoryItems) {
843      const inventoryLevel = {
844        location_id: stockLocation.id,
845        stocked_quantity: 1000000,
846        inventory_item_id: inventoryItem.id,
847      };
848      inventoryLevels.push(inventoryLevel);
849    }
850  
851    await createInventoryLevelsWorkflow(container).run({
852      input: {
853        inventory_levels: inventoryLevels,
854      },
855    });
856  
857    logger.info("Finished seeding inventory levels data.");
858  }