medusajs / medusa

The world's most flexible commerce platform.
https://medusajs.com
MIT License
26.28k stars 2.68k forks source link

draft order's `shipping_methods` empty after medusa update. Now my frontend is broken. #4821

Open BorisKamp opened 1 year ago

BorisKamp commented 1 year ago

System information

Medusa version (including plugins): ^1.14.0 Node.js version: 18.16.1 Database: postgres

I have built a management tool for a business where they can create draft orders and send the quotes to customers. After the quote (draft order) is accepted it will turn into an actual order.

I have three regions, each with a manual shipping option which is flat rate of 0 euros and visible for admin-only. On draft order create I pass this shipping method like so:

{
    "status": "open",
    "email": "boriskamp1990@gmail.com",
    "customer_id": "cus_01H1F8XSW7N4DD68WCNCSGDKHK",
    "billing_address": {
        "first_name": "Boris",
        "last_name": "Kamp",
        "phone": "0655718742",
        "company": "Cooly BV",
        "address_1": "Zwartendijk 31",
        "address_2": null,
        "city": "Naaldwijk",
        "country_code": "be",
        "province": null,
        "postal_code": "2671LL"
    },
    "shipping_address": {
        "first_name": "Boris",
        "last_name": "Kamp",
        "phone": "0655718742",
        "company": "Cooly BV",
        "address_1": "Zwartendijk 31",
        "address_2": null,
        "city": "Naaldwijk",
        "country_code": "be",
        "province": null,
        "postal_code": "2671LL"
    },
    "region_id": "reg_01H123PC1HGBNC38RJ7J5ABPSN",
    "shipping_methods": [
        {
            "option_id": "so_01H59FF7BBX7ZXG89DJZP692K5"
        }
    ],
}

When I then fetch the draft order I see the cart.shipping_methods array populated with this shipping method. When I then post a line item like so:

{
  "variant_id": "variant_01H5MGMWTZZ40XTN76TEH7YJNA",
  "unit_price": 900,
  "quantity": 1
}

My cart.shipping_methods is empty! I have not had this before I updated to Medusa 1.14.0 (came from 1.13.0). Does this ring a bell with any of you authors?

Now my client's business portal is broken as they cannot continue as no cart.shipping_methods is available.

olivermrbl commented 1 year ago

Please see the release notes for 1.14.0 for an explanation.

This is/was intended behavior, but has been broken until now.

Updating items on a cart might affect the applicable shipping options, so these are reset on every such request to make sure you can't complete an order with an invalid shipping method.

BorisKamp commented 1 year ago

Please see the release notes for 1.14.0 for an explanation.

This is/was intended behavior, but has been broken until now.

Updating items on a cart might affect the applicable shipping options, so these are reset on every such request to make sure you can't complete an order with an invalid shipping method.

Thank you for your reply. okay, but then how do I add the method again? Are they reset even if they are valid? I don't get it why I can create a draft order with this method, add an item and then the method is gone. The method has no requirements like min-max or whatever so it should always be valid unless I'm missing something?

BorisKamp commented 1 year ago

@olivermrbl can you please tell me what I need to do now? I cannot update and getting behind on Medusa versions which I don't like.

I can't imagine I'm the only one having this problem out here.

Please see my last comment from 3 weeks ago.

BorisKamp commented 1 year ago

Nobody here? C'mon guys, this is important.

olivermrbl commented 1 year ago

@BorisKamp, until we've added a more sophisticated way of updating shipping methods on line item removal, you could add the shipping method anew by updating the draft order cart directly:

POST /store/carts/[draft_order_cart]/shipping-methods
{ "option_id": "some_option_id" }

The cart id can be accessed on the draft order like so: draft_order.cart_id.

Let me know if this helps.

BorisKamp commented 1 year ago

Thanks @olivermrbl

Feels like a workaround but for now after every line item change, on draft orders, I reapply the shipping method. Probably not really efficient but no other way now I suppose.

BorisKamp commented 1 year ago

@olivermrbl can you confirm that in 1.17.1 it is no longer necessary to reapply the shipping method after a line item changed. So you guys fixed this in a sophisticated way?

olivermrbl commented 1 year ago

@BorisKamp – the PR is yet to be merged. Hope to do this early next week.

BorisKamp commented 1 year ago

@BorisKamp – the PR is yet to be merged. Hope to do this early next week.

@olivermrbl This issue still exists exactly like I described above. After each draft order line item update, create or delete I'm forced to check the shipping method on the (old) draft order and reapply it after the line item edit, create or delete, same for the shipping price.

Am I missing something or are you misunderstanding my issue? Because it is closed? it should be open imo.

BorisKamp commented 1 year ago

To be clear, after each draft order line item, create update or delete I have all this logic to reapply the shipping method & costs....

It I call reapplyShippingAfterLineItemChange from my strapi middleware when the routes are used, and draftOrder is the draft order before the request was sent.

const axios = require('axios');

export async function reapplyShippingAfterLineItemChange(draftOrder: any) {
  const shippingOptionId = draftOrder?.cart?.shipping_methods?.[0]?.shipping_option?.id

  if (shippingOptionId) {
    await reapplyShippingMethod(shippingOptionId, draftOrder)
  } else {
    await fetchShippingOptions(draftOrder)
  }
}

// When a line item is updated on Medusa the shipping methods are cleared, very annoying but we have to work around by getting the shipping method, applying it again and then setting the costs again...
// We reapply the shipping option
async function reapplyShippingMethod(shippingOptionId, draftOrder) {
  if (shippingOptionId) {
    const body = {
      option_id: shippingOptionId,
    }

    let endpoint = `/store/carts/${draftOrder?.cart_id}/shipping-methods`

    await strapi.config.mixins.medusaApi.post(endpoint, body)
      .then(async (response) => {
        const previousShippingPrice = draftOrder?.cart?.shipping_methods?.[0]?.price
        const shippingMethodId = response?.data?.cart?.shipping_methods?.[0]?.id

        if (previousShippingPrice && shippingMethodId) {
          await reapplyShippingCosts(previousShippingPrice, shippingMethodId)
        }
      })
      .catch((e) => {
        console.dir(e)
      })
  } else {
    console.error('No shippingOptionId, contact the developer')
  }
}

// Once the shippingOption is set we reapply the costs
async function reapplyShippingCosts(price, shippingOptionId) {
  const body = {
    price,
  }

  let endpoint = `/admin/shipping-methods/${shippingOptionId}`
  await strapi.config.mixins.medusaApi.post(endpoint, body)
    .catch((e) => {
      console.dir(e)
    })
}

// If no shipping option from previous draft order, we fetch them.
async function fetchShippingOptions(draftOrder) {
  if (draftOrder?.cart?.region?.id) {
    const filters = {
      region_id: draftOrder?.cart?.region?.id,
      is_return: false,
      admin_only: true,
    }

    let endpoint = `/admin/shipping-options${strapi.config.mixins.returnParams(filters)}`

    await strapi.config.mixins.medusaApi.get(endpoint)
      .then(async (response) => {
        console.log('fetchShippingOptions 3')
        if (response?.shipping_options?.[0]?.id) {
          await reapplyShippingMethod(response?.shipping_options?.[0]?.id, draftOrder)
        } else {
          console.error('No shipping methods in fetchShippingOptions(), contact developer.')
        }
      })
      .catch((e) => {
        console.dir(e)
      })
  } else {
    console.error('No region in fetchShippingOptions(), contact developer.')
  }
}