seed.ts 23 KB

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