Skip to content

Releases: medusajs/medusa

v2.1.3

20 Dec 10:41
Compare
Choose a tag to compare

Highlights

Calculated shipping option price

This release introduces dynamically calculated shipping option prices, which comprise three key changes:

- Admin support for creating dynamically priced options

When creating a shipping option, choose the "calculated" price type. Upon sending the request to create the option, our fulfillment module verifies if the provider and method support calculated prices.

- New storefront endpoint to calculate shipping option prices

To display calculated prices on the storefront, use the endpoint below. Calculated shipping options do not include a price in the regular request to retrieve options for a cart. These are calculated separately–one request for each option.

POST /store/shipping-options/:id/calculate
{ cart_id: "cart_1234", data: { ... } }

Pass custom data in the data property of the payload. The data is passed down to the provider and can be used for the calculation, e.g. distance to destination.

Our Next.js starter has been updated to include this feature. Check it out here.

- Changes to the addShippingMethodToCartWorkflow

When adding a calculated shipping option to a cart, the price is computed dynamically similarly to the calculation endpoint.

Module DML migrations

More core modules have been migrated from MikroORM to DML. These migrations come with non-breaking schema changes, primarily around index renaming and adding default timestamp columns.

Removed orphan deletion

Additionally, we've removed the default orphanRemoval: true configuration from one-to-one relationships. This is a less aggressive approach to cascade removal, meaning that disconnecting entities in such a relation will not delete the "child" of the association.

Required action

Run migrations to ensure your server functions as expected after upgrading:

npx medusa db:migrate

As part of migrating modules to use DML, we've uncovered a range of minor bugs (not affecting end-users) and improvements. You can read more about those in this PR.

Line items with custom prices

This release allows for custom prices on line items by decoupling variants and line items in the cart and order workflows.

Our core API doesn't support custom prices out of the box, however the underlying addToCartWorkflow does.

Here's an example of how to use it in a custom API Route:

// POST /store/carts/:id/custom-line-items
import { addToCartWorkflow } from "@medusajs/medusa/core-flows"

async function thirdPartyCallToComputePrice(item: any) {
  return {
    ...item,
    unit_price: Math.floor(Math.random() * 900) + 100,
  }
}

export const POST = async (req, res) => {
  const { id } = req.params
  const { items } = req.body

  const query = req.scope.resolve("query")

  const itemsWithDynamicPrice = await Promise.all(
    items.map((item) => {
      return thirdPartyCallToComputePrice(item)
    })
  )

  const workflowInput = {
    items: itemsWithDynamicPrice,
    cart_id: id,
  }

  await addToCartWorkflow(req.scope).run({
    input: workflowInput,
  })

  const updatedCart = await query.graph({
    entity: "cart",
    filters: { id },
    fields: ["id", "items.*"],
  })

  res.status(200).json({ cart: updatedCart })
}

Nesting Admin UI Routes under existing domains

This release introduces support for nesting a UI Route under an existing domain in the sidebar instead of in the extensions section.

For example, you can locate Brands under Products:

 import { defineRouteConfig } from "@medusajs/admin-sdk"
 import { Container, Heading } from "@medusajs/ui"

 const NestedProductsPage = () => {
   return (
     <Container className="divide-y p-0">
       <div className="flex items-center justify-between px-6 py-4">
         <Heading level="h1">Nested Products Page</Heading>
       </div>
     </Container>
   )
 }

 export const config = defineRouteConfig({
   label: "Nested Products",
   nested: "/products",
 })

 export default NestedProductsPage

This improvement to our existing UI Routes tooling was a community contribution from @eugenepro2.

Features

  • feat(core-flows,dashboard,js-sdk,medusa,types): support Fulfillment Options by @fPolic in #10622
  • feat: Custom line items by @olivermrbl in #10408
  • feat(order, types): Add Credit Line to order module by @riqwan in #10636
  • feat(core-flows): pass fields variant details when creating fulfillment by @fPolic in #10665

Bugs

  • fix(core-flows): export getItemTaxLinesStep by @shahednasser in #10640
  • fix(medusa): Missing metadata field on order by @olivermrbl in #10651
  • fix(dashboard): order details status by @fPolic in #10650
  • fix(notification): Only use enabled providers for notis by @olivermrbl in #10659
  • fix(core-flows): use useQueryGraphStep instead of useQueryStep by @shahednasser in #10643
  • fix(core-flows): data passed to to fulfillment provider context by @fPolic in #10660
  • fix(core-flows): refresh payment collections upon shipping changes by @riqwan in #10673
  • fix(product): updating collections with products fix by @riqwan in #10668
  • fix(core-flows): select stock locations for reservation from correct SC by @fPolic in #10661

Documentation

Chores

Other Changes

  • Add FilterableRefundReason filter by description and label by @vethan in #10606
  • feat(dashboard): ability to locate new admin route under existing route by @eugenepro2 in #10587

New Contributors

Full Changelog: v2.1.2...v2.1.3

v2.1.2

17 Dec 14:54
632c340
Compare
Choose a tag to compare

Highlights

Breaking changes

The input shape of two core workflows have changed:

  • updateLineItemInCartWorkflow
export interface UpdateLineItemInCartWorkflowInputDTO {
+   cart_id: string
+   item_id: string
-   cart: CartDTO
-   item: CartLineItemDTO
   update: Partial<UpdateLineItemDTO>
 }

  • addToCartWorkflow
export interface AddToCartWorkflowInputDTO {
+   cart_id: string
-   cart: CartDTO
   items: CreateCartCreateLineItemDTO[]
 }

Patches a regression with the Cart Module

Warning

Schema changes

In an earlier release, we migrated the data models of the Cart Module from MikroORM to our DML. As part of that migration, the tax rate column on line item tax lines and shipping method tax lines was mistakenly changed from a numeric to an integer. This led to issues with tax rates with decimal points, as they would get rounded to the nearest integer.

In this release, we are changing the rate column to real (or float() in our DML) to be consistent with how tax rates are generally represented across the codebase.

Required action

Run migrations to ensure your server functions as expected after upgrading:

npx medusa db:migrate

Features

  • refactor: migration stock location module by @thetutlage in #10471
  • refactor: migrate promotion module by @thetutlage in #10410
  • feat(core-flows, dashboard, fulfillment, fulfillment-manual, utils, types): create shipping options with calculated prices by @fPolic in #10495
  • feat: Migrate customer module to DML by @thetutlage in #10499
  • feat(file-s3): Add support for IAM role authentication to file-s3 provider by @sradevski in #10528
  • feat: add support for float properties by @thetutlage in #10551
  • feat(medusa, core-flows, fulfillment): calculate SO price endpoint by @fPolic in #10532
  • Feat/tax dml by @thetutlage in #10525
  • feat(types,fulfillment): ability to delete a canceled fulfillment by @riqwan in #10602
  • feat(core-flows): calculate SO price on cart ops by @fPolic in #10563
  • feat(medusa,pricing): Cart pricing context with customer group by @riqwan in #10579

Bugs

Documentation

Chores

Other Changes

New Contributors

Full Changelog: v2.1.1...v2.1.2

v2.1.1

10 Dec 13:21
Compare
Choose a tag to compare

Highlights

Shipping option rules

We've introduced support for pricing rules on shipping options. Initially, the feature allows you to define prices based on the cart item total. For example, you could have a free shipping option that is only available when the item total is above 100 EUR.

Every time the cart is updated, e.g. with new items, we refresh the shipping methods to ensure the correct price is applied at all times.

You'll find the new setting in the admin dashboard under "Settings > Locations & Shipping > View details > Edit prices (on shipping option)".

New languages

Our admin dashboard has been translated into Japanese.

DML Migrations

Warning

Schema changes

We've migrated our Cart, Sales Channel, API Key, Store, Workflow Engine, and Locking modules to use our Data Model API. These migrations include minor changes to the database schema, primarily around renaming indexes to respect our autogenerated naming conventions.

Read more about each of the schema changes in the PRs below.

Changes to hasOne

As part of our DML work, the behavior of hasOne has been updated in use cases where it is only defined on one side of the relation. In these cases, the mappedBy configuration of the hasOne definition needs to be set to undefined as it is not present on the other model.

For example:

const email = model.define("email", {
   email: model.text(),
   isVerified: model.boolean(),
 })

 const user = model.define("user", {
   id: model.number(),
   username: model.text(),
   email: model.hasOne(() => email, { mappedBy: undefined }), // <------------ Required config
 })

Required actions

Run migrations to ensure your server functions as expected after upgrading to v2.1.0:

npx medusa db:migrate

Features

Bugs

Documentation

Chores

Other Changes

New Contributors

Full Changelog: v2.1.0...v2.1.1

v2.1.0

04 Dec 17:55
a943dfb
Compare
Choose a tag to compare

Highlights

Improved order management

We've improved our order management with support for updating email, shipping address, and billing address.

New languages

Our admin dashboard has been translated into Italian.

Support for check constraint in Data Model API

We've added support for Postgres check constraints in our Data Model API.

For example:

const shippingMethod = model.define('ShippingMethod', {
  amount: model.bigNumber(),
})
.checks([
  (columns) => `${columns.amount} >= 0`
])

DML Migrations

Warning

Schema changes

We've migrated our Pricing, User, and Auth modules to use our Data Model API. These migrations include minor changes to the database schema:

Pricing module

  • Added column operator to price_rule table (defaults to eq)
  • Created index on (operator) in price_rule table
  • Created index on (price_id) in price_rule table
  • Created unique index on (price_id, attribute, operator) in price_rule table
  • Changed type of max_quantity column in price table from numeric to integer
  • Changed type of min_quantity column in price table from numeric to integer

Auth module

  • Added column deleted_at to auth_identity table
  • Added column deleted_at to provider_identity table
  • Created index on (deleted_at) in auth_identity table
  • Created index on (deleted_at) in provider_identity table

User module

  • Renamed unique index on (email) in invite table
  • Renamed unique index on (email) in user table

Required actions

Run migrations to ensure your server functions as expected after upgrading to v2.1.0:

npx medusa db:migrate

Features

  • feat(pricing,utils,types): add operator field to price rule by @riqwan in #10315
  • feat(pricing, types): add price rule operators to price calculations by @riqwan in #10350
  • feat(core-flows,types,medusa): ability to update/create custom shipping prices by @riqwan in #10368
  • feat(core-flows,framework,medusa): list shipping options pass in cart as pricing context by @riqwan in #10374
  • refactor: migrate pricing entities to DML models by @thetutlage in #10335
  • feature: add support for check constraints in DML by @thetutlage in #10391
  • feat(core-flows,medusa,order,types): update orders by @fPolic in #10373
  • feat(admin, js-sdk, types): update order forms by @fPolic in #10418

Bugs

Documentation

Chores

Other Changes

New Contributors

Full Changelog: v2.0.7...v2.1.0

v2.0.7

27 Nov 14:49
Compare
Choose a tag to compare

Highlights

Order transfers

You can now transfer order ownership between customers. We've added UI support in three places:

  • Order details page in Medusa Admin
  • Customer details page (Order list) in Medusa Admin
  • Self-serve in our Next.js and B2B starters

The high-level flow is as follows:

  1. Initiate transfer
POST /admin/orders/:id/transfer  { customer_id: string }

Send a request to generate a transfer token and emit an event with the order ID.

  1. Event subscriber

A subscriber picks up the event and emails the order’s current customer with the token.

  1. Accept Transfer

Customer accepts the order transfer.

POST /store/orders/:id/transfer/accept { token: string }

Product Module DML migration

Warning

Breaking changes (avoidable)

The Product module now uses our DML for data model definitions instead of MikroORM. This migration introduces improvements and fixes but results in breaking changes to some relationship APIs. These can be avoided through explicit configurations.

Required actions

  • Relation ownership on manyToMany relation

Previously, the manyToMany API inferred the owning side of relations based on the order of loading models. If the first-loaded model used mappedBy, it became the owner. Now, ownership is determined by examining both sides of the relation, before defaulting to the old behavior. This change might lead to unexpected behavior, and we therefore recommend explicitly defining the owner.

Explicitly define the owner using joinColumn, inverseJoinColumn, or pivotTable:

const ProductVariant = model
  .define("ProductVariant", {
    id: model.id({ prefix: "variant" }).primaryKey(),
    ...
    options: model.manyToMany(() => ProductOptionValue, {
      pivotTable: "product_variant_option",
      mappedBy: "variants",
      joinColumn: "variant_id",
      inverseJoinColumn: "option_value_id",
    }),
  })
  • Pivot table naming

Aside from the relation ownership, we have also updated how pivot table names are generated.

Before

We used the model names in alphabetical order and pluralized the last one of them.

Now

We use the model's table names in alphabetical order and pluralize the last one of them.

To avoid issues with your project, explicitly set pivotTable in manyToMany relations to match your existing table names:

For example:

const user = model.define('User', () => {
  addresses: model.manyToMany(() => Address, { pivotTable: 'address_users' })
})

New languages

Our admin dashboard has been translated into Brazilian Portuguese, French, Thai, and Spanish.

Features

Bugs

Documentation

Chores

New Contributors

Full Changelog: v2.0.6...v2.0.7

v2.0.6

25 Nov 11:27
Compare
Choose a tag to compare

Highlights

Product image reordering

An issue with duplicated images on product create and update in v2.0.5 has been patched. For information about the feature, see the release notes for v2.0.5.

Bugs

Full Changelog: v2.0.5...v2.0.6

v2.0.5

25 Nov 11:24
Compare
Choose a tag to compare

Highlights

Product image reordering

Warning

Schema changes

We have introduced support for re-ordering product images. Product images now have a rank field. The field is set based on the index of the image in the images payload to create and update products.

For example:

POST /admin/products
{ images: [{ url: "one" }, { url: "two" }]

Will translate to the following:

{ ..., images: [{ url: "one", rank: 0 }, { url: "two", rank: 1 }]

The same pattern is followed when updating the product.

Images are always sorted by the rank.

Schema changes

This feature comes with changes to the data models of the product module:

  • The relationship between product and images has changed from a many-to-many to one-to-many. As a result, the pivot table product_images has been dropped
  • rank has been added to the image table
  • product_id has been added to the image table

Upgrade guide

To apply the latest migrations run the following command:

npx medusa db:migrate

Cart customer transfers

We have added support for transferring carts from a guest to a registered customer.

The flow is as follows:

Create cart with guest customer

POST /store/carts
{ email: "guest@customer.com" }

Transfer cart to registered customer

POST /store/carts/:id/customer

The call to transfer assumes you are signed in and uses the customer ID from the authentication context on the request.

New languages

Our admin dashboard has been translated into German, Spaning, Turkish, and Polish

Features

Bugs

Documentation

Read more

v2.0.4

12 Nov 09:25
Compare
Choose a tag to compare

Highlights

Improved pluralization of MedusaService types

Warning

Breaking change: If you have created data models using the uncountable nouns and special rules below, you might be affected.

We've updated the type helper used to generate types for the methods of the MedusaService. It now has two conditional checks when converting a singular value to a plural value at the types level.

  • First, it checks for uncountable nouns in a dictionary.
  • Second, it looks for special rules for certain words like tooth, man, etc.

You can find the reference of uncountable nouns and special rules here.

Bugs

  • breaking: pluralize type helper to account for uncountable nouns and special rules by @thetutlage in #10011
  • fix(types): Add AdminBatchUpdateProductVariant type by @kasperkristensen in #10009
  • fix(medusa, types): filter product by external_id by @fPolic in #10010
  • fix(dashboard): handle deleted products/variants in the order domain by @fPolic in #9841
  • fix(dashboard): Load product variant edit page and fix product detail query key by @kasperkristensen in #10029

Documentation

Chores

Other Changes

Full Changelog: v2.0.3...v2.0.4

v2.0.3

11 Nov 10:21
5c22c57
Compare
Choose a tag to compare

Highlights

Replaced email with sub for Google entity ID

The Google authentication provider incorrectly used the email as the entity_id, which is an issue in case a Google account has multiple emails attached to it. This release fixes that and switches the usage to the sub field as a globally unique identifier.

If you have been using the Google authentication provider, the easiest way to migrate existing data is to hot patch @medusajs/auth-google using https://www.npmjs.com/package/patch-package so that when validating the callback, both the email and sub fields are used to retrieve the user, but only the sub is written.

See this PR for more.

Patched security issue

This release contains an important security fix for the email-password authentication provider. Please update your project as soon as possible.

The security issue was found in the password reset flow when using the email-password authentication provider. By obtaining a password reset token, it was possible to update the provider_metadata of other users’ provider identities by including a specific payload in the password reset request. To minimize risk to affected users, we will not disclose the structure of the payload.

Bugs

Documentation

Chores

Other Changes

New Contributors

Full Changelog: v2.0.2...v2.0.3

v2.0.2

06 Nov 20:57
Compare
Choose a tag to compare

This version fixes a range of bugs reported in the 2.0.0 release.

Highlights

Fixed mismatch with tax rate rule override

We identified a mismatch between how tax rate rule overrides were referenced in the dashboard and in the tax engine. When created through the dashboard, the overrides were created with an attribute key in plural form, but our tax engine expects them to be in the singular form.

For example, if you defined a tax rate rule override for a Product Collection, the dashboard would pass product_collections upon creating the override while the tax engine would look for product_collection.

Additionally, we fixed an issue with missing product type IDs on cart and order line items, which would mean tax calculations were not performed for product types.

These bugs were fixed in #9796 and #9951

Required actions

  • Re-create your tax rate rule overrides
  • Run migrations
npx medusa db:migrate

Features

Bugs

  • fix(dashboard): Allow float values for product prices by @kasperkristensen in #9859
  • fix(core-flows, dashboard): adjust stock levels when doing partial fulfilments by @fPolic in #9736
  • fix(dashboard): tax override reference by @fPolic in #9796
  • fix: consider --host flag and HOST env variable by @thetutlage in #9912
  • fix: disable admin when running integration tests by @thetutlage in #9915
  • fix(dashboard): truncate price cell titles by @fPolic in #9715
  • fix(utils): Mikro orm repository update many to many should detach all items by default by @adrien2p in #9917
  • fix(workflows-sdk): Paralellize steps rollback issue with config by @adrien2p in #9921
  • fix(dashboard): Allow using enter key to create newline in Textarea by @kasperkristensen in #9913
  • fix(types): Prev limit wrong values by @adrien2p in #9935
  • fix(utils/dml): set-relationship graphql generator from DML wrong managed belongsTo by @adrien2p in #9932
  • fix(telemetry): Pointing and resolving packages wrongly by @adrien2p in #9939
  • fix: Support relative path in SDK by @sradevski in #9942
  • fix(medusa): POST carts/[id]/complete missing early return by @SGFGOV in #9914
  • fix: Default to a relative path for the admin backend URL by @sradevski in #9947
  • fix: log cause property from the error by @thetutlage in #9944
  • fix(core-flows,medusa): Include region_id in shipping option retrieval by @olivermrbl in #9929
  • fix: do not set default host to localhost by @thetutlage in #9957
  • fix(types): add display_id to OrderDTO by @fPolic in #9953

Documentation

Chores

New Contributors

Full Changelog: v2.0.1...v2.0.2