@m3r/sdk 0.5.0

ctx.m3r

A extensão chama o Core. Hoje só sales está ligado. Regras de pedido, estoque e fiscal continuam no ERP.

ctx.m3r é request/response. Não aborta um save que o usuário já disparou no ERP — para isso use ctx.entryPoints.

src/index.ts
const order = await ctx.m3r.sales.orders.get(orderId);
ctx.logger.info(order.code, { status: order.status });

Nesta versão o client só expõe ctx.m3r.sales. purchase, stock, financial e fiscal estão no catálogo como planned — ctx.m3r.purchase não existe.

Permissões

Declare em m3r.json → permissions[]. Use SdkScope, não string solta. m3r validate recusa scope fora do catálogo. O Core recusa método sem o scope na credencial RUN.

SdkScopeMétodos
sales.order.readget, find, items, getFulfillment, cancelPreview, getDeliveryAddress
sales.order.createcreate
sales.order.updateupdate, assignCustomer, updateDeliveryAddress
sales.order.fulfillfulfill
sales.order.cancelcancel
sales.order.writeatalho aceito no validate

Sem o scope: o host devolve 403. A filial tem de pertencer à empresa da credencial.

orders — contrato público

O Core não devolve a entidade TypeORM. O shape é SdkSalesOrder.

CampoTipoNota
idstringID público (hash).
codestringCódigo do pedido.
statusstringStatus do Core.
filialIdstringObrigatório em find / create.
customerIdstring | null
customerNamestring
amountnumberTotal.
datestringISO.
deliveryDatestring | null
observationstring | nullTambém patchável em IP.
itemsSdkSalesOrderItem[]Quando o Core incluir.

Item: id, productId, name, qtdPackage, amount, discount, total, fulfilledQty.

Métodos de pedido

src/index.ts
const page = await ctx.m3r.sales.orders.find({
  filialId,
  status: "open",
  limit: 20
});

const created = await ctx.m3r.sales.orders.create({
  filialId,
  customerType: "CUSTOMER",
  customerId,
  items: [{ productId, qtdPackage: 1, amount: 10, discount: 0 }]
});

await ctx.m3r.sales.orders.update(created.id, { observation: "OK" });
await ctx.m3r.sales.orders.fulfill(created.id, {
  items: [{ salesOrderItemId: itemId, quantity: 1 }]
});
MétodoEntradaPode
get(id)id públicoLer um pedido do tenant.
find(query)filialId obrigatório; status?, customerId?, limit?, cursor?Listar. cursor é página numérica do Core.
create(input)filialId, customerType, items[] (productId, qtdPackage, amount)Criar. Motor de preço/estoque do Core vale.
update(id, input)observation?, customerName?, deliveryDate?, status?, customerId?Patch restrito. Não manda item por aqui.
items(id)Linhas.
fulfill(id, { items, creditAmount? })salesOrderItemId + quantityFatura pelo fluxo do ERP.
cancel(id, { justificativa?, confirmed? })Estorno do Core.
cancelPreview(id)Impacto antes de confirmar.
convertQuote / convertToQuoteOrçamento ↔ pedido.
assignCustomer(id, customerId)Troca de cliente.
getDeliveryAddress / updateDeliveryAddressaddressId do clienteEndereço de entrega.
groupPreview / groupfilialId + salesOrderIdsAgrupar pedidos.

Apoio ao ciclo

Leitura (e returns.create) no mesmo módulo. Contrato estável e testado: orders.

ClientMétodos
sales.customersfind({ search?, limit? })
sales.productsfind({ search?, limit?, filialId? })
sales.paymentConditionsfind(filialId)
sales.priceTablesfind(filialId)
sales.sellersfind()
sales.returnsfind(filialId), create({ filialId, … })

Pode / não pode

Pode

  • Criar e alterar pedido com as mesmas regras do ERP.
  • Paginar com cursor.
  • Depois do create, reagir em ctx.events.

Não pode

  • Passar filialId de outro tenant.
  • Mandar SQL, join ou campo interno da entidade (~30 relations).
  • Recusar o save do usuário com um update — use IP.
  • Chamar ctx.m3r.purchase / stock / financial nesta versão.