Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
{
    "schedule": {
        "Item": {
            "scheduleLineDate": "",
            "salesDocumentItem": "000150",
            "orderQuantityInSalesUnits": "10"
        }
    },
    "rotationHeader": {
        "yourReference": "SF",
        "valueShipping": "0",
        "valueAccessoryCosts": "0",
        "termsOfPaymentKey": "B028",
        "shippingConditions": "Standard",
        "sdDocumentCurrency": "BRL",
        "salesOrganization": "DC01",
        "salesOffice": "DB03",
        "salesGroup": "091",
        "salesDocumentType": "ZDX - Venda Normal",
        "salesDistrict": "Deca - MG Região 07",
        "requestedDeliveryDate": "",
        "priceListType": "Não",
        "incotermsPart2": "CIF - Custo, seguro & frete",
        "incotermsPart1": "CIF - Custo, seguro & frete",
        "division": "MS",
        "distributionChannel": "40",
        "dateForPricingAndExchangeRate": None,
        "customerPurchaseOrderNumber": "",
        "customerPurchaseOrderDate": "2020-07-30",
        "customerGroup": "false",
        "cup": "Revenda",
        "completeDeliveryDefinedForEachSalesOrder": ""
      },
    "quotePartners": {
        "Item": {
            "partnerFunction": "EmissorOrdem",
            "customerNumber": "0000032611"
        }
    },
    "quoteItems": {
        "Item": {
            "salesDocumentItem": "000150",
            "rateConditionRound": "0",
            "rateConditionAmountOrPercentage": "0.00",
            "plant": "D085",
            "materialNumber": "4688.931"
        }
    },
    "guuid": None,
    "extension": {
        "Item": {
            "dataPartOfBapiExtensionParameter3": None,
            "dataPartOfBapiExtensionParameter2": "",
            "dataPartOfBapiExtensionParameter1": None,
            "dataPartOfBapiExtensionParameter": ""
        }
    }
}

...

O modelo para o ZCPI pode ser visto no código:

Code Block

A Execução do Payload pode ser visto no comando abaixo. Para este caso, a chamada dos preços, vendas totais e impostos serão para o documento ZDX.

Code Block
for row in df_payload.rdd.collect():
    
    payload_retorno_s4_hana_interno = payload_retorno_s4_hana
    
    
    if row["DOC_TYPE"] == 'ZDX - Venda Normal':
        payload_chamada_json["schedule"]["Item"]["salesDocumentItem"] = row["ITM_NUMBER"]
        payload_chamada_json["schedule"]["Item"]["scheduleLineDate"] = today
        payload_chamada_json["rotationHeader"]["termsOfPaymentKey"] = row["PMNTTRMS"]
        payload_chamada_json["rotationHeader"]["shippingConditions"] = row["SHIP_COND"]
        payload_chamada_json["rotationHeader"]["sdDocumentCurrency"] = row["CURRENCY"]
        payload_chamada_json["rotationHeader"]["salesOrganization"] = row["SALES_ORG"]
        payload_chamada_json["rotationHeader"]["salesOffice"] = row["SALES_OFF"]
        payload_chamada_json["rotationHeader"]["salesGroup"] = row["SALES_GRP"]
        payload_chamada_json["rotationHeader"]["salesDocumentType"] = row["DOC_TYPE"]
        payload_chamada_json["rotationHeader"]["salesDistrict"] = row["SALES_DIST"]
        payload_chamada_json["rotationHeader"]["priceListType"] = row["PRICE_LIST"]
        payload_chamada_json["rotationHeader"]["incotermsPart2"] = row["INCOTERMS2"]
        payload_chamada_json["rotationHeader"]["incotermsPart1"] = row["INCOTERMS1"]
        payload_chamada_json["rotationHeader"]["division"] = row["DIVISION"]
        payload_chamada_json["rotationHeader"]["distributionChannel"] = row["DISTR_CHAN"]
        payload_chamada_json["rotationHeader"]["customerGroup"] = row["CUST_GROUP"]
        payload_chamada_json["rotationHeader"]["cup"] = row["cup"]
        payload_chamada_json["quotePartners"]["Item"]["partnerFunction"] = row["PARTN_ROLE"]
        payload_chamada_json["quotePartners"]["Item"]["customerNumber"] = row["PARTN_NUMB{
  "schedule": {
    "Item": {
      "scheduleLineDate": "",
      "salesDocumentItem": "000150",
      "orderQuantityInSalesUnits": "1"
    }
  },
    "rotationHeader": {
    "yourReference": "HUB",
    "salesDocumentType": "ZCPI",
    "valueShipping": "0",
    "valueAccessoryCosts": "0",
    "termsOfPaymentKey": "B028",
    "shippingConditions": "Standard",
    "sdDocumentCurrency": "BRL",
    "salesOrganization": "DC01",
    "salesOffice": "DB03",
    "salesGroup": "091",
    "salesDistrict": "Deca - MG Região 07",
    "requestedDeliveryDate": "",
    "priceListType": "Não",
    "incotermsPart2": "CIF - Custo, seguro & frete",
    "incotermsPart1": "CIF - Custo, seguro & frete", 
    "division": "MS",
    "distributionChannel": "40",
    "dateForPricingAndExchangeRate": null,
    "customerPurchaseOrderNumber": "",
    "customerPurchaseOrderDate": "2020-07-30",
    "customerGroup": "false",
    "cup": "Revenda",
    "completeDeliveryDefinedForEachSalesOrder": ""
  },
  "quotePartners": {
    "Item": {
      "partnerFunction": "EmissorOrdem",
      "customerNumber": "0000032611"
    }
  },
  "quoteItems": {
    "Item": {
      "salesDocumentItem": "000150",
      "rateConditionRound": "0",
      "rateConditionAmountOrPercentage": "0.00",
      "plant": "D085",
      "materialNumber": "4688.931"
    }
  },
  "guuid": None,
  "extension": {
    "Item": {
      "dataPartOfBapiExtensionParameter3": None,
      "dataPartOfBapiExtensionParameter2": "",
      "dataPartOfBapiExtensionParameter1": None,
      "dataPartOfBapiExtensionParameter": ""
    }
  }
}

Os campos do payload podem ser especificados abaixo:

Campo do Payload

Descrição

scheduleLineDate

Data de Agendamento

salesDocumentItem

Item do Documento de Vendas

orderQuantityInSalesUnits

Unidades de Quantidade De Vendas

yourReference

Referência: SF ou HUB

salesDocumentType

Tipo de Documento

valueShipping

Valor de Expedição

valueAccessoryCosts

Valor de Custos Acessórios

termsOfPaymentKey

Chave de Termos de Pagamento

shippingConditions

Condições de Expedição

sdDocumentCurrency

Moeda de Documento SD

salesOrganization

Organização de Vendas

salesOffice

Escritório de Vendas

salesGroup

Grupo de Vendas

salesDistrict

Região de Vendas

requestedDeliveryDate

Data de Entrega do Pedido

priceListType

Typo de Lista de Preço

incotermsPart2

Incoterms 2

incotermsPart1

Incoterms 1

division

Divisão

distributionChannel

Canal de Distribuição

dateForPricingAndExchangeRate

Data para Taxa de Preço e Troca

customerPurchaseOrderNumber

Número de Ordem do Pedido do Cliente

customerPurchaseOrderDate

Data de Ordem do Pedido do Cliente

customerGroup

Grupo do cliente

cup

Cup

completeDeliveryDefinedForEachSalesOrder

partnerFunction

Função Parceiro

customerNumber

Número do Cliente

salesDocumentItem

Item do Documento de Vendas

rateConditionRound

rateConditionAmountOrPercentage

plant

Planta

materialNumber

Número do Material

dataPartOfBapiExtensionParameter3

dataPartOfBapiExtensionParameter2

dataPartOfBapiExtensionParameter1

dataPartOfBapiExtensionParameter

A Execução do Payload pode ser visto no comando abaixo. Para este caso, a chamada dos preços, vendas totais e impostos serão para o documento ZDX.

Code Block
for row in df_payload.rdd.collect():
    
    payload_retorno_s4_hana_interno = payload_retorno_s4_hana
    
    
    if row["DOC_TYPE"] == 'ZDX - Venda Normal':
        payload_chamada_json["schedule"]["Item"]["salesDocumentItem"] = row["ITM_NUMBER"]
        payload_chamada_json["schedule"]["Item"]["scheduleLineDate"] = today
        payload_chamada_json["rotationHeader"]["termsOfPaymentKey"] = row["PMNTTRMS"]
        payload_chamada_json["rotationHeader"]["shippingConditions"] = row["SHIP_COND"]
        payload_chamada_json["rotationHeader"]["sdDocumentCurrency"] = row["CURRENCY"]
        payload_chamada_json["rotationHeader"]["salesOrganization"] = row["SALES_ORG"]
        payload_chamada_json["rotationHeader"]["salesOffice"] = row["SALES_OFF"]
        payload_chamada_json["rotationHeader"]["salesGroup"] = row["SALES_GRP"]
        payload_chamada_json["rotationHeader"]["salesDocumentType"] = row["DOC_TYPE"]
        payload_chamada_json["rotationHeader"]["salesDistrict"] = row["SALES_DIST"]
        payload_chamada_json["rotationHeader"]["priceListType"] = row["PRICE_LIST"]
        payload_chamada_json["rotationHeader"]["incotermsPart2"] = row["INCOTERMS2"]
        payload_chamada_json["rotationHeader"]["incotermsPart1"] = row["INCOTERMS1"]
        payload_chamada_json["rotationHeader"]["division"] = row["DIVISION"]
        payload_chamada_json["rotationHeader"]["distributionChannel"] = row["DISTR_CHAN"]
        payload_chamada_json["rotationHeader"]["customerGroup"] = row["CUST_GROUP"]
        payload_chamada_json["rotationHeader"]["cup"] = row["cup"]
        payload_chamada_json["quotePartners"]["Item"]["partnerFunction"] = row["PARTN_ROLE"]
        payload_chamada_json["quotePartners"]["Item"]["customerNumber"] = row["PARTN_NUMB"]
        payload_chamada_json["quoteItems"]["Item"]["salesDocumentItem"] = row["ITM_NUMBER"]
        payload_chamada_json["quoteItems"]["Item"]["plant"] = row["PLANT"]
        payload_chamada_json["quoteItems"]["Item"]["materialNumber"] = row["MATERIAL"]
        payload_chamada_json["guuid"] = row["uuid"]

        payload_chamada_str = json.dumps(payload_chamada_json)

        payload_saida = chamada_simulate_api(payload_chamada_str)

        payload_retorno_str = payload_saida.text
        

        if (payload_retorno_str[:5] == "<?xml"):
            payload_retorno_str = payload_retorno
            payload_retorno_str = payload_retorno_str.replace("Sem Erros!", "ERRO: Retorno enviado em XML!")
            payload_retorno_str = payload_retorno_str[:-1]
            payload_retorno_str = payload_retorno_str[1:]
            payload_chamada_str = payload_chamada_str[:-1]
        else : 
            payload_chamada_str = payload_chamada_str[:-1]
            payload_retorno_str = payload_retorno_str[:-2]
            payload_retorno_str = payload_retorno_str[2:]

        merge_json = payload_chamada_str +","+ payload_retorno_str + "}"
        print(merge_json)
        payload_gravar = json.loads(merge_json)
        print(payload_gravar)

        if (payload_gravar["quoteConditions"][0]["otherCosts"] == "NULL" or 
            payload_gravar["quoteConditions"][0]["otherCosts"] == "null" or 
            payload_gravar["quoteConditions"][0]["otherCosts"] == None
           ):
            payload_gravar["quoteConditions"][0]["otherCosts"] = 0.0

        if (payload_gravar["quoteConditions"][0]["valueTaxSubstitutionTributary"] == "NULL" or 
            payload_gravar["quoteConditions"][0]["valueTaxSubstitutionTributary"] == "null"  or 
            payload_gravar["quoteConditions"][0]["valueTaxSubstitutionTributary"] == None
           ):
            payload_gravar["quoteConditions"][0]["valueTaxSubstitutionTributary"] = 0.0

        if (payload_gravar["quoteConditions"][0]["commercialCost"] == "NULL" or 
            payload_gravar["quoteConditions"][0]["commercialCost"] == "null"  or 
            payload_gravar["quoteConditions"][0]["commercialCost"] == None
           ):
            payload_gravar["quoteConditions"][0]["commercialCost"] = 0.0

        if (payload_gravar["quoteConditions"][0]["manufacturingCost"] == "NULL" or 
            payload_gravar["quoteConditions"][0]["manufacturingCost"] == "null"  or 
            payload_gravar["quoteConditions"][0]["manufacturingCost"] == None
           ):
            payload_gravar["quoteConditions"][0]["manufacturingCost"] = 0.0

        if (payload_gravar["quoteConditions"][0]["valueAdditionalSale"] == "NULL" or 
            payload_gravar["quoteConditions"][0]["valueAdditionalSale"] == "null"  or 
            payload_gravar["quoteConditions"][0]["valueAdditionalSale"] == None
           ):
            payload_gravar["quoteConditions"][0]["valueAdditionalSale"] = 0.0

        if (len(payload_gravar["quotationItems"]) != 0):
            payload_gravar["sapReturn"] = payload_retorno_json["sapReturn"]

        if (len(payload_gravar["quotationItems"]) == 0):
            payload_gravar["quotationItems"] = payload_retorno_json["quotationItems"]
            payload_gravar["quoteConditions"] = payload_retorno_json["quoteConditions"]

        jsonData = json.dumps(payload_gravar)
        print(jsonData)

        jsonDataList = []
        jsonDataList.append(jsonData)

        jsonRDD = sc.parallelize(jsonDataList)
        df = spark.read.json(jsonRDD)

        df.write.format("delta").mode("append").saveAsTable(simulate_table_name)

Para os casos de ZCPP e ZCPI, é só atribuir a cláusula else para o primeiro condição if para o Tipo de Documento do ZDX assim:

Code Block
else:
        #if row["DOC_TYPE"] == "ZDX - Consulta Venda":
        payload_chamada_json["schedule"]["Item"]["salesDocumentItem"] = row["ITM_NUMBER"]
        payload_chamada_json["schedule"]["Item"]["scheduleLineDate"] = today
        payload_chamada_json["rotationHeader"]["termsOfPaymentKey"] = row["PMNTTRMS"]
        payload_chamada_json["rotationHeader"]["shippingConditions"] = row["SHIP_COND"]
        payload_chamada_json["rotationHeader"]["sdDocumentCurrency"] = row["CURRENCY"]
        payload_chamada_json["rotationHeader"]["salesOrganization"] = row["SALES_ORG"]
        payload_chamada_json["rotationHeader"]["salesOffice"] = row["SALES_OFF"]
        payload_chamada_json["rotationHeader"]["salesGroup"] = row["SALES_GRP"]
        payload_chamada_json["rotationHeader"]["salesDocumentType"] = row["DOC_TYPE"]
        payload_chamada_json["rotationHeader"]["salesDistrict"] = row["

...

SALES_DIST"]
        payload_chamada_json["

...

rotationHeader"]["

...

priceListType"] = row["

...

PRICE_

...

LIST"]
        payload_chamada_json["rotationHeader"]["incotermsPart2"] = row["

...

INCOTERMS2"]
        payload_chamada_json["

...

rotationHeader"]["

...

incotermsPart1"] = row["

...

INCOTERMS1"]
        payload_chamada_json["

...

rotationHeader"]["

...

division"]

...

 = row["

...

DIVISION"]
        payload_chamada_json[

...

"rotationHeader"]["distributionChannel"] = row["

...

DISTR_CHAN"]

...


        payload_chamada_

...

json["rotationHeader"]["customerGroup"] = 

...

row["CUST_GROUP"]
        payload_

...

chamada_json["rotationHeader"]["cup"] = row["cup"]
       

...

 

...

payload_

...

chamada_json["quotePartners"]["Item"]["partnerFunction"] =

...

 

...

row["PARTN_ROLE"]
        

...

payload_

...

chamada_json["quotePartners"]["Item"]["customerNumber"] = 

...

row["PARTN_NUMB"]
        

...

payload_

...

chamada_json["quoteItems"]["Item"]["salesDocumentItem"] = row["ITM_NUMBER"]
        

...

payload_

...

chamada_json["quoteItems"]["Item"]["plant"] = 

...

row["PLANT"]
        payload_

...

chamada_json["quoteItems"]["Item"]["materialNumber"] = 

...

row["MATERIAL"]
        

...

payload_chamada_

...

json["guuid"] = row["uuid"]

     

...

 

...

  payload_chamada_str = json.dumps(payload_chamada_json)

        payload_

...

saida = chamada_simulate_api(payload_chamada_str

...

)

        

...

payload_retorno_str = payload_

...

saida.text

        if 

...

(payload_retorno_str[:5] == 

...

"<?xml"):
         

...

 

...

 

...

 payload_retorno_str 

...

= payload_retorno
   

...

         payload_retorno_

...

str = 

...

payload_retorno_str.replace("Sem Erros!", "ERRO: Retorno enviado em XML!")
   

...

         payload_retorno_str 

...

= 

...

payload_

...

retorno_str[:-1]
            payload_retorno_str = payload_retorno_

...

str[1:]
            

...

payload_chamada_str = payload_chamada_

...

str[:-1]
        else :    

...


            payload

...

_chamada_str = payload_chamada_str[:-1]
            

...

payload_retorno_str = payload_retorno_

...

str[:-2]
            payload_retorno_str = 

...

payload_retorno_

...

str[2:]

        merge_json = 

...

payload_chamada_str +","+ payload_retorno_str + "}"

        payload_gravar

...

 = 

...

json.loads(merge_json)

        if (payload_gravar["quoteConditions"][0]["

...

otherCosts"] == "NULL" or 
            payload_gravar["quoteConditions"][0]["

...

otherCosts"] == "null"

...

 or 
            payload_gravar["quoteConditions"][0]["

...

otherCosts"] == None
           ):        
            payload_gravar["quoteConditions"][0]["

...

otherCosts"] = 0.0

        if (payload_gravar["quoteConditions"][0]["

...

valueTaxSubstitutionTributary"] == "NULL" or 
            payload_gravar["quoteConditions"][0]["

...

valueTaxSubstitutionTributary"] == "null"  or 
            payload_gravar["quoteConditions"][0]["

...

valueTaxSubstitutionTributary"] == None
           ):
            payload_gravar["quoteConditions"][0]["

...

valueTaxSubstitutionTributary"] = 0.0

        if (payload_gravar["quoteConditions"][0]["

...

commercialCost"] == "NULL" or 
            payload_gravar["quoteConditions"][0]["

...

commercialCost"] == "null"  or 
            payload_gravar["quoteConditions"][0]["

...

commercialCost"] == None
           ):
            payload_gravar["quoteConditions"][0]["

...

commercialCost"] = 0.0

        if (

...

payload_gravar["

...

quoteConditions"]

...

[0]["manufacturingCost"] == 

...

"NULL" or 
           

...

 

...

payload_gravar["

...

quoteConditions"][0]["manufacturingCost"] == 

...

"null"  or 
            payload_gravar["quoteConditions"

...

][0]["

...

manufacturingCost"] == None
       

...

 

...

 

...

  ):
      

...

      payload_gravar["quoteConditions"][0]["manufacturingCost"] = 0.0

...

 

...

 

...

      if (payload_gravar["quoteConditions"][0]["valueAdditionalSale"] 

...

== "NULL" or 
       

...

 

...

 

...

   payload_gravar["quoteConditions"][0]["valueAdditionalSale"] == "null"  or 

...

 

...

 

...

          

...

Para os casos de ZCPP e ZCPI, é só atribuir a cláusula else para o primeiro condição if para o Tipo de Documento do ZDX assim:

Code Block
else:payload_gravar["quoteConditions"][0]["valueAdditionalSale"] == None
           ):
           #if row["DOC_TYPE payload_gravar["quoteConditions"][0]["valueAdditionalSale"] == "ZDX - Consulta Venda": 0.0

        if (len(payload_chamada_jsongravar["schedulequotationItems"]) != 0):
            payload_gravar["ItemsapReturn"]["salesDocumentItem"] = row["ITM_NUMBER"] = payload_retorno_json["sapReturn"]

        if (len(payload_chamada_jsongravar["schedulequotationItems"]["Item"]["scheduleLineDate"] = today) == 0):
            payload_chamada_jsongravar["rotationHeaderquotationItems"]["termsOfPaymentKey"] = rowpayload_retorno_json["PMNTTRMSquotationItems"]
            payload_chamada_jsongravar["rotationHeaderquoteConditions"] = payload_retorno_json["shippingConditionsquoteConditions"]

 = row["SHIP_COND"]       jsonData = json.dumps(payload_gravar)
        payload_chamada_json["rotationHeader"]["sdDocumentCurrency"] = row["CURRENCY"]#print(jsonData)

        payload_chamada_json["rotationHeader"]["salesOrganization"]jsonDataList = row["SALES_ORG"]
        payload_chamada_json["rotationHeader"]["salesOffice"] = row["SALES_OFF"]jsonDataList.append(jsonData)

        payload_chamada_json["rotationHeader"]["salesGroup"] = row["SALES_GRP"]jsonRDD = sc.parallelize(jsonDataList)
        payload_chamada_json["rotationHeader"]["salesDocumentType"] = row["DOC_TYPE"]df = spark.read.json(jsonRDD)

        payload_chamada_json["rotationHeader"]["salesDistrict"] = row["SALES_DIST"]
        payload_chamada_json["rotationHeader"]["priceListType"] = row["PRICE_LIST"]
        payload_chamada_json["rotationHeader"]["incotermsPart2"] = row["INCOTERMS2"]
        payload_chamada_json["rotationHeader"]["incotermsPart1"] = row["INCOTERMS1"]
        payload_chamada_json["rotationHeader"]["division"] = row["DIVISION"]df.write.format("delta").mode("append").saveAsTable(simulate_table_name)

Throubleshoot

Para validar corretamento a chamada da API deve-se atentar a três principais etapas: header da função da chamada da simulate; parâmetros da chamada no formato json e verificação da execução do payload para o formato especificado no header.

Header da Função da Chamada Simulate

O desenvolvimento do notebook para realizar a requisição da API foi desenvolvido com a passagem de parâmetros no formato json. A primeira etapa é verificar se a definição da função da chamada simulate está contemplando este formato. Isto pode ser visto na especificação do header da url.

...

Parâmetros da Chamada Simulate

Um dos principais problemas que podem ocorrer com o retorno da chamada simulate é a definição dos parâmetros. A solução para este problema foi desenvolvida pelos testes de especificação um a um de cada parâmetro. O modelo ideal para a requisição ocorrer de maneira com êxito é definida no formato abaixo. Este formato pode ser usado para todas as chamadas.

Code Block
payload_chamada = json.dumps({
    "schedule": {
        payload_chamada_json["rotationHeader"]["distributionChannel"] = row["DISTR_CHAN"]"Item": {
            payload_chamada_json["rotationHeader"]["customerGroup"] = row["CUST_GROUP"]"scheduleLineDate": "",
            payload_chamada_json["rotationHeader"]["cup"] = row["cup"]"salesDocumentItem": "000150",
            payload_chamada_json["quotePartners"]["Item"]["partnerFunction"] = row["PARTN_ROLE"]"orderQuantityInSalesUnits": "10"
        payload_chamada_json["quotePartners"]["Item"]["customerNumber"] = row["PARTN_NUMB"]
 }
    },
  payload_chamada_json["quoteItems"]["Item"]["salesDocumentItem"] = row["ITM_NUMBER"]rotationHeader": {
        payload_chamada_json["quoteItems"]["Item"]["plant"] = row["PLANT"]"yourReference": "SF",
        "valueShipping": "0",
        payload_chamada_json["quoteItems"]["Item"]["materialNumber"] = row["MATERIAL"]"valueAccessoryCosts": "0",
        payload_chamada_json["guuid"] = row["uuid"]"termsOfPaymentKey": "B028",
        "shippingConditions": "Standard",
    payload_chamada_str = json.dumps(payload_chamada_json)  "sdDocumentCurrency": "BRL",
      payload_saida = chamada_simulate_api(payload_chamada_str)
 "salesOrganization": "DC01",
        payload_retorno_str = payload_saida.text"salesOffice": "DB03",
        "salesGroup": "091",
if (payload_retorno_str[:5] == "<?xml"):        "salesDocumentType": "ZDX - Venda Normal",
    payload_retorno_str = payload_retorno  "salesDistrict": "Deca - MG Região 07",
     payload_retorno_str = payload_retorno_str.replace("Sem Erros!", requestedDeliveryDate"ERRO: Retorno"",
enviado em XML!")      "priceListType": "Não",
     payload_retorno_str  = payload_retorno_str[:-1]
      "incotermsPart2": "CIF - Custo, seguro & frete",
      payload_retorno_str = payload_retorno_str[1:]
      "incotermsPart1": "CIF - Custo, seguro & frete",
      payload_chamada_str = payload_chamada_str[:-1]
 "division": "MS",
       else "distributionChannel": "40",
        "dateForPricingAndExchangeRate": None,
      payload_chamada_str = payload_chamada_str[:-1]
 "customerPurchaseOrderNumber": "",
        "customerPurchaseOrderDate": "2020-07-30",
 payload_retorno_str = payload_retorno_str[:-2]     "customerGroup": "false",
      payload_retorno_str = payload_retorno_str[2:] "cup": "Revenda",
        "completeDeliveryDefinedForEachSalesOrder": ""
merge_json = payload_chamada_str +","+ payload_retorno_str + "}"
 },
    "quotePartners": {
        "Item": {
 payload_gravar = json.loads(merge_json)          if (payload_gravar["quoteConditions"][0]["otherCosts"] == "NULL" orpartnerFunction": "EmissorOrdem",
             payload_gravar["quoteConditions"][0]["otherCosts"] == "null" orcustomerNumber": "0000032611"
        }
    },
    payload_gravar["quoteConditions"][0]["otherCosts"] == NonequoteItems": {
        "Item": {
     ):       "salesDocumentItem": "000150",
            payload_gravar["quoteConditions"][0]["otherCosts"] = 0.0"rateConditionRound": "0",
           if (payload_gravar["quoteConditions"][0]["valueTaxSubstitutionTributary"] == "NULL" or rateConditionAmountOrPercentage": "0.00",
            payload_gravar["quoteConditions"][0]["valueTaxSubstitutionTributary"] == "null"  orplant": "D085",
            "materialNumber": "4688.931"
    payload_gravar["quoteConditions"][0]["valueTaxSubstitutionTributary"] == None  }
    },
    ):"guuid": None,
    "extension": {
       payload_gravar["quoteConditions"][0]["valueTaxSubstitutionTributary"] = 0.0 "Item": {
         if (payload_gravar["quoteConditions"][0]["commercialCost"] == "NULLdataPartOfBapiExtensionParameter3": or None,
            payload_gravar["quoteConditions"][0]["commercialCost"] == "null"  or dataPartOfBapiExtensionParameter2": "",
            "dataPartOfBapiExtensionParameter1": None,
            payload_gravar["quoteConditions"][0]["commercialCost"] == NonedataPartOfBapiExtensionParameter": ""
        }
    }
}):

payload_chamada_json = json.loads(payload_chamada)

A ideia usada para Throubleshoot é adicionar parâmetro por parâmetro e executar o seguinte comando:

Code Block
payload_chamada_str = json.dumps(payload_chamada_json)
payload_saida 

...

= chamada_simulate_api(payload_chamada_str)
payload_retorno_str = payload_saida.text
print(payload_chamada_str)

Ao adicionar cada parâmetro e executar, se dar o erro no próprio parâmetro que foi especificado, então foi colocado de maneira errada. Caso, dê erro no próximo parâmetro (por não estar especificado. Lembre-se a adição é um a um), então significa que o parâmetro foi definido de maneira certo.

Observações: atentar aos parâmetros de "guuid", "dataPartOfBapiExtensionParameter3" e "dataPartOfBapiExtensionParameter1". No caso do postman, atribui null para estes parâmetros. Aqui no Databricks não deve ser especificado como “null”, e sim como None. Além disso, o parâmetro "yourReference" é case sensitive.

Para validar a ocorrência do êxito é verificar o retorno do SAP. Se o código for 200 significa que a ocorrência foi certa.

...

Utilizar apenas este parâmetro para validar não significa muito em relação ao retorno da chamada se ocorrerá com êxito. Para isso, é preciso verificar se o retorno, para os parâmetros que foram especificados, estão com valores conforme na figura abaixo. Caso dê problemas no retorno da chamada, os valores estão zerados. Isso pode estar associado com a adoção do valor do parâmetro None para “null” e caso do case sensitive do SF.

...

Verificação do retorno do Payload

Conforme discutido, o desenvolvimento do notebook do Databricks para a validação da chamada simulate espera-se o retorno no formato Json. Caso este formato não seja respeitado, o retorno dos preços, vendas totais e impostos para os tipos de documento estarão nulas. Para tanto, a validação do retorno pode ser definida na verificação do formato xml. Caso esteja, atribuirá os valores de acordo com a especificação do payload de retorno com os valores zerados. Isso significa que a API apresenta um bug que precisa ser consertado.

Code Block
if (payload_retorno_str[:5] == "<?xml"):
            

...

print("Verificado que o formato está em XML e dará problema")
           

...

 

...

payload

...

_retorno_str = payload_retorno
            payload

...

_retorno_str = payload_retorno_

...

str.replace("Sem Erros!", "ERRO: Retorno enviado em XML!")
           

...

 

...

payload_

...

retorno_str = payload_retorno_str[:-1]
            payload

...

_retorno_str = payload_retorno_

...

str[1:]
            payload_

...

chamada_str = payload_

...

chamada_

...

str[:-1]
        else : 

...


...

 

...

         

...

  print("Comportamento esperado")
      

...

 

...

 

...

    payload_chamada_str = payload_chamada_str[:-1]
  

...

          

...

payload_retorno_str =

...

 payload_retorno_str[:-2]
  

...

 

...

 

...

        payload_retorno_str 

...

Throubleshoot

Para validar corretamento a chamada da API deve-se atentar a três principais etapas: header da função da chamada da simulate; parâmetros da chamada no formato json e verificação da execução do payload para o formato especificado no header.

Header da Função da Chamada Simulate

O desenvolvimento do notebook para realizar a requisição da API foi desenvolvido com a passagem de parâmetros no formato json. A primeira etapa é verificar se a definição da função da chamada simulate está contemplando este formato. Isto pode ser visto na especificação do header da url.

...

Parâmetros da Chamada Simulate

Um dos principais problemas que podem ocorrer com o retorno da chamada simulate é a definição dos parâmetros. A solução para este problema foi desenvolvida pelos testes de especificação um a um de cada parâmetro. O modelo ideal para a requisição ocorrer de maneira com êxito é definida no formato abaixo. Este formato pode ser usado para todas as chamadas.

...

= payload_retorno_str[2:]

De acordo com a Figura abaixo pode-se a validação do retorno que ocorreu em xml e que identificamos que havia um bug na API.

...

Payload SAP ECC para o S4

O mapeamento dos campos permite realizar o de-para do payload das informações obtidas do SAP ECC para o S4. Tal processo foi realizada com o auxílio de uma planilha secundária (Anexo abaixo) que contém a dicionarização dos campos de cada tabela. Esta dicionarização possibilita mapear os campos do S4 a partir do SAP ECC, permitindo que a adequação dos campos sejam iguais.

View file
nameMapeamento BAPI SIMULATE ORDER ECC e S4.xlsx

Conforme o arquivo, a realização do mapeamento precisa do uso do notebook do databricks. O comando que cria o dataframe a partir dos campos do S4 está abaixo:

Code Block
dfvw= df.withColumn('customerNumber',get_json_object(to_json('d'),'$.results.Customer'))\
         .withColumn('salesOrganization',get_json_object(to_json('d'),'$.salesOrganization'))\
  "orderQuantityInSalesUnits": "10"         }
    },
    "rotationHeader": {
        "yourReference": "SF",.withColumn('division',get_json_object(to_json('A_SalesOrderSimulation'),'$.A_SalesOrderSimulationType.OrganizationDivision'))\
        "valueShipping": "0", .withColumn('termsOfPaymentKey',get_json_object(to_json('A_SalesOrderSimulation'),'$.A_SalesOrderSimulationType.CustomerPaymentTerms'))\
        "valueAccessoryCosts": "0",
        "termsOfPaymentKey": "B028", .withColumn('salesDocumentType',get_json_object(to_json('A_SalesOrderSimulation'),'$.A_SalesOrderSimulationType.SalesGroup'))\
        "shippingConditions": "Standard", .withColumn('distributionChannel',get_json_object(to_json('A_SalesOrderSimulation'),'$.A_SalesOrderSimulationType.DistributionChannel'))\
        "sdDocumentCurrency": "BRL", .withColumn('shippingType',get_json_object(to_json('A_SalesOrderSimulation'),'$.A_SalesOrderSimulationType.IncotermsLocation1'))\
        "salesOrganization": "DC01", .withColumn('clienteDaEntrega',lit(''))\
        "salesOffice": "DB03", .withColumn('materialNumber',get_json_object(to_json('d'),'$.results.Material'))\
        "salesGroup": "091",
        "salesDocumentType": "ZDX - Venda Normal", .withColumn('embalaLouca', when(get_json_object(to_json('rotationheader'),'$.customerGroup').cast(IntegerType()) >0,lit('true')).otherwise(lit('false')))\
        "salesDistrict": "Deca - MG Região 07", .withColumn('entregaPaletizada',lit('0').cast(BooleanType()))\
        "requestedDeliveryDate": "",
        "priceListType": "Não",
 .withColumn('dataInicioVigencia',get_json_object(to_json('quotationItems'),'$[1].returnDateForReturnablePackaging')) \
       "incotermsPart2": "CIF - Custo, seguro & frete",
  .withColumn('cup',get_json_object(to_json('rotationheader'),'$.cup'))\
      "incotermsPart1": "CIF - Custo, seguro & frete", .withColumn('plant',get_json_object(to_json('quotationItems'),'$.results.Plant'))\
        "division": "MS", .withColumn('conditionUnit',get_json_object(to_json('quotationItems'),'$[1].conditionUnit'))\
        "distributionChannel": "40",
        "dateForPricingAndExchangeRate": None, .withColumn('conditionPricingUnit' ,get_json_object(to_json('quotationItems'),'$[1].conditionPricingUnit'))\
         "customerPurchaseOrderNumber": "",.withColumn('confirmedQuantity' ,get_json_object(to_json('quotationItems'),'$[1].confirmedQuantity'))\
        "customerPurchaseOrderDate": "2020-07-30",
        "customerGroup": "false", .withColumn('conditionBaseValue',get_json_object(to_json('quotationItems'),'$[1].conditionBaseValue'))\
         "cup": "Revenda",.withColumn('salePeriod' ,get_json_object(to_json('quoteConditions'),'$[0].salePeriod'))\
        "completeDeliveryDefinedForEachSalesOrder": ""   .withColumn('salePrice',get_json_object(to_json('quoteConditions'),'$[0].salePrice'))\
         },.withColumn('valueICMS',get_json_object(to_json('quoteConditions'),'$[0].valueICMS'))\
    "quotePartners": {     .withColumn('valueICMSST',get_json_object(to_json('quoteConditions'),'$[0].valueICMSST'))\
   "Item": {             "partnerFunction": "EmissorOrdem",
.withColumn('valueCofins',get_json_object(to_json('quoteConditions'),'$[0].valueCofins'))\
           "customerNumber": "0000032611".withColumn('valueIPI',get_json_object(to_json('quoteConditions'),'$[0].valueIPI'))\
           }.withColumn('valuePIS',get_json_object(to_json('quoteConditions'),'$[0].valuePIS'))\
    },     "quoteItems": {.withColumn('totalValueItem',get_json_object(to_json('quoteConditions'),'$[0].totalValueItem'))\
         "Item": {.withColumn('valueBonus',get_json_object(to_json('quoteConditions'),'$[0].valueBonus'))\
            "salesDocumentItem": "000150",
       .withColumn('discountTotal',get_json_object(to_json('quoteConditions'),'$[0].discountTotal'))\
    "rateConditionRound": "0",    .withColumn('shippingPriceClosed',get_json_object(to_json('quoteConditions'),'$[0].shippingPriceClosed'))\
        "rateConditionAmountOrPercentage": "0.00", .withColumn('insurancePriceClosed',get_json_object(to_json('quoteConditions'),'$[0].insurancePriceClosed'))\
            "plant": "D085",.withColumn('insurancePriceOpen',get_json_object(to_json('quoteConditions'),'$[0].insurancePriceOpen'))\
            "materialNumber": "4688.931".withColumn('manufacturingCost',get_json_object(to_json('quoteConditions'),'$[0].manufacturingCost'))\
        }
    },
    "guuid": None, .withColumn('commercialCost',get_json_object(to_json('quoteConditions'),'$[0].commercialCost'))\
     "extension": {   .withColumn('otherCosts',get_json_object(to_json('quoteConditions'),'$[0].otherCosts'))\
     "Item": {   .withColumn('valueAdditionalSale',get_json_object(to_json('quoteConditions'),'$[0].valueAdditionalSale'))\
         "dataPartOfBapiExtensionParameter3": None,.withColumn('valueTaxSubstitutionTributary',get_json_object(to_json('quoteConditions'),'$[0].valueTaxSubstitutionTributary'))\
            "dataPartOfBapiExtensionParameter2": "",.withColumn('netValue',get_json_object(to_json('A_SalesOrderSimulation'),'$[0].A_SalesOrderSimulationType.NetAmount'))\
            "dataPartOfBapiExtensionParameter1": None,
 .withColumn('salePricePeriodUnit',get_json_object(to_json('quoteConditions'),'$[0].salePricePeriodUnit'))\
          "dataPartOfBapiExtensionParameter": "".withColumn('salePriceUnit',get_json_object(to_json('quoteConditions'),'$[0].salePriceUnit'))\
          }
    }
})

payload_chamada_json = json.loads(payload_chamada)

A ideia usada para Throubleshoot é adicionar parâmetro por parâmetro e executar o seguinte comando:

Code Block
payload_chamada_str = json.dumps(payload_chamada_json)
payload_saida = chamada_simulate_api(payload_chamada_str)
payload_retorno_str = payload_saida.text
print(payload_chamada_str)

...

Para validar a ocorrência do êxito é verificar o retorno do SAP. Se o código for 200 significa que a ocorrência foi certa.

...

Utilizar apenas este parâmetro para validar não significa muito em relação ao retorno da chamada se ocorrerá com êxito. Para isso, é preciso verificar se o retorno, para os parâmetros que foram especificados, estão com valores conforme na figura abaixo. Caso dê problemas no retorno da chamada, os valores estão zerados. Isso pode estar associado com a adoção do valor do parâmetro None para “null” e caso do case sensitive do SF.

...

.withColumn('tag',current_timestamp())\
         .withColumn('idsimulate',df.guuid)\
         .withColumn('dataProcesso',current_date())\

A metodologia para realizar o de-para é a seguinte:

  1. Visualiza o campo no notebook do databricks (código acima), por exemplo, o campo customerNumber

  2. Abre o arquivo do mapeamento em excel, utiliza a aba SAP ECC, procura este campo na coluna chamada “Campo Payload” e verifica o nome do campo na coluna “Parâmetro/Estrutura”.

  3. Utiliza a aba SAP S4 Hana, do mesmo arquivo, e verifica o mesmo nome de campo da coluna “Parâmetro/Estrutura”. Para este registro, obtém o campo correto na coluna “Campo do Payload”.

  4. Alterar o código

  • A partir do arquivo, na aba do SAP ECC, utiliza-se o campo chamado “Parâmetro/Estrutura” para visualizar o campo origem do SAP.

  • No código acima, realiza a adequação do campo para o mesmo nome do campo payload na cláusula que obtem o objeto do json - get_json_object(to_json('d'),'$.results.Customer')