Filiales (Locations)

La API de Filiales permite gestionar las ubicaciones de stock (Stock Locations) del club. Cada filial representa un punto fisico donde se almacena y/o dispensa producto.


El modelo de StockLocation

  • Name
    id
    Type
    string
    Description

    ID unico de la ubicacion.

  • Name
    name
    Type
    string
    Description

    Nombre de la filial.

  • Name
    address
    Type
    StockLocationAddress
    Description

    Direccion fisica de la ubicacion.

  • Name
    addressId
    Type
    string
    Description

    ID de la direccion asociada.

  • Name
    shippingEnabled
    Type
    boolean
    Description

    Si permite envios desde esta ubicacion.

  • Name
    pickupEnabled
    Type
    boolean
    Description

    Si permite retiro en esta ubicacion.

  • Name
    salesChannels
    Type
    array
    Description

    Canales de venta asociados.

  • Name
    metadata
    Type
    object
    Description

    Datos adicionales (horarios, tipo, etc).

  • Name
    createdAt
    Type
    string
    Description

    Fecha de creacion.

  • Name
    updatedAt
    Type
    string
    Description

    Fecha de ultima actualizacion.

Interface StockLocation

interface StockLocation {
  id: string
  name: string
  address?: StockLocationAddress
  addressId?: string
  metadata?: Record<string, unknown>
  createdAt?: string
  updatedAt?: string
  shippingEnabled?: boolean
  pickupEnabled?: boolean
  salesChannels?: SalesChannel[]
}

interface StockLocationAddress {
  id?: string
  addressLine1?: string
  addressLine2?: string
  city?: string
  province?: string
  countryCode?: string
  postalCode?: string
  phone?: string
}

interface SalesChannel {
  id: string
  name: string
  description?: string
  isDisabled?: boolean
}

Ejemplo

{
  "id": "sloc_high_up",
  "name": "High Up - Dispensario Principal",
  "address": {
    "addressLine1": "Av. Corrientes 1234",
    "city": "Buenos Aires",
    "province": "CABA",
    "countryCode": "AR",
    "postalCode": "C1043"
  },
  "shippingEnabled": false,
  "pickupEnabled": true,
  "salesChannels": [
    { "id": "sc_default", "name": "Default Sales Channel" }
  ]
}

GET/api/locations

Listar filiales

Lista todas las filiales del club.

Parametros de Consulta

  • Name
    include_sales_channels
    Type
    boolean
    Description

    Incluir canales de venta en la respuesta.

Request

GET
/api/locations
curl https://app.cannahub.tech/api/locations \
  -H "Authorization: Bearer {token}"

Response

{
  "locations": [
    {
      "id": "sloc_high_up",
      "name": "High Up - Dispensario",
      "address": {
        "city": "Buenos Aires",
        "countryCode": "AR"
      },
      "pickupEnabled": true,
      "shippingEnabled": false
    },
    {
      "id": "sloc_deposito",
      "name": "Deposito Central",
      "address": {
        "city": "Buenos Aires",
        "countryCode": "AR"
      },
      "pickupEnabled": false,
      "shippingEnabled": false
    }
  ]
}

GET/api/locations/:id

Obtener filial

Obtiene el detalle de una filial especifica.

Request

GET
/api/locations/:id
curl https://app.cannahub.tech/api/locations/sloc_high_up \
  -H "Authorization: Bearer {token}"

Response

{
  "location": {
    "id": "sloc_high_up",
    "name": "High Up - Dispensario Principal",
    "address": {
      "addressLine1": "Av. Corrientes 1234",
      "city": "Buenos Aires",
      "province": "CABA",
      "countryCode": "AR"
    },
    "pickupEnabled": true,
    "shippingEnabled": false,
    "salesChannels": [
      { "id": "sc_default", "name": "Default Sales Channel" }
    ]
  }
}

POST/api/locations

Crear filial

Crea una nueva filial.

Body

  • Name
    name
    Type
    string
    Description

    Nombre de la filial.

  • Name
    address
    Type
    object
    Description

    Direccion de la filial.

    • Name
      addressLine1
      Type
      string
      Description

      Direccion principal.

    • Name
      addressLine2
      Type
      string
      Description

      Direccion secundaria.

    • Name
      city
      Type
      string
      Description

      Ciudad.

    • Name
      province
      Type
      string
      Description

      Provincia/Estado.

    • Name
      countryCode
      Type
      string
      Description

      Codigo de pais (ej: "AR").

    • Name
      postalCode
      Type
      string
      Description

      Codigo postal.

    • Name
      phone
      Type
      string
      Description

      Telefono de contacto.

  • Name
    shippingEnabled
    Type
    boolean
    Description

    Habilitar envios (default: false).

  • Name
    pickupEnabled
    Type
    boolean
    Description

    Habilitar retiro (default: true).

  • Name
    salesChannelIds
    Type
    string[]
    Description

    IDs de canales de venta a asociar.

Request

POST
/api/locations
curl -X POST https://app.cannahub.tech/api/locations \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Nueva Filial Palermo",
    "address": {
      "addressLine1": "Av. Santa Fe 3200",
      "city": "Buenos Aires",
      "province": "CABA",
      "countryCode": "AR",
      "postalCode": "C1425"
    },
    "pickupEnabled": true,
    "shippingEnabled": false
  }'

Response

{
  "location": {
    "id": "sloc_palermo_01",
    "name": "Nueva Filial Palermo",
    "address": {
      "addressLine1": "Av. Santa Fe 3200",
      "city": "Buenos Aires",
      "province": "CABA",
      "countryCode": "AR",
      "postalCode": "C1425"
    },
    "pickupEnabled": true,
    "shippingEnabled": false
  }
}

PATCH/api/locations/:id

Actualizar filial

Actualiza una filial existente.

Body

  • Name
    name
    Type
    string
    Description

    Nuevo nombre.

  • Name
    address
    Type
    object
    Description

    Nueva direccion (parcial o completa).

  • Name
    shippingEnabled
    Type
    boolean
    Description

    Actualizar estado de envios.

  • Name
    pickupEnabled
    Type
    boolean
    Description

    Actualizar estado de retiro.

Request

PATCH
/api/locations/:id
curl -X PATCH https://app.cannahub.tech/api/locations/sloc_high_up \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "High Up - Dispensario Central",
    "pickupEnabled": true
  }'

Response

{
  "location": {
    "id": "sloc_high_up",
    "name": "High Up - Dispensario Central",
    "pickupEnabled": true
  }
}

DELETE/api/locations/:id

Eliminar filial

Elimina una filial. La filial no debe tener inventario activo.

Request

DELETE
/api/locations/:id
curl -X DELETE https://app.cannahub.tech/api/locations/sloc_palermo_01 \
  -H "Authorization: Bearer {token}"

Response

{
  "success": true
}

Arquitectura del Dominio

La feature Locations sigue el patron DOMAINS.md:

src/features/Club/Locations/
├── components/           # Componentes UI
│   ├── Wrapper.tsx       # Contenedor principal
│   ├── Grid/             # Vista de grilla
│   ├── Table/            # Vista de tabla
│   ├── Modals/           # Modales CRUD
│   └── Skeleton.tsx      # Estados de carga
├── hooks/
│   ├── keys.ts           # Query key factory
│   ├── queries.ts        # useLocationsQuery, useLocationQuery
│   ├── mutations.ts      # CRUD mutations
│   └── index.ts          # Barrel export
├── services/
│   └── location.client.ts  # Cliente HTTP
└── index.ts              # Barrel export principal

Query Keys

export const locationKeys = {
   all: ['locations'] as const,
   lists: () => [...locationKeys.all, 'list'] as const,
   list: (includeSalesChannels?: boolean) =>
      [...locationKeys.lists(), { includeSalesChannels }] as const,
   details: () => [...locationKeys.all, 'detail'] as const,
   detail: (id: string) => [...locationKeys.details(), id] as const,
}

Relacion con Inventario

Las filiales son fundamentales para el sistema de inventario multi-ubicacion:

StockLocation (Filial)
       │
       ├── InventoryLevel (Stock por variante)
       │        │
       │        └── stockedQuantity, reservedQuantity
       │
       └── ShippingOption (Opciones de envio/retiro)

Consultar stock por filial

import { useLocationsQuery } from '@/features/Club/Locations'
import { useInventoryLevelsQuery } from '@/features/Club/Inventory'

// Obtener filiales
const { data: locationsData } = useLocationsQuery()

// Obtener niveles de stock para una variante
const { data: levelsData } = useInventoryLevelsQuery(inventoryItemId)

// Mapear stock por filial
const stockByLocation = locationsData?.locations.map(loc => {
  const level = levelsData?.levels.find(l => l.locationId === loc.id)
  return {
    locationId: loc.id,
    locationName: loc.name,
    quantity: level?.stockedQuantity || 0,
    available: level?.availableQuantity || 0
  }
})

Mapeo Medusa

La API BFF transforma las respuestas de Medusa de snake_case a camelCase:

UI (camelCase)Medusa (snake_case)
addressLine1address_1
addressLine2address_2
countryCodecountry_code
postalCodepostal_code
shippingEnabledderivado de fulfillment_sets
pickupEnabledderivado de fulfillment_sets
salesChannelssales_channels
createdAtcreated_at
updatedAtupdated_at

Las funciones de parser estan en /src/lib/medusa/locations.ts:

import { parseMedusaLocation, parseMedusaLocations } from '@/lib/medusa/locations'

// Transforma respuesta Medusa a camelCase
const locations = parseMedusaLocations(medusaResponse.stock_locations)

Proximos Pasos

Was this page helpful?