# Medusa Marketplace #2.3 | Extending Shipping Profiles/Options

**Hello everyone!**

[In the last part](https://blog.perseides.org/marketplace-22-extending-productservice), we were able to customize the behavior of products on our marketplace, so vendors/users can now create products specific to their store and, of course, see only their own products.

### What's the goal here ?

In this part, we will extend ShippingOption to make them relevant to a store. In fact, each vendor must be able to input its own shipping options, giving the customer choices for each vendors.

We'll also extend the behavior of ShippingProfile to link them to a store too, because the shopping cart currently allows for multiple shipping methods, but the current implementation only allows for one per shipping profile, so we'll create one by default for each store, allowing for multiple shipping methods for a single cart.

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text"><strong>Note that shipping profiles are supposed to be created by administrators in the current version (</strong><code>1.2x.x</code><strong>).</strong></div>
</div>

## ShippingOption

### Extend the ShippingOption entity

As with our previous entities, we want a ShippingOption to be linked to a Store :

```typescript
// src/models/shipping-option.ts
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm'

import { ShippingOption as MedusaShippingOption } from '@medusajs/medusa'

import { Store } from './store'

@Entity()
export class ShippingOption extends MedusaShippingOption {
    @Index('ShippingOptionStoreId')
    @Column({ nullable: true })
    store_id?: string

    @ManyToOne(() => Store, (store) => store.shippingOptions)
    @JoinColumn({ name: 'store_id', referencedColumnName: 'id' })
    store?: Store
}
```

### Update the Store entity

Adding a `ManyToOne` relationship above also means updating the Store model:

```typescript
// src/models/store.ts
import { Entity, OneToMany } from 'typeorm'

import { Store as MedusaStore } from '@medusajs/medusa'

import { Product } from './product'
import { User } from './user'
import { ShippingOption } from './shipping-option'

@Entity()
export class Store extends MedusaStore {
    @OneToMany(() => User, (user) => user.store)
    members?: User[]

    @OneToMany(() => Product, (product) => product.store)
    products?: Product[]

    @OneToMany(() => ShippingOption, (shippingOption) => shippingOption.store)
    shippingOptions?: ShippingOption[]
}
```

### Create the ShippingOption migration

Once the entity and repository have been extended, we can now create our :

```apache
npx typeorm migration:create src/migrations/add-shipping-option-store-id
```

Now that the migration file has been created, we can replace the up and down functions with these:

```typescript
public async up(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.query(`ALTER TABLE "shipping_option" ADD "store_id" character varying`)
    await queryRunner.query(`CREATE INDEX "ShippingOptionStoreId" ON "shipping_option" ("store_id")`)
}

public async down(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.query(`DROP INDEX "public"."ShippingOptionStoreId"`)
    await queryRunner.query(`ALTER TABLE "shipping_option" DROP COLUMN "store_id"`)
}
```

You can now build your server using the `yarn build` command and then run the `npx medusa migrations run` command, as for our previous migrations to make the changes in your database :

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1715169330313/d3ce9924-827e-4129-9598-cc20a0b802e9.png align="center")

## ShippingProfile

### Extend the ShippingProfile entity

Once the ShippingOption entity has been fully extended, we also need to extend the ShippingProfile entity, almost like copying and pasting what we've done above.

In the same way :

```typescript
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm'

import { ShippingProfile as MedusaShippingProfile } from '@medusajs/medusa'

import { Store } from './store'

@Entity()
export class ShippingProfile extends MedusaShippingProfile {
    @Index('ShippingProfileStoreId')
    @Column({ nullable: true })
    store_id?: string

    @ManyToOne(() => Store, (store) => store.shippingProfiles)
    @JoinColumn({ name: 'store_id', referencedColumnName: 'id' })
    store?: Store
}
```

### Update the Store entity

We update our Store entity to add the new `shippingProfiles` property :

```typescript
// src/models/store.ts
import { Column, Entity, OneToMany } from 'typeorm'

import { Store as MedusaStore } from '@medusajs/medusa'

import { User } from './user'
import { Product } from './product'
import { ShippingOption } from './shipping-option'
import { ShippingProfile } from './shipping-profile'

@Entity()
export class Store extends MedusaStore {
    @OneToMany(() => User, (user) => user.store)
    members?: User[]

    @OneToMany(() => Product, (product) => product.store)
    products?: Product[]

    @OneToMany(() => ShippingOption, (shippingOption) => shippingOption.store)
    shippingOptions?: ShippingOption[]

    @OneToMany(() => ShippingProfile, (shippingProfile) => shippingProfile.store)
    shippingProfiles?: ShippingProfile[]
}
```

### Create the ShippingProfile migration

We can now create the migration file for the ShippingProfile migration to apply our changes to the database :

```apache
npx typeorm migration:create src/migrations/add-shipping-profile-store-id
```

```typescript
// src/migrations/<TIME>-add-shipping-profile-store-id.ts

// ...
public async up(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.query(`ALTER TABLE "shipping_profile" ADD "store_id" character varying`)
    await queryRunner.query(`CREATE INDEX "ShippingProfileStoreId" ON "shipping_profile" ("store_id")`)
}

public async down(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.query(`DROP INDEX "public"."ShippingProfileStoreId"`)
    await queryRunner.query(`ALTER TABLE "shipping_profile" DROP COLUMN "store_id"`)
}
// ...
```

By executing this new migration file, we should see the changes occurs in our database schema :

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1715169261250/8c6677c4-b95a-4d85-8932-413b7dfbb157.png align="center")

## What's Next ?

Next, we'll look at the two services: `ShippingProfileService` and `ShippingOptionService`, and how/what we can override some of their functions. We'll use the same reasoning as the [`ProductService`](https://blog.perseides.org/marketplace-22-extending-productservice), where we made sure to fetch only the products associated with a Store or tie a new product to a specific store.

## GitHub Branch

You can access the complete part's code [**here**](https://git.new/perseides-part-2-3)**.**

## Contact

You can contact me on Discord and X with the same username : [@adevinwild](https://twitter.com/adevinwild)
