manuelroemer/abap-lab-ss23-csrd

User Story: Create the Form Schema API

Opened this issue · 1 comments

Description

As a user, I want the application to automatically use the newest CSRD report version. To achieve this, the frontend must be able to fetch the schemas from the backend.

This will be made possible via an OData service that provides a FormSchemaSet entity that has the following attributes:

  • Id: string - a GUID
  • Type: string - a unique type of the schema, e.g., "csrd"
  • Version: number - e.g., 1, 2, ... Autoincremented.
  • SchemaJson: string - the form schema, formatted as JSON string
  • MetadataJson?: string - arbitrary metadata used by the frontend, formatted as JSON string
  • CreatedAt: string - the creation date
  • UpdatedAt: string - the last modified date

The OData service must provide the following conceptual endpoints (the URLs might vary):

  • GET /FormSchemaSet('name') - to get schemas by name
  • GET /FormSchemaSet('id') - to get schemas by ID

Acceptance Criteria

  • The OData service is functional
  • The corresponding database tables exist
  • The new endpoint is configured in the Postman collection (if present, see #16)

Additional Information

None.

Done. ABAP code of this initial version (for reference and for the sake of backups - we really need a better way to organize this):

CLASS zcl_z_00_t1_ss23_csrd_dpc_ext DEFINITION
  PUBLIC
  INHERITING FROM zcl_z_00_t1_ss23_csrd_dpc
  CREATE PUBLIC .

  PUBLIC SECTION.
  PROTECTED SECTION.
    METHODS formschemaset_get_entityset REDEFINITION.
    METHODS formschemaset_get_entity REDEFINITION.
    METHODS formschemaset_create_entity REDEFINITION.
    METHODS formschemaset_update_entity REDEFINITION.
    METHODS formschemaset_delete_entity REDEFINITION.

  PRIVATE SECTION.
    METHODS get_key
      IMPORTING
        !it_key_tab   TYPE /iwbep/t_mgw_name_value_pair
        key           TYPE string
      RETURNING
        VALUE(result) TYPE string.

    METHODS find_current_version
      IMPORTING
        type TYPE z00t1_sstring
      RETURNING VALUE(result) TYPE int4.
ENDCLASS.



CLASS zcl_z_00_t1_ss23_csrd_dpc_ext IMPLEMENTATION.
  METHOD formschemaset_get_entityset.
    DATA(filter) = io_tech_request_context->get_osql_where_clause(  ).

    SELECT id, createdAt, updatedAt, type, version, isDraft
    FROM z00t1_fschema
    WHERE (filter)
    ORDER BY type, updatedat
    INTO CORRESPONDING FIELDS OF TABLE @et_entityset.
  ENDMETHOD.

  METHOD formschemaset_get_entity.
    DATA(id) = get_key( it_key_tab = it_key_tab key = 'Id' ).

    SELECT SINGLE *
    FROM z00t1_fschema
    WHERE id = @id
    INTO @er_entity.
  ENDMETHOD.

  METHOD formschemaset_create_entity.
    io_data_provider->read_entry_data( IMPORTING es_data = er_entity ).
    GET TIME STAMP FIELD DATA(now).

    er_entity-mandt = sy-mandt.
    er_entity-id = cl_system_uuid=>create_uuid_c36_static( ).
    er_entity-createdat = now.
    er_entity-updatedat = now.

    IF er_entity-isdraft = abap_true.
      " Draft schemas always have a version of -1.
      " Once undrafted, they are assigned a real version number.
      er_entity-version = -1.
    ELSE.
      " Otherwise the version is auto-calculated to overwrite the current highest version.
      " Also explicitly reassign `isDraft` because the gateway, for whatever reason, allows null here.
      er_entity-isdraft = abap_false.
      er_entity-version = find_current_version( type = er_entity-type ) + 1.
    ENDIF.

    INSERT z00t1_fschema FROM er_entity.
  ENDMETHOD.

  METHOD formschemaset_update_entity.
    io_data_provider->read_entry_data( IMPORTING es_data = er_entity ).
    DATA(id) = get_key( it_key_tab = it_key_tab key = 'Id' ).

    " It's only possible to update the JSON schema of draft form schema entities.
    " Others are immutable.
    UPDATE z00t1_fschema
    SET schemajson = @er_entity-schemajson
    WHERE id = @id AND
          isdraft = @abap_true.

    " It IS possible to update some other properties of every form schema, even if undrafted.
    UPDATE z00t1_fschema
    SET metadatajson = @er_entity-metadatajson
    WHERE id = @id.

    " It's only possible to undraft schemas.
    " Once they are undrafted, that state cannot be reverted.
    DATA(nextVersion) = find_current_version( type = er_entity-type ) + 1.

    UPDATE z00t1_fschema
    SET isdraft = @abap_false,
        version = @nextVersion
    WHERE id = @id AND
          isdraft = @abap_true AND
          @er_entity-isdraft = @abap_false.

    " Finally, update `updatedAt`. Yes, this could have done in one of the above queries,
    " but muh separation of concerns :^).
    GET TIME STAMP FIELD DATA(now).

    UPDATE z00t1_fschema
    SET updatedat = @now
    WHERE id = @id.
  ENDMETHOD.

  METHOD formschemaset_delete_entity.
    DATA(id) = get_key( it_key_tab = it_key_tab  key = 'Id' ).
    DELETE FROM z00t1_fschema WHERE id = @id.
    DELETE FROM z00t1_fschemares WHERE formschemaid = @id.
  ENDMETHOD.

  METHOD find_current_version.
    SELECT MAX( version )
    FROM z00t1_fschema
    WHERE type = @type
    INTO @result.
  ENDMETHOD.

  METHOD get_key.
    DATA kvp TYPE /iwbep/s_mgw_name_value_pair.
    READ TABLE it_key_tab INTO kvp WITH KEY name = key.
    result = kvp-value.
  ENDMETHOD.
ENDCLASS.

Postman Collection was updated:
Image

Tables:

@EndUserText.label : 'Form Schemas of the CSRD application'
@AbapCatalog.enhancementCategory : #EXTENSIBLE_ANY
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #ALLOWED
define table z00t1_fschema {
  key mandt    : mandt not null;
  key id       : sysuuid_c36 not null;
  type         : z00t1_sstring not null;
  @EndUserText.label : 'The actual schema, as JSON'
  schemajson   : abap.string(0);
  @EndUserText.label : 'Arbitrary metadata to be used by the frontend, as JSON'
  metadatajson : abap.string(0);
  createdat    : timestamp not null;
  updatedat    : timestamp not null;
  @EndUserText.label : 'A version identifier, used to identify breaking changes'
  version      : abap.int4 not null;
  isdraft      : abap_boolean not null;
}

@EndUserText.label : 'Form Schema Results of the CSRD'
@AbapCatalog.enhancementCategory : #EXTENSIBLE_ANY
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #ALLOWED
define table z00t1_fschemares {
  key mandt    : mandt not null;
  key id       : sysuuid_c36 not null;
  @AbapCatalog.foreignKey.screenCheck : true
  formschemaid : sysuuid_c36
    with foreign key z00t1_fschema
      where mandt = z00t1_fschemares.mandt
        and id = z00t1_fschemares.formschemaid;
}