Skip to content

Instantly share code, notes, and snippets.

@adevinwild
Created May 16, 2025 11:27
Show Gist options
  • Save adevinwild/a7da8e8947a3248d8c383c03dfb778a7 to your computer and use it in GitHub Desktop.
Save adevinwild/a7da8e8947a3248d8c383c03dfb778a7 to your computer and use it in GitHub Desktop.
Learn how to compute custom shipping price based on Cart Items
import CustomFulfillmentService from "./service"
import {
ModuleProvider,
Modules
} from "@medusajs/framework/utils"
export default ModuleProvider(Modules.FULFILLMENT, {
services: [CustomFulfillmentService],
})
import { loadEnv, defineConfig } from '@medusajs/framework/utils'
loadEnv(process.env.NODE_ENV || 'development', process.cwd())
module.exports = defineConfig({
modules: [
{
resolve: "@medusajs/medusa/fulfillment",
options: {
providers: [
// default provider
{
resolve: "@medusajs/medusa/fulfillment-manual",
id: "manual",
},
{
// if module provider is in a plugin, use `plugin-name/providers/my-fulfillment`
resolve: "./src/modules/custom-fulfillment",
id: "custom-fulfillment",
},
],
},
},
],
projectConfig: {
databaseUrl: process.env.DATABASE_URL,
// databaseDriverOptions: {
// connection: { ssl: { rejectUnauthorized: false } }
// },
http: {
storeCors: process.env.STORE_CORS!,
adminCors: process.env.ADMIN_CORS!,
authCors: process.env.AUTH_CORS!,
jwtSecret: process.env.JWT_SECRET || "supersecret",
cookieSecret: process.env.COOKIE_SECRET || "supersecret",
}
}
})
import { AbstractFulfillmentProviderService } from "@medusajs/framework/utils"
import { CalculatedShippingOptionPrice, CalculateShippingOptionPriceDTO, CreateFulfillmentResult, CreateShippingOptionDTO, FulfillmentDTO, FulfillmentItemDTO, FulfillmentOption, FulfillmentOrderDTO, Logger, ValidateFulfillmentDataContext } from "@medusajs/framework/types"
class CustomFulfillmentService extends AbstractFulfillmentProviderService {
static identifier = "custom-fulfillment"
async canCalculate(data: CreateShippingOptionDTO): Promise<boolean> {
return true
}
async calculatePrice(
optionData: CalculateShippingOptionPriceDTO["optionData"],
data: CalculateShippingOptionPriceDTO["data"],
context: CalculateShippingOptionPriceDTO["context"]
): Promise<CalculatedShippingOptionPrice> {
const totalItems = context.items.reduce((sum, item) => sum + Number(item.quantity), 0)
if (!totalItems) {
return {
calculated_amount: 0,
is_calculated_price_tax_inclusive: true,
}
}
const BASE_SHIPPING_COST = 5 // $5 in cents
const ADDITIONAL_ITEM_SHIPPING_COST = 2 // $2 in cents
const totalPrice = BASE_SHIPPING_COST + (totalItems - 1) * ADDITIONAL_ITEM_SHIPPING_COST
return {
calculated_amount: totalPrice,
is_calculated_price_tax_inclusive: true,
}
}
async createFulfillment(data: Record<string, unknown>, items: Partial<Omit<FulfillmentItemDTO, "fulfillment">>[], order: Partial<FulfillmentOrderDTO> | undefined, fulfillment: Partial<Omit<FulfillmentDTO, "provider_id" | "data" | "items">>): Promise<CreateFulfillmentResult> {
return { data: {}, labels: [] }
}
async cancelFulfillment(data: Record<string, unknown>): Promise<any> {
return {}
}
async validateFulfillmentData(optionData: Record<string, unknown>, data: Record<string, unknown>, context: ValidateFulfillmentDataContext): Promise<any> {
return data
}
async validateOption(data: Record<string, unknown>): Promise<boolean> {
return true
}
async getFulfillmentOptions(): Promise<FulfillmentOption[]> {
return [{ id: "default", is_return: false }]
}
}
export default CustomFulfillmentService
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment