Este artigo visa orientar sobre o desenho e implementação de APIs TOTVS respeitando as orientações do guia de implementação de APIs, bem como o modelo de conteúdo definido nas transações de mensagem padronizada TOTVS.
As orientações presentes neste documento estão em constante ajuste. Por isso, consulte sempre esta página quando for modelar uma nova transação. |
Partindo de um modelo XML como base, veremos a seguir um exemplo de uma possível implementação de API usando segmentação do modelo de dados.
O modelo XML utilizado será Contract_2_000.xsd que está representado graficamente a seguir (clique na imagem para expandir).
Convertendo este modelo "como ele é" para o formato OpenAPI 3.0, teríamos o seguinte documento (alguns elementos previstos nos guias de implementação de APIs e mensagem padronizada - REST/JSON foram omitidos para melhor compreensão):
{ "openapi": "3.0.0", (...), "components": { "schemas": { "Contract": { "type": "object", "properties": { "CompanyId": { "type": "string" }, "BranchId": { "type": "string" }, "CompanyInternalId": { "type": "string" }, "InternalId": { "type": "string" }, "ContractNumber": { "type": "string" }, "ContractReview": { "type": "string" }, "ProjectInternalId": { "type": "string" }, "BeginDate": { "type": "string", "format": "date-time" }, "FinalDate": { "type": "string", "format": "date-time" }, "CustomerCode": { "type": "string" }, "CustomerInternalId": { "type": "string" }, "ContractTotalValue": { "type": "number", "format": "float" }, "ContractTypeCode": { "type": "string" }, "ContractTypeInternalId": { "type": "string" }, "ListOfSheet": { "type": "array", "items": { "type": "object", "properties": { "SheetNumber": { "type": "string" }, "SheetTypePoperty": { "type": "string" }, "UnitPrice": { "type": "number", "format": "float" }, "SheetTotalValue": { "type": "number", "format": "float" }, "ListOfItem": { "type": "array", "items": { "type": "object", "properties": { "ItemCode": { "type": "string" }, "ItemInternalId": { "type": "string" }, "AccountantAcountCode": { "type": "string" }, "AccountantAcountInternalId": { "type": "string" }, "CostCenterCode": { "type": "string" }, "CostCenterInternalId": { "type": "string" }, "AccountingItemCode": { "type": "string" }, "AccountingItemInternalId": { "type": "string" }, "ClassValueCode": { "type": "string" }, "ClassValueInternalId": { "type": "string" }, "ItemQuantity": { "type": "number", "format": "float" }, "ItemUnitPrice": { "type": "number", "format": "float" }, "ItemTotalValue": { "type": "number", "format": "float" }, "PercentageOfDiscount": { "type": "number", "format": "float" } } } } } } } }, "description": "Contrato" } } } } |
Entretanto, utilizar o modelo desta forma tem vários problemas como, por exemplo, na modificação do contrato, onde teríamos que enviar também as páginas (Sheet) do contrato e os itens das páginas.
Por isso, a segmentação do modelo de dados é permitida, desde que mantenha a estrutura e atributos do modelo XML original.
Nosso modelo OpenAPI poderia ser segmentado em 3 submodelos:
Convertendo isso para o modelo OpenAPI, teríamos o seguinte, lembrando que elementos como as tags de documentação foram omitidos por questões didáticas.
{ "openapi": "3.0.0", (...), "components": { "schemas": { "ContractModel": { "type": "object", "properties": { "CompanyId": { "type": "string" }, "BranchId": { "type": "string" }, "CompanyInternalId": { "type": "string" }, "InternalId": { "type": "string" }, "ContractNumber": { "type": "string" }, "ContractReview": { "type": "string" }, "ProjectInternalId": { "type": "string" }, "BeginDate": { "type": "string", "format": "date-time" }, "FinalDate": { "type": "string", "format": "date-time" }, "CustomerCode": { "type": "string" }, "CustomerInternalId": { "type": "string" }, "ContractTotalValue": { "type": "number", "format": "float" }, "ContractTypeCode": { "type": "string" }, "ContractTypeInternalId": { "type": "string" }, "ListOfSheet": { "type": "array", "items": { "$ref": "#/components/schemas/SheetModel" } } }, "description": "Contrato" }, "SheetModel": { "type": "object", "properties": { "SheetNumber": { "type": "string" }, "SheetTypePoperty": { "type": "string" }, "UnitPrice": { "type": "number", "format": "float" }, "SheetTotalValue": { "type": "number", "format": "float" }, "ListOfItem": { "type": "array", "items": { "$ref": "#/components/schemas/ItemModel" } } } }, "ItemModel": { "type": "object", "properties": { "ItemCode": { "type": "string" }, "ItemInternalId": { "type": "string" }, "AccountantAcountCode": { "type": "string" }, "AccountantAcountInternalId": { "type": "string" }, "CostCenterCode": { "type": "string" }, "CostCenterInternalId": { "type": "string" }, "AccountingItemCode": { "type": "string" }, "AccountingItemInternalId": { "type": "string" }, "ClassValueCode": { "type": "string" }, "ClassValueInternalId": { "type": "string" }, "ItemQuantity": { "type": "number", "format": "float" }, "ItemUnitPrice": { "type": "number", "format": "float" }, "ItemTotalValue": { "type": "number", "format": "float" }, "PercentageOfDiscount": { "type": "number", "format": "float" } } } } } } |
Consequentemente, esta segmentação será refletida nos endpoints das APIs. Tomando por base a divisão realizada, teríamos o seguinte template:
/v2.000/contracts/{ContractNumber}/sheets/{SheetNumber}/items/{ItemCode}
Neste template, temos as seguintes considerações:
Nos exemplos a seguir veremos a utilização dos possíveis endpoints e seus respectivos modelos:
Inclusão de um contrato de forma completa
{ "CompanyId": "1", "BranchId": "1", "CompanyInternalId": "1", "InternalId": "1|1|1", "ContractNumber": "1", "ContractReview": "1", "ProjectInternalId": "1|1", "BeginDate": "2018-07-25T14:24:00", "FinalDate": "2019-07-25T14:24:00", "CustomerCode": "1", "CustomerInternalId": "1", "ContractTotalValue": 1.0, "ContractTypeCode": "1", "ContractTypeInternalId": "1", "ListOfSheet": [{ "SheetNumber": "1", "SheetTypePoperty": "1", "UnitPrice": 1.0, "SheetTotalValue": 1.0, "ListOfItem": [{ "ItemCode": "1", "ItemInternalId": "1|1", "AccountantAcountCode": "0001", "AccountantAcountInternalId": "1|0001", "CostCenterCode": "1", "CostCenterInternalId": "1|1", "AccountingItemCode": "111", "AccountingItemInternalId": "1|111", "ClassValueCode": "001", "ClassValueInternalId": "1|001", "ItemQuantity": 1.0, "ItemUnitPrice": 1.0, "ItemTotalValue": 1.0, "PercentageOfDiscount": 0.0 } ] } ] } |
Inclusão de um contrato sem folhas (se a regra de negócio permitir)
{ "CompanyId": "1", "BranchId": "1", "CompanyInternalId": "1", "InternalId": "1|1|1", "ContractNumber": "1", "ContractReview": "1", "ProjectInternalId": "1|1", "BeginDate": "2018-07-25T14:24:00", "FinalDate": "2019-07-25T14:24:00", "CustomerCode": "1", "CustomerInternalId": "1", "ContractTotalValue": 1.0, "ContractTypeCode": "1", "ContractTypeInternalId": "1", "ListOfSheet": [] } |
Recuperando contratos (apenas cabeçalho, 1a página, até o limite de uma página)
{ "hasNext": false, "items": [{ "_expandables": ["ListOfSheet"], "CompanyId": "1", "BranchId": "1", "CompanyInternalId": "1", "InternalId": "1|1|1", "ContractNumber": "1", "ContractReview": "1", "ProjectInternalId": "1|1", "BeginDate": "2018-07-25T14:24:00", "FinalDate": "2019-07-25T14:24:00", "CustomerCode": "1", "CustomerInternalId": "1", "ContractTotalValue": 1.0, "ContractTypeCode": "1", "ContractTypeInternalId": "1", "ListOfSheet": [] } ] } |
Recuperando um contrato, expandindo os atributos ListOfSheet e ListOfItem
{ "_expandables": ["ListOfSheet"], "CompanyId": "1", "BranchId": "1", "CompanyInternalId": "1", "InternalId": "1|1|1", "ContractNumber": "1", "ContractReview": "1", "ProjectInternalId": "1|1", "BeginDate": "2018-07-25T14:24:00", "FinalDate": "2019-07-25T14:24:00", "CustomerCode": "1", "CustomerInternalId": "1", "ContractTotalValue": 1.0, "ContractTypeCode": "1", "ContractTypeInternalId": "1", "ListOfSheet": [{ "_expandable": ["ListOfItem"], "SheetNumber": "1", "SheetTypePoperty": "1", "UnitPrice": 1.0, "SheetTotalValue": 1.0, "ListOfItem": [{ "ItemCode": "1", "ItemInternalId": "1|1", "AccountantAcountCode": "0001", "AccountantAcountInternalId": "1|0001", "CostCenterCode": "1", "CostCenterInternalId": "1|1", "AccountingItemCode": "111", "AccountingItemInternalId": "1|111", "ClassValueCode": "001", "ClassValueInternalId": "1|001", "ItemQuantity": 1.0, "ItemUnitPrice": 1.0, "ItemTotalValue": 1.0, "PercentageOfDiscount": 0.0 } ] } ] } |
Incluindo uma folha no contrato
{ "SheetNumber": "1", "SheetTypePoperty": "1", "UnitPrice": 1.0, "SheetTotalValue": 1.0, "ListOfItem": [{ "ItemCode": "1", "ItemInternalId": "1|1", "AccountantAcountCode": "0001", "AccountantAcountInternalId": "1|0001", "CostCenterCode": "1", "CostCenterInternalId": "1|1", "AccountingItemCode": "111", "AccountingItemInternalId": "1|111", "ClassValueCode": "001", "ClassValueInternalId": "1|001", "ItemQuantity": 1.0, "ItemUnitPrice": 1.0, "ItemTotalValue": 1.0, "PercentageOfDiscount": 0.0 } ] } |
Incluindo um item de uma folha do contrato
{ "ItemCode": "1", "ItemInternalId": "1|1", "AccountantAcountCode": "0001", "AccountantAcountInternalId": "1|0001", "CostCenterCode": "1", "CostCenterInternalId": "1|1", "AccountingItemCode": "111", "AccountingItemInternalId": "1|111", "ClassValueCode": "001", "ClassValueInternalId": "1|001", "ItemQuantity": 1.0, "ItemUnitPrice": 1.0, "ItemTotalValue": 1.0, "PercentageOfDiscount": 0.0 } |
Eliminando um item de uma folha
Eliminando uma folha de um contrato
Portal TOTVS para APIs e Mensagem Padronizada
Guia de implementação de APIs TOTVS
Elaboração de mensagem padronizada REST/JSON
Elaboração de mensagem padronizada SOAP/XML
Repositório de mensagens padronizadas (TFS) - STABLE - requer login TOTVS para acesso.
Repositório de mensagens padronizadas (TFS) - DEV - requer login TOTVS para acesso.
Mapa de clientes internos TOTVS - lista os Product Owners e demais papeis que devem ser envolvidos no processo de aprovação.
Editor Swagger/OpenAPI - permite a criação de documentos Swagger 2.0 ou OpenAPI 3.0 através da edição de tags YAML.
Conversor Swagger 2.0 para OpenAPI - converte um documento Swagger 2.0 em um documento OpenAPI 3.0.
Modelador de APIs Restlet Studio - permite a modelagem de APIs (endpoints, tipos de dados, etc.) gerando documentação em Swagger 2.0 e RAML 1.0.
http://docs.oasis-open.org/ubl/prd1-UBL-2.1/UBL-2.1.html
http://docs.oasis-open.org/ubl/UBL-2.1-JSON/v1.0/cnd02/UBL-2.1-JSON-v1.0-cnd02.html
http://docs.oasis-open.org/ubl/UBL-2.1-JSON/v1.0/cnd02/json-schema/maindoc/
http://www.unece.org/cefact/brs/brs_index.html