seed.ts 23 KB

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