seed.ts 23 KB

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