quinta-feira, 11 de abril de 2024

RAP - Fiori elements com Extend utilizando script XLSX.js para Upload arquivo excel

 A principio dá para usar quase tudo q está aqui, 

https://community.sap.com/t5/technology-blogs-by-members/excel-upload-using-rap-part-1/ba-p/13545399

mas para mim não funcionou 100%, foi necessário alguns ajustes.
- a parte do fiori guide development pode seguir igual
- pode criar o fragment
- pode atualizar o controller conforme está no blog

Agora a parte de alterar os arquivos 
- ui5.yaml 
- package.json

Não acho necessário.. 

depois do importe do arquivo utilizando o NPM INSTALL XLXS

copiar o arquivo xlxs.js  que fica criado dentro da pasta xlsx no node_modules









Criar uma pasta tipo "lib" ou "util" dentro da pasta do ext e colar os arquivos
- xlxs.js 
- jzip.js








No arquivo manifest.json incluir a biblioteca dentro de rescursos.









No Controller NÃO pode declarar o objeco XLSX pois dentro do arquivo xlsx.js esse objetos está global.















É possível q tenha erros de conversão na planilha então tem q fazer a conversão.






















Conversão quando é campo numérico null.






terça-feira, 9 de abril de 2024

RAP - Abstract entity com Value help

 Imagina um cara que sofreu para esse treco funcionar...  


@EndUserText.label: 'Popup material não aplicado'

define abstract entity ZI_RetMatNAPl

{

@Consumption.filter.mandatory: true

@Consumption.valueHelpDefinition: [{ entity: {name: 'I_Customer_VH' , element: 'Customer' }, useForValidation: true }]

@EndUserText.label: 'Cliente'

Kunnr : kunnr;

@Consumption.filter.mandatory: true

@Consumption.valueHelpDefinition: [{ entity: {name: 'I_PlantStdVH' , element: 'Plant' }, useForValidation: true }]

@EndUserText.label: 'Centro'

Werks : werks_d;

}

==== Detalhe importante é o nome do campo que tem estar igual ao declarado no association da entidad principal, no meu caso fiquei penando até descobrir q era por causa da inicial maiúscula









== Não  sei afirmar ao certo se tem q ser dessa forma, mas foi só assim q funcionou para mim 











Não esquecer de remover esse parâmetro no manifest qdo for fazer o deploy




quarta-feira, 20 de março de 2024

RAP - Modificando itens no determination ON SAVE

===== CHAMADA  

determination preenche_campos on save { create; }


====== Implementação do método

  METHOD preenche_campos.


    READ ENTITIES OF ZI_XXXX IN LOCAL MODE

         ENTITY Item

         FIELDS ( posnr )

         WITH CORRESPONDING #( keys )

         RESULT DATA(lt_item).


    READ ENTITIES OF ZI_XXXX IN LOCAL MODE

         ENTITY Header

         FIELDS ( id Opertyp )

         WITH CORRESPONDING #( keys )

         RESULT DATA(lt_header).


    CHECK lt_header IS NOT INITIAL.

    DATA(ls_header) = lt_header[ 1 ].

    CHECK  ls_header-Opertyp = zcl_sd_XXXX=>c_tipo_op-sem_retorno.


    SELECT COUNT( * )

      FROM ztsd_XXXX

     WHERE id = ls_header-Id.


    DATA(lv_posnr) = CONV posnr( sy-dbcnt ) * 10.


    LOOP AT lt_item REFERENCE INTO DATA(lr_item).


      MODIFY ENTITIES OF ZI_XXXX IN LOCAL MODE

        ENTITY Item

        UPDATE FIELDS ( posnr )

        WITH VALUE #( ( %tky = lr_item->%tky posnr = lv_posnr %control-Posnr = if_abap_behv=>mk-on ) ).

    ENDLOOP.


  ENDMETHOD.


segunda-feira, 18 de março de 2024

RAP - Ocultando campos dinamicamente

 É possível ocultar campos dinamicamente mas somente de campos do object page, onde os campos são visualizados individualmente, a principio achei estranho q não tivesse opção para lista mas faz sentido pq cada registro pode ter uma condição diferente e não seria possível ocultar um campo em uma linha e na outra ficar visivel.

No meu caso eu tenho object page com uma lista (composition) que possui outra object page, nesse caso tive q colocar uma regra para o parent e outro para o child

======= Coloquei a condição na root view tanto do parent como do child, poderia ser utilizado o virtual element mas no meu caso como depende de um valor de campo da própria view foi mais fácil.

















No meu caso ocultei o campo de ordem de produção, ocultei tanto do datapoint do FACET quanto no campo listado na página do object page

















domingo, 10 de março de 2024

RAP - Factory action - Populando dados automático do objeto principal e do filho (Associated)

Detalhes importantes 
- %control - tudo q é ON é o q vai ser transportado para a tela de destino, se estiver OFF o campo não vai para tela
- %Is Draft - Se tiver DRAFT no dev tem q colocar no HEADER, no TARGET e no ITEM em si.





 









































CódigoFULL


METHOD OrderProd.

    DATA: lt_header TYPE TABLE FOR CREATE zi_indinternasd.

    DATA: lt_item TYPE TABLE FOR CREATE zi_indinternasd\_item.

    DATA: ls_item LIKE LINE OF lt_item.

    DATA lt_target LIKE ls_item-%target.

    DATA ls_target LIKE LINE OF lt_target.

    DATA(lt_keys) = keys.

    DATA(ls_keys) = VALUE  #( lt_keys[ 1 ] OPTIONAL ).

    CHECK ls_keys IS NOT INITIAL.

    TRY.

        DATA(lv_id) = cl_system_uuid=>create_uuid_x16_static( ).

      CATCH  cx_uuid_error.

        RETURN.

    ENDTRY.


    lt_header = VALUE #( ( %is_draft = if_abap_behv=>mk-on

                           %cid = ls_keys-%cid

                           Id = lv_id

                           Opertyp = c_tipo_op-envio

                           aufnr = ls_keys-%param-aufnr

                           %control = value #( Aufnr = if_abap_behv=>mk-on

                                               Opertyp = if_abap_behv=>mk-on

                                              )


                         ) ).


    DATA: lt_teste TYPE TABLE OF  ztsd_ind_item.


    lt_teste = VALUE #(

                      ( matnr = '000000000000000009'  menge = '10.11' preco = '1.12'  )

                      ( matnr = '000000000000000010'  menge = '20.22' preco = '2.22'  )

                      ( matnr = '000000000000000011'  menge = '30.33' preco = '3.15'  )

                      ).


    LOOP AT lt_teste INTO DATA(ls_teste).


      TRY.

          DATA(lv_item_id) = cl_system_uuid=>create_uuid_x16_static( ).

        CATCH  cx_uuid_error.

          RETURN.

      ENDTRY.


      APPEND INITIAL LINE TO lt_target ASSIGNING FIELD-SYMBOL(<lf_target>).

      <lf_target> = VALUE #( %cid = lv_item_id

                             %is_draft = if_abap_behv=>mk-on

                             Id = lv_id

                             ItemId = lv_item_id

                             Matnr = ls_teste-matnr

                             Menge = ls_teste-menge

                             Preco = ls_teste-preco

                             %control = VALUE #( Docnum = if_abap_behv=>mk-off

                                                 Itmnum = if_abap_behv=>mk-off

                                                 Matnr = if_abap_behv=>mk-on

                                                 Meins = if_abap_behv=>mk-on

                                                 Preco = if_abap_behv=>mk-on

                                                 Menge = if_abap_behv=>mk-on

                              )

                               ).


    ENDLOOP.


    APPEND INITIAL LINE TO lt_item ASSIGNING FIELD-SYMBOL(<lt_item>).

    <lt_item> = VALUE #( %cid_ref = ls_keys-%cid

                         Id = lv_id

                         %is_draft = if_abap_behv=>mk-on

                         %target = lt_target ).


    MODIFY ENTITIES OF zi_indinternasd IN LOCAL MODE

     ENTITY Header

       CREATE FROM lt_header

       CREATE BY \_item FROM lt_item

        MAPPED DATA(lt_item_upd)

        FAILED data(lt_failed)

        REPORTED data(lt_reported).


    mapped-header = lt_item_upd-header.

    mapped-item = lt_item_upd-item.



  ENDMETHOD.








terça-feira, 5 de março de 2024

Eclipse - Testando classes





CLASS ltcl_teste DEFINITION FINAL FOR TESTING

 DURATION SHORT

 RISK LEVEL HARMLESS.

  PRIVATE SECTION.

    METHODS: teste_pedi FOR TESTING RAISING cx_static_check.

    DATA lo_test TYPE REF TO <classe q vai ser testado>.

ENDCLASS.

CLASS ltcl_teste IMPLEMENTATION.

  METHOD teste_pedi.

    <classe>=><método para testart(

    EXPORTING <parametros do método a ser testado>

    CHANGING <parametros do método a ser testado>

    ).

  ENDMETHOD.

ENDCLASS. 

==================== PARA TESTAR A CLASSE ============

CTRL+SHIFT+F10

segunda-feira, 4 de março de 2024

FIORI - Value Help standard úteis



I_PlantStdVH - Centro

C_Materialvh  - Material

I_Customer_VH - Cliente

I_BusinessPartnerCustomerVH = Cliente

I_PurchaseOrgVH - Organização de compra

C_PurchasingGroupValueHelp - Grupo de compradores

C_IncotermsVersionVH - Incoterms

C_StorageLocationVH - Depósito



quinta-feira, 29 de fevereiro de 2024

RAP - Tratar Autorizações para funções especificas

 Deixar como global.











Nesse caso se eu tenho um objeto de autorização para criar/modificar e exibir. Se estiver como exibir eu desativo os botões, no caso tenho o botão standard e outro customizado.

















Pode ser assim tbm.
https://github.com/SAP-samples/abap-platform-rap-opensap/blob/main/week3/unit6.md








































===== EXEMPLO FUNCIONAL USANDO A FORMA DA SAP
-- Detalhe, testando pelo eclipse pelo binding não funciona, somente depois do deploy no ambiente do cliente


METHOD get_instance_authorizations.

    DATA lv_exibir TYPE abap_bool.

    READ ENTITIES OF ZPP_I_OrdensEncFrangoCorte IN LOCAL MODE
     ENTITY OrdemProd ALL FIELDS
     WITH CORRESPONDING #( keys )
     RESULT DATA(lt_ordens) FAILED failed.

    CHECK lt_ordens IS NOT INITIAL.

    LOOP AT lt_ordens INTO DATA(lw_ordens).

      CLEAR lv_exibir.

      AUTHORITY-CHECK OBJECT 'ZPP_ENCFRC'
       ID 'ACTVT' FIELD '02'
       ID 'WERKS' FIELD lw_ordens-werks.

      IF sy-subrc <> 0.

        AUTHORITY-CHECK OBJECT 'ZPP_ENCFRC'
         ID 'ACTVT' FIELD '03'
         ID 'WERKS' FIELD lw_ordens-werks.

        IF sy-subrc <> 0.
          APPEND VALUE #( %tky        = lw_ordens-%tky
                          %msg        = new_message_with_text( severity = if_abap_behv_message=>severity-error
                                        text   = |Sem autorização para centro: { lw_ordens-werks }| )
                        ) TO reported-ordemprod.
        ENDIF.

        lv_exibir = abap_true.

      ENDIF.

      APPEND VALUE #( %tky = lw_ordens-%tky
                      %update = COND #( WHEN lv_exibir = abap_true THEN if_abap_behv=>auth-unauthorized ELSE if_abap_behv=>auth-allowed )
                      %action-ExecOrdem = COND #( WHEN lv_exibir = abap_true THEN if_abap_behv=>auth-unauthorized ELSE if_abap_behv=>auth-allowed )
                      %action-refreshTela = COND #( WHEN lv_exibir = abap_true THEN if_abap_behv=>auth-unauthorized ELSE if_abap_behv=>auth-allowed )
                ) TO result.

    ENDLOOP.

  ENDMETHOD.









RAP - Desabilitando campos no object page nos eventos CREATE/UPDATE

 Na verdade testei somente no UPDATE mas acho q funcion no CREATE tbm.

A validação de dados de entrada não é feito qdo se clica no botão de update, é feita antes.. eu me bati um monte para fazer essa validação












sábado, 17 de fevereiro de 2024

RAP - Facets(Object list page) - Várias formas

 Adicionando campos no cabeçalho.



Resultado











========================================

Adionando abas 




Resultado



















=================================
Adicionando outra lista no object pages
- Primeiro passo criar uma entidade da lista que vai ser criado, no meu caso os impostos de um item da NF

@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Impostos '
define root view entity ZI_Impostos
  as select from I_BR_NFTax

{

  key BR_NotaFiscal               as Docnum,
  key BR_NotaFiscalItem           as Itmnum,
  key BR_TaxType                  as Taxtype,
  key TaxGroup                    as TaxGrp,
      @Semantics.amount.currencyCode: 'Currency'
      BR_NFItemBaseAmount         as Base,
      BR_NFItemTaxRate            as Rate,
      @Semantics.amount.currencyCode: 'Currency'
      BR_NFItemTaxAmount          as TaxValue,
      BR_NFItemExcludedBaseAmount as ExcBase,
      @Semantics.amount.currencyCode: 'Currency'
      BR_NFItemOtherBaseAmount    as OthBas,
      SalesDocumentCurrency       as Currency

}

Criei uma projection view tbm mas não sei se é necessário

@EndUserText.label: 'Impostos da Nota Fiscal Importação (Projection)'
@AccessControl.authorizationCheck: #NOT_REQUIRED
@Metadata.allowExtensions: true
define root view entity ZC_Impostos
  provider contract transactional_query
  as projection on ZI_Impostos
{
  key Docnum,
  key Itmnum,
  key Taxtype,
  key TaxGrp,
      Base,
      Rate,
      TaxValue,
      ExcBase,
      OthBas,
      Currency
}

Criei um METADATA
@Metadata.layer: #CORE
annotate entity ZC_Impostos with
{
  @UI:{ lineItem: [{ position: 10 }] }
  @EndUserText.label: 'Tipo Imposto'
  Taxtype;
  @UI:{ lineItem: [{ position: 20 }] }
  @EndUserText.label: 'Grupo Imposto'
  TaxGrp;
  @UI:{ lineItem: [{ position: 30 }] }
  @EndUserText.label: 'Base'
  Base;
  @UI:{ lineItem: [{ position: 40 }] }
  @EndUserText.label: 'Taxa'
  Rate;
  @UI:{ lineItem: [{ position: 50 }] }
  @EndUserText.label: 'Valor Imposto'
  TaxValue;
  @UI:{ lineItem: [{ position: 60 }] }
  @EndUserText.label: 'Base excluída'
  ExcBase;
  @UI:{ lineItem: [{ position: 70 }] }
  @EndUserText.label: 'Outras Bases'
  OthBas;
  @UI:{ lineItem: [{ position: 80 }] }
    @EndUserText.label: 'Moeda'
  Currency;

}

Fiz a associação a minha projection principal 
@EndUserText.label: 'Dados gestão importação (projection)'
@AccessControl.authorizationCheck: #NOT_REQUIRED
@Metadata.allowExtensions: true
define root view entity ZC_DadosGestaoImportacao
  provider contract transactional_query
  as projection on ZI_DadosGestaoImportacao
  association [0..*] to ZC_Impostos as _ImpList on $projection.docnum = _ImpList.Docnum
                                                     and $projection.itmnum = _ImpList.Itmnum  

{
  key zuonr,
  key belnr,
  key gjahr,
  key buzei,
      bldat,
      budat,
      usnam,
      xblnr,
      bukrs,
      --@ObjectModel.foreignKey.association: '_Lfa1'
      @ObjectModel.text.element: ['NomeFornecedor']
      lifnr,
      waers,

      _ImpList
    
No METADATA principal criei o facet para associação
-- TAB dados Impostos
  {
      id: 'Impostos',
      purpose: #STANDARD,
      type: #LINEITEM_REFERENCE,
      label: 'Impostos',
      position: 50,
      targetElement: '_ImpList'

  }
  ]

E não esquecer de adicionar a entidade no SERVICE DEFINITION
@EndUserText.label: 'Dados de Gestao de importação'
define service ZSD_DadosGestaoImportacao {
  expose ZC_DadosGestaoImportacao;
  expose ZC_Impostos;
}

Resultado















segunda-feira, 12 de fevereiro de 2024

Collect usando FOR IN GROUPS

Código exemplo abaixo, pegando dados de remessa

sELECT likp~vbeln,

       likp~ernam,

       lips~matnr,
       lips~lfimg
  INTO TABLE @DATA(lt_likp)

  FROM likp INNER JOIN lips ON lips~vbeln = likp~vbeln
 WHERE likp~lfart = 'ZVME'.

"Criar estrutura que quer fazer a somatória
TYPES: BEGIN OF ty_rem,
         matnr TYPE lips-matnr,
         lfimg TYPE lips-lfimg,
       END OF ty_rem.

TYPES ty_t_rem TYPE TABLE OF ty_rem WITH DEFAULT KEY.

DATA w_lips TYPE ty_rem.

BREAK-POINT.

DATA(lt_lips) = VALUE ty_t_rem( FOR GROUPS w_lips_x OF <ls_collect> IN lt_likp
                     GROUP BY ( matnr = <ls_collect>-matnr )
                     LET coll_line = REDUCE #( INIT ls_sum TYPE ty_rem
                                                      FOR ls_sum_likp IN GROUP w_lips_x
                                                        NEXT ls_sum-lfimg = ls_sum-lfimg + ls_sum_likp-lfimg
                                                             ls_sum-matnr = ls_sum_likp-matnr
                                                        ) IN ( coll_line ) ).
BREAK-POINT.

segunda-feira, 5 de fevereiro de 2024

Leitura de dados de estrutura BOPF

 Transações importantes

BOBX - Estruturas dos BOPF

BOBT - Teste de estrutura BOPF

Ex: /SCMTMS/TOR

Transação BOBX

- Clicar na estrutura desejada








BOBT - teste de query

Do lado esquerdo na BOBT tem as queries disponíveis.

Do lado direito na BOBX a localização das querys disponíveis na visão de estrutura

















Pegando exemplo de dados da remessa na query PLANNING_ATTRIBUTES

Registros encontrados





Fazendo pelo código do programa

"Service Manager
DATA(lo_srv_mgr/bobf/cl_tra_serv_mgr_factory=>get_service_manager/SCMTMS/IF_TOR_C=>sc_bo_key ).

DATA(lv_bo_name/SCMTMS/IF_TOR_C=>sc_bo_name.

data(lv_attname=  /SCMTMS/IF_TOR_C=>sc_query_attribute-root-planning_attributes-trq_base_btd_id.

*"Selection Parameters
DATA(lt_selparVALUE /bobf/t_frw_query_selparamattribute_name lv_attname
                                                      sign 'I'
                                                      option 'EQ'
                                                      low '0080000180' ).

*"Query key

data lt_key TYPE /BOBF/T_FRW_KEY.
data lt_docref type /scmtms/t_tor_root_k.

"Execução da query
lo_srv_mgr->queryEXPORTING iv_query_key /scmtms/if_tor_c=>sc_query-root-planning_attributes
                             "it_filter_key =
                             it_selection_parameters lt_selpar
                             "is_query_options =
                             iv_fill_data abap_true
                             "it_requested_attributes =
                   IMPORTING "eo_message = DATA(lo_message)
                      et_key lt_key
                      et_data lt_docref
                      ).


====== Abaixo de onde vem as informações na BOBX











====== Para ler os dados da estrutura abaixo do ROOT.

Transação BOBT













=========  Código ==========

Como faz parte da estrutura ROOT pega os dados a partir das chaves retornadas da leitura do root

DELETE lt_key WHERE key not in lt_r_key.

data lt_doc_tr type /SCMTMS/T_TOR_ITEM_TR_K.

  lo_srv_mgr->retrieve_by_association(
      EXPORTING
        iv_node_key             /scmtms/if_tor_c=>sc_node-root
        it_key                  lt_key                             " Key Table
        iv_edit_mode            /bobf/if_conf_c=>sc_edit_read_only " Change Mode
        iv_fill_data            abap_true                          " Data element for domain BOOLE: TRUE (='X') and FALSE (=' ')
        iv_association /scmtms/if_tor_c=>sc_association-root-item_tr_main
      IMPORTING
        "eo_message              = lo_message                         " Interface of Message Object
        et_data                 lt_doc_tr
        et_failed_key           DATA(lt_failed_key)                " Key Table
    ).










E assim sucessivamente, com outras estruturas sob o mesmo nó

data lt_doc_tr_seal type /SCMTMS/T_TOR_SEAL_K.

  lo_srv_mgr->retrieve_by_association(
      EXPORTING
        iv_node_key             /scmtms/if_tor_c=>sc_node-root
        it_key                  lt_key                             " Key Table
        iv_edit_mode            /bobf/if_conf_c=>sc_edit_read_only " Change Mode
        iv_fill_data            abap_true                          " Data element for domain BOOLE: TRUE (='X') and FALSE (=' ')
        iv_association /scmtms/if_tor_c=>sc_association-root-seal
      IMPORTING
        "eo_message              = lo_message                         " Interface of Message Object
        et_data                 lt_doc_tr_seal
        et_failed_key           lt_failed_key                " Key Table
    ).

data lt_doc_tr_item type /SCMTMS/T_TOR_ITEM_TR_K.

  lo_srv_mgr->retrieve_by_association(
      EXPORTING
        iv_node_key             /scmtms/if_tor_c=>sc_node-root
        it_key                  lt_key                             " Key Table
        iv_edit_mode            /bobf/if_conf_c=>sc_edit_read_only " Change Mode
        iv_fill_data            abap_true                          " Data element for domain BOOLE: TRUE (='X') and FALSE (=' ')
        iv_association /scmtms/if_tor_c=>sc_association-root-item_tr
      IMPORTING
        "eo_message              = lo_message                         " Interface of Message Object
        et_data                 lt_doc_tr_item
        et_failed_key           lt_failed_key                " Key Table
    ).