CLASS {{p}}freight_calculator DEFINITION PUBLIC FINAL CREATE PUBLIC. PUBLIC SECTION. TYPES: BEGIN OF ty_result, status TYPE c LENGTH 10, base TYPE p LENGTH 9 DECIMALS 2, surcharge TYPE p LENGTH 9 DECIMALS 2, total TYPE p LENGTH 9 DECIMALS 2, END OF ty_result. CONSTANTS: BEGIN OF c_status, ok TYPE c LENGTH 10 VALUE 'OK', weight TYPE c LENGTH 10 VALUE 'WEIGHT', zone TYPE c LENGTH 10 VALUE 'ZONE', END OF c_status. METHODS calculate IMPORTING iv_weight_kg TYPE p LENGTH 8 DECIMALS 2 iv_zone TYPE string iv_express TYPE abap_bool DEFAULT abap_false RETURNING VALUE(rs_result) TYPE ty_result. METHODS is_zone_supported IMPORTING iv_zone TYPE string RETURNING VALUE(rv_supported) TYPE abap_bool. PRIVATE SECTION. TYPES: BEGIN OF ty_rate, zone TYPE c LENGTH 2, rate TYPE p LENGTH 6 DECIMALS 2, END OF ty_rate, tt_rate TYPE HASHED TABLE OF ty_rate WITH UNIQUE KEY zone. CONSTANTS c_express_share TYPE p LENGTH 5 DECIMALS 2 VALUE '0.25'. METHODS normalize_zone IMPORTING iv_zone TYPE string RETURNING VALUE(rv_zone) TYPE string. METHODS rates RETURNING VALUE(rt_rate) TYPE tt_rate. METHODS rate_for_zone IMPORTING iv_zone TYPE string RETURNING VALUE(rv_rate) TYPE p LENGTH 6 DECIMALS 2. METHODS empty_result IMPORTING iv_status TYPE c LENGTH 10 RETURNING VALUE(rs_result) TYPE ty_result. METHODS base_amount IMPORTING iv_rate TYPE p LENGTH 6 DECIMALS 2 iv_weight_kg TYPE p LENGTH 8 DECIMALS 2 RETURNING VALUE(rv_base) TYPE p LENGTH 9 DECIMALS 2. METHODS surcharge_amount IMPORTING iv_base TYPE p LENGTH 9 DECIMALS 2 iv_express TYPE abap_bool RETURNING VALUE(rv_surcharge) TYPE p LENGTH 9 DECIMALS 2. ENDCLASS. CLASS {{p}}freight_calculator IMPLEMENTATION. METHOD calculate. DATA(lv_zone) = normalize_zone( iv_zone ). IF iv_weight_kg <= 0. rs_result = empty_result( c_status-weight ). RETURN. ENDIF. IF is_zone_supported( lv_zone ) = abap_false. rs_result = empty_result( c_status-zone ). RETURN. ENDIF. rs_result-base = base_amount( iv_rate = rate_for_zone( lv_zone ) iv_weight_kg = iv_weight_kg ). rs_result-surcharge = surcharge_amount( iv_base = rs_result-base iv_express = iv_express ). rs_result-total = rs_result-base + rs_result-surcharge. rs_result-status = c_status-ok. ENDMETHOD. METHOD is_zone_supported. DATA(lv_zone) = normalize_zone( iv_zone ). DATA(lt_rate) = rates( ). rv_supported = xsdbool( line_exists( lt_rate[ zone = lv_zone ] ) ). ENDMETHOD. METHOD normalize_zone. rv_zone = to_upper( replace( val = iv_zone sub = ` ` with = `` occ = 0 ) ). ENDMETHOD. METHOD rates. rt_rate = VALUE #( ( zone = 'DE' rate = '4.50' ) ( zone = 'AT' rate = '5.20' ) ( zone = 'CH' rate = '7.80' ) ( zone = 'FR' rate = '6.40' ) ( zone = 'NL' rate = '4.90' ) ( zone = 'PL' rate = '5.10' ) ( zone = 'ES' rate = '6.90' ) ). ENDMETHOD. METHOD rate_for_zone. DATA(lt_rate) = rates( ). READ TABLE lt_rate WITH TABLE KEY zone = iv_zone INTO DATA(ls_rate). rv_rate = ls_rate-rate. ENDMETHOD. METHOD empty_result. rs_result = VALUE #( status = iv_status ). ENDMETHOD. METHOD base_amount. DATA lv_amount TYPE p LENGTH 13 DECIMALS 4. lv_amount = iv_rate * iv_weight_kg. rv_base = round( val = lv_amount dec = 2 ). ENDMETHOD. METHOD surcharge_amount. IF iv_express = abap_false. RETURN. ENDIF. DATA lv_amount TYPE p LENGTH 13 DECIMALS 4. lv_amount = iv_base * c_express_share. rv_surcharge = round( val = lv_amount dec = 2 ). ENDMETHOD. ENDCLASS.