Brightmarket Sync Guide

Field maps

Cómo mapear columnas de tu fuente a campos lógicos del SDK y payloads Brightmarket.

El SDK no asume nombres de columnas de tu ERP. Vos definís en src/constants.py cómo se llaman tus campos fuente para cada clave lógica del SDK. El sync traduce esas filas a payloads de la API Brightmarket (externalId, name, defaultPrice, …).

Guía relacionada: constants.py (value maps), adapter.py (lectura).

Flujo

Tu BD / vista  →  adapter.get_*()  →  filas crudas (dict u objetos)

                         constants.py (*_FIELD_MAP + value maps)

                         brightmarket_data_sync.sync  →  writers  →  API
  • Field maps (CLIENT_FIELD_MAP, …): nombre de columna fuente por clave lógica (external_id, article_external_id, …).
  • Value maps (SEXO_MAPPING, …): traducen códigos de tu sistema a valores Brightmarket (MALE, ACCUMULATION, …).

Field maps por entidad

Cada dict en constants.py usa claves lógicas del SDK (izquierda) → tu columna fuente (valor string).

CLIENT_FIELD_MAP — flags -clients, -update_clients

Clave lógicaRequeridaUso en Brightmarket
external_idexternalId del cliente
nameNombre para armar name / lastName
fidelitynofidelity (si falta, usa external_id)
birthdatenobirthdate (formato fuente YYYYMMDD u otro parseable)
sexnoCódigo fuente → SEXO_MAPPINGsex
department_idnoId región → DEPARTAMENTO_* / COUNTRY_MAPPING
phonenoTeléfono
emailnoEmail
client_levelnoCódigo nivel → CLIENT_LEVEL_MAPPINGadd_client_level tras crear

Opt-in: CLIENT_STORE_ONLY_CONTACT_VALIDATION = True hace que sync_clients envíe storeOnlyContactValidation en create/update y pase phone/email también en update. Default False (comportamiento 2.0.0).

SKU_FIELD_MAP — flag -skus

Clave lógicaRequeridaUso
article_external_idAgrupa filas por artículo; externalId del artículo
sku_external_idexternalId del SKU
descriptionnoNombre y descripción del artículo
brandnoMarca (brandExternalId)
genre, category, class_noArman categoryExternalId
color, sizenoVariante del SKU
price, costnodefaultPrice y cost

Por defecto categoryExternalId es {genre}-{category}-{class_} y no se crean categorías en la API.

Opt-ins:

  • SKU_CREATE_CATEGORIES = True — crea categoría padre (genre) y hija (categoryExternalId con fatherExternalId) antes de create_article.
  • SKU_CATEGORY_SEPARATOR = "/" — une solo segmentos no vacíos (ej. Genero/Categoria). Si no se define, se mantiene el formato legacy con guiones.

Passthrough: si get_skus() devuelve dicts con externalId y lista skus (payload listo para la API), el SDK los envía sin field map.

TICKET_FIELD_MAP — flag -tickets

Clave lógicaRequeridaUso
ticket_idAgrupa líneas; code del ticket
client_external_idCliente del ticket
skuSKU de la línea
quantityCantidad
pricePrecio unitario
date, sale_point_id, total, subtotal, ivanoCabecera del ticket
branch_idnoSi está mapeado, resuelve channelId vía get_branch_office_channel_id
promo_idnoSi está mapeado, colecta IDs de promo por línea, resuelve el externalId vigente con resolve_promotion_external_id_for_date (fecha del ticket) y envía promotionExternalIds

Opcional en el adapter: get_pagos_by_ticket() → medios de pago por ticket.

PAYMENT_METHOD_FIELD_MAP — flag -payment_methods

Clave lógicaRequerida
external_id
name

PROMOTION_FIELD_MAP — flag -promotions

Clave lógicaRequerida
external_id
name
start_date, end_date, discount_percent, sku_external_idsno

También podés devolver dicts promotion_data listos (promotion + regularPromotionType); el SDK detecta la forma.

REWARD_FIELD_MAP — flag -rewards

Clave lógicaRequerida
client_external_id
segment
message
incentive
expiration

Requiere ORGANIZATION_ID en .env.

POINTS_MOVEMENT_FIELD_MAP — flag -points_movements

Clave lógicaRequerida
client_external_id
movement_type
points
expiration_date, commentsno

Los códigos de movement_type se traducen con POINTS_MOVEMENT_TYPE_MAPPING.

POINTS_EXPIRATION_FIELD_MAP — ajustes post-sync (opcional)

Solo si implementás get_points_expiration_adjustments() en el adapter:

Clave lógicaRequerida
client_external_id
points
commentsno

STOCK_ADJUSTMENT_FIELD_MAP — flag -stock_adjustments

Clave lógicaRequerida
sku_external_id
branch_office_external_id
stock
reason, dateno

Sin id de sucursal después de -stock_adjustments sincroniza todas las sucursales que devuelva get_stock_adjustments(); con id, filtra esa sucursal.

Qué mapa necesita cada flag CLI

Flag*_FIELD_MAP requerido
-clients / -update_clientsCLIENT_FIELD_MAP
-skusSKU_FIELD_MAP (o payloads listos)
-ticketsTICKET_FIELD_MAP
-payment_methodsPAYMENT_METHOD_FIELD_MAP
-promotionsPROMOTION_FIELD_MAP (o promotion_data listo)
-rewardsREWARD_FIELD_MAP
-points_movementsPOINTS_MOVEMENT_FIELD_MAP
-stock_adjustmentsSTOCK_ADJUSTMENT_FIELD_MAP
Ajustes de vencimientoPOINTS_EXPIRATION_FIELD_MAP + hook en adapter

mappers_from_constants(constants) carga los maps presentes en tu módulo. Si corrés un sync sin el map correspondiente, el SDK falla con un mensaje explícito (ej. Client sync requires CLIENT_FIELD_MAP in client constants).

Ejemplos

Dos clientes con distintas columnas fuente; el SDK es el mismo.

Vista SQL con nombres “clásicos”:

CLIENT_FIELD_MAP = {
    "external_id": "IdCliente",
    "name": "Nombre",
    "fidelity": "RUC",
    "birthdate": "FechaNacimiento",
    "sex": "Sexo",
    "department_id": "IdDepartamento",
}

SKU_FIELD_MAP = {
    "article_external_id": "CodigoArticulo",
    "sku_external_id": "CodigoInterno",
    "description": "Descripcion",
    "brand": "Marca",
    "color": "Color",
    "size": "Talle",
    "price": "Precio",
    "cost": "Costo",
}

Otra fuente con nombres propios:

CLIENT_FIELD_MAP = {
    "external_id": "cust_id",
    "name": "full_name",
    "sex": "gender",
}

SKU_FIELD_MAP = {
    "article_external_id": "articulo",
    "sku_external_id": "Interno",
    "description": "WebDescription",
    "brand": "Marca",
    "cost": "PREC_COS",
    "price": "PRECIO_UNI",
    "color": "COLOR",
    "size": "NRO",
}

El adapter devuelve filas tal como vienen de la consulta; los field maps conectan esas columnas con el sync.

Extensiones

CasoSolución
Reparar clientes por IDs sin re-query globalsync_clients_created_from_rows(rows, api, mappers)
Payloads de artículo/SKU demasiado ricos para un mapDevolver dicts listos desde get_skus() o handlers propios + writers del SDK
Ajuste de puntos por vencimientoget_points_expiration_adjustments() + POINTS_EXPIRATION_FIELD_MAP
Cerrar conexiones del adapterImplementar adapter.close(); el runner del SDK lo llama al finalizar

Errores frecuentes

  • CLIENT_FIELD_MAP is not configured — falta el dict o no está importado en el módulo que pasás a mappers_from_constants.
  • missing required logical keys: external_id — el dict existe pero le faltan claves obligatorias (valores vacíos no cuentan).
  • Sync crea filas vacías — el nombre de columna en el map no coincide con las claves de tus dicts (revisá mayúsculas y nombres exactos de la vista SQL).

On this page