Como Usar o Service Layer no Servidor do SAP

● Como Usar o SAP Service Layer no Servidor da Cia do Sorriso

  ---
  Dados de Acesso
  ┌─────────────────┬───────────────────────────────────┐
  │      Item       │               Valor               │
  ├─────────────────┼───────────────────────────────────┤
  │ URL Base        │ https://172.100.0.17:50000/b1s/v2 │
  ├─────────────────┼───────────────────────────────────┤
  │ Versao API      │ v2 (NUNCA usar v1)                │
  ├─────────────────┼───────────────────────────────────┤
  │ Company DB      │ SBO_CiadoSorriso                  │
  ├─────────────────┼───────────────────────────────────┤
  │ Usuario         │ manager                           │
  ├─────────────────┼───────────────────────────────────┤
  │ Certificado SSL │ Auto-assinado (usar verify=False) │
  └─────────────────┴───────────────────────────────────┘
  ---
  1. Login (Obter Sessao)

  Toda interacao com o Service Layer comeca com login. Retorna um SessionId que deve
  ser enviado como cookie em todas as requisicoes seguintes.

  curl -k -X POST "https://172.100.0.17:50000/b1s/v2/Login" \
    -H "Content-Type: application/json" \
    -d '{
      "CompanyDB": "SBO_CiadoSorriso",
      "UserName": "manager",
      "Password": "SUA_SENHA_AQUI"
    }'

  Resposta:
  {
    "SessionId": "abc123...",
    "Version": "1000190",
    "SessionTimeout": 300
  }

  Importante:
  - O SessionId tambem vem no cookie B1SESSION
  - O cookie ROUTEID pode vir junto (necessario em clusters)
  - Timeout: 300 segundos (5 min) de inatividade = sessao expira
  - No sistema de producao, a sessao e armazenada no Redis (chave SessionIdSAP, TTL
  280s)

  ---
  2. Fazendo Requisicoes Autenticadas

  Apos login, envie o B1SESSION como cookie:

  # GET - Listar itens
  curl -k -X GET
  "https://172.100.0.17:50000/b1s/v2/Items?\$top=5&\$select=ItemCode,ItemName" \
    -b "B1SESSION=abc123..."

  # POST - Criar Business Partner
  curl -k -X POST "https://172.100.0.17:50000/b1s/v2/BusinessPartners" \
    -H "Content-Type: application/json" \
    -b "B1SESSION=abc123..." \
    -d '{
      "CardCode": "C999999",
      "CardName": "Teste API",
      "CardType": "cCustomer"
    }'

  # PATCH - Atualizar Business Partner
  curl -k -X PATCH "https://172.100.0.17:50000/b1s/v2/BusinessPartners('C999999')" \
    -H "Content-Type: application/json" \
    -b "B1SESSION=abc123..." \
    -d '{"Phone1": "81999999999"}'

  ---
  3. Endpoints Usados no Sistema
  Endpoint: /Login
  Metodo: POST
  Descricao: Autenticacao
  ────────────────────────────────────────
  Endpoint: /Logout
  Metodo: POST
  Descricao: Encerrar sessao
  ────────────────────────────────────────
  Endpoint: /BusinessPartners
  Metodo: GET/POST/PATCH
  Descricao: Clientes (CardType=C) e Fornecedores/Dentistas (CardType=S)
  ────────────────────────────────────────
  Endpoint: /Orders
  Metodo: GET/POST
  Descricao: Pedidos de Venda (ORDR)
  ────────────────────────────────────────
  Endpoint: /DownPayments
  Metodo: GET/POST
  Descricao: Adiantamentos (ODPI)
  ────────────────────────────────────────
  Endpoint: /IncomingPayments
  Metodo: GET/POST
  Descricao: Recebimentos (ORCT)
  ────────────────────────────────────────
  Endpoint: /Items
  Metodo: GET
  Descricao: Consulta de Itens
  ────────────────────────────────────────
  Endpoint: /JournalEntries
  Metodo: POST
  Descricao: Lancamentos Contabeis Manuais (LCM)
  ────────────────────────────────────────
  Endpoint: /InventoryGenEntries
  Metodo: POST
  Descricao: Entrada de Mercadoria
  ────────────────────────────────────────
  Endpoint: /ProfitCenters
  Metodo: GET/POST/PATCH
  Descricao: Centros de Custo
  ────────────────────────────────────────
  Endpoint: /CreditCards
  Metodo: GET
  Descricao: Cartoes de Credito cadastrados
  ────────────────────────────────────────
  Endpoint: /Series
  Metodo: GET
  Descricao: Series de numeracao
  ---
  4. Fluxo Documental (CRITICO)

  O sistema cria documentos nesta ordem obrigatoria:

  Recebimento PV
      |
      v
  Pedido de Venda (ORDR)      POST /Orders
      |
      v
  Adiantamento (ODPI)          POST /DownPayments
      |                         (BaseType=17, BaseEntry=DocEntry do ORDR)
      v
  Recebimento (ORCT)           POST /IncomingPayments
                                (InvoiceType=it_DownPayment, DocEntry do ODPI)

  ---
  5. Query Parameters (OData)

  O Service Layer suporta OData v4:

  $top=10                           # Limitar resultados
  $skip=20                          # Pular registros (paginacao)
  $select=CardCode,CardName         # Selecionar campos
  $filter=CardType eq 'cCustomer'   # Filtrar
  $orderby=CardCode desc            # Ordenar
  $count=true                       # Contar total

  Exemplos de filtros:
  # Buscar cliente por CPF (campo Password no SAP)
  $filter=Password eq '12345678901' and CardType eq 'cCustomer'

  # Centros de custo da dimensao 2 (dentistas)
  $filter=InWhichDimension eq 2

  # Pedidos de um cliente
  $filter=CardCode eq 'C00001'

  ---
  6. Testando Conexao no Servidor

  Via API do sistema:
  # Testar conexao SAP
  curl http://localhost:8000/api/v1/integracao/testar-sap-connection

  # Health check SAP
  curl http://localhost:8000/api/v1/sap-status/health

  Via Python (dentro do container backend):
  from app.services.sap_service_layer import sap_service_layer

  # Login
  session = await sap_service_layer.login()

  # GET
  result = await sap_service_layer.get("/Items", {"$top": 1})

  # POST com retry automatico (3 tentativas, backoff 2s/4s/8s)
  result = await sap_service_layer.post("/BusinessPartners", payload)

  # PATCH com retry
  result = await sap_service_layer.patch("/BusinessPartners('C00001')", payload)

  # Metodos de alto nivel
  result = await sap_service_layer.criar_cliente({...})
  result = await sap_service_layer.criar_pedido_venda({...})
  result = await sap_service_layer.criar_adiantamento({...})
  result = await sap_service_layer.criar_recebimento({...})
  result = await sap_service_layer.criar_lancamento_contabil({...})

  ---
  7. Gerenciamento de Sessao (Redis)

  O sistema usa Redis para compartilhar a sessao SAP entre todas as requisicoes:
  ┌──────────────┬───────────────────────────────────────────┬──────┐
  │ Chave Redis  │                   Valor                   │ TTL  │
  ├──────────────┼───────────────────────────────────────────┼──────┤
  │ SessionIdSAP │ JSON com session_id, route_id, expires_at │ 280s │
  └──────────────┴───────────────────────────────────────────┴──────┘
  - Se a sessao expira (erro 401/403), o sistema faz login automatico
  - Apenas 1 worker Uvicorn em producao (multiplos workers quebram sessao)
  - Nunca armazene sessao apenas em memoria

  ---
  8. Tratamento de Erros
  ┌─────────────┬──────────────────────────────────┬────────────────────┐
  │   Status    │           Significado            │        Acao        │
  ├─────────────┼──────────────────────────────────┼────────────────────┤
  │ 200/201     │ Sucesso                          │ Processar resposta │
  ├─────────────┼──────────────────────────────────┼────────────────────┤
  │ 204         │ Sucesso sem corpo (PATCH/DELETE) │ OK                 │
  ├─────────────┼──────────────────────────────────┼────────────────────┤
  │ 401/403     │ Sessao expirada                  │ Auto-renovacao     │
  ├─────────────┼──────────────────────────────────┼────────────────────┤
  │ 400         │ Erro de validacao SAP            │ Verificar payload  │
  ├─────────────┼──────────────────────────────────┼────────────────────┤
  │ 500/502/503 │ Erro temporario                  │ Retry automatico   │
  └─────────────┴──────────────────────────────────┴────────────────────┘
  O metodo request_with_retry() faz ate 3 tentativas com backoff exponencial (2s, 4s,
   8s) para erros temporarios e timeouts.

  ---
  9. Mapeamentos Importantes
  Conceito PV: Paciente codigo
  Campo SAP: OCRD.AliasName (CardType=C)
  Endpoint: /BusinessPartners
  ────────────────────────────────────────
  Conceito PV: Dentista codigo
  Campo SAP: OCRD.AliasName (CardType=S)
  Endpoint: /BusinessPartners
  ────────────────────────────────────────
  Conceito PV: Item codigo
  Campo SAP: OITM.SWW
  Endpoint: /Items
  ────────────────────────────────────────
  Conceito PV: CPF paciente
  Campo SAP: OCRD.Password
  Endpoint: /BusinessPartners
  ────────────────────────────────────────
  Conceito PV: Unidade
  Campo SAP: BPL (Branch)
  Endpoint: Tabela integracao.unidades_config
  Servicos vs Produtos:
  - Codigo comeca com "I" = Produto → BPL 6 (MaxCare), deposito_produtos_whs
  - Outros (P, M, D) = Servico → BPL da unidade, deposito_materiais_whs

  ---
  Documentacao Oficial SAP Service Layer

  - https://help.sap.com/doc/056f69366b5345a386bb8149f1700c19/10.0/en-US/Service%20La
  yer%20API%20Reference.html
  - [SAP Business One Service Layer - SAP Help
  Portal](https://help.sap.com/docs/SAP_BUSINESS_ONE/7f234e5ed
  tried/ef5eca93473b4c71a3e5e6e3db61801c.html)
  - https://community.sap.com/topics/business-one
  - Swagger local (quando debug=True): https://172.100.0.17:50000/b1s/v2/help

Você achou esse artigo útil?